sketchucation logo sketchucation
    • Login
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

    Determining if a point is "in front" or "behind" a surface

    Scheduled Pinned Locked Moved Developers' Forum
    10 Posts 6 Posters 531 Views 6 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • T Offline
      T.M
      last edited by Gábor

      Hi there,

      I've been trying to figure out how to determine if a given point is "in front of " a surface or "behind" it, relative to the surface's normal vector.

      I can't seem to figure out any good solution so if anyone has a clue it'd be great.

      Thanks!

      1 Reply Last reply Reply Quote 0
      • thomthomT Offline
        thomthom
        last edited by

        hmmm

        Project the point to the faces in the surface, find the closest one. Then compare the vector from the point to the face with the face normal ... ?

        Thomas Thomassen — SketchUp Monkey & Coding addict
        List of my plugins and link to the CookieWare fund

        1 Reply Last reply Reply Quote 0
        • Chris FullmerC Offline
          Chris Fullmer
          last edited by

          EDIT: Ahh, Thom beat me while I was typing up the code.

          I think one way you can do it is to use the "project to plane"method. This returns a point that is on a plane, and nearest to the provided point. The vector between those 2 points is the face normal (or the opposite of the face normal). Then just test if those vectors (the one you found via projecting and the face normal) are in the same direction or not. See the code below:

          face = my_face point = my_point point2 = point.project_to__plane( face.plane ) vector = point2.vector_to( point ) if vector.samedirection?( face.normal ) puts "point is 'in front' of the face" else puts "point is 'behind' the face" end

          That should do it I think. I did not get a chance to test that for syntax accuracy or results.

          Chris

          Lately you've been tan, suspicious for the winter.
          All my Plugins I've written

          1 Reply Last reply Reply Quote 0
          • T Offline
            T.M
            last edited by

            Thanks to both of you, it seems rather obvious now! I'll try it as soon as I can

            1 Reply Last reply Reply Quote 0
            • AdamBA Offline
              AdamB
              last edited by

              Gents, Ruby is slow enough without doing extra work!

              face.plane already gives the normal + distance along then normal for the face plane.

              So just do:

              d = face.normal.dot( [testX, testY, testZ] ) - face.plane[3]

              puts(d > 0 ? "in front" : "behind")

              Developer of LightUp Click for website

              1 Reply Last reply Reply Quote 0
              • Dan RathbunD Offline
                Dan Rathbun
                last edited by

                If the point in ON the face's plane the above would give false result of "behind":

                module YourLibModule
                
                  module_function
                
                  def point_behind?( pt, face )
                    return nil if face.plane.nil?
                    return false if pt.on_plane?(face.plane)
                    d = face.normal.dot( pt.to_a ) - face.plane[3]
                    d < 0 # ? true ; false
                  end #def
                
                  def point_in_front?( pt, face )
                    return nil if face.plane.nil?
                    return false if pt.on_plane?(face.plane)
                    d = face.normal.dot( pt.to_a ) - face.plane[3]
                    d > 0 # ? true ; false
                  end #def
                
                  def point_on_face?( pt, face )
                    return nil if face.plane.nil?
                    pt.on_plane?(face.plane)
                  end #def
                
                end # YourLibModule
                
                

                You could mix the above module into a custom class using include().

                I wonder if it's worth requesting that the Sketchup::Face#classify_point() method be amended to return numerics for "in_front" and "behind" ??

                I'm not here much anymore.

                1 Reply Last reply Reply Quote 0
                • TIGT Offline
                  TIG Moderator
                  last edited by

                  In Adam's succinct example it can just return the value of the distance.

                  Usage: distance(point, face)

                  > 0 in front of face

                  < 0 behind face

                  == 0 on face

                  def distance(point, face)
                    return nil unless point.class==Sketchup;;Point3d and face.class==Sketchup;;Face
                    face.normal.dot([point.x, point.y, point.z]) - face.plane[3]
                  end
                  

                  This is then a more general purpose tool that gives the distance a point is from a face - that the user can use as needed in various ways e.g.
                  dist=distance(point, face).abs
                  to get the actual distance or error if bad arguments.
                  Or
                  ` d=distance(point, face)
                  if not d

                  passed bad arguments >> nil

                  elsif d > 0

                  in front

                  elsif d < 0

                  behind

                  else

                  on face

                  end`

                  TIG

                  1 Reply Last reply Reply Quote 0
                  • AdamBA Offline
                    AdamB
                    last edited by

                    @dan rathbun said:

                    def point_behind?( pt, face )
                    return nil if face.plane.nil? return false if pt.on_plane?(face.plane)
                    d = face.normal.dot( pt.to_a ) - face.plane[3]
                    d < 0 # ? true : false
                    end #def

                    Must say I really don't like this kind of half-hearted defensive programming style. Why would a face not have a plane? And if you're going to test for that, test for the face being a Sketchup::Face, and if you going to test for that, then also test for pt being a Geom::Point3d... and on and on and on...

                    Code like this, is going to be embedded within a "hierarchy of confidence" set of functions. You don't need to be chasing your tail all the time - especially in a very slow language like Ruby.

                    You should have strong validation on data as it enters your system, then after that you don't litter code with meaningless tests that simply slow stuff down and reduce readability.

                    There, I've got that off my chest. And nothing to do with France - England match result either.. 😄

                    Adam

                    Developer of LightUp Click for website

                    1 Reply Last reply Reply Quote 0
                    • Dan RathbunD Offline
                      Dan Rathbun
                      last edited by

                      @tig said:

                      In Adam's succinct example it can just return the value of the distance.

                      That would ignore the internal Sketchup 0.001" tolerance. I was attempting to make sure that the tolerance applied.

                      EDIT: Does the distance() method apply the internal tolerance ??

                      I'm not here much anymore.

                      1 Reply Last reply Reply Quote 0
                      • Dan RathbunD Offline
                        Dan Rathbun
                        last edited by

                        Yes Type validation would (as TIG showed,) is usually the norm for public libraries.
                        If it's a private library and you are the only one calling it's methods, you will know the rules (arg types,) and such validation can be left out to speed things up.

                        That said.. I put the nil test in as the API doc refers to "a plane if successful" but does not really say what the return value is, if the call is not successful. And as there is no "real" Plane class we cannot do a type check based on that, but if it's an array with 4 elements.
                        Comment it out if you feel it's unnecessary. (I won't feel bad.)

                        I'm not here much anymore.

                        1 Reply Last reply Reply Quote 0
                        • 1 / 1
                        • First post
                          Last post
                        Buy SketchPlus
                        Buy SUbD
                        Buy WrapR
                        Buy eBook
                        Buy Modelur
                        Buy Vertex Tools
                        Buy SketchCuisine
                        Buy FormFonts

                        Advertisement