Unloading a Component Definition

This is a follow up question to the recent question I had regarding converting components to groups.

Once I’ve successfully loaded the component and then inserted it into my container group and exploded it I no longer have use for the component definition and would like to completely remove it from the model.

I’ve tried to utilize both purge_unused and remove to accomplish this but both of these methods throws errors. I am basically passing these methods the original component definition that I loaded (after exploding the instance).

instance_data.explode
Sketchup.active_model.definitions.remove(data_compdef)

The error I’m getting for the remove method is:

Error: #<NoMethodError: undefined method `remove’ for #Sketchup::DefinitionList:0x0000000ebcd3c0>

This feature is only available for SketchUp 2018. For users of older versions, you better hope (or remind) the user to purge the model from time to time. If you purge unused definitions through a script you would also purge those that are not related to your extension and that the user might want to keep.

1 Like

That’s what I was afraid of, I guess this is not going to work.

So in previous versions of SketchUp (2015, 2016 and 2017) there is no way to remove a specific component definition from the model other than to purge all unused components which as you suggest I would rather not do.

Correct. The kludgy workaround to prevent purging other definitions was to create a temp group and insert an instance of the other unused definitions - then perform a purge. (Not - pretty, I know. The #remove method should have been added a long time ago.)

2 Likes

I think the component definition is also removed if you delete all of its content. SketchUp doesn’t allow empty definitions.

2 Likes

And if Ruby code still has a reference to the definition after removing its contained entities? Does it immediately become an invalid reference (#<DeletedEntity>) to which you cannot add entities anymore, or does SketchUp purge it as soon as there is no reference any more?

1 Like

I think the entity is truly deleted and the reference become a DeletedEntity. Haven’t poked at that part of SketchUp is some time though.

2 Likes

What would be the easiest way to delete all of the entities of the definition?

This couple of lines of code does not seem to work:

ents = data_compdef.entities
ents.erase_entities ents

This could be worth a shot.

Try definition.entities.erase_entities(definition.entities.to_a)

I think you have to pass an Array to erase_entities.

Also I changed the name data_compdef to a more generic name, and would recommend to have this extracted to a generic erase_definition method. Extracting things to separate methods with celar names, even if it’s just one line of code, can make it much easier to read, understand and maintain the code in the future.

1 Like

Buzzinga! That works, and it works remarkably well.

Thank-you once again.

I would have never thought of trying this route.

1 Like

How about simply …

definition.entities.clear!

?

5 Likes

Why didn’t I think of that :open_mouth:

2 Likes

On a tangential note, erasing groups or components with
entities.clear!
is (for some mysterious reason) much, much faster on heavy geometry than using
group.erase!

2 Likes

Group.erase! may be shared with Edge.erase! and Face.erase! and do totally unnecessary checks to see if the entity in question was binding other entities that needs to be erased too, I don’t know. That should however be implemented at a deeper level so it’s not super likely.

1 Like

Do you have an example model to demonstrate that? I would be interested in seeing what could cause such a difference.

1 Like

I tried to reproduce this but failed, but I know I have encountered a huge difference between them many times. Nevertheless, I think the difference (when it’s there…) may be somehow related to another thing which is easy to reproduce.

Below is a test script with two runs that differs by a time factor factor of >20 (skp2018/windows).
A lot of geometry is produced in 10 groups and they are then erased. If the whole operation is enclosed within a single start/commit it takes about a minute. If a new start operation is inserted before we erase the groups (start/start/commit) the operation takes 2 seconds. This is exactly the same “pull the plug” behavior I’ve encountered by using entities.clear! instead of group.erase! (even though it doesn’t make a difference in this particular script).

module GroupEraseTest2000

	def self.create_group_with_geom(no_of_faces)
		ng = Sketchup.active_model.entities.add_group
		pm = Geom::PolygonMesh.new(no_of_faces + 1, no_of_faces)

		da = Math::PI * 2 / no_of_faces.to_f
		radius = 100.m
		pm.add_point([0, 0, 10.m])
		
		(0..no_of_faces - 1).each { |idx| pm.add_point([radius * Math::cos(da * idx), radius * Math::sin(da * idx), 0])	}
		(2..pm.count_points - 1).each { |idx| pm.add_polygon([1, idx, idx + 1]) }
		pm.add_polygon([1, pm.count_points, 2])

		ng.entities.fill_from_mesh(pm)
		return ng
	end

	def self.run_test(use_second_start_operation)
		mod = Sketchup.active_model

		t0 = Time.now
		mod.start_operation("Erase Test", true, false, true)
		gs = []
		(0..9).each { |idx| gs << create_group_with_geom(5000) }
		
		t1 = Time.now
		
		mod.start_operation("Erase", true) if use_second_start_operation
		
		gs.each { |g| g.erase!}
		mod.commit_operation
		
		t2 = Time.now
		puts "----------------"
		puts "Second start used:  "+use_second_start_operation.to_s
		puts "Create Geometry:  "+(t1 - t0).to_s+"  s"
		puts "Erase Geometry:   "+(t2 - t1).to_s+"  s"

	end

	run_test(false)
	run_test(true)
end
1 Like

That’s an interesting one. I see the difference you describe:

----------------
Second start used:  false
Create Geometry:  1.897473  s
Erase Geometry:   42.885206  s
----------------
Second start used:  true
Create Geometry:  1.90262  s
Erase Geometry:   1.819289  s

I logged your example in the issue tracker: Performance differences in erasing geometry in the Ruby API · Issue #212 · SketchUp/api-issue-tracker · GitHub
worth looking into.

1 Like

for the record, this is even slower on my mac running SU v19…

Second start used:  false
Create Geometry:  3.178602  s
Erase Geometry:   138.855325  s
----------------
Second start used:  true
Create Geometry:  3.083154  s
Erase Geometry:   3.538786  s

john

1 Like

For what it is worth, it is the commit_operation that is taking an insufferable long time, not the erase.

LongTermCommitment.rb (1.3 KB)

1 Like