Solved Copy mesh from one object to another with Python

Hi! I'm looking for quick way to copy all points, edges and polygons data from one poly object to another with Python tag.

Right now i'm using this loops:

    for i in range(0, pointCount):
        targetObj.SetPoint(i, sourceObj.GetPoint(i))

    for i in range(0, polygonCount):
        poly = sourceObj.GetPolygon(i)
        if poly.IsTriangle():
            targetObj.SetPolygon(i, c4d.CPolygon(poly.a, poly.b, poly.c))
        else:
            targetObj.SetPolygon(i, c4d.CPolygon(poly.a, poly.b, poly.c, poly.d))

It's missing hidden edges for Ngons feature but already really slow on 10k+ polygons. Is there way to do it faster?

I'm looking into Edit->Copy & Edit->Paste commands but its really hacky way since its tag, not a single execution script.
Also C4DAtom.CopyTo() looks promising but I have no idea what flag I should pass to copy only mesh, not every object property

Hello @karpique,

Thank you for reaching out to us. There are two things you could optimize out in your code. Frist, the loop around targetObj.SetPoint, since there is PointObject.SetAllPoints, taking a list of points and being much faster. Secondly, you could also optimize away the branching in your code with poly.IsTriangle(), since both tris and quads are being handled as quads by Cinema 4D (a tri is a handled as a CPolygon where c == d). So, you could just write:

for i in range(0, polygonCount):
    poly = sourceObj.GetPolygon(i)
    targetObj.SetPolygon(i, c4d.CPolygon(poly.a, poly.b, poly.c, poly.d))

Unlike for points, there is unfortunately no method in Python to write CPolygon in bulk with, making writing polygons in Python quite slow. As you mentioned, you could also use C4DAtom.CopyTo, but there is no clean way to "copy only (the) mesh", since geometry information is being stored in tags and not the node itself. This will also copy n-gons:

"""Example for copying polygons and n-gons from one node to another.

Run this with a polygon object selected in the script manger.
"""

import c4d

def main():
    """
    """
    # Create a Opolygon node of matching size
    res = c4d.PolygonObject(op.GetPointCount(), op.GetPolygonCount())
    # We first have to insert that new node into a document, this could also
    # be a temporary document.
    doc.InsertObject(res)
    c4d.EventAdd()
    # Then we just copy over stuff from the source. We cannot use the 
    # COPYFLAGS_NO_BRANCHES flag, as this will prevent copying tag data,
    # which is also being used to store point and polygon information.
    flags = c4d.COPYFLAGS_NO_ANIMATION | c4d.COPYFLAGS_NO_HIERARCHY | c4d.COPYFLAGS_NO_BITS
    op.CopyTo(res, flags)
    

if __name__=='__main__':
    main()

There are some other routes you could take, like. c4d.utils.SendModelingCommand and joining your mesh to copy with an empty mesh or handling it in a more hands-on-fashion by copying over the Tpoint and Tpolygon tags manually, and thereby avoid copying unwanted tag information.

Cheers,
Ferdinand

MAXON SDK Specialist
developers.maxon.net

@ferdinand thanks for qiuck answer and quality info! I went with copying Tpoint and Tpolygn tags, but now stuck with translating hidden Ngon edges — can you point the right way to do that?

I feel like it sholud be some functions from c4d.PolygonObject class but stuck in here:

bs = c4d.BaseSelect()
bs.SetAll([0] * polyObj.GetPolygonCount() * 4)
ng = c4d.utils.Neighbor()
ng.Init(polyObj)
#doesnt work as expected, hidden ngon edges are not showing up
polyObj.SetSelectedEdges(ng, bs, c4d.EDGESELECTIONTYPE_HIDDEN) 

Hi:

Do you want to make a complete copy of another polygon object from scratch using Python tags?Including n-gon edges.

You hide edges incorrectly, it's still not an n-gon edge, it's just an edge selection.I have the full Python tag code, which is fast, but I won't post it here.However, this Python tag only runs in R23 and up.Since Python cannot directly create polygons with n-gon edges, it can only be done with the Model Elimination command in versions R23 and above.

Your Python code isn't optimal, so it's not fast.The fastest way to do this is to use C++, which can create polygons with n-gon edges directly and at tens of times the speed of Python tags.Also, Python tags create n-gon polygons that don't have the same edge indexes as the n-gon polygons that copy objects, which is one of Python's flaws.

Hello @karpique,

the Ngon interface is not being exposed to Python, which makes handling them always a bit harder there. You will have to either copy the PolygonObject itself, like shown by me above, which will handle Ngons properly. Or you have to use PolygonObject.GetNGonTranslationMap to manually recrate the Ngons on the new PolygonObject. Due to the absence of the Ngon interface in Python, you would have to do this with c4d.utils.SendModelingCommand and the symbol MCOMMAND_MELT. Due to this being rather cumbersome, I showed the more general solution in my previous posting. If you want to clean up an object with that more general solution, you could iterate over all tags and remove any tag that is not of type Tphong, Tpoint, or Tpolygon (you might want to include other tag types, depending on what your goals are).

Cheers,
Ferdinand

MAXON SDK Specialist
developers.maxon.net

This post is deleted!

@ferdinand thanks! I have one more question: after replacing Tpoint and Tpolygon tags object seems to keep it's old bounding box parameters and disappear from viewport accordigly to them. Is there a way to update this property?

Hi @karpique,

hard to say from the outside without any code to see what you are doing, but my educated guess would be that

myObjectWithFaultyBòundingBox.Message(c4d.MSG_UPDATE)
c4d.EventAdd()

will solve your porblem.

Cheers,
Ferdinand

MAXON SDK Specialist
developers.maxon.net

@ferdinand I get Ngon translation map and applied MCOMMAND_MELT but stuck again — as I understand SendModellingCommand only returns new object with melted ngons, but my goal is to correct object that already exists in scene...

Is there any other ways of setting up Ngon translation map with python?