# Finding all connected groups

My goal is make two (or more) connected groups as one group.

There are dozens of possibilities for groups to be connected.
Can you tell us your interpretation of “connected groups”? Please explain in sufficient detail!

I guess there will be no solution for your request as “two-line” code…

In picture you can see some connected groups that I wish to find.

. I wish to solve this problem in different steps. In first step I need to know name of other group that is connected to my group.

An idea.
You have to get an array of all vertices position of all the faces of “my group”. Transformation of group must be taken into consideration when you retrieving the position. You will get Point3d array. You may need to make it uniq!.

You have to get an array of all group in a model excluding “my group”.
You have to iterate through each of this group entities and check the faces for all above mentioned points with .classify_point method if it is on it or not. (This time you heve to use both PointInside , PointOnEdge, PointOnVertex for.classify_point condition). Transformation of group must be taken into consideration when you make the compassion.
If you get ‘hit’ you can store the group to an array for later processing…check the names, etc.

Lets have a simple 2D example. Following we have face1 (one point in common), face2 (One line in common), face3 (an area in common), face4 (Nothing in common) and face_main. If we have only face_main, how can we find face1, face2 and face3?

``````mod = Sketchup.active_model  # Open model
ent = mod.entities  # All entities in model
sel = mod.selection  # Current selection

pt1 = [20, 20, 0]
pt2 = [15, 30, 0]
pt3 = [25, 30, 0]
face1 = ent.add_face pt1, pt2, pt3
pt1 = [13, 10, 0]
pt2 = [17, 10, 0]
pt3 = [15, 5, 0]
face2 = ent.add_face pt1, pt2, pt3
pt1 = [15, 15, 0]
pt2 = [30, 10, 0]
pt3 = [30, 20, 0]
face3 = ent.add_face pt1, pt2, pt3
pt1 = [0, 0, 0]
pt2 = [10, 0, 0]
pt3 = [0, 10, 0]
face4 = ent.add_face pt1, pt2, pt3
pt1 = [10, 10, 0]
pt2 = [10, 20, 0]
pt3 = [20, 20, 0]
pt4 = [20, 10, 0]
face_main = ent.add_face pt1, pt2, pt3, pt4
``````

!! dirty & cheap !!

``````#the snippet of your previous post continued like:

all_faces = ent.grep(Sketchup::Face).to_a
other_faces = all_faces - [face_main]
p_v = Sketchup::Face::PointOnVertex
p_e = Sketchup::Face::PointOnEdge
p_i = Sketchup::Face::PointInside
faces_con = []
all_faces.each{|face_a|
face_a.vertices.each{|vert|
if face_a == face_main
other_faces.each{|face_o|
result = face_o.classify_point(vert.position)
if result == p_v || result == p_e || result == p_i
faces_con<<face_o
end
}
else
result = face_main.classify_point(vert.position)
if result == p_v || result == p_e || result == p_i
faces_con<<face_a
end
end
}
}
puts "------"
puts "found total #{faces_con.size} connected face(s)..."
faces_con.uniq!
puts "...and : #{faces_con.size} of them are unique"
puts "The face(s) connected to face_main (#{face_main}) are:#{faces_con} "
sel.clear
puts "The number of face(s) in selection:"
puts "------"
``````
1 Like

I wish to merge face2 and face3 to face_main if faces are in same height. Can you also help me for it?

There are dozens of possibilities for “merge” and “same height”.

Same as picture

!! MORE dirty & cheap !!

``````#the snippet of my previous snippet continued like:

faces_con.each{|f|
gr_temp.explode
}
2.times{
ent.grep(Sketchup::Edge).to_a.each{|e|
next unless e.valid?
if e.start.edges.size == 1 || e.end.edges.size == 1
e.erase!
next
end
next if e.faces.size != 2
e.erase!
}
}
``````
1 Like

If you take at look at the top right example, you’ll see that it has no vertices lying on or in the other group.
Also, none of the bounding box corners would be within the other group’s bounds.

For this scenario we have suggested in the past that a boolean intersect be done on two copies of the groups. And then the result examined to see if it has an length or volume. (Lastly the temporary result is deleted.)

