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