Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 获取离直线最近的点_C#_Math_Geometry - Fatal编程技术网

C# 获取离直线最近的点

C# 获取离直线最近的点,c#,math,geometry,C#,Math,Geometry,我想要一个直接的C#函数来得到一个最近的点(从点p)到线段AB。一个抽象函数可能看起来像这样。我已经搜索了这么多,但没有找到一个可用的(由我)解决方案 public Point getClosestPointFromLine(Point A, Point B, Point P); 算法将非常简单: 你有3个点-三角形。从那里你应该可以找到AB,AC,BC 把这件事说出来: 通过将y差除以x差,求出AB的斜率a1;然后画一条垂直线(坡度为a2=-1/a1,需要通过将P的坐标转换为y=a2*x+b

我想要一个直接的C#函数来得到一个最近的点(从点p)到线段AB。一个抽象函数可能看起来像这样。我已经搜索了这么多,但没有找到一个可用的(由我)解决方案

public Point getClosestPointFromLine(Point A, Point B, Point P);

算法将非常简单:

你有3个点-三角形。从那里你应该可以找到AB,AC,BC

把这件事说出来:

通过将y差除以x差,求出AB的斜率a1;然后画一条垂直线(坡度为a2=-1/a1,需要通过将P的坐标转换为y=a2*x+b2来求解偏移量(b2);然后你有两条直线(即两个线性方程),你需要求解交点。那将是你最近的一点

做正确的数学运算,这个函数将非常容易编写

详细说明一下:

Original line:
y = a1 * x + b1
a1 = (By - Ay) / (Bx - Ax)   <--
b1 = Ay - a1 * Ax            <--

Perpendicular line:
y = a2 * x + b2
a2 = -1/a1                   <--
b2 = Py - a2 * Px            <--

Now you have P which lies on both lines:
y = a1 * x + b1
y = a2 * x + b2
--------------- subtract:
0 = (a1 - a2) * Px + (b1 - b2)
x = - (b1 - b2) / (a1 - a2)  <--
y = a1 * x + b1              <--
原始行:
y=a1*x+b1

a1=(By-Ay)/(Bx-Ax)最近的点
C
将位于斜率为AB倒数且与
p
相交的直线上。这听起来像是家庭作业,但为了提高扰流板警戒级别,我将给出一些非常有力的提示:

  • 这样的线路只能有一条

  • 这是一个双线方程组。只需求解
    x
    y

  • a
    B
    之间画一条线段;称之为
    L
    L
    的方程式为
    y=mx+b
    ,其中
    m
    是y坐标与x坐标的比值。在表达式中使用
    A
    b
    求解
    b

  • 执行与上面相同的操作,但对于
    CP
    。现在求解联立线性方程组

  • 谷歌搜索将为您提供选择

    • 您的点(
      X
      )将是点
      a
      B
      的线性组合:

      X = k A + (1-k) B
      
      要使
      X
      实际位于线段上,参数
      k
      必须介于0和1之间(包括0和1)。您可以按如下方式计算k:

      k_raw = (P-B).(A-B)  /  (A-B).(A-B)
      
      (其中,句点表示点积)

      然后,要确保该点实际位于线段上,请执行以下操作:

      if k_raw < 0:
          k= 0
      elif k_raw > 1:
          k= 1
      else:
          k= k_raw
      
      如果k_原始值<0:
      k=0
      elif k_raw>1:
      k=1
      其他:
      k=k_原始
      
      这里的Ruby伪装成伪代码,假设
      对象都有
      x
      y
      字段

      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
      

      或者:

      来自维基百科。首先,找到Q,这是从P向“正确的方向”迈出一步的第二点。这给了我们四点

      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
      

      出于性能原因,可以进行缓存、跳过步骤等操作。

      Justin L.的回答几乎可以,但它不会检查标准化距离是否小于0或高于AB向量大小。当P向量投影超出边界(从线段AB)时,它将无法正常工作。 以下是更正后的伪代码:

          function GetClosestPoint(A, B, P)
      {
        vectorAP = (p.x - a.x, p.y - a.y)     //Vector from A to P
        vectorAB = (b.x - a.x, b.y - a.y)     //Vector from A to B
      
        magnitudeAB = vectorAB[0]^2 + vectorAB[1]^2  
        //Magnitude of AB vector (it's length)
      
      
        ABAPproduct = vectorAB[0]*vectorAP[0] + vectorAB[1]*vectorAP[1] 
        //The product of a_to_p and a_to_b
      
      
        distance = ABAPproduct / magnitudeAB       
        //The normalized "distance" from a to your closest point
      
        if ( distance < 0)     //Check if P projection is over vectorAB
          {
              returnPoint.x = a.x
              returnPoint.y = a.y
          }   
        else if (distance > magnitudeAB)
          {
              returnPoint.x = b.x
              returnPoint.y = b.y
          }
        else
          {
              returnPoint.x = a.x + vectorAB[0]*distance
              returnPoint.y = a.y + vectorAB[1]*distance
          }
      
      }
      
      函数GetClosestPoint(A、B、P) { vectorAP=(p.x-a.x,p.y-a.y)//从a到p的向量 vectorAB=(b.x-a.x,b.y-a.y)//从a到b的向量 震级AB=向量AB[0]^2+向量AB[1]^2 //AB向量的大小(其长度) ABAPproduct=vectorAB[0]*vectorAP[0]+vectorAB[1]*vectorAP[1] //a_到p和a_到b的乘积 距离=ABAppProduct/magnitudeAB //从a到最近点的标准化“距离” if(距离<0)//检查P投影是否在向量ab上 { returnPoint.x=a.x returnPoint.y=a.y } 否则如果(距离>震级AB) { returnPoint.x=b.x 返回点y=b.y } 其他的 { returnPoint.x=a.x+vectorAB[0]*距离 returnPoint.y=a.y+vectorAB[1]*距离 } }
如果有人对基于上述内容的C#XNA函数感兴趣:

    public static Vector2 GetClosestPointOnLineSegment(Vector2 A, Vector2 B, Vector2 P)
    {
        Vector2 AP = P - A;       //Vector from A to P   
        Vector2 AB = B - A;       //Vector from A to B  

        float magnitudeAB = AB.LengthSquared();     //Magnitude of AB vector (it's length squared)     
        float ABAPproduct = Vector2.Dot(AP, AB);    //The DOT product of a_to_p and a_to_b     
        float distance = ABAPproduct / magnitudeAB; //The normalized "distance" from a to your closest point  

        if (distance < 0)     //Check if P projection is over vectorAB     
        {
            return A;

        }
        else if (distance > 1)             {
            return B;
        }
        else
        {
            return A + AB * distance;
        }
    }
公共静态向量2 GetClosestPointOnLineSegment(向量2 A、向量2 B、向量2 P)
{
Vector2ap=P-A;//从A到P的向量
Vector2ab=B-A;//从A到B的向量
float magnityAB=AB.LengthSquared();//AB向量的大小(它的长度平方)
float ABAPproduct=Vector2.Dot(AP,AB);//a_到p和a_到b的点积
float distance=ABAPproduct/magnificatab;//从a到最近点的标准化“距离”
if(距离<0)//检查P投影是否在向量ab上
{
返回A;
}
否则,如果(距离>1){
返回B;
}
其他的
{
返回A+AB*距离;
}
}

这个答案基于射影几何的思想

计算叉积(Ax,Ay,1)×(Bx,By,1)=(u,v,w)。结果向量描述了连接A和B的线:其方程为ux+vy+w=0。但你也可以把(u,v,0)解释为一个点,在垂直于这条线的方向上无限远。做另一个叉积,你会得到连接帽点到P:(u,v,0)×(Px,Py,1)的线。要使这条线和AB线相交,需要做另一个叉积:((u,v,0)×(Px,Py,1))×(u,v,w)。结果将是一个同质坐标向量(x,y,z),从中可以读取最近点的坐标(x/z,y/z)

综合所有因素,得出以下公式:

使用计算机代数系统,可以找到以下坐标:

x=((Ax-Bx)*Px+(Ay-By)*Py)*(Ax-Bx)+(Ay*Bx-Ax*By)*(Ay-By)
y=-(Ay*Bx-Ax*By)*(Ax-Bx)+(Ax-Bx)*Px+(Ay-Bx)*Py)*(Ay-By)
z=(Ax-Bx)^2+(Ay-By)^2
正如您所注意到的,有很多重复出现的术语。为这些发明(几乎任意)名称,您可以得到以下最终结果,使用伪代码编写:

    function GetClosestPoint(A, B, P)
{
  vectorAP = (p.x - a.x, p.y - a.y)     //Vector from A to P
  vectorAB = (b.x - a.x, b.y - a.y)     //Vector from A to B

  magnitudeAB = vectorAB[0]^2 + vectorAB[1]^2  
  //Magnitude of AB vector (it's length)


  ABAPproduct = vectorAB[0]*vectorAP[0] + vectorAB[1]*vectorAP[1] 
  //The product of a_to_p and a_to_b


  distance = ABAPproduct / magnitudeAB       
  //The normalized "distance" from a to your closest point

  if ( distance < 0)     //Check if P projection is over vectorAB
    {
        returnPoint.x = a.x
        returnPoint.y = a.y
    }   
  else if (distance > magnitudeAB)
    {
        returnPoint.x = b.x
        returnPoint.y = b.y
    }
  else
    {
        returnPoint.x = a.x + vectorAB[0]*distance
        returnPoint.y = a.y + vectorAB[1]*distance
    }

}
dx=A.x-B.x
dy=A.y-B.y
det=A.y*B.x-A.x*B.y
点=dx*P.x
private static PointF ClosestPointToSegment(PointF P, PointF A, PointF B)
{
    PointF a_to_p = new PointF(), a_to_b = new PointF();
    a_to_p.X = P.X - A.X;
    a_to_p.Y = P.Y - A.Y; //     # Storing vector A->P  
    a_to_b.X = B.X - A.X;
    a_to_b.Y = B.Y - A.Y; //     # Storing vector A->B

    float atb2 = a_to_b.X * a_to_b.X + a_to_b.Y * a_to_b.Y;
    float atp_dot_atb = a_to_p.X * a_to_b.X + a_to_p.Y * a_to_b.Y; // The dot product of a_to_p and a_to_b
    float t = atp_dot_atb / atb2;  //  # The normalized "distance" from a to the closest point
    return new PointF(A.X + a_to_b.X * t, A.Y + a_to_b.Y * t);
}
public static double DistanceTo(this Point from, Point to)
    {
        return Math.Sqrt(Math.Pow(from.X - to.X, 2) + Math.Pow(from.Y - to.Y, 2));
    }

public static double DistanceTo(this Point point, Point lineStart, Point lineEnd)
    {
        double tI = ((lineEnd.X - lineStart.X) * (point.X - lineStart.X) + (lineEnd.Y - lineStart.Y) * (point.Y - lineStart.Y)) / Math.Pow(lineStart.DistanceTo(lineEnd), 2);
        double dP = ((lineEnd.X - lineStart.X) * (point.Y - lineStart.Y) - (lineEnd.Y - lineStart.Y) * (point.X - lineStart.X)) / lineStart.DistanceTo(lineEnd);

        if (tI >= 0d && tI <= 1d)
            return Math.Abs(dP);
        else
            return Math.Min(point.DistanceTo(lineStart), point.DistanceTo(lineEnd));
    }
P.DistanceTo(A, B);
s2 = ClosestPointToSegment(point_x, Point_y, Segment_start_x, Segment_start_y, Segment_end_X, Segment_end_Y)

Public Shared Function DistanceTo(x1 As Double, y1 As Double, x2 As Double, y2 As Double) As Double
    Return Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2))
