Surface Outer Loop?
-
Any ideas on how to get an ordered list of outer vertices from a surface?
A surface being a set of faces with possible hidden interior edges and visible outer edges.
I want to go through the model and create a list of vertices (in order) for each surface in the model.
-
A combination of Select Outer Edges http://sketchucation.com/forums/viewtopic.php?t=20274 and the edge sort routine found in FollowMe and Keep http://sketchucation.com/forums/viewtopic.php?t=16465 should do it.
-
IDEA: How about creating a
Geom::PolygonMesh
from the "surface" ?The
Geom::PolygonMesh
class can report hidden edges using a negative value, see it's
polygons() method. -
How about posting some sample surfaces to test with ?
Here's a shot at it.
Assume argumentsurface
is an array ofSketchup::Drawingelement
subclass objectsdef get_surface_border(surface) # border = [] edges = [] verts = [] # t1 = Time.now.to_f # for f in surface.grep(Sketchup;;Face) for e in f.outer_loop edges << e if e.faces.length == 1 end end # border << edges.pop # edges.length.times do |n| for e in edges border << edges.delete(e) if e.start == border.last.end end end # for e in border verts << e.start unless verts.include?(e.start) verts << e.end unless verts.include?(e.end) end # t2 = Time.now.to_f # if @@debug if edges.empty? puts("All Edges added to border") else puts("Edges left over; (#{edges.length})") for e in edges puts("#{e.inspect}") puts(" start( #{e.start.position.x}, #{e.start.position.y}, #{e.start.position.z})") puts(" end( #{e.end.position.x}, #{e.end.position.y}, #{e.end.position.z})") end end # puts("Elapsed Time in secs; #{t1 - t2}") end # return verts # end # get_surface_border()
-
File has 198 faces, but only 51 surfaces.
I think I have the surface loops settled - just need to put the edge loop vertices in "loop" order.
-
Never mind lines 9 thru 13, then. I could not tell what you wanted from the meager description in the OP.
(I assumed the surface edges would bound only 1 face.)Something similar to lines 15 thru 26 for sorting.
(Basically pick an edge, somehow, then find the next edge whose start vertex == the previous one's end vertex.) -
Unless there is a Sketchup::Surface entity, which doesn't seem to be the case, it would seem to be impossible to isolate the surface from its neighbors. Also since the surfaces are not grouped, the outer_loop edges are shared with the adjacent surface/face and can not be identified using the .face.length==1.
Dan, your code could work with one tweek. The statement, for e in f.outer_loop needs .edges added to it.
-
It's not impossible - just very convoluted !
Pick any face.
Find its edges.
Discard all edges that are not hidden/soft/smooth.
If there are no edges left then it's a lone face.
If there are one or more edges remaining then find the faces also using those edges - not including the already 'got' face[s]..
These will form part of the 'surface'.
Ripple out looking at these faces and their edges in a similar way, collecting the faces that share hidden/soft/smooth edges with them in turn - again not including any faces already 'got'.
Eventually you'll have a collection of all faces connected to the first face by 'non-solid' edges - i.e. the faces forming a surface.
Now you can get all of the solid-edges that these faces use.
Of course some of these solid-edges might not be the surface's 'perimeter' [e.g. a solid edge shared by to faces that are otherwise connected through some non-solid edges and other faces] - these rogues can be discarded simply by looking to see if their faces are all within the faces-collection: all solid-edges that have a face that is not in the surface-set, OR have no other faces will form the surface's perimeter[s].
Now go through those and find all connected edges [common vertices] - these edge-sets could be an outer and perhaps one or more 'inner loops'. To order the edge sets into a list on sequential vertices is covered in code like 'weld'... the basis is that you choose an edge in the edge-set and look at its end-vertex, then find the other edge that is in the edge-set that is also using that vertex and then get that edge's other_vertex and so on stepping around, eventually returning to the first edge's start vertex... you have by then assembled an array of ordered vertices in the loop... if you want to establish if the 'loop' of vertices is cw or ccw you'll need to do some vector magic, assembling the angles between the vectors from a set of three vertices in order and their 'cross', from that you can establish if the loop goes cw or ccw ? -
@jim said:
File has 198 faces, but only 51 surfaces.
I think I have the surface loops settled - just need to put the edge loop vertices in "loop" order.
Maybe you can grab something from TT_Lib2: https://bitbucket.org/thomthom/tt-library-2/src/7a54ed9e11bf31db6fd326476996fc878003402f/TT_Lib2/edges.rb?at=Version%202.7.0
-
@thomthom said:
Maybe you can grab something from TT_Lib2: https://bitbucket.org/thomthom/tt-libra ... on%202.7.0
Thanks, Thomthom - those work great.
Here's the surface code, for those interested in such things.
def self.surface_from_face(face) surface = adjacent_faces(face) end def self.adjacent_faces(face, faces_found = []) faces_found << face if faces_found.empty? edges = face.edges edges.each do |edge| if edge.soft? and edge.smooth? faces_to_add = edge.faces - faces_found faces_found.concat(faces_to_add) faces_to_add.each{|f| adjacent_faces(f, faces_found)} end end faces_found end def self.all_surfaces model = Sketchup.active_model if model.selection.length == 0 all_faces = model.entities.grep(Sketchup;;Face) else all_faces = model.selection.grep(Sketchup;;Face) end surfaces = [] while(all_faces.size > 0) surface = surface_from_face(all_faces[0]) surfaces << surface all_faces = all_faces - surface end surfaces end
-
Here's my variant: http://sketchucation.com/forums/viewtopic.php?f=180&t=41211#p365380
Would be interesting to profile them.
Advertisement