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

    c4d.MCOMMAND_EXPLODESEGMENTS makes target object dead

    Cinema 4D SDK
    macos python 2024
    2
    6
    1.1k
    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.
    • bacaB
      baca
      last edited by

      Hi,

      I'm appliyng "Explode Segments" command on polygon object with several segments.
      While command returns true, the target object is turn "dead". So I can't retrieve children segments.

      import c4d
      
      def main():
          childOp = op.GetDown()
      
          if childOp:
              cloneOp = (childOp.GetDeformCache() or childOp.GetCache() or childOp).GetClone(c4d.COPYFLAGS_NO_HIERARCHY)
              resultOp = cloneOp
      
              if cloneOp.CheckType(c4d.Opolygon):
                  cloneOp.GetPolygonS().SelectAll(cloneOp.GetPolygonCount())
      
                  bc = c4d.BaseContainer()
                  success = c4d.utils.SendModelingCommand(
                      command=c4d.MCOMMAND_EXPLODESEGMENTS,
                      list=[cloneOp],
                      mode=c4d.MODELINGCOMMANDMODE_ALL,
                      bc=bc,
                      doc=doc,
                  )
      
                  print(f"\nMCOMMAND_EXPLODESEGMENTS: success={success}, targetOp={cloneOp}")
                  if success:
                      resultOp = cloneOp.GetDown()
      
              childOp.Touch()
              return resultOp
      
          return c4d.PolygonObject(0,0)
      

      Tested on 2024, 2023 and R25 - same issue everythere.

      I believe it worked perfectly some time ago.
      Or maybe it's MacOs only issue (I have MacBook M1)

      1 Reply Last reply Reply Quote 0
      • bacaB
        baca
        last edited by

        Okay, found a solution.
        Support team please tell if that's proper approach:

        import c4d
        
        def main() -> c4d.BaseObject:
            childOp = op.GetDown()
        
            if childOp:
                sourceOp = (childOp.GetCache().GetDeformCache() or childOp.GetCache()) if childOp.GetCache() else (childOp.GetDeformCache() or childOp)
                cloneOp = sourceOp.GetClone()
                resultOp = sourceOp.GetClone()
        
                if cloneOp.CheckType(c4d.Opolygon):
                    newDoc = c4d.documents.BaseDocument()
                    newDoc.InsertObject(cloneOp)
        
                    success = c4d.utils.SendModelingCommand(
                        command=c4d.MCOMMAND_EXPLODESEGMENTS,
                        list=[cloneOp],
                        mode=c4d.MODELINGCOMMANDMODE_ALL,
                        bc=c4d.BaseContainer(),
                        doc=newDoc,
                    )
        
                    if success:
                        explodeOp = newDoc.GetFirstObject()
                        if explodeOp and explodeOp.IsAlive():
                            resultOp = (explodeOp.GetDown() or explodeOp).GetClone()
        
                childOp.Touch()
                return resultOp
        
            return c4d.PolygonObject(0,0)
        
        ferdinandF 1 Reply Last reply Reply Quote 0
        • ferdinandF
          ferdinand @baca
          last edited by ferdinand

          Hey @baca,

          Thank you for reaching out to us. Yes, what you do there is correct in the aspect that inputs must be part of a document when passed to SMC. There are, however, other problems in your code.

          1. MCOMMAND_EXPLODESEGMENTS can only be used on SplineObject inputs, your code is testing for Opolygon. This is not true, MCOMMAND_EXPLODESEGMENTS can also be used to split disjunct islands in a polygonal mesh.
          2. You cannot run MCOMMAND_EXPLODESEGMENTS on the generator or deform cache of a real spline, because that is a LineObject which is not a valid input for MCOMMAND_EXPLODESEGMENTS (or pretty much all other spline SMC). When you run the command manually in the editor, you will see that its output will ignore deformation, it operates on a real spline (c4d.SplineObject) level.

          Cheers,
          Ferdinand

          Result:
          13e98a5d-ced4-4be0-92b4-f8f032be7a0b-image.png

          Code:

          """Demonstrates how to run the modelling command MCOMMAND_EXPLODESEGMENTS.
          
          Apart from generating a dangling reference, your script also made some other mistakes, as for 
          example using Opolygon as an input (the command is for splines), and retrieving the cache of your
          input, which will not work in this case because the cache of a spline is a line object which is an
          invalid input for MCOMMAND_EXPLODESEGMENTS.
          
          Must be run as a script manager script.
          
          Note:
              This example uses the 2024 API with mxutils.CheckType, in earlier versions you can remove these
              calls (but then lack error and type safety).
          
          See:
              Geometry Model (Caches): https://github.com/PluginCafe/cinema4d_py_sdk_extended/blob/master/
                  scripts/04_3d_concepts/modeling/geometry/geometry_caches_s26.py
              Modelling Command: https://github.com/PluginCafe/cinema4d_py_sdk_extended/blob/master/scripts/
                  04_3d_concepts/modeling/modeling_commands/smc_extrude_s26.py
          """
          __version__ = "2024.0"
          
          import c4d
          from mxutils import CheckType
          
          op: c4d.BaseObject | None # The active object, can be #None.
          doc: c4d.documents.BaseDocument # The active document.
          
          def main() -> None:
              """
              """
              # Assert that op is not none and get its child.
              child: c4d.BaseObject = CheckType(op).GetDown()
              if not child:
                  raise RuntimeError("Selected object has no child.")
              
              # Get a SplineObject for child when possible. Either #child is a spline itself, or it is a
              # generator holding a spline. We cannot unpack the caches of a SplineObject (GetCache, 
              # GetDeformCache) as they will hold LineObject instances which are not a valid input for 
              # MCOMMAND_EXPLODESEGMENTS. 
              spline: c4d.SplineObject = CheckType(
                  child if isinstance(child, c4d.SplineObject) else child.GetRealSpline(), c4d.SplineObject)
              
              # Clone that object and insert it into a temporary document. Because we clone the object, we
              # must insert it into a document before we pass it to SMC as the operands for SMC must be part
              # of a document. If not, SMC will rectify that for us, which will cause #clone to become a
              # dangling reference, be "dead".
              clone: c4d.SplineObject = CheckType(spline.GetClone(c4d.COPYFLAGS_NO_HIERARCHY))
              temp: c4d.documents.BaseDocument = CheckType(c4d.documents.BaseDocument())
              temp.InsertObject(clone)
          
              # Run the command.
              if not c4d.utils.SendModelingCommand(
                  command=c4d.MCOMMAND_EXPLODESEGMENTS, list=[clone], mode=c4d.MODELINGCOMMANDMODE_ALL, 
                  bc=c4d.BaseContainer(), doc=temp):
                  raise RuntimeError(f"Could not execute MCOMMAND_EXPLODESEGMENTS on {op}.")
              
              # The result of MCOMMAND_EXPLODESEGMENTS is parented to the operand, we insert them into our
              # document.
              for item in clone.GetChildren():
                  item.SetName(f"{item.GetName()} (SMC)")
                  item.Remove()
                  doc.InsertObject(item)
              
              c4d.EventAdd()
          
          if __name__ == "__main__":
              main()
          

          MAXON SDK Specialist
          developers.maxon.net

          bacaB 1 Reply Last reply Reply Quote 0
          • bacaB
            baca @ferdinand
            last edited by baca

            Thanks @ferdinand,

            Since there's no dedicated command to polygons "Explode Islands". And "Explode Segments" is not described in documentation as "For Splines only" I applied it multiple times on both polygon and spline geometry.
            But seems it was long time ago...

            I think only issue is that earlier explode islands keeps original object, but makes it with 0 points, and all segments were nested as children.

            But now if there are more than one segment — it destroys original object, and creates additional Null object, which has nested segments.
            If there are one segment — it keeps existing object, like command has no effect.

            Not very consistent I would say.
            And either it wasn't notified regarding the new behavior, either I missed it.

            Anyway, my code in first reply works fine with both polygon and spline geometries in 2024.2 currently.

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

              Hey @baca,

              if the command would indeed work on polygons, I would be VERY surprised. There is also no "Explode Islands" command or SMC I am aware of (there is a scene nodes operator of that name, but that is not even the same universe of operation as we are here working with).

              46e92027-f885-4899-ac8e-175a9d1ae9c1-image.png

              The user documentation is very clear about explode segments only working on splines:

              0dca2405-d891-45a7-9c1a-413cc2b503ef-image.png

              I am happy when things work out for you, but I also must keep a bit in mind that there might be future readers who want to draw information from this thread. Under this light I would currently classify the assertion that MCOMMAND_EXPLODESEGMENTS can be applied to polygonal geometry as incorrect.

              What you can do in the classic scene graph is run MCOMMAND_SPLIT which is similar to the 'Explode Mesh Islands' operator but does not come with the detecting islands portion of the node operator. To emulate that, you could do this:

              1. Select 0th polygon in a mesh.
              2. SMC: MCOMMAND_SELECTCONNECTED
              3. SMC: MCOMMAND_SPLIT
              4. Delete the selected polygons.
              5. When no polygons are left, exit, otherwise goto 1.

              Maybe I am misunderstanding what you are trying to do?

              Cheers,
              Ferdinand

              MAXON SDK Specialist
              developers.maxon.net

              bacaB 1 Reply Last reply Reply Quote 1
              • bacaB
                baca @ferdinand
                last edited by

                @ferdinand said in c4d.MCOMMAND_EXPLODESEGMENTS makes target object dead:

                1. Select 0th polygon in a mesh.
                2. SMC: MCOMMAND_SELECTCONNECTED
                3. SMC: MCOMMAND_SPLIT
                4. Delete the selected polygons.
                5. When no polygons are left, exit, otherwise goto 1.

                Oh, great idea.
                Not that elegant, but seems legit.
                Thanks again.

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