Curved surfaces with Ruby
-
Hi,
I'm trying to understand how to work with curved surfaces in SU using Ruby. I'd like to, for example, get an array of face objects that make up a surface. The API documentation seems very poor as it says that Faces are flat polygons, but when I select the outside of a cylinder, the Ruby console tells me it's a Face object. I tried using add_faces_from_mesh, but it just splits the surface into one of the component faces and the remaining surface, and returns 0.
-
Make a cylinder.
Have View > Hidden Geometry OFF.
Pick the curved part.
It selects as one object.
Entity Info says it's a 'Surface'.Deselect it.
Have View > Hidden Geometry ON.
You can now see the facets making the surface.
Pick a facet.
Entity Info says it's a 'Face'.Faces that share common edge, where those edges are 'smooth' are part of a surface.
Within Sketchup when hidden geometry is 'off' these select as a single object, take materials as a single thing etc...Within Ruby a 'surface' is not very much accessible.
Its faces and edges etc are.
There is one 'trick' surface using selections...
selection.is_surface?
This determines if the selection contains only all of the faces that are part of a single curved surface. Returns:
True if the selection contains all of the faces that belong to a single curved surface.
False if the selection does not contain all of the faces that belong to a single curved surface.Since a surface's faces are all connected and their shared edges are smooth? you can devise ways of getting all of the faces in a surface from one face in that surface...
What is the intention of your code ? -
@tig said:
Since a surface's faces are all connected and their shared edges are smooth? you can devise ways of getting all of the faces in a surface from one face in that surface...
What is the intention of your code ?I'd like to know:
All the points/vertices that make the surface.
All the normals of the faces that make up the surface.I also want to be able to take a set of points and project them onto the surface, or rather find the intersection point between a ray and the surface.
Your suggestion about connected faces is a bit vague. I would still need to be able to get one of the faces in the surface (without help from the user) and I don't know what makes an edge 'smooth'.
-
Starting at the end...
Iterate the faces.
edges=face.edges
Iterate the edges
edge.smooth?
>> true or false
An edge can also have .soft? and .hidden? true/false.
To find all of the faces connected to a selected_face use
connected_faces=selected_face.all_connected.find_all{|e|e.is_a?(Sketchup::Face)}
To find all faces connected to the selected_face that are have a smooth edge and are thereby part of a common 'surface' you need to iterate the connected_faces in turn and their edges, testing foredge.smooth?
and if so add that face to an array (which you kick off with surface=[selected_face]) unless it's already there, likesurface<<face unless surface.include?(face)
assuming a test tells us it has a smooth common edge. As you collect faces then face=surface[-1] so you keep moving out from the first face until no more faces are available/connected-smoothly...
How are you 'getting' the face ? You say you don't want help from the user, BUT there must be some clue to 'get' it
If the user is preselecting it and hidden-geometry is off then that selection consists of all connected faces anyway ? So thenselection.to_a
should be 'all connected faces' ??Once you have the faces then their vertices are easy to collect.
verts=[] faces.each{|f|verts<<f.vertices} verts.flatten.uniq!
The array 'verts' is now all of the vertices used by the faces.Similarly the normals
normals=[] faces.each{|f|normals<<f.normal}
If you make the surface as a group then
ray=model.raytest(point, vector)
returns nil for a miss OR an array of a point and an array of what's been hit.
To check that the hit is on the group useray[1].include?(group)
which is true if the containing groups is hit.
A typical hit 'ray' might be something like[point3d, [group,face]]
The hit 'point' isray[0]
-
@tig said:
selection.to_a should be 'all connected faces' ??
THAT's what I needed! Thanks! I should have probably spotted that before, but I made a silly mistake in my experimentations with the console and got myself thinking that when I selected a surface, Ruby thought the whole thing was just one face.
-
If you want to get a Surface - identical to how SketchUp defines with - when Entity Info display Surface - based on faces connected by soft+smooth edges when this snippet works: http://forums.sketchucation.com/viewtopic.php?f=180&t=41211#p365381
-
@thomthom said:
If you want to get a Surface - identical to how SketchUp defines with - when Entity Info display Surface - based on faces connected by soft+smooth edges when this snippet works: http://forums.sketchucation.com/viewtopic.php?f=180&t=41211#p365381
Awesome! That snippet was exactly what I needed and it works great. Also glad to understand what soft and smooth edges are.
Thanks a lot!
-
@alexmojaki said:
Also glad to understand what soft and smooth edges are.
For a detailed breakdown of what each property does (soft and smooth has very distinct functions) check out this article: http://www.thomthom.net/thoughts/2012/06/soft-vs-smooth-vs-hidden-edges/
Advertisement