Select objets by point number
-
Hi
I have a lego project on Cinema4D with a lot of identical objects. I would like replace all identicals objets by intances. Can select objets by the points number? for exemple i would like to select all objects with 152 points. Is it possible?
Thanks !
-
F ferdinand moved this topic from General Talk
-
Hello @Pitchi,
Welcome to the Maxon developers forum and its community, it is great to have you with us!
Getting Started
Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.
- Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
- Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
- Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.
It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: Asking Questions.
About your First Question
You posted in the wrong forum (I have moved your question). You therefore also did not set the tags the
Cinema 4D SDK
forum asks users to set such as the API you want to use (I assume Python) and the version of Cinema 4D you want to target.But, yes, that is possible. You must just iterate over the object tree and then replace things. The tricky thing is to figure out when two nodes (objects) are the same. Just using the point count would be of course an incredibly poor measure of equality. But even when you properly compare the geometry, you could have two objects with identical geometry but different parameters (e.g., one is in layer A and one in layer B) or different nodes attached to them (e.g., one has material tag, and one does not). This can all be dealt with but requires some work and knowledge of our API. What then often also happens is that you want changes for equability except for X and Y which you want to ignore (which then interferes with you just plainly comparing the data containers of nodes for example).
So, long story short, there might be more technical hurdles than you think, but that is all possible. But we cannot write a finished solution for you. We in fact expect users to post code and a concrete API question before we answer. Below you can find a sketch for how you could do this (only works in Cinema 4D 2025.0.0+ because I used
mxutils.IterateTree
.Cheers,
FerdinandResult
Before
After (Cube.1 and .2 have been replaced with instances, but .3 not because it has different point values).
Code
"""Replaces all polygon objects that have the same topology as the selected object with instance objects. This will only operate on editable polygon objects. This script requires Cinema 4D 2025.0.0 or higher. It could be translated to older versions, mxutils.IterateTree would then have to be replaced. """ import c4d import mxutils doc: c4d.documents.BaseDocument # The currently active document. op: c4d.BaseObject | None # The primary selected object in `doc`. Can be `None`. def ComparePolygonObjects(a: c4d.PolygonObject, b: c4d.PolygonObject) -> bool: """Compares two polygon objects for equality, evaluated over their points and topology. """ # When the point values aren't the same, both objects cannot be the same. if a.GetAllPoints() != b.GetAllPoints(): return False # For the topology we unfortunately must be a bit more manual. topologyA: list[c4d.CPolygon] = a.GetAllPolygons() topologyB: list[c4d.CPolygon] = b.GetAllPolygons() if len(topologyA) != len(topologyB): return False # We iterate over all polygons in #a and #b in pairs (x, y) and compare each vertex of the polygon # for referencing the same point. Internally, Cinema 4D stores everything as quads, hence us # blindly checking a, b, c, and d. for x, y in zip(topologyA, topologyB): if (x.a != y.a or x.b != y.b or x.c != y.c or x.d != y.d): return False return True def ReplaceWithInstance(source: c4d.PolygonObject, target: c4d.PolygonObject) -> None: """Replaces #target with an instance object of #source, while copying over the transform and name of #target. """ doc: c4d.documents.BaseDocument = source.GetDocument() # Create an instance object and copy over the necessary data. instance: c4d.BaseObject = mxutils.CheckType(c4d.BaseObject(c4d.Oinstance)) instance[c4d.INSTANCEOBJECT_LINK] = source # Link the source object. instance.SetName(target.GetName()) # Copy the name. if target.GetNBit(c4d.NBIT_OM1_FOLD): # Unfold the instance when the target was unfolded. instance.ChangeNBit(c4d.NBIT_OM1_FOLD, c4d.NBITCONTROL_SET) ml: c4d.Matrix = target.GetMl() # A copy of the PSR of #target in relation to its parent. # Get an insertion point, remove the target, and insert the instance. Also move all the children # from #target to #instance previous: c4d.BaseObject = target.GetPred() parent: c4d.BaseObject = target.GetUp() doc.AddUndo(c4d.UNDOTYPE_DELETE, target) target.Remove() doc.InsertObject(instance, parent, previous) doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, instance) doc.AddUndo(c4d.UNDOTYPE_CHANGE, instance) instance.SetMl(ml) # Write the local transform back to the instance. for child in target.GetChildren(): doc.AddUndo(c4d.UNDOTYPE_CHANGE, child) child.Remove() child.InsertUnderLast(instance) def main() -> None: """ """ # Get out when the selected object is not a polygon object. if not isinstance(op, c4d.PolygonObject): raise TypeError("You must selected an editable PolygonObject to replace.") # Get the points and polygons of the currently selected object. basePoints: list[c4d.Vector] = op.GetAllPoints() basePolygons: list[c4d.CPolygon] = op.GetAllPolygons() # Now iterate over all objects in the scene, stepping over all non-polygon objects and ourselves, # to find objects to remove. removeNodes: list[c4d.PolygonObject] = [] for node in mxutils.IterateTree(doc.GetFirstObject(), True): if not isinstance(node, c4d.PolygonObject): continue # Continue when #op and #node are the same entity or when they are not equal. if op == node or not ComparePolygonObjects(op, node): continue removeNodes.append(node) # And now finally remove all objects in one undo. if removeNodes: doc.StartUndo() for node in removeNodes: ReplaceWithInstance(op, node) doc.EndUndo() c4d.EventAdd() if __name__ == '__main__': main()
-
Thanks you for your help