KnickKnack

OffsetYSpline rev0.2.1

Dec 15th, 2016
255
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

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×