SOLVED CSTO over object.GetClone() produces excess geometry

Hi,

I need alternative to GetCache(), and CSTO seems to be a good option.
But Python tag produces wrong geometry when executed over clone of the object with CSTO.
It additionally produces geometry which should be hidden by parent generators (for ex. Cloner under Volume Builder).
Behavior is the same in Python Expression, or Python Tag Plugin, and it affects Cinema4D R21+ at the least.

Here's the code:

                srcClone = srcObj.GetClone(c4d.COPYFLAGS_NO_ANIMATION)
                doc.InsertObject(srcClone)

                cstoResult = c4d.utils.SendModelingCommand(
                    command=c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                    list = [srcClone],
                    mode = c4d.MODELINGCOMMANDMODE_ALL,
                    bc = c4d.BaseContainer(),
                    doc = doc
                )

                srcClone.Remove()

            for resObj in cstoResult:
                for resChildObj in HierarchyIterator(resObj.GetDown()):
                    cloneObject = resChildObj.GetClone(c4d.COPYFLAGS_NO_HIERARCHY)
                    cloneObject.InsertUnderLast(selfObj)

Viewport:
bug.jpg

Don't like the idea to call CSTO over original object, because it rebuilds object cache and affect DIRTYFLAGS_CACHE.
What's the issue, is it possible to resolve it?

Plugin https://www.dropbox.com/s/fxz8g7p8uuwc5y0/c4d_tag_csto.zip?dl=0
Scene simple csto test.c4d

Thanks.

Hi,

Not related to the issue, you are modifying the scene inside the execute function from a TagData, this function isn't executed on the main thread, so you are not allowed to modify the scene. That's really a bad idea.

I got some questions:
why can't you use GetCache? Why you can't affect DIRTYFLAGS_CACHE?

The bahaviour is the same if you use the script manager. The problem is that you clone the object but it doesn't clone the caches.
The following code works on the script manager, but the problem is that you need to ExecutePasses that could modify the DIRTYFLAGS_CACHE. (specially if you are using mograph)

You could isolate the object on a new document (using IsolateObjects) the problem is that with mograph, the effector will not follow. So you would need to write some code to copy also those effectors and re-link them inside the new document.

If you can tell us more about what you are trying to do, we could maybe find a better solution. Using a NodeData for example to generate this "polygon result".

def main():
    srcClone = op.GetClone(c4d.COPYFLAGS_NO_ANIMATION)
    doc.InsertObject(srcClone)
    doc.ExecutePasses(None, False, False, False, c4d.BUILDFLAGS_NONE)
    srcClone.GetDown().Message(c4d.MSG_UPDATE)
    

    cstoResult = utils.SendModelingCommand(
                    command=c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                    list = [srcClone],
                    mode = c4d.MODELINGCOMMANDMODE_ALL,
                    bc = c4d.BaseContainer(),
                    doc=doc
                )
    srcClone.Remove()
    doc.InsertObject(cstoResult[0])
    c4d.EventAdd()
# Execute main()

Cheers,
Manuel

@m_magalhaes Hi Manuel,

Thanks for the reply.

  1. I've read the caution in API documentation, but I have tried it once and now can't stop to use it.
    At least for now I don't face app crashes, so maybe C4D have some safety margin for python developers 😉
  2. I can use cache, and I use it. But I want both options to be available.
    BTW when I'm using Cache from execute it also gives me whole tree including the Cloner sub-tree, when executing at Expression priority. In Generator priority GetCache() produces expected results.
  3. I don't like to affect DIRTYFLAGS_CACHE, because I'm also optimizing redraw based on dirty check with flag c4d.DIRTYFLAGS_DESCRIPTION | c4d.DIRTYFLAGS_DATA | c4d.DIRTYFLAGS_CHILDREN | c4d.DIRTYFLAGS_CACHE
    Also it seems like VolumeBuilder starts to re-generate mesh after CSTO called, and I went into infinite redraw.
  4. Thanks for pointing to IsolateObjects method, but as you mentioned I have to find all linked objects, which is not a trivial task in C4D.
    I wouldn't go that way.
  5. Provided solution with the ExecutePasses is updating geometry very rarely (if it supposed to be executed from python tag).
  6. Currently made a solution to check baseObject.GetInfo() & c4d.OBJECT_INPUT to stop further children processing.
    Seems to work good enough.

hi,

1- it's might not be a crash but a scenario where an NodeData starts with some hierarchy, a tag modifies the object's order, the NodeData doesn't work anymore because the hierarchy have changed.
2 - Sounds logical to me as you may know, the calculation is done in a sequence Generators are executed after Expressions. That's why you must make your code execute after the generators to be able to retrieve the caches.
5 - some c4d object (specially mograph) have some special behavior. if ExecutePasses doesn't work, try two time in a row, or even three. It may sound like a joke but it is not. But if you do that in a tag, that could lead to an infinite loop.
6 - as long as it's working fine for you, I'm happy 😄

Cheers,
Manuel

@m_magalhaes Thanks Manuel,
I appreciate your wise support every time.

Merry Xmas and Happy New Year!