<?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[Spline modeling commands via OBJECT_MODIFIER (Python)]]></title><description><![CDATA[<p dir="auto">Hello PluginCafe <img src="http://developers.maxon.net/forum/assets/plugins/nodebb-plugin-emoji/emoji/android/1f642.png?v=0b8ddba251d" class="not-responsive emoji emoji-android emoji--slightly_smiling_face" style="height:23px;width:auto;vertical-align:middle" title=":)" alt="🙂" /></p>
<p dir="auto">I'm trying to affect Spline Objects via OBJECT_MODIFIER plugin but it has no influence when the modeling commands are taking place.</p>
<p dir="auto">Let's assume I want to select an arbitrary number of points and delete them by utilizing MCOMMAND_DELETE</p>
<pre><code>class Oresplines(plugins.ObjectData):
    
    def ModifyObject(self, mod, doc, op, op_mg, mod_mg, lod, flags, thread):

        op.GetPointS().SelectAll(5)

        res = c4d.utils.SendModelingCommand(command  = c4d.MCOMMAND_DELETE,
                                            list     = [op],
                                            mode     = 1,
                                            doc      = doc,
                                            flags    = 0)

        return True
</code></pre>
<p dir="auto">When I'm making the plugin a child of some polygonal object, it works as expected.</p>
<p dir="auto"><img src="https://i.imgur.com/Xod0UQY.gif" alt="alt text" class=" img-fluid img-markdown" /></p>
<p dir="auto">But if I attempt to make it a child of the desired spline, nothing changes.</p>
<p dir="auto"><img src="https://i.imgur.com/KTYO1Gd.gif" alt="alt text" class=" img-fluid img-markdown" /></p>
<p dir="auto">Let me know if I'm doing something wrong.</p>
]]></description><link>http://developers.maxon.net/forum/topic/11239/spline-modeling-commands-via-object_modifier-python</link><generator>RSS for Node</generator><lastBuildDate>Sun, 17 May 2026 06:05:50 GMT</lastBuildDate><atom:link href="http://developers.maxon.net/forum/topic/11239.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 13 Jan 2019 13:21:20 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Spline modeling commands via OBJECT_MODIFIER (Python) on Tue, 15 Jan 2019 18:12:38 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/m_adam">@<bdi>m_adam</bdi></a> said in <a href="https://developers.maxon.net/forum/post/56835" target="_blank" rel="noopener noreferrer nofollow ugc">Spline modeling commands via OBJECT_MODIFIER (Python)</a>:</p>
<blockquote>
<p dir="auto">Maxime</p>
</blockquote>
<p dir="auto">Thank you, Maxime for your explicit and informative answer! <img src="http://developers.maxon.net/forum/assets/plugins/nodebb-plugin-emoji/emoji/android/2665.png?v=0b8ddba251d" class="not-responsive emoji emoji-android emoji--hearts" style="height:23px;width:auto;vertical-align:middle" title="♥" alt="♥" /><br />
I'll take a look into it.</p>
]]></description><link>http://developers.maxon.net/forum/post/56845</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/56845</guid><dc:creator><![CDATA[merkvilson]]></dc:creator><pubDate>Tue, 15 Jan 2019 18:12:38 GMT</pubDate></item><item><title><![CDATA[Reply to Spline modeling commands via OBJECT_MODIFIER (Python) on Tue, 15 Jan 2019 11:36:51 GMT]]></title><description><![CDATA[<p dir="auto">Hi <a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/merkvilson">@<bdi>merkvilson</bdi></a>, to be honest, I completely overlooked the problem and thought op within ModifyObject would be a splineObject.<br />
To clarify MCOMMAND_DELETE do not work on LineObject (which are the object for spline cache).<br />
So in order to do so here a hacky solution.<br />
Use the actual spline object from the scene, and then Apply the delete into this SplineObject (since there is no way to get a SplineObject from a LineObject).</p>
<pre><code>class Oresplines(plugins.ObjectData):

    # Get obj and all its Children into a list 
    def GetChildren(self, obj, next, modifiedObjs=None):
        if modifiedObjs is None:
            modifiedObjs = list()

        while obj and obj != next:
            modifiedObjs.append(obj)
            self.GetChildren(obj.GetDown(), next, modifiedObjs)
            obj = obj.GetNext()
        return modifiedObjs

    # Compare 2 line object and tell if it's the same one (based on the topology + space position of the object)
    def compareOline(self, a, b):
        if type(a) != type(b): return False
        if not a.CheckType(c4d.Oline): return False
        
        # Do different pass of checks from speedier to slower in order to leave as soon as possible if object does not match.

        # Fast check, check for pt count
        if a.GetPointCount() != b.GetPointCount():
            return False

        # Fast check
        if a.GetMg() != b.GetMg():
            return False

        # slower check
        if a.GetAllPoints() != b.GetAllPoints():
            return False

        tagA = a.GetTag(c4d.Tline)
        tagB = b.GetTag(c4d.Tline)
        if not tagA or not tagB:
            return False

        # Even slower
        if tagA.GetAllHighlevelData() != tagB.GetAllHighlevelData():
            return False

        return True

    def ModifyObject(self, mod, doc, op, op_mg, mod_mg, lod, flags, thread):
        # Handle polygons
        if not op.IsInstanceOf(c4d.Oline):
            op.GetPointS().SelectAll(5)
            res = c4d.utils.SendModelingCommand(command  = c4d.MCOMMAND_DELETE,
                                                list     = [op],
                                                mode     = 1,
                                                doc      = doc,
                                                flags    = 0)
            return True

        # First step is to get all objects modified by our modifier.
        # Modifier works only if they are within another object. And all children of this hierarchy are modified.
        parent = mod.GetUp()
        isInGroup = bool(parent)

        # Should never happen if we are not in a group, nothing is modified, so ModifyObject is never called.
        if not isInGroup: return True
        
        # Get all children of the parent (aka all objects modified by our modifier).
        modifiedObjs = self.GetChildren(parent, mod.GetNext())

        # Iterate over all modified objects, and check which LineObject is currently modified in the curent ModifyObject call.
        spline = None
        for obj in modifiedObjs:
            cache = obj.GetCache()
            if not cache:
                continue
            
            # Comparison of Oline might fail, C4D do not guarantee the execution order of ModifyObject.
            # So if we get A and B identical e.g. 2 c4d.Osplinecircle with same parameters,
            # ModifyObject may currently edit B before A, while the compare will return True to the first object matching the condition
            # So it may return true on A while B was modified. But in the end, it does not really matter since both will be modified just order might get swapped.
            if self.compareOline(cache, op):
                spline = obj
                break

        # Check if our modified object is a spline and nothing else
        if not spline or not spline.GetInfo()&amp;c4d.OBJECT_ISSPLINE:
            return True

        # Then we get a copy of the SplineObject located in the scene
        splineObj = spline.GetRealSpline().GetClone()
        if not splineObj: return True

        # Create a tempo document for our delete operation
        workDoc = c4d.documents.BaseDocument()
        workDoc.InsertObject(splineObj)

        # Select and delet our points
        splineObj.GetPointS().SelectAll(1)
        res = c4d.utils.SendModelingCommand(command  = c4d.MCOMMAND_DELETE,
                                            list     = [splineObj],
                                            mode     = c4d.MODELINGCOMMANDMODE_POINTSELECTION,
                                            doc      = workDoc,
                                            flags    = 0)

        if not res:
            return True

        # Build the cache, in order to generate a Oline object from the resulting SplineObject
        workDoc.ExecutePasses(thread, False, False, True, c4d.BUILDFLAGS_INTERNALRENDERER)

        # Get the Cache (Oline object) of our modified splineObject
        oLineModified = splineObj.GetCache()
        if not oLineModified: return True

        # Copy our modified LineObject to the op LineObject
        oLineModified.CopyTo(op, c4d.COPYFLAGS_NONE)

        return True
