Reference to deleted Group

#1

I’m being hit by a known sketchup bug - that of groups being aggressively deleted, however, in my case the known work around provided by @DanRathbun does not work. I’m creating the construction point, but the group is still being deleted. Further reading…



My code is creating the group, adding the construction point, then adding geometry or recursively adding more groups/geometry during an import. I’m not even deleting the construction point, but still I’m getting the reference to deleted group. So it seems that adding a construction point isn’t enough, what else do I need to do?

0 Likes

#2

post a failing code snippet, or we’re all stabbing in the dark…

john

0 Likes

#3

Failing code snippet. hopefully another set of eyes can spot the issue!

		def import_node(entities, node, matrix)
			mesh_id = node.get_mesh()
			mtx = node.get_matrix()
			
			group = entities.add_group
			
			group.transformation = mtx
			# create a new construction point
			point1 = Geom::Point3d.new(@cpointpos,@cpointpos,@cpointpos)
			@cpointpos = @cpointpos + 1.0
			constpoint = group.entities.add_cpoint point1
			
			
			if mesh_id != nil
				
				scale_up = IDENTITY
				scale_down = IDENTITY
				if(@internal_scale != 1.0)
					scale_down = Geom::Transformation.scaling(1.0/@internal_scale,1.0/@internal_scale,1.0/@internal_scale)
					scale_up = Geom::Transformation.scaling(@internal_scale,@internal_scale,@internal_scale)
				end
				
				# make a component if the mesh is referenced multiple times
				if @components.is_mesh_component(mesh_id)
					
					component = @components.get_component_definition(mesh_id)
					if component == nil
						# The component does not exist, create it
						meshName = @meshes[mesh_id].get_name()
						if meshName == nil
							meshName = "mesh_id_" + mesh_id.to_s
						end
						component = Sketchup.active_model.definitions.add meshName
						
						group2 = component.entities.add_group
						group2.transformation = scale_down
						
						# create a new construction point
						point1 = Geom::Point3d.new(@cpointpos,@cpointpos,@cpointpos)
						@cpointpos = @cpointpos + 1.0
						constpoint2 = group2.entities.add_cpoint point1
						# add geometry
						create_mesh(group2, mesh_id, scale_up)
						
						@components.add_component_definition(mesh_id, component)
					end
					group.entities.add_instance(component, IDENTITY)
				else
					group2 = group.entities.add_group
					group2.transformation = scale_down
					# create a new construction point
					point1 = Geom::Point3d.new(@cpointpos,@cpointpos,@cpointpos)
					@cpointpos = @cpointpos + 1.0
					constpoint = group2.entities.add_cpoint point1
					# add geometry
					create_mesh(group2, mesh_id, scale_up)
				end
				
			end
			
			children = node.get_children()
			
			if(group.deleted?)
				# never gets here
				puts 'Group was deleted!'
				return
			end
			
			if children != nil
				children.each { |child_id|
					child = @nodes[child_id]
					# reference to deleted group here
					import_node(group.entities, child, matrix)
				}
			end
			
		end
0 Likes

#4

Can you post a snippet of code we can execute?

Including how you invoke start_operation and commit_operation also helps.

One thing to check is the return values of your method calls. For instance Entities.add_face could fail - and in which case return nil. This could be because of too small edges etc. But a (what I think) flaw in the method is that if it fails to create a fail it also abort the current operation.

So if you create a group, and then start adding faces to it and one of it fails - then you could get the Reference to deleted Group error if that’s the next thing you reference after add_face.

If so, an alternative could be to use entities.fill_from_mesh to populate multiple faces. (It’s more robust to face creation error - and also faster.)

0 Likes

#5

Thanks ThomThom,

I tried using a Geom::PolygonMesh but I believe it has a serious flaw making it unusable: it tries to be too smart when adding points so that each point is unique (clearly it is using its own hash table internally), but then I can’t apply a different uv to each point.

start_operation looks like this:

begin
	Sketchup.active_model.start_operation TRANSLATE["title"],true,false,false
	# create stuff
rescue => e
	Sketchup.active_model.abort_operation
	return 1
end
Sketchup.active_model.commit_operation

face creation is also wrapped in a begin/rescue clause…

begin
	face = entities.add_face points
	if expected_normal != nil
		# flip the new face is it is now facing the correct direction according to the provided normals
		dot = face.normal.dot expected_normal
		if dot < 0.0
			face.reverse!
		end
	end
	face.material = material
rescue
end

So if the face is nil, the operations following should fail.

0 Likes

