modeling_command_join¶
Demonstrates how to execute the ‘Join’ tool.
modeling_command_join.py¶
#coding: utf-8
"""Demonstrates how to execute the 'Join' tool.
Invokes 'Join' tool on the currently selected objects in the active document via `SendModelingCommand`.
Topics:
* The 'Join' tool
* c4d.utils.SendModelingCommand()
Note:
See `modeling_command_extrude.py` for a more in depth overview of the topic of `SendModelingCommand`.
"""
__author__ = "Ferdinand Hoppe"
__copyright__ = "Copyright (C) 2026 MAXON Computer GmbH"
__date__ = "08/04/2022"
__license__ = "Apache-2.0 License"
__version__ = "S26"
import c4d
import typing
doc: c4d.documents.BaseDocument # The currently active document.
op: typing.Optional[c4d.BaseObject] # The selected object within that active document. Can be None.
def main(doc: c4d.documents.BaseDocument) -> None:
"""Runs the example.
Args:
doc: The active document.
"""
# Retrieve all directly selected objects.
objects = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_NONE)
# The join tool requires its inputs to be parented to a null object. This implies using a dummy
# document as the user could have selected parts of a hierarchy where it would be then ambiguous
# which parts should be moved where:
#
# Object 1
# Object 1.1 [selected]
# Object 1.1.1
# Object 2
# Object 2.1 [selected]
# Object 2.1.1
#
# An empty dummy document to carry the command out with.
temp = c4d.documents.BaseDocument()
# Insert clones of all input objects under a new null object and insert that null object into
# the dummy document.
null = c4d.BaseObject(c4d.Onull)
for node in objects:
clone = node.GetClone(c4d.COPYFLAGS_NO_HIERARCHY)
clone.InsertUnderLast(null)
temp.InsertObject(null)
# The settings of the 'Join' tool.
bc = c4d.BaseContainer()
# Merge possibly existing selection tags.
bc[c4d.MDATA_JOIN_MERGE_SELTAGS] = True
# Execute the Join command in the dummy document.
res = c4d.utils.SendModelingCommand(command=c4d.MCOMMAND_JOIN,
list=[null],
mode=c4d.MODELINGCOMMANDMODE_ALL,
bc=bc,
doc=temp,
flags=c4d.MODELINGCOMMANDFLAGS_CREATEUNDO)
if not res:
raise RuntimeError(f"Modelling command failed for {op}.")
# The 'Join' command returns its result in the return value of SendModelingCommand()
joinResult = res[0]
if not isinstance(joinResult, c4d.BaseObject):
raise RuntimeError("Unexpected return value for Join tool.")
joinResult.SetName("Join Result (SMC)")
# Insert the joined geometry back into the original document as a new object, wrapping the
# operation into an undo.
if not doc.StartUndo():
raise RuntimeError("Could not open undo stack.")
doc.InsertObject(joinResult)
if not doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, joinResult):
raise RuntimeError("Could not add undo item.")
if not doc.EndUndo():
raise RuntimeError("Could not close undo stack.")
# Inform Cinema 4D that the document has been modified.
c4d.EventAdd()
if __name__ == '__main__':
# #doc is a predefined module attribute as defined at the top of the file.
main(doc)