Emulating Axis Mode



  • On 27/03/2013 at 04:54, xxxxxxxx wrote:

    Matrix maths is still not my favorite topic. 🙂
    I can't get this to work properly. I want to emulate the Axis Mode in Cinema, a function that
    moves the object's axis to a specific point (and rotation) without changing the polygon-object's
    points and children's global position (and rotation). It won't work properly, see this video.

    Can someone pls point out what's wrong or maybe even explain how to do it?
    Thanks!

    >
    > import c4d
    >
    > def move_axis(obj, new_matrix=c4d.Matrix()) :
    > mat = obj.GetMl() * new_matrix
    > if obj.CheckType(c4d.Opoint) :
    > points = obj.GetAllPoints()
    > for i, p in enumerate(points) :
    > obj.SetPoint(i, p * mat)
    > obj.Message(c4d.MSG_UPDATE)
    >
    > for child in obj.GetChildren() :
    > child.SetMl(child.GetMl() * mat)
    >
    > obj.SetMl(new_matrix)
    >
    > def main() :
    > if not op:
    > return
    >
    > doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
    > move_axis(op)
    > c4d.EventAdd()
    >
    > main()
    ~~
    ~~
    Edit: Video comes in a few seconds.



  • On 27/03/2013 at 05:00, xxxxxxxx wrote:

    Interesting. I just switched the matrices that are to be multiplied for the children and it seems to
    work. Isn't the order un-important for matrix multiplication?

    >
    > import c4d
    >
    > def move_axis(obj, new_matrix=c4d.Matrix()) :
    > mat = obj.GetMl() * new_matrix
    > if obj.CheckType(c4d.Opoint) :
    > points = obj.GetAllPoints()
    > for i, p in enumerate(points) :
    > obj.SetPoint(i, p * mat)
    > obj.Message(c4d.MSG_UPDATE)
    >
    > for child in obj.GetChildren() : child.SetMl(mat * child.GetMl())
    >
    > obj.SetMl(new_matrix)
    >
    > def main() :
    > if not op:
    > return
    >
    > doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
    > move_axis(op)
    > c4d.EventAdd()
    >
    > main()

    Thanks,
    -Niklas



  • On 27/03/2013 at 05:09, xxxxxxxx wrote:

    Hm it still doesn't work when moving the axis to another position but the origin:

    >     move_axis(op, c4d.Matrix(off=c4d.Vector(100)))



  • On 27/03/2013 at 05:29, xxxxxxxx wrote:

    This seems to work:

    >
    > import c4d
    >
    > def move_axis(obj, new_matrix=c4d.Matrix()) :
    > mat = obj.GetMl() * ~ new_matrix
    > if obj.CheckType(c4d.Opoint) :
    > points = obj.GetAllPoints()
    > for i, p in enumerate(points) :
    > obj.SetPoint(i, p * mat)
    > obj.Message(c4d.MSG_UPDATE)
    >
    > for child in obj.GetChildren() :
    > child.SetMl(mat * child.GetMl())
    > obj.SetMl(new_matrix)
    >
    > def main() :
    > if not op:
    > return
    >
    > doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
    > move_axis(op, c4d.Matrix(off=c4d.Vector(100)))
    > c4d.EventAdd()
    >
    > main()

    Any reasons why this should not work?

    Btw, I'm aware that saving the global matrix, then offseting the parent object and then
    resetting the children to their previous global matrix works as well, but it is much less performant.

    >
    > def move_axis(obj, new_matrix=c4d.Matrix()) :
    > mat = obj.GetMl() * ~new_matrix
    > if obj.CheckType(c4d.Opoint) :
    > points = obj.GetAllPoints()
    > for i, p in enumerate(points) :
    > obj.SetPoint(i, p * mat)
    > obj.Message(c4d.MSG_UPDATE)
    >
    > children = obj.GetChildren()
    > matrices = [x.GetMg() for x in children]
    > obj.SetMl(new_matrix)
    > [x.SetMg(m) for x, m in zip(children, matrices)]

    -Niklas



  • On 27/03/2013 at 06:08, xxxxxxxx wrote:

    Damn Matrix Maths! 😂

    New version, just switched operands. I'll try to find some information about matrix multiplication..

    >
    > def move_axis(obj, new_matrix=c4d.Matrix()) :
    > mat = ~new_matrix * obj.GetMl()
    > if obj.CheckType(c4d.Opoint) :
    > points = obj.GetAllPoints()
    > for i, p in enumerate(points) :
    > obj.SetPoint(i, p * mat)
    > obj.Message(c4d.MSG_UPDATE)
    >
    > for child in obj.GetChildren() :
    > child.SetMl(mat * child.GetMl())
    > obj.SetMl(new_matrix)

    Pretty sure this won't work in all cases, again.

    PS: The changed line above must also be adjusted for the other way when storing the childrens
    matrix before changing the objects matrix.



  • On 27/03/2013 at 08:16, xxxxxxxx wrote:

    I'm puzzled why you are using local matrices throughout your code?

    I don't have an example of moving just the axis handy. But I do have an example of moving the parent object without moving it's children.
    It's in C++. But i think you can handle that:

    //Freeze Children  
    //This code allows the parent object to move without moving it's children  
      
    Bool MenuTest::Execute(BaseDocument *doc)  
    {  
      BaseDocument *doc = GetActiveDocument();  //Get the active document  
      BaseObject *obj = doc->GetActiveObject(); //Get the active object  
      if(!obj)return FALSE;  
      
      Matrix mg_old = obj->GetMg();             //Save the parent's old matrix  
      
      Matrix mg_new;                            //This will be the parent's new matrix - set it to your liking(world Zero by default)  
      obj->SetMg(mg_new);                       //Apply the new matrix to the parent object  
      obj->Message(MSG_UPDATE);  
      
      mg_new != mg_new;                         //Invert new matrix - needed later  
      
      //Cycle through children  
      for (obj = obj->GetDown(); obj; obj = obj->GetNext())  
      {  
          Matrix ml_child = obj->GetMl();    //Get child's local matrix  
      
          //Bring it into the child's old global space by multiplying  
          //with the parent's old global matrix  
          Matrix mg_old_child = mg_old * ml_child;  
      
          //Set the child's new local matrix by multiplying  
          //with the parent's inverted new global matrix  
          obj->SetMl(mg_new * mg_old_child);  
          obj->Message(MSG_UPDATE);  
      }  
      
      EventAdd();  
      
      return TRUE;  
    }
    

    -ScottA



  • On 28/03/2013 at 15:05, xxxxxxxx wrote:

    Some time ago I asked the question "I have e.g. a plane I want to rotate, not from the center, but from a specific side. So, I need to change the object axis."

    Cesar did help me with the following:
    "I think you can do it by change the position of the object and all his points to keep their global position."

    He also provided some code that worked well for me.
    Perhaps it is of interest for you.

    See this post https://plugincafe.maxon.net/topic/6725/7361_object-axis-modification-in-python


Log in to reply