Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Register
    • Login
    1. Home
    2. matniedoba
    • Profile
    • Following 0
    • Followers 0
    • Topics 3
    • Posts 12
    • Best 0
    • Controversial 0
    • Groups 0

    matniedoba

    @matniedoba

    0
    Reputation
    35
    Profile views
    12
    Posts
    0
    Followers
    0
    Following
    Joined Last Online

    matniedoba Unfollow Follow

    Latest 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
      matniedobaM
      matniedoba
    • 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
      matniedobaM
      matniedoba
    • 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
      matniedobaM
      matniedoba
    • 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
      matniedobaM
      matniedoba
    • 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
      matniedobaM
      matniedoba
    • 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
      matniedobaM
      matniedoba
    • 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 News & Information
      matniedobaM
      matniedoba
    • 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
      matniedobaM
      matniedoba
    • RE: c4dpy.exe and VS Code on Windows?

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

      posted in Cinema 4D SDK
      matniedobaM
      matniedoba
    • 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
      matniedobaM
      matniedoba