Tag plugin and Dirty check



  • I have a tag plugin that is attached to an object with several children.
    In the tag I test if one of the childrens matrix is changed.

    class AFONTTAG(plugins.TagData):
        def Execute(self, tag, doc, op, bt, priority, flags):
            child = op.GetDown().GetDown()    
            if (child.IsDirty(c4d.DIRTYFLAGS_MATRIX)): 
               ....
    

    My issue is that, if one of the children is dirty (in this case due to scaling), I get the scale of the child using child[c4d.ID_BASEOBJECT_REL_SCALE], to calculate the new size of the object.

    Note: This is done is Object Mode, because one of the grandchildren has a Pose Morph tag.

    To calculate the size I use GetRad() and multiple it with the scale.

    However, sometimes GetRad() returns (0,0,0)?

    I know the tag is threaded, so that might have something to do with it?
    I do not insert objects, just change the position of the children.

    What am I doing wrong?

    class AFONTTAG(plugins.TagData):
    
        def Execute(self, tag, doc, op, bt, priority, flags):
    
            child = op.GetDown().GetDown()    
    
            if (child.IsDirty(c4d.DIRTYFLAGS_MATRIX)): 
                bbRadiusA = child.GetRad()
                if (bbRadiusA[0] == 0):             #Sometime zero!!!
                    print "error: ", bbRadiusA
                    return True
                
                if (doc.GetAction() == c4d.ID_MODELING_SCALE):                        
                    a = child.GetRad()
                    b = child[c4d.ID_BASEOBJECT_REL_SCALE]
                    bbRadiusA = a * c4d.Matrix(v1=c4d.Vector(b[0],0,0), v2=c4d.Vector(0,b[1],0), v3=c4d.Vector(0,0,b[2]))
    
                .....
                    
            return c4d.EXECUTIONRESULT_OK
            
    if __name__ == "__main__":
    
        bmp = bitmaps.BaseBitmap()
        dir, file = os.path.split(__file__) 
        bitmapfile = os.path.join(dir, "res", "AFont.png")
        result = bmp.InitWith(bitmapfile)
        
        PLUGINSTRINGTAG = "AFont TEST"
        okyn = plugins.RegisterTagPlugin(id=PLUGIN_ID_AFONTTAG, str=PLUGINSTRINGTAG, info=c4d.TAG_VISIBLE|c4d.TAG_EXPRESSION|c4d.TAG_MULTIPLE, g=AFONTTAG, description="afonttag",  icon=bmp)
        if (not okyn): 
            print "Error initializing " + PLUGINSTRINGTAG
            
    

    Here the hierarchy.
    9870fabf-329e-40d8-80c9-cef5bba5c15a-image.png



  • Hi pim, thanks for reaching out us.

    With regard to your issue I've tried to replicate the behavior and I was able to have the BaseObject::GetRad() returning a 0-valued vector only when performing undo steps.
    If this is the sole case then it's likely to be caused by the Subdivision Surface generator actually regenerating its cache after your custom tag has been executed. This is also confirmed with the Subdivision Surface generator not being in the hierarchy: all the tests never produced a single 0-valued vector returned by BaseObject::GetRad().

    If, instead, you're able to reproduce in a different scenario, please provide detailed steps in order to dig down more.

    Cheers, Riccardo



  • Ok, but how to solve the issue "Subdivision Surface generator actually regenerating its cache after your custom tag has been executed."? What can I do know that the BaseObject::GetRad() will return a valid value?

    For example, set the priority, wait awhile, etc.?

    -Pim



  • Ok, I have a scene file and a plugin that reproduces the error all the time.

    The error is always there when I have saved the file and reload the file.
    In Execute(), I test whether one of the children is dirty and this is true when loading the scene.
    I then get the bounding box of the children and there it goes wrong.
    Cinema always returns a bbox of zero.

    3af77ee5-868a-4590-b467-9c905076f533-image.png
    No Undo steps are performed.

    Here the Execute() part of the tag plugin (only the part to show where it goes wrong).

        def Execute(self, tag, doc, op, bt, priority, flags):
    
            children = op.GetChildren()
            
            childIsDirty = False
            for index, obj in enumerate(children):      # check if one of the children is dirty.
                child = obj.GetDown()      
    
                if not(child): return True
                if (child.IsDirty(c4d.DIRTYFLAGS_MATRIX)): 
                    childIsDirty = True
                    break
                    
            if (childIsDirty):
                for child in children:     
                    sssObj = child.GetDown()                # get Subdivision Surface Object
                    bbRadiusA = sssObj.GetRad()             # Get BBox
                    if (bbRadiusA[0] == 0):
                        print "ERROR GetRad: ", bbRadiusA, sssObj.GetName()    
                                                
            return c4d.EXECUTIONRESULT_OK
    

    If needed I can send you the complete source file and the scene file.

    Hope we can solve this.
    -Pim



  • I create a workaround that is working.
    I think, like you say, that the Subdivision Surface is not ok, when I initially load the scene.
    I now get the polygon object under the sss and that works.


Log in to reply