Specific Edge Selection of a Group

So here is another interesting but seemingly challenging algorithm question.

I have the group below (wall cladding - dutch lap). Notice that it has a lot of 3D geometry, it is not just a texture.

In this case I am trying to hide the edges at the perimeter of the wall only.

I can easily hide all the edges given the group, using this piece of code I am currently using:

all_clad_edges = group_clad.entities.grep(Sketchup::Edge)
for edgei in all_clad_edges do
  edgei.hidden = true
end

I know the dimensions of the wall panel (width and height) and all of the x, y, z data so I’m thinking there should be a way to select or find just those edges along the perimeter…

I think that if you can write down a clear, precise definition of what you mean by “perimeter” the exercise will lead you to the required logic for your code.

1 Like

Off the top I think if I can find the four faces that define the top, bottom and two sides of the panel I can then run through all the edges and see which ones are common to any of these four faces.

Actually I’m making this problem too hard, just get the four faces and then use the edges method to gather all the edges that are bounding these four faces.

Okay, easy. Think first about the right-side edges in your images. They all will have the same x and y, but some edges differing z coordinates.

right_side_edges = all_clad_edges.select do |edge|
  pt1 = edge.start.position
  pt2 = edge.end.position
  p1.x == x && pt1.y == y && pt2.x == x && pt2.y == y
end

EDIT: hmmm … perhaps not true ? The horizontal edges have the same x and z, but different y value.

1 Like

Perhaps the face method is more robust. Although there are more than 4 faces per board.
Select the ones you want by the face normal vectors.

1 Like

Correct, there are more than four faces however there are only ever four faces that define the perimeter of the cladding: top, bottom, left and right.

I think this is the best way to go. I just need to figure out a good robust way of finding them, which actually shouldn’t be too hard since I know the x,y dimensions of the panel.

So here is my first crack at a “robust” algorithm.

I do know the x,y of the panel but there could be situations in the future that I do not.

  1. Take the bounding box of the group, get the min and max of this bounding box.
  2. Find the two vertices at these min and max positions.
  3. Find the faces that use these two vertices, there should only ever be 3 faces per vertex.
  4. Reject the face that’s normal is in the Y direction. (The panel is always drawn along the X axis).
  5. The remaining four faces define the perimeter.
  6. Use the edges method to gather all the edges for each face.
  7. Add the four arrays to create one array and also eliminate redundant edges.
  8. Cycle through this array and hide each edge.

This actually seems very simple, when broken down this way, am I missing anything?

Try …

all_clad_faces = group_clad.entities.grep(Sketchup::Face)
# Hide perimeter_faces:
all_clad_faces.each do |face|
  next unless face.normal.parallel?(X_AXIS) || face.normal.parallel?(Z_AXIS)
  face.edges.each { |edge| edge.hidden= true }
end

You might need to have references for the group x_axis and y_axis if not aligned to the model axis.

ADD: Something like ?

all_clad_faces = group_clad.entities.grep(Sketchup::Face)
# Hide perimeter_faces:
gt = group_clad.transformation
x_axis, y_axis = gt.xaxis, gt.yaxis
all_clad_faces.each do |face|
  next unless face.normal.parallel?(x_axis) || face.normal.parallel?(y_axis)
  face.edges.each { |edge| edge.hidden= true }
end

… depends upon whether face.normal returns a vector per the internal group axis or not.
It also may depend upon what the current edit context (active_path) is.

1 Like

Does this not work?

all_clad_vertex = group_clad.entities.grep(Sketchup::Vertex)

This does work:

all_clad_edges = group_clad.entities.grep(Sketchup::Edge)

How do I get all of the vertices in a group?

P.S.
I don’t see a way to do this so I will adjust accordingly.

Here is my code thus far and it seems to work for rectangular walls:

                all_clad_faces = group_clad.entities.grep(Sketchup::Face)

				backface = all_clad_faces.find {|f| f.normal.samedirection?(Y_AXIS)}

				bbg = backface.bounds
				bb_min = bbg.min
				bb_max = bbg.max

				min_x = bb_min.x.round(6)
				min_z = bb_min.z.round(6)
				max_x = bb_max.x.round(6)
				max_z = bb_max.z.round(6)

				all_clad_vertex = backface.vertices

				vmin = all_clad_vertex.find{ |v| (v.position.x.round(6) == min_x) && (v.position.z.round(6) == min_z) }
				vmax = all_clad_vertex.find{ |v| (v.position.x.round(6) == max_x) && (v.position.z.round(6) == max_z) }

				if vmin && vmax
					minfaces = vmin.faces
					maxfaces = vmax.faces

					minfaces.each do |face|
						unless face.normal.parallel?(Y_AXIS) 
							face.edges.each { |edge| edge.hidden = true }
						end
					end

					maxfaces.each do |face|
						unless face.normal.parallel?(Y_AXIS)
							face.edges.each { |edge| edge.hidden = true }
						end
					end


				else
					puts "Could not find min and max vertices of cladding, hidden clad lines aborted."
				end

Like so …

verts = group_clad.entities.grep(Sketchup::Edge).flat_map(&:vertices).uniq

ADD: It also works for faces because: Face#vertices exists.

1 Like

I will keep this small chunk of code for future reference. I’m surprised one cannot simply grep for the vertices though. I am still learning.

That’s because vertices are used by geometry but aren’t themselves geometry. You can get them from an entity, but there is no collection you can grep for them.

1 Like

In addition to what Steve said, think of vertices as second order properties of higher order geometry objects.

2 Likes

I don’t think my algorithm is 100% bullet proof yet but it does the job for now. The trick was to grab the back face of the cladding which will always be a single face with its normal vector in the positive Y direction. Once I have that it isn’t too hard to grab strategic vertices on that face along the perimeter and then find the perimeter faces themselves.

I guess I mostly solved this one myself but it certainly helped to bounce ideas back and forth. Sometimes that is all that is needed to take the blinders off and then see a novel solution that was not immediately apparent.

Once again thank-you Dan, your help is duly noted and much appreciated.

1 Like