</code></pre>
<p dir="auto">If you have any question, please let me know. <img src="http://developers.maxon.net/forum/assets/plugins/nodebb-plugin-emoji/emoji/android/1f604.png?v=0b8ddba251d" class="not-responsive emoji emoji-android emoji--smile" style="height:23px;width:auto;vertical-align:middle" title=":smile:" alt="😄" /><br />
Cheers,<br />
Maxime.</p>
]]></description><link>http://developers.maxon.net/forum/post/56835</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/56835</guid><dc:creator><![CDATA[m_adam]]></dc:creator><pubDate>Tue, 15 Jan 2019 11:36:51 GMT</pubDate></item><item><title><![CDATA[Reply to Spline modeling commands via OBJECT_MODIFIER (Python) on Mon, 14 Jan 2019 12:34:38 GMT]]></title><description><![CDATA[<p dir="auto">Hello Maxime <img src="http://developers.maxon.net/forum/assets/plugins/nodebb-plugin-emoji/emoji/android/1f642.png?v=0b8ddba251d" class="not-responsive emoji emoji-android emoji--slightly_smiling_face" style="height:23px;width:auto;vertical-align:middle" title=":)" alt="🙂" /><br />
Indeed, I know how to perform this operation in CommandData/Script but my question was about Object Modifier plugins (aka deformers).</p>
<ul>
<li><strong><a href="https://www.dropbox.com/s/j51trd9amq8zqhz/Spline%20Deformers.zip?dl=0" target="_blank" rel="noopener noreferrer nofollow ugc">Download plugin</a></strong></li>
</ul>
]]></description><link>http://developers.maxon.net/forum/post/56824</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/56824</guid><dc:creator><![CDATA[merkvilson]]></dc:creator><pubDate>Mon, 14 Jan 2019 12:34:38 GMT</pubDate></item><item><title><![CDATA[Reply to Spline modeling commands via OBJECT_MODIFIER (Python) on Tue, 15 Jan 2019 11:29:09 GMT]]></title><description><![CDATA[<p dir="auto">Hi <a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/merkvilson">@<bdi>merkvilson</bdi></a>, just a quick reminder I turned on your topic as a Question, Please See <a href="https://developers.maxon.net/forum/topic/11004/q-a-new-functionality" target="_blank" rel="noopener noreferrer nofollow ugc">Q&amp;A Functionnality</a>.</p>
<p dir="auto">Regarding your issue, C4D does not let you modify a Spline generator. As you may know, all spline generator hold a c4d.LineObject in their cache. And MCOMMAND_DELETE does fail on a LineObject, it only supports PolygonObject or SplineObject.<br />
So you first need to convert your spline generator as a SplineObject.</p>
<pre><code>import c4d