End Function


Public Shared Function DistanceTo(point_x As Double, point_y As Double, lineStart_x As Double, lineStart_y As Double, lineEnd_x As Double, lineEnd_y As Double) As Double
    Dim tI As Double = ((lineEnd_x - lineStart_x) * (point_x - lineStart_x) + (lineEnd_y - lineStart_y) * (point_y - lineStart_x)) / Math.Pow(DistanceTo(lineStart_x, lineStart_y, lineEnd_x, lineEnd_y), 2)
    Dim dP As Double = ((lineEnd_x - lineStart_x) * (point_y - lineStart_y) - (lineEnd_y - lineStart_y) * (point_x - lineStart_x)) / DistanceTo(lineStart_x, lineStart_y, lineEnd_x, lineEnd_y)

    If tI >= 0R AndAlso tI <= 1.0R Then
        Return Math.Abs(dP)
    Else
        Return Math.Min(DistanceTo(point_x, point_y, lineStart_x, lineStart_y), DistanceTo(point_x, point_y, lineEnd_x, lineEnd_y))
    End If
End Function
Private Shared Function ClosestPointToSegment(P_x As Double, p_y As Double, A_x As Double, a_y As Double, B_x As Double, b_y As Double) As Double()
    Dim a_to_p As PointF = New PointF(), a_to_b As PointF = New PointF()
    Dim rikthex As Double, rikthey As Double
    Dim s1(1) As Double
    Dim p1_v1_X As Double, p1_v1_y As Double, distanca1 As Double, distanca2 As Double
    a_to_p.X = P_x - A_x
    a_to_p.Y = p_y - a_y
    a_to_b.X = B_x - A_x
    a_to_b.Y = b_y - a_y
    Dim atb2 As Single = a_to_b.X * a_to_b.X + a_to_b.Y * a_to_b.Y
    Dim atp_dot_atb As Single = a_to_p.X * a_to_b.X + a_to_p.Y * a_to_b.Y
    Dim t As Single = atp_dot_atb / atb2
    rikthex = A_x + a_to_b.X * t
    rikthey = a_y + a_to_b.Y * t
    If A_x > B_x Then
        If rikthex < A_x And rikthex > B_x Then 'pika duhet ne rregulll
            If a_y > b_y Then
                If rikthey < a_y And rikthey > b_y Then 'pika duhet ne rregulll

                Else
                    distanca1 = DistanceTo(P_x, p_y, A_x, a_y)
                    distanca2 = DistanceTo(P_x, p_y, B_x, b_y)
                    If distanca1 < distanca2 Then
                        rikthex = A_x
                        rikthey = a_y
                    Else
                        rikthex = B_x
                        rikthey = b_y
                    End If

                End If
            Else
                If rikthey > a_y And rikthey < b_y Then 'pika duhet ne rregulll

                Else
                    distanca1 = DistanceTo(P_x, p_y, A_x, a_y)
                    distanca2 = DistanceTo(P_x, p_y, B_x, b_y)
                    If distanca1 < distanca2 Then
                        rikthex = A_x
                        rikthey = a_y
                    Else
                        rikthex = B_x
                        rikthey = b_y
                    End If

                End If

            End If
        Else
            distanca1 = DistanceTo(P_x, p_y, A_x, a_y)
            distanca2 = DistanceTo(P_x, p_y, B_x, b_y)
            If distanca1 < distanca2 Then
                rikthex = A_x
                rikthey = a_y
            Else
                rikthex = B_x
                rikthey = b_y
            End If
        End If
    Else
        If rikthex > A_x And rikthex < B_x Then 'pika duhet ne rregulll
            If a_y > b_y Then
                If rikthey < a_y And rikthey > b_y Then 'pika duhet ne rregulll

                Else
                    distanca1 = DistanceTo(P_x, p_y, A_x, a_y)
                    distanca2 = DistanceTo(P_x, p_y, B_x, b_y)
                    If distanca1 < distanca2 Then
                        rikthex = A_x
                        rikthey = a_y
                    Else
                        rikthex = B_x
                        rikthey = b_y
                    End If

                End If
            Else
                If rikthey > a_y And rikthey < b_y Then 'pika duhet ne rregulll

                Else
                    distanca1 = DistanceTo(P_x, p_y, A_x, a_y)
                    distanca2 = DistanceTo(P_x, p_y, B_x, b_y)
                    If distanca1 < distanca2 Then
                        rikthex = A_x
                        rikthey = a_y
                    Else
                        rikthex = B_x
                        rikthey = b_y
                    End If

                End If

            End If
        Else
            distanca1 = DistanceTo(P_x, p_y, A_x, a_y)
            distanca2 = DistanceTo(P_x, p_y, B_x, b_y)
            If distanca1 < distanca2 Then
                rikthex = A_x
                rikthey = a_y
            Else
                rikthex = B_x
                rikthey = b_y
            End If
        End If
    End If
    s1(0) = rikthex
    s1(1) = rikthey
    Return s1

End Function