在垂直于线向量的 3D 空间中绘制一个点

Plot a point in 3D space perpendicular to a line vector

提问人:pJay 提问时间:4/6/2020 最后编辑:pJay 更新时间:4/7/2020 访问量:1110

问:

An example of what I'm trying to achieve

我正在尝试计算 3D 空间中与线向量正交/垂直的点。

所以我有 P1 和 P2 组成这条线。然后,我试图找到一个半径以 P1 为中心的点,该点与直线正交。

我想使用三角函数来做到这一点,而没有任何特定于编程语言的函数。

目前,我正在通过在线向量周围填充一个圆来测试此函数的准确性。

我还在 3D 空间中旋转线矢量,看看绘制的圆会发生什么,这就是我的结果不同的地方。

一些不良影响包括: 旋转并穿过线矢量的圆。 圆的半径似乎减小到零,然后随着线矢量的方向变化而增长。

我用这个问题来让我开始,并对代码进行了一些调整。

任何帮助将不胜感激 - 我现在已经花了 3 天时间画圆圈。这是我到目前为止的代码

//Define points which form the line vector
dx = p2x - p1x;
dy = p2y - p1y;
dz = p2z - p1z;

// Normalize line vector
d = sqrt(dx*dx + dy*dy + dz*dz);

// Line vector
v3x = dx/d;
v3y = dy/d;
v3z = dz/d;

// Angle and distance to plot point around line vector
angle = 123 * pi/180 //convert to radians
radius = 4;

// Begin calculating point
s = sqrt(v3x*v3x + v3y*v3y + v3z*v3z);

// Calculate v1.
// I have been playing with these variables (v1x, v1y, v1z) to try out different configurations.
v1x = s * v3x;
v1y = s * v3y;
v1z = s * -v3z;

// Calculate v2 as cross product of v3 and v1.
v2x = v3y*v1z - v3z*v1y;
v2y = v3z*v1x - v3x*v1z;
v2z = v3x*v1y - v3y*v1x;

// Point in space around the line vector
px = p1x + (radius * (v1x * cos(angle)) + (v2x * sin(angle)));
py = p1y + (radius * (v1y * cos(angle)) + (v2y * sin(angle)));
pz = p1z + (radius * (v1z * cos(angle)) + (v2z * sin(angle)));

编辑

在封锁期间与这个问题搏斗了几天之后,我终于设法让它工作起来。我要感谢 MBo 和 Futurologist 的宝贵意见。

虽然我无法让他们的例子发挥作用(更有可能是因为我有过错),但他们的回答为我指明了正确的方向,并指向了那个尤里卡时刻!

关键在于交换正确的向量。

所以谢谢你们俩,你们真的帮助了我。这是我的最终(工作)代码:

//Set some vars
angle = 123 * pi/180;
radius = 4;

//P1 & P2 represent vectors that form the line.
dx = p2x - p1x;
dy = p2y - p1y;
dz = p2z - p1z;

d = sqrt(dx*dx + dy*dy + dz*dz)

//Normalized vector
v3x = dx/d;
v3y = dy/d;
v3z = dz/d;

//Store vector elements in an array
p = [v3x, v3y, v3z];

//Store vector elements in second array, this time with absolute value
p_abs = [abs(v3x), abs(v3y), abs(v3z)];

//Find elements with MAX and MIN magnitudes
maxval = max(p_abs[0], p_abs[1], p_abs[2]);
minval = min(p_abs[0], p_abs[1], p_abs[2]);

//Initialise 3 variables to store which array indexes contain the (max, medium, min) vector magnitudes.
maxindex = 0;
medindex = 0;
minindex = 0;

//Loop through p_abs array to find which magnitudes are equal to maxval & minval. Store their indexes for use later.
for(i = 0; i < 3; i++) {
    if (p_abs[i] == maxval) maxindex = i;
    else if (p_abs[i] == minval) minindex = i;
}

//Find the remaining index which has the medium magnitude
for(i = 0; i < 3; i++) {
    if (i!=maxindex && i!=minindex) {
        medindex = i;
        break;
    }
}

//Store the maximum magnitude for now.
storemax = (p[maxindex]);

//Swap the 2 indexes that contain the maximum & medium magnitudes, negating maximum. Set minimum magnitude to zero.
p[maxindex] = (p[medindex]);
p[medindex] = -storemax;
p[minindex] = 0;

//Calculate v1. Perpendicular to v3.
s = sqrt(v3x*v3x + v3z*v3z + v3y*v3y);
v1x = s * p[0];
v1y = s * p[1];
v1z = s * p[2];