The drawback to this approach is that it makes modifications to the model, so some have used this approach within an undo operation and then call `Sketchup.undo` or abort the operation after doing the determination of intersect.

1 Like

Thank you so much. I will back to this codes many times…

Thank you for advice. I will check it carefully.

Dear Dezmo,
Lets make it more interesting… In following example we have faces in different groups. Can you help me to solve problem for this scenario?

``````mod = Sketchup.active_model  # Open model
ent = mod.entities  # All entities in model
sel = mod.selection  # Current selection

pt1 = [20, 20, 0]
pt2 = [15, 30, 0]
pt3 = [25, 30, 0]
face1 = grp1.entities.add_face pt1, pt2, pt3
pt1 = [13, 10, 0]
pt2 = [17, 10, 0]
pt3 = [15, 5, 0]
face2 = grp2.entities.add_face pt1, pt2, pt3
pt1 = [15, 15, 0]
pt2 = [30, 10, 0]
pt3 = [30, 20, 0]
face3 = grp3.entities.add_face pt1, pt2, pt3
pt1 = [0, 0, 0]
pt2 = [10, 0, 0]
pt3 = [0, 10, 0]
face4 = grp4.entities.add_face pt1, pt2, pt3
pt1 = [0, 0, 0]
pt2 = [0, 10, 0]
pt3 = [10, 10, 0]
pt4 = [10, 0, 0]
face_main = grp_main.entities.add_face pt1, pt2, pt3, pt4
tr = Geom::Transformation.new [10, 10, 0]
grp_main.transform! tr
ents = Sketchup.active_model.active_entities
all_faces = []
ents.each{ |entity|
case entity
when Sketchup::ComponentInstance, Sketchup::Group
entg = entity.definition.entities
entg.each{ |entityg|
case entityg
when Sketchup::Face
if entityg.normal == [0, 0, -1]
all_faces << entityg
end
end
}
end
}
other_faces = all_faces - [face_main]
p_v = Sketchup::Face::PointOnVertex
p_e = Sketchup::Face::PointOnEdge
p_i = Sketchup::Face::PointInside
``````

I will not ask a third time.

From the randomly copy-pasted code snippest above, I came to the conclusion that the help so far has had no effect.
Instead of sitting down and looking at the basics, you’re waiting for someone else to write it. It won’t be me.
Sorry.

Ruby learning resources

1 Like

Apologize my mistake. In fact after I put faces in groups you codes work but I could not see. After I deleted groups I find one merged face.

I added following codes and deleted connected faces and their parent group. My problem solved.

``````num = faces_con.size.to_i
loop do
face_b = faces_con.pop
grp_f = face_b.parent.instances[0]
grp_f.erase!
num -=1
break if num == 0
end
main_grp.erase!
``````

For friends whom are interest on this topic… You need to use following code.
" entities.intersect_with recurse, transformation1, entities1, transformation2, hidden, entities2 ".
It looks confusing but you can find clear explanation and simple example in this link. About 'intersect_with' method • sketchUcation • 1. This method will return you an array. If array.size is one means 2 groups has one line in common. if two means one face in common. 3 or more means volume in common.

Dear Dezmo,

I run your following codes for 2 cases. As you can see in photo it works for lower case but cannot work for upper case. Would you please let me know problem. Also I will be highly appreciate if you can explain code a little.

``````          2.times{
ent.grep(Sketchup::Edge).to_a.each{|e|
next unless e.valid?
if e.start.edges.size == 1 || e.end.edges.size == 1
e.erase!
next
end
next if e.faces.size != 2
e.erase!
}
``````

I also do some test on codes. Following codes works but I am not sure it is right or not.

``````               e.erase! if e.faces.size > 1
``````

Yes this is correct for removing dividing edges. Example …

``````ent.grep(Sketchup::Edge) do |edge|
edge.erase if edge.faces.size > 1
end
``````

FYI`Enumerable#grep` is a block form iterator method. It produces an array so you need not use `.to_a` and you need not use `.each` as it is already an `Array#each` iterator.

1 Like