Hide Input Child Objects in GetContour[SOLVED]
On 22/11/2016 at 15:32, xxxxxxxx wrote:
1. How do I hide my child input objects? I'm using Touch() in GetContour() but it only works when I'm editing the child-objects.
2. How do I ensure that grandchildren don't reappear when nested in another generator?
I've created a simplified example plugin demonstrating my issues:
BitBucket Snippet of ScaleSplineObject.pyp
And, while harder to read, here's the full source embedded:
"""Scale Spline Object Takes a child-spline as input and scaled it's point's down by 50%. Tangents are unaffected. v0.0.1 by Donovan Keith <firstname.lastname@example.org> Usage Instructions ------------------ 1. Save in a file called ScaleSplineObject.pyp 2. Place in C4D Plugins director 3. Restart C4D 4. Plugins > Scale Spline Object 5. Add an NSide spline 6. Make the NSide spline a child of the Scale Spline Object. Outstanding Issues ------------------- - [ ] Nested child objects aren't properly hidden. To recreate: ScaleSpline | -- Scale Spline | -- NSide - [ ] GetDirty() probably needs to be reimplemented. """ # =====================================================================================================================# # Imports # =====================================================================================================================# import c4d # =====================================================================================================================# # Class Definitions # =====================================================================================================================# class ScaleSplineObject(c4d.plugins.ObjectData) : PLUGIN_ID = 1038342 # TODO: Replace with your own ID from PluginCafe.com def __init__(self) : self.last_child = None def Init(self, op) : return True def ConversionCommand(self, op, command_id) : """Allows you to easily perform a MakeEditable or CSTO on an object. reference: https://plugincafe.maxon.net/topic/5237/5232_python-make-object-editable Returns early if op is a Spline """ if op is None: return op_clone = op.GetClone() if op_clone is None: return # Is it a spline? No need to convert. if op_clone.CheckType(c4d.Ospline) : return op_clone # Perform the MakeEditable or CSTO in temporary document temp_doc = c4d.documents.BaseDocument() if not temp_doc: return temp_doc.InsertObject(op_clone) result_list = c4d.utils.SendModelingCommand(command=command_id, list=[op_clone], doc=temp_doc) # Did anything go wrong? Bail if not result_list: return # Return the first object in the result list return result_list def MakeEditable(self, op) : """Returns a clone of `op` that's been made editable. Can return None.""" return self.ConversionCommand(op, command_id=c4d.MCOMMAND_MAKEEDITABLE) def CurrentStateToObject(self, op) : """Returns a clone of the current state of `op`. Can return None.""" return self.ConversionCommand(op, command_id=c4d.MCOMMAND_CURRENTSTATETOOBJECT) def GetAsSpline(self, op) : """Clones object as a c4d.Ospline - using the following priority * Object if Spline * Object Made Editable, if Spline * Current State to Object, if Spline Note: MakeEditable won't account for deformed splines, however, it will give you a spline with fewer points which is preferable to CSTO for a lot of modeling operations. """ if op is None: return # Return op if it's a spline if op.CheckType(c4d.Ospline) : return op.GetClone() # Make it editable if it is. made_editable = self.MakeEditable(op) if made_editable is not None: if made_editable.CheckType(c4d.Ospline) : return made_editable # Peform a CSTO if need be # TODO: See if this ever actually executes, probably doesn't current_state = self.CurrentStateToObject(op) if current_state is not None: if current_state.CheckType(c4d.Ospline) : return current_state def LocalizeSpline(self, op, spline) : """Converts all of `spline`'s point to local space for `op` This is necessary because GetContour assumes the spline is in the same location as the object itself. """ # Verify Inputs if (op is None) or (spline is None) : return # Get points spline_points = spline.GetAllPoints() if not spline_points: return has_tangents = (spline.GetTangentCount() > 0) spline_tangents =  # Retrieve matrices for conversion math spline_mg = spline.GetMg() if not spline_mg: return op_mg = op.GetMg() if not op_mg: return inverse_op_mg = ~op_mg # Localize all points for i, spline_point in enumerate(spline_points) : global_point = spline_point * spline_mg local_point = global_point * inverse_op_mg spline_points[i] = local_point # Calculate new tangent positions if has_tangents: # Get tangents for point tangent = spline.GetTangent(i) vl = tangent["vl"] vr = tangent["vr"] # Transform tangents into their global locales global_vl = (spline_point + vl) * spline_mg global_vr = (spline_point + vr) * spline_mg # Transform tangents from global points to point-local vectors. vl = (global_vl * inverse_op_mg) - local_point vr = (global_vr * inverse_op_mg) - local_point # Store the updated points & tangents. spline_tangents.append((vl, vr)) spline.SetTangent(i, vl, vr) # Neutralize spline's Matrix spline.SetMg(op_mg) # Restore spline to previous positions spline.SetAllPoints(spline_points) # Update tangent positions as well for i, tangent in enumerate(spline_tangents) : vl, vr = tangent spline.SetTangent(i, vl, vr) def CheckDirty(self, op, doc) : """Marks the object as dirty if it's child object has been modified.""" if not op: return # Is there a new or missing child object? child = op.GetDown() if child != self.last_child: # Dirty! self.last_child = child op.SetDirty(c4d.DIRTY_DATA) return # Can't do anythng without a child object. if child is None: return # Has the child ben modified? if child.IsDirty(c4d.DIRTYFLAGS_MATRIX | c4d.DIRTYFLAGS_DATA | c4d.DIRTYFLAGS_CHILDREN) : # Dirty! op.SetDirty(c4d.DIRTYFLAGS_DATA) def ModifySpline(self, spline) : """Scales all spline points down by 50%""" point_scaling_factor = 0.5 if spline is None: return spline_points = spline.GetAllPoints() if spline_points is None: return for i, spline_point in enumerate(spline_points) : spline_points[i] = spline_point * point_scaling_factor spline.SetAllPoints(spline_points) def GetContour(self, op, doc, lod, bt) : """Return the result of the generator spline.""" # Create an Empty Spline if not op: return # Retrieve the child input object child = op.GetDown() if child is None: return # Tell C4D the child is a generator input object and should be hidden. child.Touch() # Get the child input object as a spline clone we can modify. result_spline = self.GetAsSpline(child) if result_spline is None: return # Scale down the spline points. self.ModifySpline(result_spline) # Ensure the spline points are localized to this generator's PSR. self.LocalizeSpline(op, result_spline) return result_spline # =====================================================================================================================# # Registration # =====================================================================================================================# if __name__ == "__main__": c4d.plugins.RegisterObjectPlugin(id=ScaleSplineObject.PLUGIN_ID, str="ScaleSplineObject", g=ScaleSplineObject, description=None, icon=None, info=c4d.OBJECT_GENERATOR | c4d.OBJECT_INPUT | c4d.OBJECT_ISSPLINE)
On 22/11/2016 at 15:37, xxxxxxxx wrote:
These posts seem to be related:
- Object generator, GVO, cache and child objects - Plugin Cafe Forums
Solution doesn't work because GetContour() doesn't have access to DependenceList() nor HierarchyHelp.
- Touching Input object which in turn has input - Plugin Cafe Forums
I think this is the same problem I'm having, no resolution was ever posted.
- GetContour And op->Touch() - Plugin Cafe Forums
Seems to indicate that Touch() doesn't work properly in GetContour(), and that without access to HierarchyHelp, these will be long-standing issues.
Any thoughts? It seems like I have to choose between:
1. Use GetVirtualObjects so I can easily hide children, but then create a spline that is incompatible with Hair, SketchAndToon, and any other plugins that use GetRealSpline() as a test to see if something is a spline.
2. Use GetContour() and end up with flickering sub-objects and poor object hiding.
On 24/11/2016 at 02:51, xxxxxxxx wrote:
Hi Donovan, thanks for writing us.
with reference to your question, the solution proposed here should provide the functionality desired in terms of hiding child spline in generators.
On 28/11/2016 at 21:24, xxxxxxxx wrote:
Unfortunately, the example you've posted:
1. Does not hide child objects.
2. Only works with SplineObjects instead of Spline Primitives (try to add a Circle as a child for example).
Are you sure you posted the most recent version?
On 15/12/2016 at 13:08, xxxxxxxx wrote:
Hi Donovan, thanks for writing us.
i've provided a new answer here with updated code which should hide the child objects and work with procedural primitives as well.