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


Log in to reply