Is 'Geom.point_in_polygon_2D' broken?

Hi everyone!

I am trying to leverage the Geom.point_in_polygon_2D function to test if a 2D point is located on a face with holes. (I am assuming that z = 0 everywhere.) After seeing that I get unexpected results in my code I decided to write the following snippet:

entities = Sketchup.active_model.entities
entities.clear!

entities.add_face([0, 0], [100, 0], [100, 100], [0, 100])
entities.add_face([10, 10], [90, 10], [90, 90], [10, 90])

faces = entities.grep(Sketchup::Face)
face_with_hole = faces[0].vertices.length == 8 ? faces[0] : faces[1]

(0..50).each do |x|
  (0..50).each do |y|
    p = [x * 2.0, y * 2.0]
    if Geom.point_in_polygon_2D(p, face_with_hole.vertices, true)
      entities.add_cpoint(p)
    end
  end
end

The above simply creates an inner and outer square that basically determine a 2D hollow face with 8 edges (and 8 points). However, when adding the points that are supposed to be within the “frame” of thickness 10 I got the following curious diagram:

I understand that there might be floating point errors going on, but is this output expected? Or, a better question might be: is Geom.point_in_polygon_2D handling only polygons without holes?

Geom.point_in_polygon_2D is expecting an array of points.

Try to solve this problem one your own before taking a sneak peak at the solution I’ve attached. Some of the Ruby methods are a little more difficult if you’re new to this game.

inside_polygon.rb (1.2 KB)

I’m assuming that there is a reason you aren’t using the Face’s classify_point-instance_method

1 Like

Short answer: Yes. No Holes.
You must pass a sequence of points which form a closed polygon (convex or concave).

In your code, your should first test that the point is within the outer loop of the face

Geom.point_in_polygon_2D(p, face_with_hole.outer_loop.vertices, true)

then, you can test that the point is NOT within the holes, if any:

!face_with_hole.loops[1..-1].find { |loop| Geom.point_in_polygon_2D(p, loop.vertices, true)  }
1 Like

Thanks a lot guys, this was super helpful. I wasn’t aware of the outer_loop and loops methods, so my problem is now fixed.

I’m assuming that there is a reason you aren’t using the Face’s classify_point-instance_method

I didn’t know about this either (shows that I am a beginner with the SU API :sweat_smile:). However, I can’t use this because the face I’m working with changes a lot during the operations I perform on it. Thus, I need to save the outer loop and the inner loops to some arrays and then carry out the containment test using Geom.point_in_polygon_2D.

Again, thanks for the quick responses, both of you!