transform parent without transforming children

On 27/07/2014 at 11:56, xxxxxxxx wrote:

Hi there,

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.

Thanks,
Martin

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[0].SetMg(i[1])  

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!
Martin

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

-ScottA

On 29/07/2014 at 01:36, xxxxxxxx wrote:

Hey Scott,

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!
Martin

  
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[0].SetMg(i[1])  
  
  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?

-ScottA

On 29/07/2014 at 15:29, xxxxxxxx wrote:

Hi Scott,

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.

Martin

On 29/07/2014 at 16:11, xxxxxxxx wrote:

This stuff?

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

-ScottA

On 31/07/2014 at 03:09, xxxxxxxx wrote:

kind of...
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.

like:

  
  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

Cheers
Martin

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)

-ScottA