Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Emulating Axis Mode

    Scheduled Pinned Locked Moved PYTHON Development
    7 Posts 0 Posters 759 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      Helper
      last edited by

      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

      .

      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.

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        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

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          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)))

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            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

            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              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.

              1 Reply Last reply Reply Quote 0
              • H Offline
                Helper
                last edited by

                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

                1 Reply Last reply Reply Quote 0
                • H Offline
                  Helper
                  last edited by

                  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://developers.maxon.net/forum/topic/6725/7361_object-axis-modification-in-python

                  1 Reply Last reply Reply Quote 0
                  • First post
                    Last post