transform parent without transforming children
On 27/07/2014 at 11:56, xxxxxxxx wrote:
is it possible to transform the main object from my objectplugin without transforming the children?
Move, scale or rotate the object but the children stay the same.
On 28/07/2014 at 08:32, xxxxxxxx wrote:
You could set up a double null. What you do the the parent just do the opposite to the child null and parent everything under that, possibly even a third so the values aren't being changed directly. It will take a little bit of math to get the rotation ans scale working correctly but shouldn't be to hard.
On 28/07/2014 at 15:14, xxxxxxxx wrote:
thank you for answering,
it sounds like a workaround to me? or I did´nt get it exactly. Why I do need null objects and translation matrices?
What I´m tring to do with my objectplugin is something like this. Inside the Message function, store
the children´s matrices before moving the axis of the parentobject and write it back when finished.
But the childrenMatr-List is not updated properly.
def Message(self, node, type, data) : inst = node.GetDataInstance() childrenMatr= if type== c4d.MSG_MOVE_START: print "start transform" childrenMatr= children= node.GetChildren() for ch in children: childrenMatr.append([ch,ch.GetMg()]) print childrenMatr, "before" if type== c4d.MSG_MOVE_FINISHED: print "finished transform" print childrenMatr,"after" for i in childrenMatr: i.SetMg(i)
or much better will be to realize it in real time, like for example with my self written handels:
def SetHandle(self, op, hit_id, p, info) : data = op.GetDataInstance() if data is None: return p= abs(p) size= data.GetVector(10001) val = (p-info.position)*info.direction if hit_id is 0: data.SetVector(10001,c4d.Vector(size.x+val,size.y,size.z)) if data.GetBool(10002)== 1:#lockproportions data.SetVector(10001,c4d.Vector(size.x+val,size.x+val,size.x+val)) elif hit_id is 1: data.SetVector(10001,c4d.Vector(size.x,size.y+val,size.z)) if data.GetBool(10002)== 1:#lockproportions data.SetVector(10001,c4d.Vector(size.y+val,size.y+val,size.y+val)) elif hit_id is 2: data.SetVector(10001,c4d.Vector(size.x,size.y,size.z+val)) if data.GetBool(10002)== 1:#lockproportions data.SetVector(10001,c4d.Vector(size.z+val,size.z+val,size.z+val)) def MoveHandle(self, op, undo, mouse_pos, hit_id, qualifier, bd) : mg = op.GetUpMg() * undo.GetMl() info = c4d.HandleInfo() self.GetHandle(op, hit_id, info) self.SetHandle(op, hit_id , (info.CalculateNewPosition(bd, mg, mouse_pos)), info) return True
Thanks for any help!
On 28/07/2014 at 17:24, xxxxxxxx wrote:
What you need to do is move the parent object.
Then move the children objects the same amount...but in the inverse direction to put them back where they originally were.
import c4d def main() : obj = doc.GetActiveObject() mg_old = obj.GetMg() #Save the parent's old matrix mg_new = c4d.Matrix() #This will be the parent's new matrix mg_new.off = c4d.Vector(-610,0,0) #Move the selected parent object to this location obj.SetMg(mg_new) #Apply the new matrix to the parent object obj.Message(c4d.MSG_UPDATE) mg_new = ~mg_new #Invert new matrix - needed later #Cycle through children obj = obj.GetDown() while obj: 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 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(c4d.MSG_UPDATE) obj = obj.GetNext() c4d.EventAdd() if __name__=='__main__': main()
On 29/07/2014 at 01:36, xxxxxxxx wrote:
thanks for the reply!
It´s a workaround, too.
As I mentioned before:
"Why I do need null objects and translation matrices?"
A global matrix is only relativ to the scene origin, therefore the hierarchy has no influence.
I can store the children global matrices and write it back
Code below shows a much simpler approach of what you are doing:
My problem is to do this in real time if the user move the axis of my objectplugins mainobject.
I can not find the right routine to detect the motion of the axis.
Thanks for any help!
def main() : if op is None:return childrenMatr= children= op.GetChildren() for ch in children: childrenMatr.append([ch,ch.GetMg()]) parentMatr= op.GetMg() #fake movement op.SetMg(c4d.Matrix((parentMatr.off+c4d.Vector(200,0,0)),parentMatr.v1,parentMatr.v2,parentMatr.v3,)) op.Message(c4d.MSG_UPDATE) for i in childrenMatr: i.SetMg(i) c4d.EventAdd() if __name__=='__main__': main()
On 29/07/2014 at 09:18, xxxxxxxx wrote:
The code I posted is just another way to do it. And it might be a bit faster for larger hierarchies.
Lists can become slow if you store too much data in them. But either way should work.
I'm confused about what your actual problem is?
You asked how to transform the parent without moving the children. Yet you already knew how to do it (using lists).
Now you're asking how to detect the direction that the user is dragging the parent object. Which is something that I'm guessing you also already know how to do using a class member variable to store the original position. And comparing the current position with that logged position.
You know how to move the parent without moving the children(actually move them back).
You seem to know how to get the direction of travel the parent is being dragged by the user.
So what is that's the problem you're having?
What is happening when you apply your parent's dragged vector to your "Send children home" code?
Is there a lag or some other problem?
On 29/07/2014 at 15:29, xxxxxxxx wrote:
I didn´t see that coming, doing all the calculations is faster than only storing values .
Your code is faster!
Tested it with a million objects and it was round about 100ms faster.
Great, thank you for the hint.
That is indeed a reason for the translation matrix.
My question was about all the tasks in this field.
I don´t know how to detect the axis and the transformation mode.
I´m only able to detect the handles I wrote by myself, but not the c4d axis
and if the user is in scale, rotation or move mode.
On 29/07/2014 at 16:11, xxxxxxxx wrote:
import c4d def main() : activetool = doc.GetAction() #Get the current active tool print activetool #200000088 == Move mode is active #200000089 == Scale mode is active #These are the ID#s for the Move, Scale, and Rotate tools #200000090 == Rotate mode is active #Example for setting the move tool #If the move tool is not active...activate it if activetool != 200000088: doc.SetAction(200000088) #This is new in R14++ for getting the state of the axis tool AxisMode = doc.IsAxisEnabled() print AxisMode c4d.EventAdd() if __name__=='__main__': main()
On 31/07/2014 at 03:09, xxxxxxxx wrote:
hence the object plugin mainobject is like a parametrical object
AxisMode = doc.IsAxisEnabled() print AxisMode
the axismode is never enabled, even if the user checked the button.
got it now, I guess !
easiest way I found out is to get the object´s drawpass, read the change of information and do a recalculation for the children.
def Draw(self, node, drawpass, bd, bh) : if drawpass==c4d.DRAWPASS_OBJECT: self.GetAxisMotion(node, node.GetAbsPos(), node.GetAbsRot(), node.GetAbsScale(), node.GetRad()*2)
and inside the self.GetAxisMotion() function I can recalculate the children´s matrices like you showed above:
def GetAxisMotion(self, node, pos, rot, sca, bbox) : doc = c4d.documents.GetActiveDocument() if doc.GetMode()==c4d.Mmodel: #model mode or 11 print bbox elif doc.GetMode()==c4d.Mobject: #object mode or 1 print sca print pos print rot
Thanks for the help
and your patience Scott
On 31/07/2014 at 07:38, xxxxxxxx wrote:
Glad you got it worked out.
I didn't understand that you were looking for a sort of trigger event that would execute your Move Parent code.
Dirty can sometimes help you detect when an object is moved too:
#Get & Set the object's dirty value getDirt = op.GetDirty(c4d.DIRTY_DATA|c4d.DIRTY_MATRIX |c4d.DIRTY_CHILDREN|c4d.DIRTY_CACHE|c4d.DIRTY_SELECT) setDirt = op.SetDirty(c4d.DIRTY_DATA|c4d.DIRTY_MATRIX |c4d.DIRTY_CHILDREN|c4d.DIRTY_CACHE|c4d.DIRTY_SELECT)