<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[How to fix the bug of objects position in script]]></title><description><![CDATA[<p dir="auto">Guys! Please, help. I cannot fix this problem.</p>
<p dir="auto">The main idea of ​​this script is:</p>
<ol>
<li>add selected objects and materials of these objects to the layer</li>
<li>insert all objects under null.<br />
But position of objects changes. How to fix it?</li>
</ol>
<p dir="auto">: <a href="https://drive.google.com/file/d/1R-M22Z95Gbc-3hXnsW03kBy0gMWwqZno/view?usp=sharing" target="_blank" rel="noopener noreferrer nofollow ugc">video</a></p>
<pre><code>import c4d

def main():

    doc.StartUndo()


    layer = c4d.documents.LayerObject()
    # Set layer name (another option tp set the name)
    # Get the invisible root layer
    layerRoot = doc.GetLayerObjectRoot()
    # Insert the layer under the parent
    layer.InsertUnder(layerRoot)

    name = layer.GetName()
    rvalue = c4d.gui.RenameDialog(name) # rename
    print(rvalue)
    layer [c4d.ID_BASELIST_NAME] = rvalue
    #layer.DelBit(c4d.BIT_ACTIVE)

    null_obj = c4d.BaseObject(c4d.Onull)
    null_obj [c4d.ID_LAYER_LINK] = layer
    null_obj [c4d.ID_BASELIST_NAME] = rvalue
    doc.InsertObject(null_obj)


    doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, layer)
    doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, null_obj)

    s = doc.GetSelection()
    vp = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_NONE)


    for obj in vp:

        print obj

        obj [c4d.ID_LAYER_LINK] = layer
        obj.InsertUnder(null_obj)

        obj_mat_tags = [t for t in obj.GetTags() if t.IsInstanceOf(c4d.Ttexture)]

        for tag in obj_mat_tags:

            mat = tag.GetMaterial()
            print mat
            mat [c4d.ID_LAYER_LINK] = layer


    doc.EndUndo()
    c4d.EventAdd()

if __name__ == '__main__':
    main()
</code></pre>
<p dir="auto">I use r21 version of c4d.</p>
]]></description><link>http://developers.maxon.net/forum/topic/13742/how-to-fix-the-bug-of-objects-position-in-script</link><generator>RSS for Node</generator><lastBuildDate>Fri, 11 Sep 2026 07:58:22 GMT</lastBuildDate><atom:link href="http://developers.maxon.net/forum/topic/13742.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 28 Dec 2021 12:26:11 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to How to fix the bug of objects position in script on Tue, 28 Dec 2021 14:39:42 GMT]]></title><description><![CDATA[<p dir="auto">Hello <a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/roman">@<bdi>roman</bdi></a>,</p>
<p dir="auto">Thank you for reaching out to us. R21 has left the SDK support cycle, which primarily means we will not debug again such versions anymore and also do not fix bugs for it anymore. I have provided below a solution for your problem which has been tested with R25 because of that, but it should run fine in R21.</p>
<p dir="auto">Your problem primarily is rooted in you simply reparenting the objects. Objects store their transformation - their position, scale and orientation -  as a matrix relative to their parent. So, when you have the objects <code>a, b, c</code> with the local positions <code>(0, 100, 0), (0, 50, 0), (0, 0, 0)</code> and <code>b</code> being parented to <code>a</code>, then the effective global position of <code>b</code> is <code>(0, 100, 0) + (0, 50, 0) = (0, 150, 0)</code>. When you then parent <code>b</code> to <code>c</code>, its position will change from <code>(0, 150, 0)</code> to <code>(0, 50, 0)</code> since <code>c</code> only contributes the null vector to the position of its children. The same principle applies to the scale and orientation stored in the local transform matrix of an object. You were also missing some undo-steps, at least I assumed you did not skip them intentionally.</p>
<p dir="auto">The topic is also covered in the <a href="https://developers.maxon.net/docs/py/2023_2/manuals/data_algorithms/classic_api/matrix.html#objects-and-matrices" target="_blank" rel="noopener noreferrer nofollow ugc">Python API Matrix Manual</a>.</p>
<p dir="auto">Cheers,<br />
Ferdinand</p>
<p dir="auto">The result:<br />
<img src="https://developers.maxon.net/forum/assets/uploads/files/1640700023739-reparent.gif" alt="reparent.gif" class=" img-fluid img-markdown" /></p>
<p dir="auto">The script:</p>
<pre><code>"""Moves the selected objects to a new layer and parent object.

Your problem primarily is rooted in you simply reparenting the objects. 
Objects store their transformation - their position, scale and orientation -  
as a matrix relative to their parent. So, when you have the objects `a, b, c` 
with the local positions `(0, 100, 0), (0, 50, 0), (0, 0, 0)` and `b` being 
parented to `a`, then the effective global position of `b` is `(0, 100, 0) + 
(0, 50, 0) = (0, 150, 0)`. When you then parent `b` to `c`, its position will 
change from `(0, 150, 0)` to `(0, 50, 0)` since `c` only contributes the null 
vector to the position of its children. The same principle applies to the 
scale and orientation stored in the local transform matrix of an object. You 
were also missing some undo-steps, at least I assumed you did not skip them 
intentionally.
"""

import c4d

def main():
    """Entry point.
    """
    # Start an undo stack item.
    doc.StartUndo()

    # Add a new top-level layer
    newLayer = c4d.documents.LayerObject()
    layerRoot = doc.GetLayerObjectRoot()
    newLayer.InsertUnder(layerRoot)
    doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, newLayer)

    # Let the user name the new layer
    newName = c4d.gui.RenameDialog(newLayer.GetName())
    newLayer [c4d.ID_BASELIST_NAME] = newName

    # Create a null object to parent the objects moved to the new layer to.
    newLayerNull = c4d.BaseObject(c4d.Onull)
    newLayerNull [c4d.ID_LAYER_LINK] = newLayer
    newLayerNull [c4d.ID_BASELIST_NAME] = newName
    doc.InsertObject(newLayerNull)
    doc.AddUndo(c4d.UNDOTYPE_NEWOBJ, newLayerNull)

    # Iterate over the selected objects and attach them both to the new layer
    # and layer null-object.
    for item in doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_NONE):

        # Set the layer of the current item, detach it from its previous 
        # parent and store its global matrix.
        doc.AddUndo(c4d.UNDOTYPE_CHANGE, item)
        item [c4d.ID_LAYER_LINK] = newLayer
        itemMg = item.GetMg()
        item.Remove()

        # Attach the object to the null and set its global matrix to the old
        # value.
        item.SetMg(itemMg)
        item.InsertUnder(newLayerNull)

        # Get all materials attached with material tags to the item.
        isTex = lambda item: item.IsInstanceOf(c4d.Ttexture)
        for material in [t.GetMaterial() for t in item.GetTags() if isTex(t)]:
            doc.AddUndo(c4d.UNDOTYPE_CHANGE, material)
            material[c4d.ID_LAYER_LINK] = newLayer

    # Close the undo item and push an update event to Cinema 4D.
    doc.EndUndo()
    c4d.EventAdd()

if __name__ == '__main__':
    main()
</code></pre>
]]></description><link>http://developers.maxon.net/forum/post/68241</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/68241</guid><dc:creator><![CDATA[ferdinand]]></dc:creator><pubDate>Tue, 28 Dec 2021 14:39:42 GMT</pubDate></item></channel></rss>