垂直于给定点的线段

时间:2012-04-24 15:23:38

标签: math 3d geometry

我想计算给定线上与给定点垂直的点。

我有一个线段AB并且在线段之外有一个点C.我想计算AB上的点D,使得CD垂直于AB。

Find point D

我必须找到D点。

它与this非常相似,但我想考虑Z坐标,因为它在3D空间中没有正确显示。

10 个答案:

答案 0 :(得分:20)

function getSpPoint(A,B,C){
    var x1=A.x, y1=A.y, x2=B.x, y2=B.y, x3=C.x, y3=C.y;
    var px = x2-x1, py = y2-y1, dAB = px*px + py*py;
    var u = ((x3 - x1) * px + (y3 - y1) * py) / dAB;
    var x = x1 + u * px, y = y1 + u * py;
    return {x:x, y:y}; //this is D
}

question

答案 1 :(得分:20)

证明: 点D在垂直于AB的线CD上,当然D属于AB。 记下两个向量CD.AB = 0的Dot积,并表示D属于AB的事实为D = A + t(B-A)。

我们最终得到3个方程:

 Dx=Ax+t(Bx-Ax)
 Dy=Ay+t(By-Ay)
(Dx-Cx)(Bx-Ax)+(Dy-Cy)(By-Ay)=0

在第三个方程中减去前两个方程给出:

(Ax+t(Bx-Ax)-Cx)(Bx-Ax)+(Ay+t(By-Ay)-Cy)(By-Ay)=0

分配以解决t给出:

(Ax-Cx)(Bx-Ax)+t(Bx-Ax)(Bx-Ax)+(Ay-Cy)(By-Ay)+t(By-Ay)(By-Ay)=0

给出:

t= -[(Ax-Cx)(Bx-Ax)+(Ay-Cy)(By-Ay)]/[(Bx-Ax)^2+(By-Ay)^2]

摆脱负面迹象:

t=[(Cx-Ax)(Bx-Ax)+(Cy-Ay)(By-Ay)]/[(Bx-Ax)^2+(By-Ay)^2]

一旦有了t,就可以从前两个方程中找出D的坐标。

 Dx=Ax+t(Bx-Ax)
 Dy=Ay+t(By-Ay)

答案 2 :(得分:4)

使用矢量点积有一个简单的封闭形式解决方案(不需要循环或近似)。

想象一下你的点作为向量,其中A点位于原点(0,0),所有其他点都是从它引用的(你可以通过从每个点减去点A来轻松地将你的点转换为这个参考帧)。

在这个参考帧中,D点只是矢量B上C点的vector projection,表示为:

// Per wikipedia this is more efficient than the standard (A . Bhat) * Bhat
Vector projection = Vector.DotProduct(A, B) / Vector.DotProduct(B, B) * B

通过向其添加点A,可以将结果向量转换回原始坐标系。

答案 3 :(得分:3)

AB线上的点可以通过以下方式进行参数化:

M(x)= A + x *(B-A),对于x real。

你想要D = M(x)使得DC和AB是正交的:

点(B-A,C-M(X))= 0。

即:点(B-A,C-A-x *(B-A))= 0,或点(B-A,C-A)= x *点(B-A,B-A),给出:

x =点(B-A,C-A)/点(B-A,B-A),除非A = B,否则定义。

答案 4 :(得分:2)

您要做的是vector projection

答案 5 :(得分:1)

对于在 C# 中可能需要此功能的任何人,我会为您节省一些时间:

double Ax = ;
double Ay = ;
double Az = ;
    
double Bx = ;
double By = ;
double Bz = ;
    
double Cx = ;
double Cy = ;
double Cz = ; 
    
double t = ((Cx - Ax) * (Bx - Ax) + (Cy - Ay) * (By - Ay)) / (Math.Pow(Bx - Ax, 2) + Math.Pow(By - Ay, 2));
    
double Dx = Ax + t*(Bx - Ax);
double Dy = Ay + t*(By - Ay);

答案 6 :(得分:0)

这里我将已回答的代码从“cuixiping”转换为matlab代码。

function Pr=getSpPoint(Line,Point)
% getSpPoint(): find Perpendicular on a line segment from a given point
x1=Line(1,1);
y1=Line(1,2);
x2=Line(2,1);
y2=Line(2,1);
x3=Point(1,1);
y3=Point(1,2);

px = x2-x1;
py = y2-y1;
dAB = px*px + py*py;

u = ((x3 - x1) * px + (y3 - y1) * py) / dAB;
x = x1 + u * px;
y = y1 + u * py;

Pr=[x,y];

end

答案 7 :(得分:0)

我没有看到这个答案,但Ron Warholic对Vector Projection提出了很好的建议。 ACD只是一个直角三角形。

  1. 创建向量AC,即(Cx-Ax,Cy-Ay)
  2. 创建向量AB,即(Bx-Ax,By-Ay)
  3. AC和AB的点积等于矢量之间角度的余弦。即cos(theta)= ACx * ABx + ACy * ABy。
  4. 向量的长度是sqrt(x * x + y * y)
  5. AD的长度= cos(θ)*长度(AC)
  6. 归一化AB,即(ABx /长度(AB),ABy /长度(AB))
  7. D = A + NAB *长度(AD)

答案 8 :(得分:0)

以下是基于Corey Ogburn的this thread答案的python实现。
它将点 q 投影到由 p1 p2 定义的线段上,从而产生点 r
如果 r 超出线段,它将返回null:

def is_point_on_line(p1, p2, q):

    if (p1[0] == p2[0]) and (p1[1] == p2[1]):
        p1[0] -= 0.00001

    U = ((q[0] - p1[0]) * (p2[0] - p1[0])) + ((q[1] - p1[1]) * (p2[1] - p1[1]))
    Udenom = math.pow(p2[0] - p1[0], 2) + math.pow(p2[1] - p1[1], 2)
    U /= Udenom

    r = [0, 0]
    r[0] = p1[0] + (U * (p2[0] - p1[0]))
    r[1] = p1[1] + (U * (p2[1] - p1[1]))

    minx = min(p1[0], p2[0])
    maxx = max(p1[0], p2[0])
    miny = min(p1[1], p2[1])
    maxy = max(p1[1], p2[1])

    is_valid = (minx <= r[0] <= maxx) and (miny <= r[1] <= maxy)

    if is_valid:
        return r
    else:
        return None

答案 9 :(得分:-1)

既然你没有说明你正在使用哪种语言,我会给你一个通用答案:

只需要一个循环通过你的AB段中的所有点,从它们“绘制一个段”到C,得到从C到D和从A到D的距离,并应用pithagoras定理。如果AD ^ 2 + CD ^ 2 = AC ^ 2,那么你已经找到了自己的观点。

此外,您可以通过最短边开始循环来优化代码(考虑AD和BD边),因为您可以更早地找到这一点。