How to get the splineobject of primitives?[SOLVED]

On 14/12/2016 at 08:23, xxxxxxxx wrote:

Hey,

I hope it´s a noobish question. I´d like to get the splineobject with tangents of a primitiv, for example circle.
This is what I already tried:

import os  
import math  
import sys  
import c4d  
  
from c4d import plugins, utils, bitmaps, gui  
  
PLUGIN_ID = 123455589  
  
class TEST(plugins.ObjectData) :  
  
  def Init(self, node) :  
      return True  
  
  def GetVirtualObjects(self, op, hierarchyhelp) :  
      child = op.GetDown()  
      if not child: return None  
  
      print child.GetCache()  
  
      res = c4d.utils.SendModelingCommand(  
          command = c4d.MCOMMAND_MAKEEDITABLE,   
          list = [child.GetClone()],   
          mode = c4d.MODELINGCOMMANDMODE_ALL,  
          bc = c4d.BaseContainer(),  
          doc = op.GetMain())[0]  
  
      print res  
  
      res = c4d.utils.SendModelingCommand(  
          command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,   
          list = [child.GetClone()],   
          mode = c4d.MODELINGCOMMANDMODE_ALL,  
          bc = c4d.BaseContainer(),  
          doc = op.GetMain())[0]  
  
      print res, res.GetPointCount()  
  
      print op.GetAndCheckHierarchyClone(hierarchyhelp,child,c4d.HIERARCHYCLONEFLAGS_ASSPLINE,False)["clone"]  
        
      return None  
  
if __name__ == "__main__":  
  dir, file = os.path.split(__file__)  
  icon = bitmaps.BaseBitmap()  
  icon.InitWith(os.path.join(dir, "res", "TEST.tif"))  
  plugins.RegisterObjectPlugin(id=PLUGIN_ID, str="TEST2",  
                              g=TEST,  
                              description="TEST2",  
                              info=c4d.OBJECT_GENERATOR,  
                              icon=icon)  

But

print child.GetCache()

(first print) returns <c4d.LineObject object called 'Circle' with ID 5137 at 0x0000000012661C70>,

print res

(second print) returns <dead c4d.SplineObject object at 0x0000000012661DB0>

print res

(third print) returns <c4d.SplineObject object called 'Circle/Spline' with ID 5101 at 0x0000000012661DF0> 68 (68 points means that all the intermediate points became points)

print op.GetAndCheckHierarchyClone(hierarchyhelp,child,c4d.HIERARCHYCLONEFLAGS_ASSPLINE,False)["clone"]

(last print) returns <c4d.BaseObject object called 'Circle/Circle' with ID 5181 at 0x0000000010B1E1F0>.

Any other ideas or THE solution?

Thx and greetings
rownn

On 14/12/2016 at 16:08, xxxxxxxx wrote:

The best method that I've found is to use SendModelingCommand with Make Editable. Doesn't work in all cases, but that's your best shot if you want to maintain the original points.

On 14/12/2016 at 16:09, xxxxxxxx wrote:

You'll probably want to watch the progress on this thread:
https://plugincafe.maxon.net/topic/9791/13170_getvirtualobjects-v-getcontour-for-spline-gen&PID;=52510#52510

On 14/12/2016 at 16:16, xxxxxxxx wrote:

Try cloning the result you get after the MakeEditable, that should keep it alive.

  
"""Make Editable   
Inserts the "editable" version of the selected object.   
  
v0.0.1   
by Donovan Keith   
"""   
  
import c4d   
from c4d import gui   
  
def MakeEditable(op) :   
    if not op:   
        return   
       
    op_clone = op.GetClone()   
    if not op_clone:   
        return   
       
    result_list = c4d.utils.SendModelingCommand(   
                                command = c4d.MCOMMAND_MAKEEDITABLE,   
                                list = [op_clone],   
                                mode = c4d.MODELINGCOMMANDMODE_ALL,   
                                bc = c4d.BaseContainer(),   
                                doc = op.GetDocument())   
                                   
    if not result_list:   
        return   
       
    result = result_list[0].GetClone()   
    return result   
  
