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

    Help with Matrix Manipulation after c4d.MCOMMAND_JOIN

    Cinema 4D SDK
    python r23 r20
    3
    16
    2.8k
    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.
    • M
      mogh
      last edited by

      Hi Zipit,
      Matrix manipulation still does not behave as I want ... the polygon objects jump and rotate
      I want them to stay in their postion after the join comand ....

      I brute forced almost every combination of matrix , ~matrix, local matrix no luck ...

      I am out of ideas
      kind regards

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

        Hi @mogh,

        unfortunately it is not quite clear to me what you are trying to do, because both your snippets are not executable, i.e. are just snippets or include pseudo-code. However, from this general setting and your wording in your first posting, I assume you are simply trying "to move the axis of an object without moving its points", i.e. do what the move axis tool does. Below you find a simple script which shows you how to change the transform of a PointObject without changing the global coordinates of its points.

        If this is not what you are looking for, I would ask you to show us code that is executable and to explain in more detail what kind of transform you are looking for.

        Cheers,
        Ferdinand

        """Demonstrates how to "move" the transform of a point object.
        
        "Moves" the transform of a PointObject without changing the global 
        coordinates of its points, i.e. does what the move axis tool does. 
        
        You have to select a point object and then another object and it will move 
        the axis of the point object to the scond one.
        """
        
        import c4d
        
        def set_point_object_transform(node, transform):
            """Sets the global transform of a point object while keeping its points
            in place.
        
            Args:
                node (c4d.PointObject): The point object to move the axis for.
                transform (c4d.Matrix): The new global transform for the object.
            
            Raises:
                TypeError: When node or transform are not of specified type.
            """
            if (not isinstance(node, c4d.PointObject) or 
                not isinstance(transform, c4d.Matrix)):
                msg = f"Illegal argument types: {type(node)}{type(transform)}"
                raise TypeError(msg)
        
            mg = node.GetMg()
            # Move the points in the global frame and then into the new frame.
            points = [p * mg * ~transform for p in node.GetAllPoints()]
            # Set the points and stuff ;)
            node.SetAllPoints(points)
            node.Message(c4d.MSG_UPDATE)
            node.SetMg(transform)
        
        def main():
            """Runs set_point_object_transform() on the current selection.
            """
            nodes = doc.GetActiveObjects(0)
            if len(nodes) < 2:
                return
        
            node, transform = nodes[0], nodes[1].GetMg()
            set_point_object_transform(node, transform)
            c4d.EventAdd()
        
        if __name__ == "__main__":
            main()
        

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • M
          mogh
          last edited by

          Thank you for your patience and time Zipit.

          I implemented your code into mine, but sadly it does the same as mine ... all the polygon objects move and rotate.

          I will make a stripped down version of the code so you can have a better look at it.

          Thank you for your time.
          kind regards
          mogh

          1 Reply Last reply Reply Quote 0
          • M
            mogh
            last edited by mogh

            So this is the compact version I could come up with. (including your Code @Zipit)

            Please add some poly Objects under Nulls called "Axis" into your scene, an nest them arbitrary, with random rotation and location to se the problem when they are joined.

            Thank you for your time.

            #!py3
            import c4d, sys, os
            from c4d import gui
            from c4d.documents import GetActiveDocument
            #Version 1.4 Striped version
            # This Script needs Null-Objects Called "Axis" with polygon objects to run
            
            def GetNextObject(op):
                if not op: return
                if op.GetDown(): return op.GetDown()
                while op.GetUp() and not op.GetNext():
                    op = op.GetUp()
                return op.GetNext()
            
            def get_all_objects (op):
                allachsen_list = list()
                all_objects_list = list()
                while op:
                    if op.GetName() == 'Achsen-Objekt' or op.GetName() == 'Axis' :
                        allachsen_list.append(op)
                    all_objects_list.append(op)
                    op = GetNextObject(op)
                return all_objects_list, allachsen_list
            
            def JoinCommand(doc, op):
                res = c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_JOIN,
                                            list = [op],
                                            mode = c4d.MODELINGCOMMANDMODE_ALL,
                                            doc = doc)
                                            
                # Cheks if the command didn't failed
                if res is False:
                    raise TypeError("return value of Join command is not valid")
                elif res is True:
                    print ("Command successful. But no object.")
                elif isinstance(res, list):
                    if c4d.GetC4DVersion() < 21000: res[0].SetAbsPos(c4d.Vector()) 
                    op.Remove()
                    return res[0] # Returns the first item containing the object of the list.  ??? GetClone() ???
            
            def set_point_object_transform(node, transform):
                if (not isinstance(node, c4d.PointObject) or 
                    not isinstance(transform, c4d.Matrix)):
                    msg = f"Illegal argument types: {type(node)}{type(transform)}"
                    raise TypeError(msg)
            
                mg = node.GetMg()
                # Move the points in the global frame and then into the new frame.
                points = [p * mg * ~transform for p in node.GetAllPoints()]
                # Set the points and stuff ;)
                node.SetAllPoints(points)
                node.Message(c4d.MSG_UPDATE)
                node.SetMg(transform)
            
            def joinmanagment(n):
                # n "Axis" null will be not alive in a few steps get everything we need from it
                if n.GetUp() :
                    parent = n.GetUp()
                else:
                    print ("No Parent To Axis Null. Probably not save to run this sript anyway.")
                    c4d.StatusClear()
                    c4d.StatusSetText ('No Parent found! - Probalby mo CAD import Doc. Script Stopped.')
                    exit()
                    return False
            
                parentmg = n.GetMg()
                newobject = JoinCommand(doc, n) # combine the poly objects
            
                if not newobject.IsAlive():
                    raise TypeError("Object is not alive.")
                    return False
            
                newobject.SetName(str(parent.GetName()))
                newobject.InsertUnder(parent)
                
                #node, transform = nodes[0], nodes[1].GetMg()
                set_point_object_transform(newobject, parentmg)
            
            def main():
                c4d.CallCommand(13957) # Konsole löschen
                doc = GetActiveDocument()
                op = doc.GetFirstObject()
            
                c4d.StatusSetSpin()
                all_objects, allachsen = get_all_objects(op) # get two lists
                null_counter = len(allachsen)
            
                if null_counter == 0: # check if found something to do.
                    c4d.StatusClear()
                    c4d.StatusSetText ('No Axis Objects found, nothing to do here.')
                    print ("No Axis Objects found, nothing to do here.")
                    exit()
            
                counter = len(all_objects)
                secondcounter = 0    
                c4d.StatusSetText ('%s Objects are processed.' %(null_counter))
            
                for n in allachsen:
                    secondcounter += 1
                    c4d.StatusSetBar(100*secondcounter/counter) #statusbar
                    if joinmanagment(n) == False:
                        break
            
                c4d.StatusClear()
                c4d.EventAdd() # update cinema 4d
                print ('END OF SCRIPT')
                return True
            
            if __name__=='__main__':
                main()
            
            1 Reply Last reply Reply Quote 0
            • X
              x_nerve
              last edited by

              Hi:

              The merge object simply generates a new polygon object, because the merge in the modeling command cannot be used, so it can be resolved in other ways.The answer to your question is, in fact, how the connection generator works.I've written it out, but I can't generate an N-gon face.Create a new blank object, the object to be connected as a subset of the blank object, and then click the middle key of the mouse to select all blank objects and all subsets to achieve the effect of connection generator.

              import c4d
              
              #e-mail : [email protected]
              
              def main():
                  nodes = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
                  if nodes == None : return
                  Object = [i for i in nodes
                          if i.GetType() == 5100]
              
                  node = c4d.BaseObject(5100)
                  doc.InsertObject(node)
                  c4d.EventAdd()
              
                  points = []
              
                  Number_One = 0
                  while Number_One < len(Object):
              
                      for i in Object[Number_One].GetAllPoints():
              
                          n = i * Object[Number_One].GetMg()
                          points.append(n * ~node.GetMg())
              
                      Number_One = Number_One + 1
              
                  Polygons = [i.GetAllPolygons() for i in Object]
              
                  Cpolygons = Polygons[0]
              
                  Polygon_Indexe = []
                  if len(Object) > 1:
              
                      Number_Two = 0
                      while Number_Two < len(Object) - 1:
              
                          Point_Count = [ Object[0].GetPointCount() ]
                          if Number_Two > 0:
              
                              for i in Object[:-1 * (len(Object) - Number_Two )]:
                                  Point_Count.append(Point_Count[-1] + i.GetPointCount())
              
                          for i in Polygons[Number_Two  + 1]:
              
                              if str(i).count("d") == 1:
              
                                  Polygon_Indexe.append(c4d.CPolygon(i.a + Point_Count[-1] ,i.b +Point_Count[-1] ,i.c + Point_Count[-1] ,i.d + Point_Count[-1] ))
              
                              else:
              
                                  Polygon_Indexe.append(c4d.CPolygon(i.a + Point_Count[-1] ,i.b + Point_Count[-1] ,i.c +Point_Count[-1] ))
              
                          Number_Two  = Number_Two + 1
              
                  Cpolygons += Polygon_Indexe
              
                  node.ResizeObject(len(points),len(Cpolygons))
                  node.SetAllPoints(points)
              
                  for i in range(len(Cpolygons)):
                      node.SetPolygon(i,Cpolygons[i])
              
                      node.Message(c4d.MSG_UPDATE)
                      c4d.EventAdd()
              
                  node.Message(c4d.MSG_UPDATE)
                  c4d.EventAdd()
              
              if __name__=='__main__':
                  main()
              
              1 Reply Last reply Reply Quote 0
              • M
                mogh
                last edited by

                @x_nerve as I understand you copy polygons and point from one object to another, which is a solution, still I do not understand why the join command would not work.

                I get a polygon object from my join comand which is ok, it just needs to reposition on its old place with all the axis and nulls kept, and oriented as it was.

                kind regards
                mogh

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

                  Hi @mogh,

                  thank you @x_nerve for jumping in, we really appreciate that, but I am not quite sure that I can follow, if you think there is a bug in MCOMMAND_JOIN, we would ask you to report that in a separate thread, because as I said, I currently do not really fully grasp the problem.

                  @mogh

                  I understand your problem better now, and the direct answer you are looking for is to change line 50 in your script from:

                  points = [p * mg * ~transform for p in node.GetAllPoints()]

                  to

                  points = [p * ~transform for p in node.GetAllPoints()]

                  You have to do that, because you are operating in local coordinates in the way the rest of the script works. At least this is my current understanding of your goals. At the end of the post you will find both the modified full script and the test scene I did run your script on.

                  As a more general advice, since I saw that you did delete my docstring: You should write them for all your methods/functions/classes, because this would have told you that that specific function was operating in global space. Coding is mostly an exercise in breaking stuff down into manageable parts, and doc strings help to express that "divide and conquer" strategy, rather than viewing a script as "a single thing". Which in turn then makes revisiting or debugging your code easier.

                  Cheers,
                  Ferdinand

                  PC12991_scene.c4d

                  #!py3
                  import c4d, sys, os
                  from c4d import gui
                  from c4d.documents import GetActiveDocument
                  #Version 1.4 Striped version
                  # This Script needs Null-Objects Called "Axis" with polygon objects to run
                  
                  def GetNextObject(op):
                      if not op: return
                      if op.GetDown(): return op.GetDown()
                      while op.GetUp() and not op.GetNext():
                          op = op.GetUp()
                      return op.GetNext()
                  
                  def get_all_objects (op):
                      allachsen_list = list()
                      all_objects_list = list()
                      while op:
                          if op.GetName() == 'Achsen-Objekt' or op.GetName() == 'Axis' :
                              allachsen_list.append(op)
                          all_objects_list.append(op)
                          op = GetNextObject(op)
                      return all_objects_list, allachsen_list
                  
                  def JoinCommand(doc, op):
                      res = c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_JOIN,
                                                  list = [op],
                                                  mode = c4d.MODELINGCOMMANDMODE_ALL,
                                                  doc = doc)
                  
                      # Cheks if the command didn't failed
                      if res is False:
                          raise TypeError("return value of Join command is not valid")
                      elif res is True:
                          print ("Command successful. But no object.")
                      elif isinstance(res, list):
                          if c4d.GetC4DVersion() < 21000: res[0].SetAbsPos(c4d.Vector())
                          op.Remove()
                          return res[0] # Returns the first item containing the object of the list.  ??? GetClone() ???
                  
                  def set_point_object_transform(node, transform):
                      if (not isinstance(node, c4d.PointObject) or
                          not isinstance(transform, c4d.Matrix)):
                          msg = f"Illegal argument types: {type(node)}{type(transform)}"
                          raise TypeError(msg)
                      
                      print ("sp:", node, transform)
                      mg = node.GetMg()
                      # Move the points in the global frame and then into the new frame.
                      points = [p * ~transform for p in node.GetAllPoints()]
                      # Set the points and stuff ;)
                      node.SetAllPoints(points)
                      node.Message(c4d.MSG_UPDATE)
                      node.SetMg(transform)
                  
                  def joinmanagment(n):
                      # n "Axis" null will be not alive in a few steps get everything we need from it
                      if n.GetUp() :
                          parent = n.GetUp()
                      else:
                          print ("No Parent To Axis Null. Probably not save to run this sript anyway.")
                          c4d.StatusClear()
                          c4d.StatusSetText ('No Parent found! - Probalby mo CAD import Doc. Script Stopped.')
                          exit()
                          return False
                  
                      parentmg = n.GetMg()
                  
                      newobject = JoinCommand(doc, n) # combine the poly objects
                  
                      if not newobject.IsAlive():
                          raise TypeError("Object is not alive.")
                          return False
                  
                      newobject.SetName(str(parent.GetName()))
                      newobject.InsertUnder(parent)
                      newobject.SetMg(newobject.GetMl())
                      # node, transform = nodes[0], nodes[1].GetMg()(add QA contact)
                      set_point_object_transform(newobject, parentmg)
                  
                  def main():
                      c4d.CallCommand(13957) # Konsole löschen
                      doc = GetActiveDocument()
                      op = doc.GetFirstObject()
                  
                      c4d.StatusSetSpin()
                      all_objects, allachsen = get_all_objects(op) # get two lists
                      null_counter = len(allachsen)
                  
                      if null_counter == 0: # check if found something to do.
                          c4d.StatusClear()
                          c4d.StatusSetText ('No Axis Objects found, nothing to do here.')
                          print ("No Axis Objects found, nothing to do here.")
                          exit()
                  
                      counter = len(all_objects)
                      secondcounter = 0
                      c4d.StatusSetText ('%s Objects are processed.' %(null_counter))
                  
                      for n in allachsen:
                          secondcounter += 1
                          c4d.StatusSetBar(100*secondcounter/counter) #statusbar
                          if joinmanagment(n) == False:
                              break
                  
                      c4d.StatusClear()
                      c4d.EventAdd() # update cinema 4d
                      print ('END OF SCRIPT')
                      return True
                  
                  if __name__=='__main__':
                      main()
                  

                  MAXON SDK Specialist
                  developers.maxon.net

                  1 Reply Last reply Reply Quote 0
                  • M
                    mogh
                    last edited by

                    @zipit thank you very much - position and rotation seem to be working now. (staying put)

                    another problem ocured though "NormalTag" information seems to flip and maually flipping back does not help ... so all the polygons are "shaded" weird now. --- the callcomand "connect and delete" which I want to replace because of speed keeps them intact.

                    Should I open a new thread or leafe the problem open ?

                    regarding docstring: i just wanted the code to be slim so people can read it fast without scrolling its still in my lengthy script. Will keep it next time.

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

                      Hi,

                      we would appreciate it if you would open a new thread for that. As a quick tip, aside from using SMC, inverting the normal of a polygon just means inverting its point index order. I have shown it for example here. But this can come with multiple problems, especially regarding texture coordinates. I think have dealt with problem here on the forum multiple times (including dealing with secondary mesh attributes like texture coordinates). If any questions remain, please feel free to open a new thread.

                      About the doc strings: In the end you should do what you are comfortable with. It was just a tip and a little insight on why many people find it useful.

                      Cheers,
                      Ferdinand

                      MAXON SDK Specialist
                      developers.maxon.net

                      1 Reply Last reply Reply Quote 0
                      • X
                        x_nerve
                        last edited by x_nerve

                        Hi:

                        @mogh

                        The MCOMMAND_JOIN modeling command is now ready to execute properly.The merged object cannot be directly visible in the document, so the merged object must be inserted into the document.Also, the global matrix of the merged object is the same as the first object in the parent-child list.I also got it from the forum.

                        import c4d
                        from c4d import utils
                        
                        #e-mail : [email protected]
                        
                        def main():
                        
                            nodes = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
                            if nodes == None : return
                            Objects = [i for i in nodes
                                    if i.GetType() == 5100]
                        
                            settings = c4d.BaseContainer()
                            settings[c4d.MDATA_JOIN_MERGE_SELTAGS] = True
                            
                            result = c4d.utils.SendModelingCommand(
                                c4d.MCOMMAND_JOIN, Objects ,
                                c4d.MODELINGCOMMANDMODE_ALL, settings, doc)
                        
                            doc.InsertObject(result[0])
                            c4d.EventAdd()
                            
                            points = []
                        
                            Number_One = 0
                            while Number_One < len(Objects):
                        
                                for i in Objects[Number_One].GetAllPoints():
                        
                                    n = i * Objects[Number_One].GetMg()
                                    points.append(n * ~result[0].GetMg())
                        
                                Number_One = Number_One + 1
                        
                            result[0].SetAllPoints(points)
                        
                            result[0].Message(c4d.MSG_UPDATE)
                            c4d.EventAdd()
                            
                            print (result[0])
                        
                        if __name__=='__main__':
                            main()
                        
                        
                        1 Reply Last reply Reply Quote 0
                        • ferdinandF
                          ferdinand
                          last edited by

                          Hi @mogh,

                          I initially did not want to make things super complicated here, which is why I did a bit work around the oddities of your script in my answer. Given the other threads of yours which deal with that project, it seems advisable to point out that a cleaner version of your script could look like the script attached at the end. The doc string will tell you about the pro's and con's. You can also try uncommenting the c4d.EventAdd in line 155 to see if you can get Cinema more into sync (regarding https://developers.maxon.net/forum/topic/13007).

                          Cheers,
                          Ferdinand

                          """Demonstrates how to handle MCOMMAND_JOIN while keeping things in place.
                          
                          You can also use the old version, but there you would have to deal with the
                          normal tags. This version mostly just rectifies some minor oddities in your
                          original code. This version does not need to transform the vertices, but 
                          instead places the new object by the inverse transform of its former parent
                          (see line 123).
                          
                          Things get much more complicated (and computationally expensive) when you use 
                          the old version, since you then have to also modify the normals. The 
                          disadvantage  of this version is that the axis placement is not "as nice".
                          
                          See https://developers.maxon.net/forum/topic/13004/ for how to deal with the normal
                          tags.
                          """
                          
                          import c4d
                          
                          
                          def get_nodes_by_name(doc, patterns):
                              """Returns all nodes in a document whose name appears in patterns.
                          
                              Note:
                                  Despite its name, the strings in `patterns` are not evaluated as
                                  regular expressions at the moment. In fact this function does not
                                  ensure that the elements in patters are strings at all.
                          
                              Args:
                                  doc (c4d.documents.BaseDocument): The document to get the nodes from.
                                  patterns (list[str]): The name patterns to get the nodes for.
                          
                              Returns:
                                  list[c4d.BaseObjeect]: The nodes in `doc` which match patterns.
                          
                              Raises:
                                  TypeError: On invalid argument types.
                              """
                              # Validate arguments.
                              if not isinstance(doc, c4d.documents.BaseDocument):
                                  msg = f"Expected BaseDocument for `doc`. Received: {type(doc)}."
                                  raise TypeError(msg)
                              if not isinstance(patterns, list):
                                  msg = f"Expected list for `patterns`. Received: {type(patterns)}."
                                  raise TypeError(msg)
                          
                              # Get all relevant nodes.
                              result, visited = [], []
                              node = doc.GetFirstObject()
                              while node is not None:
                                  # Append new nodes to the visited and result lists.
                                  if node not in visited:
                                      visited.append(node)
                                  if node.GetName() in patterns and node not in result:
                                      result.append(node)
                                  # Traverse the scene graph depth first.
                                  node_down = node.GetDown()
                                  if node_down and node_down not in visited:
                                      node = node_down
                                  elif node.GetNext():
                                      node = node.GetNext()
                                  else:
                                      node = node.GetUp()
                              return result
                          
                          
                          def join_with_children(node, merge_selection_tags=True):
                              """Joins the children of `node` into a single object.
                          
                              Also adjusts the transform of the resulting node and removes the old
                              geometry and inserts the new one. 
                          
                              Args:
                                  node (c4d.BaseObject): The node to join the children for.
                                  merge_selection_tags (bool, optional): If to also merge selections.
                                   Defaults to `True`.
                          
                              Returns:
                                  bool: If the operation was successful.
                          
                              Raises:
                                  RuntimeError: When SMC failed.
                                  TypeError: On invalid argument types.
                                  ValueError: When `node` is not attached to a document.
                              """
                              # Validate arguments.
                              if not isinstance(node, c4d.BaseObject):
                                  msg = f"Expected BaseObject for `node`. Received: {type(node)}"
                                  raise TypeError(msg)
                          
                              doc = node.GetDocument()
                              if doc is None:
                                  msg = f"Node is not attached to a document: {node}."
                                  raise ValueError(msg)
                          
                              # A special condition of yours I am just mimicking here.
                              parent = node.GetUp()
                              if parent is None:
                                  return
                          
                              # Run SMC
                              smc_data = c4d.BaseContainer()
                              smc_data[c4d.MDATA_JOIN_MERGE_SELTAGS] = merge_selection_tags
                              result = c4d.utils.SendModelingCommand(
                                  command=c4d.MCOMMAND_JOIN,
                                  list=[node],
                                  mode=c4d.MODELINGCOMMANDMODE_ALL,
                                  bc=smc_data,
                                  doc=doc,
                                  flags=c4d.MODELINGCOMMANDFLAGS_NONE)
                          
                              # Evaluate SMC output.
                              if (not isinstance(result, list) or
                                  len(result) == 0 or
                                      not isinstance(result[0], c4d.BaseObject)):
                                  msg = f"SendModelingCommand failed on: {node}"
                                  raise RuntimeError(msg)
                          
                              # This didn't not make much sense, since you did overwrite the transform
                              # of result[0] on a later point anyways.
                              # if c4d.GetC4DVersion() < 21000:
                              #     result[0].SetAbsPos(c4d.Vector())
                          
                              # Replace the old with the new geometry.
                              result = result[0]
                              # Your renaming does not make much sense to me, since every new node
                              # will then just be named after its parent. i.e. "CADimport_XXX", feel
                              # free to uncomment, if this was intended.
                              # result.SetName(parent.GetName())
                              result.SetMg(~parent.GetMg())
                              result.InsertUnder(parent)
                              node.Remove()
                          
                          
                          def main():
                              """Does the whole CAD cleanup thing.
                              """
                              # The name patterns for the nodes to collapse.
                              patterns = ["Achsen-Objekt", "Axis"]
                              # Get all nodes that match that pattern.
                              targets = get_nodes_by_name(doc, patterns)
                              count = len(targets)
                          
                              c4d.StatusSetSpin()
                              # Loop over these nodes.
                              #
                              # Your approach did not respect the special case when an `axis` object
                              # is a direct child of another `axis` object. Which will lead to
                              # incorrect results, since you (and I here) traverse the scene graph
                              # top-down-depth-first. I did not address this to keep the code relatively
                              # familiar.
                              for i, node in enumerate(targets):
                                  # Join one of the targets and do some mild interface indication.
                                  join_with_children(node)
                                  # Uncomment to let Cinema update for each modification of the scene.
                                  # c4d.EventAdd()
                                  c4d.StatusSetText(f"{i}/{count} groups joined.")
                              # Clean up after ourselves.
                              c4d.StatusSetText("")
                              c4d.StatusClear()
                              c4d.EventAdd()
                          
                          
                          if __name__ == '__main__':
                              main()
                          

                          MAXON SDK Specialist
                          developers.maxon.net

                          1 Reply Last reply Reply Quote 1
                          • M
                            mogh
                            last edited by

                            I am building of your script from here on. Thank You.

                            FYI zipit:
                            While your def get_nodes_by_name(doc, patterns) might be saver and more sound it takes 10x longer then my version to collect all axis ... (which is not the slow party of the script and could be neglegted - I was just buffled by the profiling i ran)

                            kind regards
                            mogh

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

                              Hi,

                              ten times slower sounds rough. It is probably because I was a bit lazy and used a lookup table (visited) to traverse the scene-graph, which is a rather expensive thing to do. Feel free to use the fixed traversal if performance becomes an issue here.

                              Cheers,
                              Ferdinand

                              MAXON SDK Specialist
                              developers.maxon.net

                              1 Reply Last reply Reply Quote 0
                              • M mogh referenced this topic on
                              • First post
                                Last post