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"
-
hello,
please use our forum functionalitiesas said in the documentation, Current State to Object should be use on a clone. And using a temporary document can help.
If you were not using a cloner, you could use
HIERARCHYCLONEFLAGS_ASSPLINE
. But with a cloner, the objects are returned as lineObject. And the chamfer only accept SplineObject (it checks for Ospline type).To avoid to run through the hierarchy, i've used a Join command and using the chamfer on the result.
def GetVirtualObjects(self, op, hh): objRet = c4d.BaseObject(c4d.Onull) doc = op.GetDocument() if doc is None: return objRet objInput = op.GetDown() if objInput is None: return objRet # If we set the flags to HIERARCHYCLONEFLAGS_ASSPLINE the result will be a lineObject and not a SplineObject. This will not pass the Chamfer tool. hierarchyClone = op.GetAndCheckHierarchyClone(hh, objInput, c4d.HIERARCHYCLONEFLAGS_NONE , True) if hierarchyClone["dirty"] is False: return hierarchyClone["clone"] # Retrieves the cloner cloner = op.GetDown() # Creates a temporary document. tempDoc = c4d.documents.BaseDocument() # Use a clone of the cloner so we can send it to a temporary document. cloned = cloner.GetClone(c4d.COPYFLAGS_NONE) # Insert the cloned object to the temporary document. tempDoc.InsertObject(cloned) # Retrieves the currect states. result = utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT, list = [cloned] , doc= tempDoc) spline = None if result: spline = result[0].GetDown() else: return objRet # Use the join command so we only have one spline object. (that help in case of a hierarchy) result = utils.SendModelingCommand(command = c4d.MCOMMAND_JOIN, list = result , doc= tempDoc) # Champher the spline if result[0].IsInstanceOf(c4d.Ospline): bc = c4d.BaseContainer() bc[c4d.MDATA_SPLINE_CHAMFERFLAT] = True bc[c4d.MDATA_SPLINE_CHAMFERRADIUS] = 19.0 res = utils.SendModelingCommand(command = c4d.ID_MODELING_SPLINE_CHAMFER_TOOL, list = result, bc = bc) if res: return result[0] return objRet
Cheers,
Manuel. -
@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?
-
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.
-
hello,
you can retrieve the hierarchy clone "asis" with
hierarchyClone = op.GetAndCheckHierarchyClone(hh, objInput, c4d.HIERARCHYCLONEFLAGS_ASIS , True)
Than use Currentstate to object and join the result as with the cloner.
in my previous code you can just change this line to see the result.
cloner = hierarchyClone["clone"]
The problem is that if you have a polygon object, the join command will return a polygon object and a spline.
One workaround would be to run through the hierarchy and remove the polygon objects.Just an idea, have you tried a deformer instead of a generator ? (just like our bevel deformer for polygon object)
Cheers,
Manuel -
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.
-
hello,
funny i've learned something (once again)
I told that setting the flag to
HIERARCHYCLONEFLAGS_ASSPLINE
will return a LineObject and the chamfer tool want SplineObject.
The fun fact is that the join command will transform that line object to a SplineObject.So no need to use the CSTO to a temp document. Just use the Join command on the result of the GetAndCheckHierarchyClone
def GetVirtualObjects(self, op, hh): objRet = c4d.BaseObject(c4d.Onull) doc = op.GetDocument() if doc is None: return objRet objInput = op.GetDown() if objInput is None: return objRet # If we set the flags to HIERARCHYCLONEFLAGS_ASSPLINE the result will be a lineObject and not a SplineObject. This will not pass the Chamfer tool. hierarchyClone = op.GetAndCheckHierarchyClone(hh, objInput, c4d.HIERARCHYCLONEFLAGS_ASSPLINE , True) if hierarchyClone["dirty"] is False: print "return cache" return hierarchyClone["clone"] spline = hierarchyClone["clone"] # Use the join command so we only have one spline object. (that help in case of a hierarchy) result = utils.SendModelingCommand(command = c4d.MCOMMAND_JOIN, list = [spline], doc= doc) res = None # Champher the spline if result[0].IsInstanceOf(c4d.Ospline): bc = c4d.BaseContainer() bc[c4d.MDATA_SPLINE_CHAMFERFLAT] = True bc[c4d.MDATA_SPLINE_CHAMFERRADIUS] = 19.0 res = utils.SendModelingCommand(command = c4d.ID_MODELING_SPLINE_CHAMFER_TOOL, list = result, bc = bc) print res if res: return result[0] return objRet
Cheers,
Manuel -
Amazing! Thank you Manuel! It works with multiple objects, Cloners etc. Without your help I would not make it