def main() :   
    spline = MakeEditable(op)   
    if not spline:   
        return   
       
    doc.StartUndo()   
    doc.InsertObject(spline)   
    doc.AddUndo(c4d.UNDOTYPE_NEW, spline)   
    c4d.EventAdd()   
    doc.EndUndo()   
       
  
if __name__=='__main__':   
    main()   

On 15/12/2016 at 01:29, xxxxxxxx wrote:

Hey Donovan,

thanks for your reply. I hope I got it, but its a bit strange.
This seems to work.

clone = child.GetClone()  
  
res = c4d.utils.SendModelingCommand(  
          command = c4d.MCOMMAND_MAKEEDITABLE,   
          list = [clone],   
          mode = c4d.MODELINGCOMMANDMODE_ALL,  
          bc = c4d.BaseContainer(),  
          doc = op.GetMain())[0].GetClone()

This seems to work, too. (Without cloning the result)

clone = child.GetClone()  
  
res = c4d.utils.SendModelingCommand(  
          command = c4d.MCOMMAND_MAKEEDITABLE,   
          list = [clone],   
          mode = c4d.MODELINGCOMMANDMODE_ALL,  
          bc = c4d.BaseContainer(),  
          doc = op.GetMain())[0]

This doesnt work:

res = c4d.utils.SendModelingCommand(  
          command = c4d.MCOMMAND_MAKEEDITABLE,   
          list = [child.GetClone()],   
          mode = c4d.MODELINGCOMMANDMODE_ALL,  
          bc = c4d.BaseContainer(),  
          doc = op.GetMain())[0].GetClone()

So it seems Ive to put the clone into a varaible before calling c4d.MCOMMAND_MAKEEDITABLE.

Thanks again and greetings
rownn

On 15/12/2016 at 02:12, xxxxxxxx wrote:

Yeah, I think what's happening is that if you do .GetClone() in the function call SendModelingCommand() owns the clone. When SMC is done executing garbage collection kills the reference to the clone.

By making the clone and assigning it to a variable, you're ensuring that it will be "needed" by the calling function and that garbage collection won't delete it prematurely.

At least that's my best guess. I remember working through the exact same issue and it felt like voodoo as I was trying to figure out where I'd gone wrong.

On 15/12/2016 at 02:44, xxxxxxxx wrote:

Ok, cloning the result is nessesary if you wanne store the object ... makes sence.

On 15/12/2016 at 12:41, xxxxxxxx wrote:

Hi Rown, thanks for writing us.

With reference to your question,  I suggest to use the GetRealSpline() method once you've checked the primitive type of the input object. This method basically returns for procedural curve generator the spline data (like points and tangents).
If beside querying for the spline data your intent is to use the child inside the GetVirtualObjects() I suggest to experiment with GetHierarchyClone() combined with GetAndCheckHierarchyClone() as shown in the short snippet below. At the moment the GetHierarchyClone() behaves a little bit differently than how it's implemented in C++ (we're working to fix it in future) but using it combined with GetAndCheckHierarchyClone() provides a viable alternative

