path = 'some/path.skp'
d = Sketchup.active_model.definitions.load(path)
instance = Sketchup.active_model.entities.add_instance(d, IDENTITY)
puts "definition guid: #{d.guid}"
# redraw instance which has dynamic attributes
# redraw_without_undo method just is a copy of redraw_with_undo but without operation transaction
$dc_observers.get_latest_class.redraw_without_undo(instance)
puts "definition guid: #{instance.definition.guid}"
# in this case, guid changes, that's what I what.
In this case, the definition’s guid will be changed.
But if wrap those codes into an operation transaction like this:
Sketchup.active_model.start_operation 'test', true
path = 'some/path.skp'
d = Sketchup.active_model.definitions.load(path)
instance = Sketchup.active_model.entities.add_instance(d, IDENTITY)
puts "definition guid: #{d.guid}"
# redraw instance which has dynamic attributes
# redraw_without_undo method just is a copy of redraw_with_undo but without operation transaction
$dc_observers.get_latest_class.redraw_without_undo(instance)
puts "definition guid: #{instance.definition.guid}"
Sketchup.active_model.commit_operation
# in this case, guid doesn't change, that's not what I what.
The definition’s guid won’t change, and after this operation, even import the definition from the path again, the new imported definition is same as instance.definition
But if in the operation transaction use redraw_with_undo instead of redraw_without_undo, the definition’s guid changed, too.
Sketchup.active_model.start_operation 'test', true
path = 'some/path.skp'
d = Sketchup.active_model.definitions.load(path)
instance = Sketchup.active_model.entities.add_instance(d, IDENTITY)
puts "definition guid: #{d.guid}"
# redraw instance which has dynamic attributes
$dc_observers.get_latest_class.redraw_with_undo(instance)
puts "definition guid: #{instance.definition.guid}"
Sketchup.active_model.commit_operation
# in this case, guid changes, that's what I want.
Generally, with DCs, if the attribute settings cause the DC code to modify the DC component’s definition, then it must get a new guid. This can occur with material changes, or stretching where extra copies of subcomponents are generated.
So, in your test make sure that you do the exact same attribute changes.
We cannot reproduce the error on our machines without a test component file and the change to the attributes before the redraw calls. Also, whenever reporting an error with the API and/or an extension, it is normal to state the SketchUp/API version and the version of the extension.
FYI, in this second case, because the DC method starts a new undo operation, the operation you had already started is automatically committed.
Thanks. The result of the first case is what I want. I want the definition’ guid changed after redraw since after redraw the entities of the definition would be changed.
Yes, this is why using redraw_without_undo instead of redraw_with_undo, cause I want call redraw method multiple times under single operation.
What I do is define a new mehtod named redraw_without_undo like this:
class DynamicComponentsV1
def redraw_without_undo(entity)
determine_movetool_behaviors(entity)
DCProgressBar::clear()
redraw(entity)
DCProgressBar::clear()
refresh_dialogs()
end
end
And the original method named redraw_with_undo should be like this:
I do worry. Do so, would engrain poor coding habits in you. And later on you may forget that you “monkey-patched” classes you should not have. Again, use a refinement.
I already weighed in on this. The DC code is very complex and closed source.
I really don’t have much interest in digging deeper into it. (I have my own projects.)
Based on the document of ComponentDefinition’s guid
The guid method is used to retrieve the unique identifier of this component definition. The guid changes after the component definition is modified and the component edit is exited.
This means definition’s guid will be changed only if the definition is modified.
When using Sketchup.active_model. start_operation(‘test’, true), the second parameter will ignore the modification untill commit_operation
disable_ui (Boolean) (defaults to: false) — if set to true, then SketchUp’s tendency to update the user interface after each geometry change will be suppressed. This can result in much faster Ruby code execution if the operation involves updating the model in any way.
So in the operation block, the definition’s modification will be igonred, and the guid of definition won’t change.
In this case, if we import a definition from a file, and add an instance to the active model, then redraw it, then repeat this operation for several times(import the same definition file), and we wrap those operations into one start_operation / commit_operation block, we’ll find that Sketchup only import definition from file for once, the rest of import will use the definition exist in the active model, even if the definition has been changed(but guid doesn’t change)
So I think Sketchup shoud introduce a new parameter for DefinitionList#import, which if set to true, Sketchup will always import definition from file, even if the definition exists in the active model.
SketchUp 2023.0 had a similar fix for the #load method and added a :allow_newer paramter in SketchUp 2021.0:
Fixed Sketchup::DefinitionList#load not loading component if the model already contained a different component associated with the same path.
So a possible workaround might be to do the import from a non-SKP file, then save it out as a SKP component file, thereafter use Sketchup::DefinitionList#load.