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

    How to fix the bug of objects position in script

    Cinema 4D SDK
    python r21
    2
    2
    632
    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.
    • ROMANR
      ROMAN
      last edited by ferdinand

      Guys! Please, help. I cannot fix this problem.

      The main idea of ​​this script is:

      1. add selected objects and materials of these objects to the layer
      2. insert all objects under null.
        But position of objects changes. How to fix it?

      : video

      import c4d
      
      def main():
      
          doc.StartUndo()
      
      
          layer = c4d.documents.LayerObject()
          # Set layer name (another option tp set the name)
          # Get the invisible root layer
          layerRoot = doc.GetLayerObjectRoot()
          # Insert the layer under the parent
          layer.InsertUnder(layerRoot)
      
          name = layer.GetName()
          rvalue = c4d.gui.RenameDialog(name) # rename
          print(rvalue)
          layer [c4d.ID_BASELIST_NAME] = rvalue
          #layer.DelBit(c4d.BIT_ACTIVE)
      
          null_obj = c4d.BaseObject(c4d.Onull)
          null_obj [c4d.ID_LAYER_LINK] = layer
          null_obj [c4d.ID_BASELIST_NAME] = rvalue
          doc.InsertObject(null_obj)
      
      
          doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, layer)
          doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, null_obj)
      
          s = doc.GetSelection()
          vp = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_NONE)
      
      
          for obj in vp:
      
              print obj
      
              obj [c4d.ID_LAYER_LINK] = layer
              obj.InsertUnder(null_obj)
      
              obj_mat_tags = [t for t in obj.GetTags() if t.IsInstanceOf(c4d.Ttexture)]
      
              for tag in obj_mat_tags:
      
                  mat = tag.GetMaterial()
                  print mat
                  mat [c4d.ID_LAYER_LINK] = layer
      
      
          doc.EndUndo()
          c4d.EventAdd()
      
      if __name__ == '__main__':
          main()
      

      I use r21 version of c4d.

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @ROMAN
        last edited by ferdinand

        Hello @roman,

        Thank you for reaching out to us. R21 has left the SDK support cycle, which primarily means we will not debug again such versions anymore and also do not fix bugs for it anymore. I have provided below a solution for your problem which has been tested with R25 because of that, but it should run fine in R21.

        Your problem primarily is rooted in you simply reparenting the objects. Objects store their transformation - their position, scale and orientation - as a matrix relative to their parent. So, when you have the objects a, b, c with the local positions (0, 100, 0), (0, 50, 0), (0, 0, 0) and b being parented to a, then the effective global position of b is (0, 100, 0) + (0, 50, 0) = (0, 150, 0). When you then parent b to c, its position will change from (0, 150, 0) to (0, 50, 0) since c only contributes the null vector to the position of its children. The same principle applies to the scale and orientation stored in the local transform matrix of an object. You were also missing some undo-steps, at least I assumed you did not skip them intentionally.

        The topic is also covered in the Python API Matrix Manual.

        Cheers,
        Ferdinand

        The result:
        reparent.gif

        The script:

        """Moves the selected objects to a new layer and parent object.
        
        Your problem primarily is rooted in you simply reparenting the objects. 
        Objects store their transformation - their position, scale and orientation -  
        as a matrix relative to their parent. So, when you have the objects `a, b, c` 
        with the local positions `(0, 100, 0), (0, 50, 0), (0, 0, 0)` and `b` being 
        parented to `a`, then the effective global position of `b` is `(0, 100, 0) + 
        (0, 50, 0) = (0, 150, 0)`. When you then parent `b` to `c`, its position will 
        change from `(0, 150, 0)` to `(0, 50, 0)` since `c` only contributes the null 
        vector to the position of its children. The same principle applies to the 
        scale and orientation stored in the local transform matrix of an object. You 
        were also missing some undo-steps, at least I assumed you did not skip them 
        intentionally.
        """
        
        import c4d
        
        def main():
            """Entry point.
            """
            # Start an undo stack item.
            doc.StartUndo()
        
            # Add a new top-level layer
            newLayer = c4d.documents.LayerObject()
            layerRoot = doc.GetLayerObjectRoot()
            newLayer.InsertUnder(layerRoot)
            doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, newLayer)
        
            # Let the user name the new layer
            newName = c4d.gui.RenameDialog(newLayer.GetName())
            newLayer [c4d.ID_BASELIST_NAME] = newName
        
            # Create a null object to parent the objects moved to the new layer to.
            newLayerNull = c4d.BaseObject(c4d.Onull)
            newLayerNull [c4d.ID_LAYER_LINK] = newLayer
            newLayerNull [c4d.ID_BASELIST_NAME] = newName
            doc.InsertObject(newLayerNull)
            doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, newLayerNull)
        
            # Iterate over the selected objects and attach them both to the new layer
            # and layer null-object.
            for item in doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_NONE):
        
                # Set the layer of the current item, detach it from its previous 
                # parent and store its global matrix.
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, item)
                item [c4d.ID_LAYER_LINK] = newLayer
                itemMg = item.GetMg()
                item.Remove()
        
                # Attach the object to the null and set its global matrix to the old
                # value.
                item.SetMg(itemMg)
                item.InsertUnder(newLayerNull)
        
                # Get all materials attached with material tags to the item.
                isTex = lambda item: item.IsInstanceOf(c4d.Ttexture)
                for material in [t.GetMaterial() for t in item.GetTags() if isTex(t)]:
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, material)
                    material[c4d.ID_LAYER_LINK] = newLayer
        
            # Close the undo item and push an update event to Cinema 4D.
            doc.EndUndo()
            c4d.EventAdd()
        
        if __name__ == '__main__':
            main()
        

        MAXON SDK Specialist
        developers.maxon.net

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