Navigation

    • Register
    • Login
    • Search
    1. Home
    2. matniedoba
    3. Posts
    • Profile
    • More
      • Following
      • Followers
      • Topics
      • Posts
      • Best
      • Groups

    Posts made by matniedoba

    RE: Generator sticks in a dirty loop

    Thank you @zipit for your comprehensive response, especially with the link to the coding guide. I guess it might be better to create the spline manually from the points which are connected by the edges without the usage of SendModellingCommand. It was good for prototyping functionality but as you mentioned, it is hard to debug. I appreciate you took the time (and I know it's a lot of convoluted code) to read through it. @r_gigante -> the work is currently on my side so you don't need to bother. I think I have enough information to do a second iteration and rewriting this from scratch.

    posted in Cinema 4D SDK •
    Generator sticks in a dirty loop

    Dear Python experts,

    I am working on a Python Generator Plugin which creates Splines from Polygon Edges including some cleanup procedures. The problem I am facing is that the Generator works in a simple setup (e.g. it has a Voronoi Fracture or Clone under it) but when it comes in complex setups with more children it spins in an endless dirty loop. It really gets evil when Fields are involved in that setup. I tried everything including SetOptimizeCache(True) or checking dirty states of the children with a loop but nothing really helped here. Maybe it is because of all these modelling commands which probably make a scene dirty.

    Could you provide me with some help? I know it is a generic question, I would like to be more specific but I don't know how. I would really appreciate your help here.

    Here is the code of the entire plugin:

    import os
    import c4d
    from c4d import plugins, utils, bitmaps
    from c4d.utils import SplineHelp
    
    class SplFromEdge(plugins.ObjectData):
    
        def Init(self, node):
            # Retrieves the BaseContainer Instance to set the default values
            #self.SetOptimizeCache(True)
            data = node.GetDataInstance()
            if data is None:
                return False
            
            data.SetBool(c4d.WELDSIMILAR, False)
            data.SetFloat(c4d.THRESHOLD, 0.01)
            data.SetInt32(c4d.O_SPLINEFROMEDGEMODE, c4d.O_SPLINEFROMEDGEMODE_TAG)
            data.SetBool(c4d.O_SPLINEFROMEDGEMODE_AUTOUPDATE , True)
            data.SetBool(c4d.CLOSE,True)
            data.SetBool(c4d.O_SPLINEFROMEDGEMODE_OPTIMIZE, True)
            return True
    
        #grey out the threshold in the UI
        def GetDEnabling(self, node, id, t_data, flags, itemdesc):
            data = node.GetDataInstance()
            weld = data.GetBool(c4d.WELDSIMILAR)
            if id[0].id == c4d.THRESHOLD:
                return weld
    
            # Retrieves the current interpolation
            inter = node[c4d.O_SPLINEFROMEDGEMODE]
    
            # Defines enable state for the selection
            if id[0].id == c4d.EDGESELECTION:
                return inter == c4d.O_SPLINEFROMEDGEMODE_TAG
            return True
    
    
        #iterator to go through the whole hierarchy
        def walk(self,op) :  
            if not op: return  
            elif op.GetDown() :  
                return op.GetDown()  
            while op.GetUp() and not op.GetNext():  
                op = op.GetUp()  
            return op.GetNext()  
        
        #has all modeling operators
        def ExecModelingCommand(self, doc,opCtrl, op, parent):
            if op is None:
                return
    
            data = opCtrl.GetDataInstance()
            threshold = data.GetReal(c4d.THRESHOLD)
            weld = data.GetBool(c4d.WELDSIMILAR)
            mode = data.GetInt32(c4d.O_SPLINEFROMEDGEMODE)
            selectionSet = data.GetString(c4d.EDGESELECTION)
            optimize = data.GetBool(c4d.O_SPLINEFROMEDGEMODE_OPTIMIZE)
            close = data.GetBool(c4d.CLOSE)
            
            splineHelper = SplineHelp()
            container = c4d.BaseContainer()
            
            childObject = op.GetClone(c4d.COPYFLAGS_NONE)
            # Creates a temporary document.
            tempDoc = c4d.documents.BaseDocument()
            # Insert the cloned object to the temporary document.
            tempDoc.InsertObject(childObject)
            
            tempParent = c4d.BaseObject(c4d.Onull)
    
            if childObject is None or (mode==c4d.O_SPLINEFROMEDGEMODE_TAG and selectionSet==""):
                return
     
            parent.SetMg(childObject.GetMg())
    
            c4d.StatusSetText("Creating Splines from Edges")
            c4d.StatusSetSpin()
    
            res = utils.SendModelingCommand(command=c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                                        list=[childObject],
                                        mode=c4d.MODELINGCOMMANDMODE_ALL,
                                        bc=container,
                                        doc=tempDoc)
    
            if res is None:
                return
            
            editableObject = res[0]
            #select edges based on a selection tag
            def selectEdges(obj,tag):
                selection = tag.GetBaseSelect()
                polyselection = obj.GetEdgeS()
                selection.CopyTo(polyselection)
    
            #iterate through the new created polygon objects and look for the ones with an edge selection tag
            objectList = []   
    
            while editableObject:
                if editableObject.CheckType(c4d.Opolygon):
                    if mode==c4d.O_SPLINEFROMEDGEMODE_TAG:
                        for i in editableObject.GetTags():
                            if i.GetName()==selectionSet and i.CheckType(c4d.Tedgeselection):
                                #select
                                selectEdges(editableObject,i)
                                #add to list                        
                                objectList.append(editableObject)
                    elif mode==c4d.O_SPLINEFROMEDGEMODE_ALL:
                        utils.SendModelingCommand(c4d.MCOMMAND_SELECTALL, 
                                                list = [editableObject], 
                                                mode = c4d.MODELINGCOMMANDMODE_EDGESELECTION, 
                                                bc = c4d.BaseContainer())
                        objectList.append(editableObject)
                editableObject = self.walk(editableObject)
           
            if not objectList:
                c4d.StatusClear()
                return
    
            for i in objectList:
                i.InsertUnderLast(tempParent)
    
            spl = utils.SendModelingCommand(command=c4d.MCOMMAND_EDGE_TO_SPLINE,
                                                list=objectList,
                                                mode=c4d.MODELINGCOMMANDMODE_ALL,
                                                doc=objectList[0].GetDocument()) 
    
            c4d.StatusSetText("Optimizing Spline Objects")
            
            #Exploding Splines with multiple Segments which came from Edge to Spline
            splitList = []
            for i in objectList:
                child = i.GetDown()
                if child is not None:
                    if child.CheckType(c4d.Ospline):
    
                        splineHelper.InitSpline(child)
                        if splineHelper.GetSegmentCount() !=1:
                            splitList.append(child)
     
            #Explode Splines using the Explode Command
            if splitList:
                expSplines = utils.SendModelingCommand(command=c4d.MCOMMAND_EXPLODESEGMENTS,
                                                                        list=splitList,
                                                                        mode=c4d.MODELINGCOMMANDMODE_ALL,
                                                                        flags=c4d.MODELINGCOMMANDFLAGS_NONE,
                                                                        doc=splitList[0].GetDocument()) 
            
            #Creating a Spline List which will be later added under a parent object
            splineList = []
            obj=objectList[0]
            while obj:
                if obj.CheckType(c4d.Ospline):
                    splineHelper.InitSpline(obj)
                    if splineHelper.GetSegmentCount() !=0:
                        #Add all spline objects to a dedicated spline list. Every object which is not in that list will be deleted
                        splineList.append(obj)
                obj = self.walk(obj)
    
            #optimize the spline for duplicate points
            optimizeBC = c4d.BaseContainer()
            optimizeBC[c4d.MDATA_OPTIMIZE_POINTS]= optimize
            optimizeBC[c4d.MDATA_OPTIMIZE_UNUSEDPOINTS]= True
            optimizeBC[c4d.MDATA_OPTIMIZE_TOLERANCE]= 0.01
            optimizedSplines = utils.SendModelingCommand(command=c4d.MCOMMAND_OPTIMIZE,
                                                                        list=splineList,
                                                                        bc= optimizeBC,
                                                                        mode=c4d.MODELINGCOMMANDMODE_ALL,
                                                                        flags=c4d.MODELINGCOMMANDFLAGS_NONE)
            
            #filter overlapping objects
            c4d.StatusSetText("Cleaning Up and Welding")
    
            positionList = []
            keyList = []
            noDuplicateSplineList = []
            for i in splineList:
                points = i.GetAllPoints()
                bary = c4d.Vector(0)
                #find the center of all points            
                for j in points:
                    bary+=j
                bary = bary / len(points)
                # move the points by the amount represented by the new axis center              
                for index, point in enumerate(points) :  
                    point = point - bary 
                    i.SetPoint(index, point)  
                # notify about the points repositioning  
                i.Message(c4d.MSG_UPDATE)  
                # adjust the matrix offset component accordingly 
                currentMg = i.GetMg() 
                currentMg.off += bary
                # reposition the object in the space 
                i.SetMg(currentMg)
                #adjust object position
                polyParent = i.GetUp()
                offset = polyParent.GetMg().off
                #insert and adjust object position
                i.InsertUnderLast(tempParent)
                i[c4d.SPLINEOBJECT_CLOSED]=close
                currentMg = i.GetMg()
                currentMg.off += offset
                i.SetMg(currentMg)
                #remove overlapping splines if welding is active
                if weld:
                    #check spline object position if it mateches a certain threshold
                    overlapping = False
                    if positionList:
                        for j in positionList:
                            p1 = i.GetMg().off
                            p2 = j.GetMg().off
                            distance = (p2-p1).GetLength()
                            
                            if distance <= threshold: 
                                overlapping = True  
                    #check if it's overlapping and clear it
                    key = int((i.GetRad().x+i.GetRad().y+i.GetRad().z)/threshold)
                    if key in keyList and overlapping:
                        i.Remove()                    
                    else:
                        keyList.append(key)
                        positionList.append(i)
                        noDuplicateSplineList.append(i)
                else:
                    noDuplicateSplineList.append(i)
            c4d.StatusClear()
            
            #put everything under the parent null and return it
            for i in noDuplicateSplineList:
                i.InsertUnderLast(parent)
    
            return parent
        
        def GetVirtualObjects(self, op, hh):
    
            doc = op.GetDocument()
            data = op.GetDataInstance()       
    
            objInput = op.GetDown()
            
            if objInput is None:
                return None
            
            objRet = c4d.BaseObject(c4d.Onull)
            if doc is None or objRet is None:
                return None
    
            
            hierarchyClone = op.GetAndCheckHierarchyClone(hh, objInput, c4d.HIERARCHYCLONEFLAGS_ASPOLY, True)
            
            if hierarchyClone["dirty"] is False:
                return hierarchyClone["clone"]
                
            clone = hierarchyClone["clone"]
                    
            if clone is None:
                return op.GetCache()
        
            self.ExecModelingCommand(doc, op, clone, objRet)
            return objRet
    
    ###############################################################################################################
    # Plugin Registration
    ###############################################################################################################
    
    PLUGIN_ID_GENERATOR = 954679
    
    def RegisterObjectData(id, name, bmpPath, objData, desc, flags):
        bmp = bitmaps.BaseBitmap()
        bmp.InitWith(os.path.join(bmpPath, "res", "icon.tif"))
        plugins.RegisterObjectPlugin(id=id, str=name,
                                    g=objData,
                                    description=desc, icon=bmp,
                                    info=flags)
    
    if __name__ == "__main__":
        path, fn = os.path.split(__file__)
    
        RegisterObjectData(PLUGIN_ID_GENERATOR, "Spline from Edge", path, SplFromEdge, "osplinefromedge", c4d.OBJECT_GENERATOR | c4d.OBJECT_INPUT)
    
    posted in Cinema 4D SDK •
    RE: Trouble with GetAndCheckHierarchyClone

    Amazing! Thank you Manuel! It works with multiple objects, Cloners etc. Without your help I would not make it 😉

    posted in Cinema 4D SDK •
    RE: Trouble with GetAndCheckHierarchyClone

    Hey Manuel,

    I tried this method but I encountered another issue. The copy to another document does not work in a setup with a Mograph Effector. Therefore, I am inserting the object to the original document and try to remove the original. But that does not work. When I make ChamferGen editable, it creates the original Connect+Children objects as well as the editable Spline Object. I tried stuff like cloner.Remove() but that did not work. The setup is linked below.

    Screenshot 2020-02-18 at 19.00.21.png

    posted in Cinema 4D SDK •
    RE: Trouble with GetAndCheckHierarchyClone

    I also have another question. How should I change the setup to support multiple children? (see image) I tried to insert multiple objects in the tempDoc via a loop but nothing really worked.

    Screenshot 2020-02-16 at 15.32.47.png

    posted in Cinema 4D SDK •
    RE: Trouble with GetAndCheckHierarchyClone

    @m_magalhaes

    Thank you for your help! It works. I really like the tip of the temporary document. Does it make sense to use c4d.documents.KillDocument(doc) after the process is complete to free up resources?

    posted in Cinema 4D SDK •
    RE: Goodbye

    Hey Sebastian,
    I wish you the best on your next challenges! Thank you so much for being such a help for the C4D Community!

    posted in Maxon Announcements •
    Trouble with GetAndCheckHierarchyClone

    Hey folks,

    I could need your help on building a Python Generator version of the Chamfer Tool. It's based on the Py-Parametric tools build by Andreas back in days. There were very helpful for setting up the generator. But here comes the issue:
    Using GetAndCheckHierarchyClone does not work well with the MCOMMAND_CURRENTSTATETOOBJECT (at least this is what I think). When I test the plugin and use a Cloner with Splines under a Connect Object, it only affects the first clone. When I make the Connect Object editable, it works on all objects. See images.
    When I bypass the dirty check and add replace "clone" by "op" in line 63 in the "GetVirtualObjects" method, than it works, but very badly.

    I would appreciate any kind of help 🙂

    import os
    import c4d
    from c4d import plugins, utils, bitmaps
    
    ###############################################################################################################
    #Based on the Py-Parametric Tools by Andreas Block
    ###############################################################################################################
    
    class ModelingCommandGeneratorModifier(plugins.ObjectData):
        _toolId = -1
        _doSelection = False
        _selectId = -1
    
        def InitCommon(self, toolId, doSelection, selectId):
            self._toolId = toolId
            self._doSelection = doSelection
            self._selectId = selectId
    
        def ExecModelingCommand(self, doc, opCtrl, op, parent):
            if op is None:
                return
            
            splineObjects = []
            if op.GetDown().CheckType(c4d.Ospline) is False:
                splineObjects = utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                                    list = [op.GetDown()],
                                    mode = c4d.MODELINGCOMMANDMODE_ALL,
                                    bc = c4d.BaseContainer(),
                                    doc = doc)
            else:
                splineObjects.append(op.GetDown())
    
            if not splineObjects:
                return
                
            if splineObjects[0].CheckType(c4d.Ospline) is True:
                res = utils.SendModelingCommand(command = self._toolId,
                                                list = splineObjects,
                                                mode = c4d.MODELINGCOMMANDMODE_ALL,
                                                bc = opCtrl.GetDataInstance(), # settings,
                                                doc = doc)
                if res is True:
                    splineObjects[0].InsertUnderLast(parent)
            
        def GetVirtualObjects(self, op, hh):
            doc = op.GetDocument()
            objInput = op.GetDown()
            
            if objInput is None:
                return None
            
            objRet = c4d.BaseObject(c4d.Onull)
            if doc is None or objRet is None:
                return None
            hierarchyClone = op.GetAndCheckHierarchyClone(hh, objInput, c4d.HIERARCHYCLONEFLAGS_NONE, True)
            if hierarchyClone["dirty"] is False:
                return hierarchyClone["clone"]
            clone = hierarchyClone["clone"]
            if clone is None:
                return objRet
            
            #When I replace "clone" to "op" and bypass the dirty checks, than it works but very sluggish
            self.ExecModelingCommand(doc, op, clone, objRet)
            return objRet
    
    class ChamferGen(ModelingCommandGeneratorModifier):
        def Init(self, op):
            ModelingCommandGeneratorModifier.InitCommon(self, c4d.ID_MODELING_SPLINE_CHAMFER_TOOL, False, -1)
            InitChamferDesc(self, op)
            return True
    
    def InitChamferDesc(inst, op):
        inst.InitAttr(op, bool, [c4d.MDATA_SPLINE_CHAMFERFLAT])
        inst.InitAttr(op, float, [c4d.MDATA_SPLINE_CHAMFERRADIUS])
        
        op[c4d.MDATA_SPLINE_CHAMFERRADIUS] = 5.0
    
    
    ###############################################################################################################
    # Plugin Registration
    ###############################################################################################################
    
    PLUGIN_ID_GENERATOR = 9036026
    
    
    
    def RegisterObjectData(id, name, bmpPath, objData, desc, flags):
        bmp = bitmaps.BaseBitmap()
        bmp.InitWith(os.path.join(bmpPath, "res", "icon.tif"))
        plugins.RegisterObjectPlugin(id=id, str=name,
                                    g=objData,
                                    description=desc, icon=bmp,
                                    info=flags)
    
    if __name__ == "__main__":
        path, fn = os.path.split(__file__)
    
        RegisterObjectData(PLUGIN_ID_GENERATOR, "ChamferGen", path, ChamferGen, "ochamfergen", c4d.OBJECT_GENERATOR | c4d.OBJECT_INPUT)
    
        print "ChamferGen 1.0 successfully initialized"
    
    

    Screenshot 2020-02-13 at 18.43.51.png
    Screenshot 2020-02-13 at 18.44.03.png

    posted in Cinema 4D SDK •
    RE: c4dpy.exe and VS Code on Windows?

    Thanks Maxime for clarifying. So we will wait for your fix 🙂

    posted in Cinema 4D SDK •
    RE: c4dpy.exe and VS Code on Windows?

    Hey, I run into the same issue on a Mac. I followed the instruction how to use c4dpy in VS Code but when I am pasting the path to c4dpy in the python interpreter settings, it does not accept it. No messages, nothing. I cannot select c4dpy as a python interpreter.

    Greetings
    Matthäus

    1fc74f8e-9504-47bf-ab74-301732217153-grafik.png

    posted in Cinema 4D SDK •
    RE: Porting a python command plugin to R21

    The problem is solved. It was so trivial :D. I unchecked the plugins folder which I added in the preferences. My plugins folder was in the C4D directory, so as you described, it was loaded twice.
    Leaning for me: Never place a custom plugins folder in the C4D directory!
    Recommendation to the SDK team: Maybe you could adjust the error message in the console, which mentions that plugin folders should not be in the C4D directory. I would assume that many users/ devs will place the folder there, because of a habit from older versions.

    Thank you @r_gigante and @zipit for your quick response!

    posted in Cinema 4D SDK •
    Porting a python command plugin to R21

    Hey folks,

    I am currently porting a command plugin to C4D R21, because some users reported that it is not working for them. However, on a Mac it works on R21 but I get this error message in the console:

    Traceback (most recent call last):
      File "/Applications/Maxon Cinema 4D R21/PLugins/SelectionToObject/SeletionToObject.pyp", line 271, in <module>
    okyn = plugins.RegisterCommandPlugin(PLUGIN_ID,"Selection to Object",0,bmp,"Selection to Object",SelectionToObject())
    RuntimeError:The plugin ID '1054093999' collides with another plugin ID in 'SeletionToObject'.
    You have to use a unique ID for registering your plugin!
    You can get a personal number for free from PluginCafe at www.plugincafe.com
    

    I already got a new plugin ID from PluginCafe but it does not solve the problem.

    Here is the main function of the plugin, which throws the error:

    PLUGIN_ID = 1054093
    
    if __name__=='__main__':
        bmp=bitmaps.BaseBitmap()
        path, fn = os.path.split(__file__)
        bmp.InitWith(os.path.join(path,"res","Icon.tif"))
        okyn = plugins.RegisterCommandPlugin(PLUGIN_ID,"Selection to Object",0,bmp,"Selection to Object",SelectionToObject())
        if (okyn):
            print "Selection to Object successfully initialized"
    

    Any help would be appreciated. Thank you 🙂

    posted in Cinema 4D SDK •