Hide Input Child Objects in GetContour[SOLVED]



  • On 22/11/2016 at 15:32, xxxxxxxx wrote:

    Hi,

    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 <donovanskeith@gmail.com>   
      
    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[0]   
      
        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)   
    

    Thanks!



  • 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.

    Best, Riccardo.



  • On 28/11/2016 at 21:24, xxxxxxxx wrote:

    Hi Riccardo,

    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.

    Best, Riccardo


Log in to reply