Check if a face is situated on a specific face

Hello, SketchUp Community. I’m beginner to SketchUp and Ruby, and I need your help, please:)
I’ve got groups which represents some template roof tiles, in future I need to replace them with others. So, I wrote a function which determine the bottom face of a tile, and I need to check if that bottom tile’s face is situated on external face, if so, I need to erase it.
This is how it now looks:


And that is the result I try to get:

And that is the code:

        vertices = external_face.vertices
        face_pts = []
        vertices.each {|v|
        tmp = [(v.position.x).round, (v.position.y).round, (v.position.z).round]
        face_pts.push(tmp)
        }   
        new_group_array.each {|tile|
            #RETURNS BOTTOM FACE OF TILE
            bottom_face = find_tiles_bottom_face(tile, pushpull_var)
  
            points = []
            
            edges = bottom_face.edges
            edges.each {|edge| 
                  temp = [(edge.start.position.x).round, (edge.start.position.y).round, (edge.start.position.z).round]
                  points.push(temp)}
            }
            
            #WANT TO DELETE TILE IF IT'S BOTTOM FACE IS ON EXTERNAL FACE
            face_pts.all? {|pt| points.any?{|mp|
                if mp == pt
                  tile.erase!
                end
                  }
            external_face.erase!
          } 

I saw that maybe because I was working with mm, bottom face of tiles is not situated exactly on the level of external face, because of that I rounded values, but it did not help me to see if some tiles a located on external face. I think maybe of some method to check if a specific face is situated above a face, and if that face is external face, I need to erase entire tile.
I also posted .skp file, if that helps.
Thank you much in advance for your help!!! example1.skp (1.6 MB)

Look at the Sketchup::Face#classify_point method.

You could also get the plane from each face and compare them.

1 Like

Thank you for your answer. I tried this method to check which bottom faces is on external face, but I got just that at least 2 vertices of bottom faces are “PointOnVertex” with external face, and another vertices are “PointNotOnPlane”, and that result are for all tiles from external face, and for most of tiles not from external face
I had something like that:

new_group_array.each {|tile|
            #RETURNS BOTTOM FACE OF TILE
            bottom_face = find_tiles_bottom_face(tile, pushpull_var)
            vertices = bottom_face.vertices
            

            vertices_count = 0
            vertices.each {|pt|
             result = external_face.classify_point(pt.position)
             if result != Sketchup::Face::PointNotOnPlane
              vertices_count  += 1  
            end}
            p vertices_count    
        }

So, I though the problem is that bottom faces are not on exact the same Z level, so I brute force to down value of Z bottom_faces until I don’t find a face, if I find a face, so it is situated on external face.

def determine_if_in_area_z_is_given_face(face, points)
      for i in 0..1000
          p "iteration: #{i}"
          p "points: #{points}"
          result = face.classify_point(points)
          if result == Sketchup::Face::PointInside || result == Sketchup::Face::PointOnEdge
              p result
              p points
              return true
          end
          points[2] -= 0.0001 #represent value of Z
      end
      return false
end

tiles_to_delete = []
    
        new_group_array.each {|tile|
            #RETURNS BOTTOM FACE OF TILE
            bottom_face = find_tiles_bottom_face(tile, pushpull_var)
            vertices = bottom_face.vertices
            
            result = -1
            result = determine_if_in_area_z_is_given_face(external_face, vertices[0].position)
            if result 
               tiles_to_delete.push(tile) 
            end}
         
            
        }
tiles_to_delete.each {|e| e.erase!}

And it really founds at some point, not so far, usually after 40 iterations, that it somehow intersects with external face, but that result are also for tiles who do not have under it external face. So, the result was not that I was expecting.lala
I’m thinking the solution could be a method, which find if lower of a face, is situated a face. But I don’t know what could be done for that.

Thanks for you reply!
I don’t understand exactly what to do with planes from each face. I tested and saw that all faces from external face, and most of faces from center will have the same plane, and most of faces which are situated on the edges will have another values for plane.

I haven’t been following carefully enough to be clear what your goal is. Comparing the planes obtained from various faces will tell you if those faces are (duh!) co-planar.

This is an interesting subtopic for a coding challenge. SketchUp doesn’t actually have a plane class. Instead it returns an array of the coefficients of the plane equation (Ax + By + Cz + D = 0)

But the elements returned are Float.

Float objects represent inexact real numbers using the native architecture’s double-precision floating point representation.

What precision does Ruby use to determine if the coefficients match ?

Or … more “precisely” (pun intended) what should an API coder do to compare the coefficients within a reasonable precision for a SketchUp model ?

There’s an interesting issue that depends on what the comparison will be used for: the consequence of a small difference in the plane equation coefficients will depend on how large the planar objects being compared are.

To compare if a set of points is On a Plane within SketchUp’s tolerance;

points.all? { |point| point.on_plane?(plane) }

That matched how SketchUp does it.

2 Likes

Also, I remember that Scott rounded (or truncated) his Floats in the DC extension to 7 decimal places to eliminate floating point errors. I guess they only show up in further decimals ?

And here is a method definition snippet (based on thomthom’s) …

# Test whether the vertex positions of face1 are coplanar with face2,
# within SketchUp’s geometric tolerance.
# @param face1 [Sketchup::Face]
# @param face2 [Sketchup::Face]
# @return [Boolean] True if the two face arguments are coplanar.
def coplanar_faces?(face1, face2)
  face1.vertices.map(&:position).all? { |point|
    point.on_plane?(face2.plane)
  }
end

EDIT: Also note that Thomas previously posted another example from one of his GitHub repos:

1 Like