c4d.MCOMMAND_EXPLODESEGMENTS makes target object dead
-
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) -
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)
-
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.
This is not true,MCOMMAND_EXPLODESEGMENTS
can only be used onSplineObject
inputs, your code is testing forOpolygon
.MCOMMAND_EXPLODESEGMENTS
can also be used to split disjunct islands in a polygonal mesh.- You cannot run
MCOMMAND_EXPLODESEGMENTS
on the generator or deform cache of a real spline, because that is aLineObject
which is not a valid input forMCOMMAND_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,
FerdinandResult:
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()
-
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.
-
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).
The user documentation is very clear about explode segments only working on splines:
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:- Select 0th polygon in a mesh.
- SMC: MCOMMAND_SELECTCONNECTED
- SMC: MCOMMAND_SPLIT
- Delete the selected polygons.
- When no polygons are left, exit, otherwise goto 1.
Maybe I am misunderstanding what you are trying to do?
Cheers,
Ferdinand -
@ferdinand said in c4d.MCOMMAND_EXPLODESEGMENTS makes target object dead:
- Select 0th polygon in a mesh.
- SMC: MCOMMAND_SELECTCONNECTED
- SMC: MCOMMAND_SPLIT
- Delete the selected polygons.
- When no polygons are left, exit, otherwise goto 1.
Oh, great idea.
Not that elegant, but seems legit.
Thanks again.