Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware 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

    Move just the axis of a polygonal object

    General Talk
    3
    10
    2.0k
    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.
    • R
      rui_mac
      last edited by

      I have a list with all the coordinates of the vertexes of a polygonal object, all in global coordinates, that I got with:

      op_mg = child.GetMg()
      points = op.GetAllPoints()
                      
      for p,pt in enumerate(points) :
          points[p]=pt*op_mg
      

      After setting the global matrix of my polygonal object to the matrix that I want its axis to be, now I want to relocate all the points the location where they were previously (globally).
      But I want it to be able to happen, no matter how deep inside a hierarchy my polygonal object is.
      Meaning... I want to be able to relocate the axis of my polygonal object to a specific global location, even if my object is inside a hierarchy, but I want to keep all the vertexes in their initial global location.
      How can I do this?!?
      I have been working with matrixes but no matter what I do, the points of the object always end up moving.

      1 Reply Last reply Reply Quote 0
      • M
        mp5gosu
        last edited by

        It's actually the axis and the points that have to move.

        1 Reply Last reply Reply Quote 0
        • ManuelM
          Manuel
          last edited by Manuel

          Hello @rui_mac

          you don't really need to deal with hierarchy as long as you are using global space.
          you have to come back to local space with the new matrix, by multiplying the points position with the inverse matrix.
          Be sure to also move the axis of the object as @mp5gosu stated and to ask the object to update itself.

                  # Retrieves selected object
                  op = doc.GetActiveObject()
                  if op is None:
                      raise TypeError("There's no object selected.")
              
                  # Retrieves the matrix of the object
                  opmg = op.GetMg()
              
                  # Retrieves the point in global space
                  pointsGlob = [p * opmg for p in op.GetAllPoints()]
              
                  # Starts the undo process (the initial scene to be restored after an undo action)
                  doc.StartUndo()
              
                  # Notifies a change on the obj
                  doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
              
                  # Updates the matrix
                  opmg.off = c4d.Vector(0)
                  # Updates the axis of the object
                  op.SetMg(opmg)
              
                  # Notifies the object, that internal data changed and it needs to be updated
                  op.Message(c4d.MSG_UPDATE)
              
                  # Inverses the matrix to come back to local space
                  invopmg = ~opmg
              
                  # Retrieves points from global to local space
                  newPoints = [p * invopmg for p in pointsGlob]
              
                  # Updates the points
                  doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                  op.SetAllPoints(newPoints)
              
                  # Ends the undo process (the final scene state)
                  doc.EndUndo()
              
                  # Updates Cinema 4D
                  c4d.EventAdd()
              
          

          Cheers
          Manuel

          MAXON SDK Specialist

          MAXON Registered Developer

          1 Reply Last reply Reply Quote 3
          • R
            rui_mac
            last edited by

            That is what I was trying to do, but it is still not working.

            Lets assume I have a list to objects that are the objects that are all children of a Null. The objects can be children or childs of childs, or even deeper, but they all are inside a Null.
            I want all the geometry of those children to remain in the same spacial location but I wan all the axis to move to the location of the Null (no matter how deep the objects are in the hierarchy.
            My current code is as follows:

            main_mg = op.GetMg() # the global matrix of the parent Null
            
            # op_list is a list that contains all the childs of the Null.
            # Some of them are childs of childs or even deeper.
            
            doc.StartUndo()
            
            for op in op_list:
            
                child_mg = op.GetMg()
                pointsG = [p * child_mg for p in op.GetAllPoints()]
                
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
            
                op.SetMg(main_mg)
                op.Message(c4d.MSG_UPDATE)
                inv_mg = ~child_mg
                nPoints = [p * inv_mg for p in pointsG]
                
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                op.SetAllPoints(nPoints)
                
            doc.EndUndo()
            c4d.EventAdd()
            
            

            But it is not working!!
            All the geometry still moves.

            1 Reply Last reply Reply Quote 0
            • ManuelM
              Manuel
              last edited by

              @rui_mac said in Move just the axis of a polygonal object:

              inv_mg = ~child_mg

              Be careful about the matrix you are using as reference to go from global to local.
              The object new matrix now is the same as the null. If you are using the old one (child_mg), the points will move the same way you moved the axis. But if you are using the new one, the points be changed to global to local and in fact will not move. (and that's the goal)

              inv_mg = ~main_mg
              

              forget about the hierarchy in that case.
              It's just matrix operation local to global and global to local.

              @m_adam share his code, he think that could help you in your project.

              Let me know if it's still not clear.

              Cheers
              Manuel

              MAXON SDK Specialist

              MAXON Registered Developer

              1 Reply Last reply Reply Quote 1
              • R
                rui_mac
                last edited by

                Thank you so much. It is clearer now.
                It works!!

                1 Reply Last reply Reply Quote 0
                • R
                  rui_mac
                  last edited by

                  Spoke too soon.
                  It works, but not for childs of childs of childs...
                  This is my current code:

                  import c4d
                  
                  op_list=[]
                  
                  def Get_Op(op):
                      global op_list
                  
                      while (op):
                          op_list.append(op)
                          Get_Op(op.GetDown())
                          op = op.GetNext()
                      return None
                  
                  
                  # Main function
                  def main():
                      global op_list
                  
                      selected = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_0)
                      if len(selected)!=1: return
                      op = selected[0]
                      
                      main_mg = op.GetMg()
                  
                      child = op.GetDown()
                      op_list = []
                  
                      if child != None:
                          Get_Op(child)
                          
                          if len(op_list)!= 0:
                  
                              doc.StartUndo()
                  
                              for op in op_list:
                                  
                                  if op.GetType()==c4d.Opolygon:
                  
                                      child_mg = op.GetMg()
                                      pointsGlob = [p * child_mg for p in op.GetAllPoints()]
                  
                                      doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                                      op.SetMg(main_mg)
                                      op.Message(c4d.MSG_UPDATE)
                                      
                                      inv_mg = ~main_mg
                                      newPoints = [p * inv_mg for p in pointsGlob]
                  
                                      doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                                      op.SetAllPoints(newPoints)
                                      op.Message(c4d.MSG_UPDATE)
                  
                              doc.EndUndo()
                  
                              c4d.EventAdd()
                  
                  # Execute main()
                  if __name__=='__main__':
                      main()
                  

                  And it doesn't work with the Cap1 and Cap2 objects, in this hierarchy:

                  alt text

                  Everything remains in the same location, with the axis moved to the location of the outermost parent Null, except the Cap1 and Cap2 objects, as their geometry changes location.

                  1 Reply Last reply Reply Quote 0
                  • ManuelM
                    Manuel
                    last edited by Manuel

                    after trying several solutions, i've change your function with this one for non recursive iteration[URL-REMOVED]. and using the same idea to local to global and global to local but with the child "locoal" matrix. (the one you get with GetMl)

                    import c4d
                    
                    def GetNextObject(op):
                        # Non recursive hierarchy iteration
                        if op==None:
                            return None
                      
                        if op.GetDown():
                            return op.GetDown()
                      
                        while not op.GetNext() and op.GetUp():
                            op = op.GetUp()
                      
                        return op.GetNext()
                        
                        
                    def UpdateObject (op, newpos):
                        # Update the object by moving it to the new position 
                        # and moving back the points to their old position
                    
                        # Store the old matrix of the object
                        old_mg = op.GetMg()
                    
                        # Retrieve the points position in global space
                        pointsGlob = [p * old_mg for p in op.GetAllPoints()]
                    
                        # Add an Undo state to the document
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                    
                        # update the object position matrix    
                        op.SetMg(newpos)
                    
                        # Inverses the matrix to come back to local space
                        inv_mg = ~newpos
                    
                        # Retrieves points from global to local space
                        newPoints = [p * inv_mg for p in pointsGlob]
                    
                        # Add an Undo state to the document
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                    
                         # Updates the points
                        op.SetAllPoints(newPoints)
                    
                        # Notifies a change on the obj
                        op.Message(c4d.MSG_UPDATE)
                    
                    def UpdateChildsMatrix(op, oldMg, newMg):
                        # Update the Childrend Matrix after the parent have been moved
                    
                        op = op.GetDown()
                        # For All child of the object
                        while op:
                            # Store the local matrix to a global space with the old matrix object
                            newChildMg = oldMg * op.GetMl()
                    
                            # Calculate the new local matrix of the object.
                            newChildMg =  ~newMg * newChildMg
                    
                            # Set the new local matrix of the object        
                            op.SetMl(newChildMg)
                    
                            # Notifies a change on the obj
                            op.Message(c4d.MSG_UPDATE)    
                    
                            # Get the next Object if any
                            op = op.GetNext()
                        
                        
                    
                    
                    # Main function
                    def main():
                        # Get all Selected Object
                        selected = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_NONE)
                    
                        if len(selected) != 1:
                            return
                    
                        mainOp = selected[0]
                    
                        op_list = []
                    
                        # Get the first object if any
                        nextObj = GetNextObject(mainOp)
                        while nextObj:
                            # Add all object found in the array
                            op_list.append(nextObj)
                            # Retreive the next Object
                            nextObj = GetNextObject(nextObj)
                    
                        # Retreive the global position of the main object
                        main_mg = mainOp.GetMg()
                    
                        # if there's no child, just leave
                        if len(op_list) == 0:
                            return
                    
                        # Starts the undo process (the initial scene to be restored after an undo action)
                        doc.StartUndo()
                    
                        for op in op_list:
                            # Check if it's a polygon Object
                            if op.GetType()==c4d.Opolygon:
                                #save the matrix to have a chance to update the child
                                savedMatrix = op.GetMg()
                    
                                # Move the object to the new location without moving the points
                                UpdateObject(op,main_mg)
                    
                                # Because we moved the parent, we should move back the children.
                                UpdateChildsMatrix(op, savedMatrix, main_mg)
                                        
                                
                    
                        # Ends the undo process (the final scene state)
                        doc.EndUndo()
                        
                        # Updates Cinema 4D
                        c4d.EventAdd()
                    
                    # Execute main()
                    if __name__=='__main__':
                        main()
                    

                    Cheers
                    Manuel


                    [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

                    MAXON SDK Specialist

                    MAXON Registered Developer

                    1 Reply Last reply Reply Quote 1
                    • R
                      rui_mac
                      last edited by

                      Thank you so much, Manuel.
                      It was, mainly, that children matrix update that was missing.
                      Now, it works fine ☺

                      1 Reply Last reply Reply Quote 0
                      • ManuelM
                        Manuel
                        last edited by

                        hi,

                        when you will be sure that it's solved, don't forget to mark this thread as solved please.

                        Cheers
                        Manuel

                        MAXON SDK Specialist

                        MAXON Registered Developer

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