A SetBit problem aka cann't select node.
-
Hi !
I am try to set my scatter rig , the basic rule is :
- node selected : set the node to the
Scatter Object
, try find selection tag and set to the "Scater Aera" - tag selected : set the node which tag on to the
Scatter Object
, tag to the "Scater Aera"
All they worked , but in the context " only tag selected " , the the scatter object doesn't active in object manager , I cann't find how this heppend .
the scatter shoud be :
the " tag " context , it returns like this , the scatter is set right and active is object manager , but it doesn't active in attribute manager .
How can I fix this ?
( It's a bare-bone rig that i can show this problem and easy to read , If a non delete setting is needed please let me kow)@ Windows 11 21H2 Cinema 4D 2023.0.0
from typing import Optional import c4d doc: c4d.documents.BaseDocument # The active document op: Optional[c4d.BaseObject] # The active object, None if unselected def redshift_scatter() -> c4d.BaseObject : # Modifier ID ModifierID = 1018545 ModifierName = 'Scatter : ' selection = False doc.StartUndo() selectedtag = doc.GetActiveTag() node = doc.GetActiveObject() # pass if nothing selected if not node and (not selectedtag or not selectedtag.CheckType(5673)) : return # node selected if node : doc.AddUndo(c4d.UNDOTYPE_BITS,node) node.DelBit(c4d.BIT_ACTIVE) tags = [tag for tag in node.GetTags() if tag.CheckType(5673)] if len(tags)==[]: pass if len(tags) == 1 : scatter_selection = tags[0].GetName() selection = True else: if selectedtag in tags : scatter_selection = selectedtag.GetName() selection = True doc.AddUndo(c4d.UNDOTYPE_BITS,selectedtag) selectedtag.DelBit(c4d.BIT_ACTIVE) # selection tag elif (selectedtag and selectedtag.CheckType(5673)) and not node: scatter_selection = selectedtag.GetName() selection = True node = selectedtag.GetObject() # deselect tag doc.AddUndo(c4d.UNDOTYPE_BITS,selectedtag) selectedtag.DelBit(c4d.BIT_ACTIVE) # world matrix. pos = node.GetMg() # Modifier Modifier = c4d.BaseObject(ModifierID) Modifier[c4d.ID_MG_MOTIONGENERATOR_MODE] = 0 Modifier[c4d.MG_OBJECT_LINK] = node #Modifier[c4d.MG_POLYSURFACE_SEED] = seed Modifier[c4d.MG_POLY_MODE_] = 3 # surface if selection : Modifier[c4d.MG_POLY_SELECTION] = scatter_selection Modifier.SetName(ModifierName + node.GetName()) Modifier.SetMg(pos) # Set the world (global) matrix. Modifier.InsertAfter(node) doc.AddUndo(c4d.UNDOTYPE_NEWOBJ,Modifier) Modifier.SetBit(c4d.BIT_ACTIVE) doc.EndUndo() c4d.EventAdd() return Modifier if __name__ == '__main__': redshift_scatter()
thanks
- node selected : set the node to the
-
Hello @dunhou,
Thank you for reaching out to us. We are quite busy now now, I must unfortunately push your question to the end of next week.
Please excuse the delay and cheers,
FerdinandPS: I glanced at your post, and this might be a priority issue in the internal event loop, and you seem to have a problem with the Attribute Manger not updating as you want it to. You can try your luck with
c4d. SendCoreMessage(c4d.COREMSG_CINEMA_FORCE_AM_UPDATE)
after your lastEndUndo
andEventAdd
, but that is more a guess than a solution, as I do not have time to read and run your script right now. -
That's all right I will move on another work for now.
Thanks for your time -
Hey @dunhou,
sorry for the delay, 2023.1 was consuming my time. The problem with your code is that it produces what is called a
TriState
selection in the C++ API, i.e., multiple things are selected and Cinema 4D tries then to display the intersection of attributes of the selected entities in the Attribute Manager. Which happened to be the empty set in your case, hence the empty Attribute Manager. The most straight forward way to solve this, is to simply useBaseDocument.SetActiveObject
and start a new selection.Find your modified code below; I have marked the minor change I made with a change fence. Also find a more technical explanation there.
Cheers,
FerdinandThe result:
The code:from typing import Optional import c4d doc: c4d.documents.BaseDocument # The active document op: Optional[c4d.BaseObject] # The active object, None if unselected def redshift_scatter() -> c4d.BaseObject : # Modifier ID ModifierID = 1018545 ModifierName = 'Scatter : ' selection = False doc.StartUndo() selectedtag = doc.GetActiveTag() node = doc.GetActiveObject() # pass if nothing selected if not node and (not selectedtag or not selectedtag.CheckType(5673)) : return # node selected if node : doc.AddUndo(c4d.UNDOTYPE_BITS,node) node.DelBit(c4d.BIT_ACTIVE) tags = [tag for tag in node.GetTags() if tag.CheckType(5673)] if len(tags)==[]: pass if len(tags) == 1 : scatter_selection = tags[0].GetName() selection = True else: if selectedtag in tags : scatter_selection = selectedtag.GetName() selection = True doc.AddUndo(c4d.UNDOTYPE_BITS,selectedtag) selectedtag.DelBit(c4d.BIT_ACTIVE) # selection tag elif (selectedtag and selectedtag.CheckType(5673)) and not node: scatter_selection = selectedtag.GetName() selection = True node = selectedtag.GetObject() # deselect tag doc.AddUndo(c4d.UNDOTYPE_BITS,selectedtag) selectedtag.DelBit(c4d.BIT_ACTIVE) # world matrix. pos = node.GetMg() # Modifier Modifier = c4d.BaseObject(ModifierID) Modifier[c4d.ID_MG_MOTIONGENERATOR_MODE] = 0 Modifier[c4d.MG_OBJECT_LINK] = node #Modifier[c4d.MG_POLYSURFACE_SEED] = seed Modifier[c4d.MG_POLY_MODE_] = 3 # surface if selection : Modifier[c4d.MG_POLY_SELECTION] = scatter_selection Modifier.SetName(ModifierName + node.GetName()) Modifier.SetMg(pos) # Set the world (global) matrix. Modifier.InsertAfter(node) doc.AddUndo(c4d.UNDOTYPE_NEWOBJ,Modifier) # --- Change Start ----------------------------------------------------------------------------- # This line was the problem in your code. You sort of did everything correctly, you # deleted the selection bits in line #26, #39, and #49. But your code has sort of a fault, as # in that you do not make sure that all tags are deselected in all cases. #tag in line #28 # contains only a subset of tags. Cinema 4D considers the scene state therefore to still be a # multi-selection after your script ran. # Cinema 4D allows you to select multiple objects and will then display the intersection of # attributes of all selected nodes in the Attribute Manager. In the C++ API this is called a # TriState, the Python API does not really understand the concept. So what happened here, is # that Cinema 4D tried to build that TriState for the old selected tag and the # new object, which happens to be the empty set, hence the empty AM in your screen cast. # You could either make sure that really everything is deselected by managing the bits more # carefully, or do what I have done here, use the convenience function BaseDocument:: # SetActiveObject() to "nuke" the scene selection state. The second argument defines if you # want to add to an existing selection or start a new one. c4d.SELECTION_NEW is the default # value, I have added it here only for verbosity. # Modifier.SetBit(c4d.BIT_ACTIVE) doc.SetActiveObject(Modifier, c4d.SELECTION_NEW) # --- Change End ------------------------------------------------------------------------------- doc.EndUndo() c4d.EventAdd() return Modifier if __name__ == '__main__': redshift_scatter()
-
@ferdinand Thanks for the new solution for
SetActiveObject
. It works as expected.Much appreciated !