我想计算给定线上与给定点垂直的点。
我有一个线段AB并且在线段之外有一个点C.我想计算AB上的点D,使得CD垂直于AB。
我必须找到D点。
它与this非常相似,但我想考虑Z坐标,因为它在3D空间中没有正确显示。
答案 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
}
答案 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只是一个直角三角形。
答案 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边),因为您可以更早地找到这一点。