KnickKnack

OffsetYSpline rev0.2.1

Dec 15th, 2016
224
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. """Offset-Y Spline
  2. Takes a child-spline as input and offset all its points on the y-axis by a specific value. Tangents are unaffected.
  3.  
  4. Usage Instructions
  5. ------------------
  6. 1. Save in a file called OffsetYSpline.pyp
  7. 2. Locate it in the plugin folder
  8. 3. Start Cinema
  9. 4. Create a generating spline
  10. 5. From the Plugin menu, select OffsetYSpline
  11. 6. Set the generating spline as input child of the OffsetYSpline
  12. """
  13.  
  14.  
  15. #   =====================================================================================================================#
  16. #       Imports
  17. #   =====================================================================================================================#
  18. import os
  19.  
  20. import c4d
  21.  
  22. PLUGIN_ID = 98989801
  23.  
  24.  
  25. #   =====================================================================================================================#
  26. #       Global Functions Definitions
  27. #   =====================================================================================================================#
  28. # Global function responsible to set the close status of a spline
  29. def SetClosed(spline, value):
  30.     if spline is not None:
  31.         spline.SetParameter(c4d.DescID(c4d.DescLevel(c4d.SPLINEOBJECT_CLOSED)), value, c4d.DESCFLAGS_SET_FORCESET)
  32.         spline.GetDataInstance().SetBool(c4d.SPLINEOBJECT_CLOSED, value)
  33.         return True
  34.  
  35.     return False
  36.  
  37. # Global function responsible to check the close status of a spline
  38. def IsClosed(spline):
  39.     if spline is None:
  40.         return False
  41.  
  42.     if spline.GetCacheParent() is not None:
  43.         return spline.GetCacheParent().IsClosed()
  44.     else:
  45.         return spline.IsClosed()
  46.  
  47. # Global function responsible to copy the spline parameters across a source and a destination
  48. def CopySplineParamsValue(sourceSpline, destSpline):
  49.     if sourceSpline is None or destSpline is None:
  50.         return False
  51.  
  52.     sourceRealSpline = sourceSpline.GetRealSpline()
  53.     if sourceRealSpline is not None:
  54.         sourceRealSplineBC = sourceRealSpline.GetDataInstance()
  55.         if sourceRealSplineBC is not None:
  56.             destSpline.SetParameter(c4d.SPLINEOBJECT_INTERPOLATION, sourceRealSplineBC.GetInt32(c4d.SPLINEOBJECT_INTERPOLATION), c4d.DESCFLAGS_SET_FORCESET)
  57.             destSpline.SetParameter(c4d.SPLINEOBJECT_MAXIMUMLENGTH, sourceRealSplineBC.GetFloat(c4d.SPLINEOBJECT_MAXIMUMLENGTH), c4d.DESCFLAGS_SET_FORCESET)
  58.             destSpline.SetParameter(c4d.SPLINEOBJECT_SUB, sourceRealSplineBC.GetInt32(c4d.SPLINEOBJECT_SUB), c4d.DESCFLAGS_SET_FORCESET)
  59.             destSpline.SetParameter(c4d.SPLINEOBJECT_ANGLE, sourceRealSplineBC.GetFloat(c4d.SPLINEOBJECT_ANGLE), c4d.DESCFLAGS_SET_FORCESET)
  60.             return True
  61.  
  62.     return False
  63.  
  64. # Global function responsible to return the final representation of the spline
  65. def FinalSpline(source):
  66.     if source is None:
  67.         return None
  68.  
  69.     # check is source can be threated as a spline
  70.     if (not source.IsInstanceOf(c4d.Oline)) and (not(source.GetInfo()&c4d.OBJECT_SPLINE)):
  71.         return None
  72.  
  73.     if source.GetDeformCache() is not None:
  74.         # it seems it's never hit      
  75.         source = source.GetDeformCache()
  76.  
  77.     # return the spline is a procedural curve
  78.     if (not source.IsInstanceOf(c4d.Ospline)) and (source.GetRealSpline() is not None):
  79.         return source.GetRealSpline()
  80.  
  81.     return source
  82.  
  83. # Global function responsible for modifying the spline
  84. def OffsetSpline(inputSpline, offsetValue):
  85.     if inputSpline is None:
  86.         return None
  87.  
  88.     # just return if the input object doesn't belong to spline or line type
  89.     if not inputSpline.IsInstanceOf(c4d.Ospline) and not inputSpline.IsInstanceOf(c4d.Oline):
  90.         return None
  91.  
  92.     # local matrix for updating the point position in parent space
  93.     inputML = inputSpline.GetMl()
  94.  
  95.     # local matrix for updating the tangents direction and scaling in parent space
  96.     inputScaleRotate = inputSpline.GetMl()
  97.     inputScaleRotate.off = c4d.Vector(0,0,0)
  98.  
  99.     # retrieve child points count and type
  100.     pointsCnt = inputSpline.GetPointCount()
  101.     tangentsCnt = 0
  102.     splineType = 0
  103.  
  104.     if (inputSpline.GetType() == c4d.Ospline):
  105.         tangentsCnt = inputSpline.GetTangentCount()
  106.         splineType = inputSpline.GetInterpolationType()
  107.  
  108.     # allocate the resulting spline
  109.     resSpline = c4d.SplineObject(pointsCnt, splineType)
  110.     if resSpline is None:
  111.         return None
  112.  
  113.     # set the points position and tangency data
  114.     for i in range(pointsCnt):
  115.         #currPos = inputSpline.GetPoint(i)
  116.         currPos = inputML * inputSpline.GetPoint(i)
  117.         resSpline.SetPoint(i, c4d.Vector(currPos.x,currPos.y+offsetValue, currPos.z))
  118.         # set in case the tangency data
  119.         if tangentsCnt != 0:
  120.             currTan = inputSpline.GetTangent(i)
  121.             resSpline.SetTangent(i, inputScaleRotate*currTan["vl"], inputScaleRotate*currTan["vr"])
  122.  
  123.     # return the computed spline
  124.     return resSpline
  125.  
  126. # Global function responsible to return the first enabled object in a hierarchy
  127. def RecurseOnChild(op):
  128.     if op is None:
  129.         return None
  130.    
  131.     childObj = op.GetDown()
  132.     if childObj is None:
  133.         return None
  134.    
  135.     #skip deformers
  136.     isModifier = childObj.GetInfo()&c4d.OBJECT_MODIFIER
  137.     if isModifier:
  138.         return None
  139.    
  140.     # check and return the first active child
  141.     if childObj.GetDeformMode():
  142.         return childObj
  143.     else:
  144.         return RecurseOnChild(childObj)
  145.  
  146. # Global function responsible to recursively check the dirty flag in a hierarchy
  147. def RecursiveCheckDirty(op):
  148.     res = 0
  149.  
  150.     if op is None:
  151.         return res
  152.    
  153.     current = op
  154.     nextObj = op.GetNext()
  155.     childObj = op.GetDown()
  156.  
  157.     res += current.GetDirty(c4d.DIRTYFLAGS_DATA | c4d.DIRTYFLAGS_MATRIX)
  158.  
  159.     if childObj is not None:
  160.         res += RecursiveCheckDirty(childObj)
  161.  
  162.     if nextObj is not None:
  163.         res += RecursiveCheckDirty(nextObj)
  164.  
  165.     return res
  166.  
  167. # =====================================================================================================================#
  168. #   Class Definitions
  169. # =====================================================================================================================#
  170. class OffsetYSpline(c4d.plugins.ObjectData):
  171.  
  172.     def Init(self, op):
  173.         if op is None:
  174.             return False
  175.  
  176.         bc = op.GetDataInstance()
  177.         if bc is None:
  178.             return False
  179.         bc.SetInt32(c4d.PY_OFFSETYSPLINE_OFFSET, 100)
  180.  
  181.         self._countourChildDirty = -1
  182.         self._childDirty = -1
  183.  
  184.         return True
  185.  
  186.     def GetDimension(self, op, mp, rad):
  187.         mp.x = 0
  188.         mp.y = 0
  189.         mp.z = 0
  190.         rad.x = 0
  191.         rad.y = 0
  192.         rad.z = 0
  193.  
  194.         if op is None:
  195.             return
  196.  
  197.         bc = op.GetDataInstance()
  198.         if op.GetDown() is not None:
  199.             rad.x = op.GetDown().GetRad().x
  200.             rad.y = op.GetDown().GetRad().y
  201.             rad.z = op.GetDown().GetRad().z
  202.             mp.x = op.GetMg().off.x
  203.             mp.y = op.GetMg().off.y + bc.GetFloat(c4d.PY_OFFSETYSPLINE_OFFSET)
  204.             mp.z = op.GetMg().off.z
  205.  
  206.     def CheckDirty(self, op, doc):
  207.         if op is None or doc is None:
  208.             return
  209.  
  210.         childDirty = 0
  211.  
  212.         child = op.GetDown()
  213.  
  214.         if child is not None:
  215.             childDirty = RecursiveCheckDirty(child)
  216.  
  217.         if (childDirty != self._countourChildDirty):
  218.             op.SetDirty(c4d.DIRTYFLAGS_DATA)
  219.  
  220.         self._countourChildDirty = childDirty
  221.  
  222.     def GetVirtualObjects(self, op, hh):
  223.         if op is None or hh is None:
  224.             return None
  225.  
  226.         child = None
  227.         childSpline = None
  228.         resSpline = None
  229.         dirty = False
  230.         cloneDirty = False
  231.         temp = None
  232.         childDirty = -1
  233.  
  234.         cache = op.GetCache()
  235.         bc = op.GetDataInstance()
  236.         if bc is None:
  237.             return c4d.BaseObject(c4d.Onull)
  238.         offsetValue = bc.GetFloat(c4d.PY_OFFSETYSPLINE_OFFSET)
  239.  
  240.         # look for the first enabled child in order to support hierarchical
  241.         child = RecurseOnChild(op)
  242.         if child is None:
  243.             self._childDirty = -1
  244.             self._countourChildDirty = -1
  245.             return c4d.BaseObject(c4d.Onull)
  246.  
  247.         # Store now the closure state of the child cause child will be later on overwritten
  248.         isChildClosed = IsClosed(child.GetRealSpline())
  249.  
  250.         # Use the GetHierarchyClone and the GetAndCheckHierarchyClone to operate as a two-step
  251.         # GetHierarchyClone operates when passing a bool reference in the first step to check
  252.         # the dirtyness and a nullptr on a second step to operate the real clone
  253.         resGHC = op.GetHierarchyClone(hh, child, c4d.HIERARCHYCLONEFLAGS_ASSPLINE)
  254.         if resGHC is None:
  255.             resGHC = op.GetAndCheckHierarchyClone(hh, child, c4d.HIERARCHYCLONEFLAGS_ASSPLINE, False)
  256.            
  257.         if resGHC is not None:
  258.             cloneDirty = resGHC["dirty"]
  259.             temp = resGHC["clone"]
  260.        
  261.         dirty |= cloneDirty
  262.  
  263.         # recursively check the dirty flag for the children (deformers or other generators)
  264.         if temp is not None and (temp.IsInstanceOf(c4d.Ospline) or (temp.GetInfo()&c4d.OBJECT_ISSPLINE) or temp.IsInstanceOf(c4d.Oline)):
  265.             childDirty = RecursiveCheckDirty(child)
  266.             if childSpline is None:
  267.                 childSpline = temp
  268.  
  269.         child.Touch()
  270.  
  271.         dirty |= op.IsDirty(c4d.DIRTYFLAGS_DATA)
  272.  
  273.         # compare the dirtyness of local and member variable and accordingly update the generator's
  274.         # dirty status and the member variable value
  275.         # check is &= or |=
  276.         dirty |= self._childDirty != childDirty
  277.         self._childDirty = childDirty
  278.  
  279.         if not dirty and cache is not None:
  280.             return cache
  281.  
  282.         if childSpline is None:
  283.             return c4d.BaseObject(c4d.Onull)
  284.  
  285.         #operate the spline modification
  286.         resSpline = OffsetSpline(FinalSpline(childSpline), offsetValue)
  287.         if resSpline is None:
  288.             return c4d.BaseObject(c4d.Onull)
  289.  
  290.         # restore the closing status of the spline
  291.         SetClosed(resSpline, isChildClosed)
  292.  
  293.         # copy the spline tags
  294.         childSpline.CopyTagsTo(resSpline, True, c4d.NOTOK, c4d.NOTOK)
  295.  
  296.         # copy the spline parameters value
  297.         CopySplineParamsValue(childSpline, resSpline)
  298.  
  299.         # notify about the generator update
  300.         resSpline.Message(c4d.MSG_UPDATE)
  301.  
  302.         return resSpline
  303.  
  304.     def GetContour(self, op, doc, lod, bt):
  305.         if op is None:
  306.             return None
  307.  
  308.         if doc is None:
  309.             doc = op.GetDocument()
  310.  
  311.         if doc is None:
  312.             return None
  313.  
  314.         child = None
  315.         childSpline  = None
  316.         resSpline = None
  317.  
  318.         bc = op.GetDataInstance()
  319.         if bc is None:
  320.             return None
  321.         offsetValue = bc.GetFloat(c4d.PY_OFFSETYSPLINE_OFFSET)
  322.  
  323.  
  324.         child = RecurseOnChild(op)
  325.         if child is None:
  326.             self._childDirty = 0
  327.             self._countourChildDirty = 0
  328.             return None
  329.  
  330.         # Store now the closure state of the child cause child will be later on overwritten
  331.         isChildClosed = IsClosed(child.GetRealSpline())
  332.  
  333.         # emulate the GetHierarchyClone in the GetContour by using the SendModelingCommand
  334.         temp = child
  335.         if temp is not None:
  336.             temp = temp.GetClone(c4d.COPYFLAGS_NO_ANIMATION)
  337.             if temp is None:
  338.                 return None
  339.  
  340.             result = c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_CURRENTSTATETOOBJECT, list = [temp], doc = doc)
  341.  
  342.             if result is False:
  343.                 return None
  344.  
  345.             if isinstance(result, list) and temp is not result[0] and result[0] is not None:
  346.                 temp = result[0]
  347.                 if (temp.GetType() == c4d.Onull):
  348.                     result2 = c4d.utils.SendModelingCommand(command = c4d.MCOMMAND_JOIN, list = [temp], doc = doc)
  349.  
  350.                     if result2 is False:
  351.                         return None
  352.  
  353.                     if isinstance(result2, list) and result2[0] is not None and temp is not result2[0]:
  354.                         temp = result2[0]
  355.  
  356.  
  357.         if (temp is not None and (temp.IsInstanceOf(c4d.Ospline) or (temp.GetInfo()&c4d.OBJECT_SPLINE) or temp.IsInstanceOf(c4d.Oline))):
  358.             if childSpline is None:
  359.                 childSpline = temp
  360.        
  361.         if childSpline is None:
  362.             return None
  363.  
  364.         #operate the spline modification
  365.         resSpline = OffsetSpline(FinalSpline(childSpline), offsetValue)
  366.         if resSpline is None:
  367.             return None
  368.  
  369.         # restore the closing status of the spline
  370.         SetClosed(resSpline, isChildClosed)
  371.  
  372.         # copy the spline parameters value
  373.         CopySplineParamsValue(childSpline, resSpline)
  374.  
  375.         # notify about the generator update
  376.         resSpline.Message(c4d.MSG_UPDATE)
  377.  
  378.         return resSpline
  379.  
  380. # =====================================================================================================================#
  381. #   Plugin registration
  382. # =====================================================================================================================#
  383.  
  384. if __name__ == "__main__":
  385.     c4d.plugins.RegisterObjectPlugin(id=PLUGIN_ID,
  386.                                 str="Py-OffsetYSpline(DR)",
  387.                                 g=OffsetYSpline,
  388.                                 description="DataRepo_OoffsetYSpline",
  389.                                 icon=None,
  390.                                 info=c4d.OBJECT_GENERATOR | c4d.OBJECT_INPUT | c4d.OBJECT_ISSPLINE)
RAW Paste Data