MCOMMAND_JOIN for objects with different parents

On 16/02/2015 at 02:01, xxxxxxxx wrote:

Hi

Seems like MCOMMAND_JOIN joins all objects together when they have the same parent object. In this
case, it will only join the first two objects which are in in the Boole 0 object.

import c4d
  
def main() :
    objects = doc.GetActiveObjects(0)
    result = c4d.utils.SendModelingCommand(
        c4d.MCOMMAND_JOIN, objects, doc=doc)
    doc.InsertObject(result[0])
    c4d.EventAdd()
  
main()

Is there a way without temporarily restructuring the objects?

Thanks,
Niklas

On 16/02/2015 at 09:02, xxxxxxxx wrote:

Hello,

the MCOMMAND_JOIN command has no further options that would allow to define it's behavior in that regard. You could create temporary clones of your objects, make them child objects of a temporary null object and use that null object as your argument as described in this thread.

Best wishes,
Sebastian

On 23/02/2015 at 06:01, xxxxxxxx wrote:

Thank you Sebastian, I think I found a working solution.

  
import c4d
import collections
  
def join_objects(objects, doc) :
    r"""
    Connects all polygon or spline objects in the iterable *objects*
    into a single polygon or spline object and returns it. The
    operation will be hosted temporarily be hosted by the document
    *doc*. The resulting object's axis is at the world origin.
  
    It is already enough to pass the root object of a hierarchy that
    contains polygon and/or spline objects to join the complete
    hierarchy.
    
    :raise TypeError:
        If *objects* is not an iterable object or *doc* is not a
        BaseDocument.
    :raise ValueError:
        If the objects could not be joined.
    """
  
    # Validate the input parameters.
    if not isinstance(objects, collections.Iterable) :
        raise TypeError('objects must be iterable')
    if not isinstance(doc, c4d.documents.BaseDocument) :
        raise TypeError('doc must be BaseDocument')
  
    # The root object of all objects that need to be joined.
    root = c4d.BaseObject(c4d.Onull)
    doc.InsertObject(root)
    context = []
  
    try:
        # Move all objects under the root object and save the
        # original state.
        for obj in objects:
            mg = obj.GetMg()
            context.append([obj, obj.GetUp(), obj.GetPred(), mg])
            obj.Remove()
            obj.InsertUnder(root)
            obj.SetMg(mg)
  
        # Execute the join command on the root object.
        result = c4d.utils.SendModelingCommand(
            c4d.MCOMMAND_JOIN, root.GetChildren(), doc=doc)
        
        if not result:
            raise ValueError('could not join objects')
  
        # Just make sure the object is not in the hierarchy somewhere
        # and reset the objects matrix as it is strangely offset after
        # the command executed.
        result[0].Remove()
        result[0].SetMl(c4d.Matrix())
        result[0].SetName(context[0][0].GetName())
        return result[0]
  
    finally:
        # Restore the original states of all objects and the document.
        root.Remove()
        for obj, parent, pred, mg in context:
            obj.Remove()
            if pred:
                obj.InsertAfter(pred)
            elif parent:
                obj.InsertUnder(parent)
            obj.SetMg(mg)

There seems to be a bug when passing [root] instead of root.GetChildren() as it does not only
use root and its child objects for joining but also roots neighbors on the same hierarchy level.

Best,
Niklas

On 24/02/2015 at 01:22, xxxxxxxx wrote:

Hello,

great that you found a solution. If you think you found a bug please post some simple code with the described behavior in the Bug subforum. Thanks.

Best wishes,
Sebastian