def MakeEditableClone(obj):
	# We clone the obj, since MakeEditable, modify the passed object and we don't want that.
    oDoc = obj.GetClone()
    doc = c4d.documents.BaseDocument()
    doc.InsertObject(oDoc)
    
    res = c4d.utils.SendModelingCommand(
        command = c4d.MCOMMAND_MAKEEDITABLE,
        list = [obj],
        mode = c4d.MODELINGCOMMANDMODE_ALL,
        doc = doc)
    
    if not res:
        return False
    
    return res[0]

def Delete(obj):
    oDoc = obj.GetClone()
    if oDoc.GetDocument() is None:
        doc.InsertObject(oDoc)

    oDoc.GetPointS().SelectAll(1)
    
    res = c4d.utils.SendModelingCommand(command  = c4d.MCOMMAND_DELETE,
                                            list     = [oDoc],
                                            mode     = 1,
                                            doc      = doc,
                                            flags    = 0)
    
    if res == True:
        retObj = oDoc.GetClone()
        oDoc.Remove()
        return retObj
    
    return False

def main():
    splineObj = MakeEditableClone(op)
    if not splineObj: return
    
    finalSpline = Delete(splineObj)
    if not finalSpline: return
    
    doc.InsertObject(finalSpline)
    
    c4d.EventAdd()

# Execute main()
if __name__=='__main__':
    main()
</code></pre>
<p dir="auto">If you have any questions, please let me know!<br />
Cheers,<br />
Maxime.</p>
]]></description><link>http://developers.maxon.net/forum/post/56822</link><guid isPermaLink="true">http://developers.maxon.net/forum/post/56822</guid><dc:creator><![CDATA[m_adam]]></dc:creator><pubDate>Tue, 15 Jan 2019 11:29:09 GMT</pubDate></item></channel></rss>