If we assume that the cumulative length of the outer perimeter edges will always be a larger value than any of the interior sum lengths of inner loops, then a comparison can be made to get the outer perimeter.
After collecting all edges and filtering out duplicates …
Step 2 would be to divide the array of all edges into a nested array of loops. In this case a loop is a collection of edges that are connected via shared vertices.
Step 3 would be Interating the loops array to find the longest loop.
Probably not foolproof, as you might have a inner loop that meanders and has more edges and so longer length than the outer perimeter.
Having done step 2 resulting in a nested array of loops, step 3 might be to determine which loop edges do not share an internal face. These would be the inner loops to be skipped leaving the outer perimeter loop.
The idea would be to geometrically sniff out what is “inside” a loop as opposed to “outside” a loop.
A space inside an inner loop is a space shared by the edges that bound that space. The trick is to somehow determine this. Perhaps firing rays from the midpoint of the loop edges to see if they hit one of the other edges?
An alternative is to fill the holes with edge.find_faces and then gather all of the edges that are only connected to a single face.
model = Sketchup.active_model
ents = model.active_entities
sel = model.selection
model.start_operation("dummy", true)
grp = ents.grep(Sketchup::Group)[0] # grab the first group in the entities
edges = grp.entities.grep(Sketchup::Edge)
# fill the holes and return any edges that continue to have only one face
outer_loop = edges.select { | edge |
edge.find_faces if edge.faces.size == 1
edge.faces.size == 1 # return true for the outer_loop edges
}
model.abort_operation
sel.clear
sel.add(outer_loop)
puts outer_loop
Now, it is also best to pass the parent’s transformation (or any cumulative transformation of the instance path) into the #area method so that instance scaling is applied to the face area values.
Althougth @sWilliams solution is very tempting and easy to implement I think that aborting the process could be problematic somtimes so, I finally will implement the option with both loops. Thnaks to both @DanRathbun and @sWilliams