Move just the axis of a polygonal object
-
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. -
It's actually the axis and the points that have to move.
-
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 -
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. -
@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 -
Thank you so much. It is clearer now.
It works!! -
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:
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.
-
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.
-
Thank you so much, Manuel.
It was, mainly, that children matrix update that was missing.
Now, it works fine -
hi,
when you will be sure that it's solved, don't forget to mark this thread as solved please.
Cheers
Manuel