How to calculate positions, like it was a child



  • On 08/01/2014 at 16:18, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   13,14,15 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Hi, I am trying to build up a repertoire of code for moving object in the global 3D space.
    I do this partly because I need it, and also because it helps me understand what really goes on inside C4D.

    I found out that I can use this, in order to position one object between two other objects, in 3D space.

            Matrix mA = cubeA->GetMg();
            Matrix mB = cubeB->GetMg();
            Matrix mMid = cubeMid->GetMg();
            Vector vMidPos = (mA.off + mB.off) / 2;
            mMid.off = vMidPos;
            cubeMid->SetMg(mMid);
     
    

    Anyone seeing any flaws int this code, please correct it!
    Now, as I said, I want to make a whole library of such related functions, so I have two questions now:

    1. Does such a collection / library of these kind of functions exist?
    2. One actual function I need:
      How do I position objectB in global space when objectA is moved / rotated in global space? As if objectB was a child of objectA (but it is not). I would really like a piece of code for this particular case.

    I have experimented with matrices and added, subtracted, multiplied and inverted them, but it is more of pure luck that my code works, that of knowledge about what really goes on. And I am familiar with Quaternions, I love them, so to say.



  • On 09/01/2014 at 12:49, xxxxxxxx wrote:

    Anyone on this? My question 1) or 2)?
    It is not so much about achieving a certain specific task, as it is for me to understand how objects can be moved and "assessed" int the Cinema 4D 3D space.



  • On 13/01/2014 at 10:24, xxxxxxxx wrote:

    Hi, I can't speak to number 1, and there's are much better programmers than me on these forums, but for number 2 I can try.  It's in python, should just be syntax differences though, I can do a c++ version later, didn't have time right now.

      
      
      #parentobject  is the  'parent' object  
      #childobject is the 'child' object  
        
      #currentmatrix is the matrix of the 'child' before it's parent has been taken into account  
      startingpos = currentmatrix.off  
      parentmatrix = parentobject.GetMg()  
      childmatrix = childobject.GetMg()  
      
      #Gets rid of the offset to get the new posistion after taking the rotation of the parent into account  
      parentmatrixnooffset=parentobject.GetMg()  
      parentmatrixnooffset.off = c4d.Vector()  
      startingpos *=parentmatrixnooffset  
        
      #The new rotation of the child  
      childmatrix=parentmatrix*currentmatrix  
      
      #The new posistion of the object  
      childmatrix.off = parentmatrix.off+startingpos  
        
      childobject.SetMg(childmatrix)  
    

    I hope that helps.
    Dan



  • On 13/01/2014 at 18:30, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Hi, I can't speak to number 1, and there's are much better programmers than me on these forums

    Yes, there are good programmers here, who have a "3D head". Actually, I make a living, programming, but not in 3D. My challenge is to understand how objects move in the C4D 3D space. When I have come that far, understanding this, I assume the current task we discuss here would be child's play.

    I have tried to write your Python code in C++, but what I ended up with does not work. There are several things that are unclear to me, see my comments. I would really appreciate if you , or anyone else for that matter, would look into it and contribute, to make this code work!

            //parentobject  is the  'parent' object
            //childobject is the 'child' object
        
            //currentmatrix is the matrix of the 'child' before it's parent has been taken into account
            **// Am I doing it right here?**
    	Matrix currentmatrix = childobject->GetMg();
            Vector startingpos = currentmatrix.off;
            
            Matrix parentmatrix = parentobject->GetMg();
            Matrix childmatrix = childobject->GetMg();
      
            //Gets rid of the offset to get the new posistion after taking the rotation 
    	//of the parent into account
            Matrix parentmatrixnooffset = parentobject->GetMg();
            
    	 **// I assume this is what you want with your Python code?**
    	parentmatrixnooffset.off = Vector(0);
            startingpos *= parentmatrixnooffset;
        
            //The new rotation of the child
            childmatrix = parentmatrix * currentmatrix;
      
            //The new posistion of the object
            childmatrix.off = parentmatrix.off + startingpos;
        
            childobject->SetMg(childmatrix);
    

    There is something fundamentally wrong here, do you intend to pass the matrix  currentmatrix  as a function argument?



  • On 14/01/2014 at 08:59, xxxxxxxx wrote:

    Hi,

    I'm just starting to get the hang of the 3D space myself.  Everything looks fine in your except for:

      
        
        
          
         **// Am I doing it right here?  
        ** Matrix currentmatrix = childobject->GetMg();
    

    I explained it poorly.  I'm not sure how you're currently using this, in a command plugin, so it's a one shot or if it's continuously being called and updated.

    If you using this code then the distance between the parent and child keep getting added together.  Everytime you call it the child will likely move in more and more extreme ways.

    You want currentmatrix to be the beginning matrix of the child before it's been moved to be relative to the parent.  This won't be changed or updated unless you want to change the relative position of the child.  If that makes sense, I don't know how else to explain it without knowing the context of where you're using it.

    I also just realized that I might be trying to do something different than you wanted.  What my code should do is if you have the two objects in a scene and hit the button, it will move the child into a position rotation relative to the parent, as if the parent had had no change in position and rotation and then was changed to it's current position with the child underneath it.

    Sorry if that all is confusing.

    Dan



  • On 15/01/2014 at 09:21, xxxxxxxx wrote:

    Here is code that works! This is what I needed, to rotate as a child.
    However, it does not move as a child, so it has to be refined.
    I have also added comments on parts I do not understand fully.

        void RotateAsChild(GeListNode* node, BaseObject* parentobject
            , BaseObject* childobject, Bool &positionRegistered, Matrix &currentmatrix)
        {
        	if(!parentobject || !childobject)
        		return;
            if(!positionRegistered)
        	{
        		currentmatrix = childobject->GetMg();
        		positionRegistered = TRUE;
        	}
            Vector startingpos = currentmatrix.off - parentobject->GetMg().off;
      		
        	Matrix parentmatrix = parentobject->GetMg();
        	Matrix childmatrix = childobject->GetMg();
        	
        	//Gets rid of the offset to get the new posistion after taking the rotation
        	//of the parent into account
        	Matrix parentmatrixnooffset = parentobject->GetMg();
        	
        	// I assume this is what you want with your Python code?
        	parentmatrixnooffset.off = Vector(0);
        	// What is happening here a)
            startingpos *= parentmatrixnooffset;
        	
        	//The new rotation of the child
        	// What is happening here b)
        	childmatrix = parentmatrix * currentmatrix;
        	
        	//The new posistion of the object
        	childmatrix.off = parentmatrix.off + startingpos;
        	
        	childobject->SetMg(childmatrix);
        }
    

    And then sample code for testing this:

        Matrix mCurrent;
        Bool posReg; 
        void TestRotateAsChild(GeListNode* node, BaseDocument* doc)
        {
        	BaseObject* parentobject = doc->SearchObject("parentobject");
        	BaseObject* childobject = doc->SearchObject("childobject");
        	if(!parentobject || !childobject)
        		return;
        	BaseObject* obj = doc->GetActiveObject();
            if(obj != parentobject)
        	{
        		posReg = FALSE;
        		return;
        	}
            RotateAsChild(node, parentobject, childobject, posReg, mCurrent);
        }
    

    I hope this can be useful to more than me! I spent a lot of time to make this work, and am glad that I got this help here. Much more than this, I wish there was a common library for functions like this, that we could build up together. And save us a lot of time.

    If Dan or someone else can extend the code above so that it not only rotates as a child, but also moves as a child - fine! (It can be done in a separate function I think).



  • On 15/01/2014 at 22:04, xxxxxxxx wrote:

    Hi folks, here is code that works, I finally made it. I wonder if some experienced guys, perhaps in the Maxon R&D, are snig gering behind my back, watching me when I try to achieve something that is pretty basic to them :)

        void PositionAsChild(GeListNode* node, BaseObject* parentObject
            , BaseObject* childObject, Matrix startMatrix, Vector startPosition)
        {
        	if(!parentObject || !childObject)
        		return;
      
        	Matrix parentMatrix = parentObject->GetMg();
        	Matrix childMatrix = childObject->GetMg();
        	
        	//Gets rid of the offset to get the new posistion after taking the rotation
        	//of the parent into account
        	Matrix parentMatrixNoOffset = parentObject->GetMg();
        	parentMatrixNoOffset.off = Vector(0);
        	////////////////////////////////
      
            Vector calculatedStartPosition = startPosition;
            
            // What is this
            calculatedStartPosition *= parentMatrixNoOffset;
        	
        	childMatrix = parentMatrix * startMatrix;
        	
        	//The new posistion of the object
        	childMatrix.off = parentMatrix.off + calculatedStartPosition;
        	childObject->SetMg(childMatrix);
        }
    

    This works both for rotation and for movements (translation).
    The clue here is to store the Matrix startMatrix, and the Vector startPosition.
    They have to be stored somewhere, because everything is calculated based on these start values. If the Child object is being moved, startMatrix and startPosition have to be reset calcuated) to new values. Like this:

                startMatrix = childObject->GetMg();
                startPosition = startMatrix.off - parentObject->GetMg().off;
    

    I hope this will be useful to others, one day one will search the forum and find this. I need it in my plugins, and spent a lot of time figering it out.
    The one thing I do not understand (yet) is this:  calculatedStartPosition *= parentMatrixNoOffset;
    A Vector multiplied / added with a Matrix.

    Anyone like to comment on this? Dan, are you there? Without your help, I would never have made it!


Log in to reply