//Calculate v2 as cross product of v3 and v1.
v2x = v3y*v1z - v3z*v1y;
v2y = v3z*v1x - v3x*v1z;
v2z = v3x*v1y - v3y*v1x;

//For each circle point.
circlepointx = p2x + radius * (v1x * cos(angle) + v2x * sin(angle))
circlepointy = p2y + radius * (v1y * cos(angle) + v2y * sin(angle))
circlepointz = p2z + radius * (v1z * cos(angle) + v2z * sin(angle))
数学 几何 语言无关 的三角学

评论

0赞 walnut 4/6/2020
我用 and 标签替换了 and,因为您明确想知道与该语言无关的东西。如果这不是您的意图,请告诉我。javac++language-agnostic

答:

1赞 MBo 4/6/2020 #1

你的问题太模糊了,但我可以猜到你真正想要的是什么。

你有穿过两点和 .您想要构建一个半径圆以直线为中心并垂直于直线的圆。p1p2rp1

首先找到这条线的方向向量 - 你已经知道怎么做 - 归一化向量。v3

现在你需要垂直于的任意向量:找到具有最大量级和第二量级的分量。例如,是最大的,并且具有第二等。交换它们,否定最大的,并使第三个分量为零:v3v3abs(v3y)abs(v3x)

p = (-v3y, v3x, 0)

该向量垂直于(它们的点积为零)v3

现在将其规范化

pp = p / length(p)

现在得到双正态向量作为 和 的叉积(我有单位长度,不需要归一化),它垂直于 和v3ppv3pp

b = v3 x pp

现在建立需要的圈子

circlepoint(theta) = p1 + radius * pp * Cos(theta) + radius * b * Sin(theta)

请注意,以弧度为单位的角度是

angle = degrees * pi / 180

评论

0赞 pJay 4/6/2020
我已经更新了我的问题以使其更清晰(以及弧度问题)。澄清一下,在您的示例向量 p 元素中,x,y,z 分别变为 -v3y、v3x、0?
0赞 MBo 4/6/2020
是的,没错。看来我正确地理解了你的需求。
1赞 Futurologist 4/6/2020 #2
#Input:
# Pair of points which determine line L: 
P1 = [x_P1, y_P1, z_P1]
P2 = [x_P1, y_P1, z_P1]

# Radius:
Radius = R

# unit vector aligned with the line passing through the points P1 and P2:
V3 = P1 - P2
V3 = V3 / norm(V3)

# from the three basis vectors, e1 = [1,0,0], e2 = [0,1,0], e3 = [0,0,1] 
# pick the one that is the most transverse to vector V3
# this means, look at the entries of V3 = [x_V3, y_V3, z_V3] and check which
# one has the smallest absolute value and record its index. Take the coordinate 
# vector that has 1 at that selected index. In other words, 
# if min( abs(x_V3), abs(y_V)) = abs(y_V3), 
# then argmin( abs(x_V3), abs(y_V3), abs(z_V3)) = 2 and so take e = [0,1,0]:   
e = [0,0,0]
i = argmin( abs(V3[1]), abs(V3[2]), abs(V3[3]) )
e[i] = 1

# a unit vector perpendicular to both e and V3:  
V1 = cross(e, V3)
V1 = V1 / norm(V1)

# third unit vector perpendicular to both V3 and V1:
V2 = cross(V3, V1)

# an arbitrary point on the circle (i.e. equation of the circle with parameter s):
P = P1 + Radius*( np.cos(s)*V1 + np.sin(s)*V2 ) 


# E.g. say you want to find point P on the circle, 60 degrees relative to vector V1:
s = pi/3
P = P1 + Radius*( cos(s)*V1 + sin(s)*V2 ) 

Python 中的测试示例:

import numpy as np

#Input:
# Pair of points which determine line L: 
P1 = np.array([1, 1, 1])
P2 = np.array([3, 2, 3])
Radius = 3

V3 = P1 - P2
V3 = V3 / np.linalg.norm(V3)
e = np.array([0,0,0])
e[np.argmin(np.abs(V3))] = 1

V1 = np.cross(e, V3)
V1 = V1 / np.linalg.norm(V3)

V2 = np.cross(V3, V1)

# E.g., say you want to rotate point P along the circle, 60 degrees along rel to V1:
s = np.pi/3
P = P1 + Radius*( np.cos(s)*V1 + np.sin(s)*V2 ) 

评论

0赞 pJay 4/6/2020
如果这假设我已经在某处与线有关,恐怕我没有。我已经更新了我的答案,使事情更清楚一些。
0赞 Futurologist 4/6/2020
@pJay 那现在呢。基本上,求半径为 R 的圆的方程,以点 P1 为中心,位于穿过点 P1 并垂直于直线 P1 P2 的平面上。