#6

Ah, yes, if you want UV mapping that isn’t continuous then that will be a challenge. However, in one extension I have worked around this by relying on the order the faces are traversed afterwards. After using fill_from_mesh I traverse the faces in the Entities collection and use position_material.

This doesn’t prevent add_face from aborting the operation. I’d suggest that you investigate the faces that fail to create and determine why. Then try to avoid feeding that to the method.

0 Likes

#7

Hmmm, it seems that is undocumented - is it guaranteed to be the same order that the polygons were added to the mesh? I will try this method as I’d love to speed up my import extension. Thankies!

The faces that are being imported are small, so I could check that the distance between each point is larger than 0.005 inches, but this leaves ugly gaps in the model - alternatively, and this is what I’ve opted to do as a decent workaround: I am scaling the mesh up by a factor of a thousand, and scaling the group down by the same factor.

0 Likes

#8

No - not part of the API contract. Implementation detail - so use at own risk (as I did). But it was the only way I could do what I needed with sufficient speed.

Yes, that is something I’ve been meaning to implement myself in one of my extensions when I detect small faces.

0 Likes

#9

Note - I also check that the num faces generated matched the input. Because fill_from_mesh might also fail to create small faces.

0 Likes

#10

Tried it, it worked to an extent - the first set of geometry imported into the group, but it failed on the second set (adding another mesh into the same group, and ignoring faces already present) - so no, this can’t be relied upon. I think an API change would be needed - we need to be able to include UV coordinates during mesh.add_point

0 Likes

#11

It requires that the entities collection to be filled is empty.

If you need to add to an Entities collection with existing entities you need to use add_faces_from_mesh.

I’ve been wanting another way to bulk-generate meshes. With better control over each face and edge. PolygonMesh isn’t fit for that task. It’s a simple internal class to handle triangulation of faces (single faces).

The C API’s SUGeometryInput is more towards what you want. (Though I’m not too happy about it’s API either.)

0 Likes

#12

Oops, yes, that is what I was using.

I’ve started to look at the C API, as a few of the larger models have taken hours to import. Meanwhile I’m impatiently waiting for the Sketchup Extension Warehouse team to approve my ruby glTF exporter and glTF importer. :frowning:

0 Likes

#13

Are you receiving the emails from moderation? (If not, check your spam filter.)

glTF Import got rejected because of invalid Ruby syntax in gltf_matrix.rb line 42.
glTF Export got rejected because of loading problems (it was marked for encryption (where RB files are replaced with RBS/RBE files - but it wasn’t using Sketchup.require which is needed to lead encrypted files.)

0 Likes

#14

No, nothing in junk, I didn’t receive anything. :frowning:
gltf_matrix.rb isn’t even used, there is a comment at the start of the file to indicate such.
I’m not sure what you mean by Sketchup.require
do you mean require ‘sketchup’?
I’ve resubmitted, I guess they are bottom of the queue again now - I’m going to cry.

0 Likes

#15

Hmm… What email provider and client do you use?

I’d recommend not including anything that isn’t used. As our automated tools and reviewers will process everything.

In order to load encrypted files you need to use Sketchup.require instead of the normal require. (And also omit the .rb file extension of the filename. SketchUp will resolve to RBE, RBS or RB) To test the effect of encrypting you can use this page: https://extensions.sketchup.com/en/developer_center/extension_signature

0 Likes

#16

I’m using outlook.com

I can’t find any information on how to use Sketchup.require, where is it documented?

0 Likes

#17

When loading encrypted files, instead of

require 'MyExtension/my_file.rb'

you do:

Sketchup.require 'MyExtension/my_file'

If you perform this replacement and reupload your extensions we can review them again.

0 Likes

#18

@DanRathbun Is there a way to make the Onebox pull info from the linked method? When I posted a link to a method it is completely replaced by the box which only refer to the parent module. Can the Onebox fetch the anchor info and dynamically provide different content?

0 Likes

Ruby API Docs - Contributing
#19

Done, and resubmitted. This wasn’t in any of the examples I saw. I assume it only needs to be replaced in the top level rb file.

I’m getting the ‘Extension Submission Update’ emails, but that is all I’ve ever received.

0 Likes

#20

No, any require statements that pull in an encrypted file needs to be replaced with Sketchup.require. This is because Ruby have no idea on how to load encrypted files.

Use the Developer Portal and test the effect of the encryption. Upload your RBZ file, then download the result and install it. Make sure your extension loads. https://extensions.sketchup.com/en/developer_center/extension_signature

0 Likes