get closest point to a line

后端 未结 12 2004
逝去的感伤
逝去的感伤 2020-11-28 04:45

I\'d like to have a straight forward C# function to get a closest point (from a point P) to a line-segment, AB. An abstract function may look like this. I\'ve search through

12条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-11-28 05:06

    Here's Ruby disguised as Pseudo-Code, assuming Point objects each have a x and y field.

    def GetClosestPoint(A, B, P)
    
      a_to_p = [P.x - A.x, P.y - A.y]     # Storing vector A->P
      a_to_b = [B.x - A.x, B.y - A.y]     # Storing vector A->B
    
      atb2 = a_to_b[0]**2 + a_to_b[1]**2  # **2 means "squared"
                                          #   Basically finding the squared magnitude
                                          #   of a_to_b
    
      atp_dot_atb = a_to_p[0]*a_to_b[0] + a_to_p[1]*a_to_b[1]
                                          # The dot product of a_to_p and a_to_b
    
      t = atp_dot_atb / atb2              # The normalized "distance" from a to
                                          #   your closest point
    
      return Point.new( :x => A.x + a_to_b[0]*t,
                        :y => A.y + a_to_b[1]*t )
                                          # Add the distance to A, moving
                                          #   towards B
    
    end
    

    Alternatively:

    From Line-Line Intersection, at Wikipedia. First, find Q, which is a second point that is to be had from taking a step from P in the "right direction". This gives us four points.

    def getClosestPointFromLine(A, B, P)
    
      a_to_b = [B.x - A.x, B.y - A.y]   # Finding the vector from A to B
                                            This step can be combined with the next
      perpendicular = [ -a_to_b[1], a_to_b[0] ]
                                        # The vector perpendicular to a_to_b;
                                            This step can also be combined with the next
    
      Q = Point.new(:x => P.x + perpendicular[0], :y => P.y + perpendicular[1])
                                        # Finding Q, the point "in the right direction"
                                        # If you want a mess, you can also combine this
                                        # with the next step.
    
      return Point.new (:x => ((A.x*B.y - A.y*B.x)*(P.x - Q.x) - (A.x-B.x)*(P.x*Q.y - P.y*Q.x)) / ((A.x - B.x)*(P.y-Q.y) - (A.y - B.y)*(P.y-Q.y)),
                        :y => ((A.x*B.y - A.y*B.x)*(P.y - Q.y) - (A.y-B.y)*(P.x*Q.y - P.y*Q.x)) / ((A.x - B.x)*(P.y-Q.y) - (A.y - B.y)*(P.y-Q.y)) )
    
    end
    

    Caching, Skipping steps, etc. is possible, for performance reasons.

提交回复
热议问题