def GetVirtualObjects(self, op, hh) :
    if op is None or hh is None:
        return None
  
    cloneDirty = False
    clone = None
    childDirty = -1
    dirty = False
  
    child = op.GetDown()
    if not child: 
        return None
  
    if not (child.IsInstanceOf(c4d.Ospline) or child.IsInstanceOf(c4d.Oline) or child.GetInfo()&c4d.OBJECT_SPLINE) :
        print ("Child object doesn't belong to spline/line primitive type")
        return None
  
    realSpline = child.GetRealSpline()
    if realSpline is not None:
        PrintSplineData(realSpline)
  
    resGHC = op.GetHierarchyClone(hh, child, c4d.HIERARCHYCLONEFLAGS_ASSPLINE)
    if resGHC is None:
        resGHC = op.GetAndCheckHierarchyClone(hh, child, c4d.HIERARCHYCLONEFLAGS_ASSPLINE, False)
    
    if resGHC is not None:
        cloneDirty = resGHC["dirty"]
        clone = resGHC["clone"]
    
    # it should return true only if the cloned object has been updated
    # but it seems that it returns true even if child has not changed
    dirty |= cloneDirty
  
    # add the dirty status of the operator data
    dirty |= op.IsDirty(c4d.DIRTYFLAGS_DATA)
  
    # recursively compute the child dirty status
    childDirty = RecursiveCheckDirty(child)
  
    child.Touch()
  
    # compare the dirtyness of local and member variable and accordingly update the generator's 
    # dirty status and the member variable value
    dirty |= self._childDirty != childDirty
    self._childDirty = childDirty
  
    cache = op.GetCache()
    if not dirty and cache is not None:
        return cache        
  
    return clone

Best, Riccardo

On 01/01/2017 at 06:18, xxxxxxxx wrote:

Hey KnickKnack,

sorry for my late reply.
I thank you for your hint to use GetRealSpline(), but I wasn´t able to understand all intensions in your code, so I have writting the following and it works for me.

import os  
import math  
import sys  
import c4d  
  
from c4d import plugins, utils, bitmaps, gui  
  
PLUGIN_ID = 12345557  
  
class ObjektDataTest(plugins.ObjectData) :  
  
  def __init__(self) :  
      self.child = None  
      self.sourcePoints = []  
  
  def checkIsDirty(self, spline) :  
      if spline: pnts = spline.GetAllPoints()  
      else: pnts = []   
      if pnts != self.sourcePoints:   
          self.sourcePoints = pnts  
          return True  
      else: return False  
  
  def getSplineObject(self, child) :  
      if child.CheckType(c4d.Oinstance) :  
          if child[c4d.INSTANCEOBJECT_LINK].GetType() in self.acceptedTypes: realSpline = child[c4d.INSTANCEOBJECT_LINK].GetRealSpline()  
      else: realSpline = child.GetRealSpline()  
  
      if realSpline: return {'splineObject': realSpline, 'dirty': self.checkIsDirty(realSpline)}  
      else: return {'splineObject': None, 'dirty': False}  
  
  
      return {'splineObject': None, 'dirty': False}  
  
  
  def GetVirtualObjects(self, op, hh) :  
      if op is None or hh is None: return None  
      child = op.GetDown()  
      if not child:return None  
      if not child[c4d.ID_BASEOBJECT_GENERATOR_FLAG]: return None  
  
  
      if self.child != child: childNew = True  
      else: childNew = False  
  
      self.child = child  
      gSO = self.getSplineObject(child)  
      realSpline = gSO['splineObject']  
  
      if not realSpline: return None  
  
      if op.GetCache() == None or child.IsDirty(c4d.DIRTYFLAGS_DATA) or child.IsDirty(c4d.DIRTYFLAGS_MATRIX) or gSO['dirty'] or op.IsDirty(c4d.DIRTYFLAGS_DATA) or childNew:  
          print "DO STUFF", realSpline.GetPointCount()  
          obj = realSpline.GetClone()  
            
      else: obj = op.GetCache().GetClone()  
  
      return obj  
  
  
if __name__ == "__main__":  
  dir, file = os.path.split(__file__)  
  icon = bitmaps.BaseBitmap()  
  icon.InitWith(os.path.join(dir, "res", "ObjektDataTest.tif"))  
  plugins.RegisterObjectPlugin(id=PLUGIN_ID, str="ObjektDataTest",  
                              g=ObjektDataTest,  
                              description="ObjektDataTest",  
                              icon=icon,  
                              info=c4d.OBJECT_GENERATOR)  
  

Thx again and a happy new year!!
rownn

EDIT: Have optimized the code