输入是空间中的一些随机线段,其两端的坐标为 p1(x1,y1,z1) 和 p2(x2,y2,z2)。
任务如下 - 有必要对其坐标进行此类转换,使其严格垂直,同时保持其长度。图片中的演示(绿色 - 原始,蓝色 - 旋转)。
这个想法是取原始线段上的任意点(用 A1 表示),并添加第二个点 (A2),该点比点 A1 高出原始线段的长度。但这是行不通的,因为我们应用于该段以旋转它的变换将应用于其他 3D 对象。
还有一个想法是计算线段与所有轴(x、y、z)之间的角度,然后将线段的所有坐标依次乘以沿所有轴的旋转矩阵。但执行此操作后的新段并没有达到预期(看起来不直)。
预先知道角度 alpha、beta、gamma 为 45 度,可以检查角度是否取正确,图中(绿色部分),例如坐标为 p1(0,0,0) p2(1 ,1,1) 被取
尝试实现获取旋转矩阵的算法:
import numpy as np
# нормализовать вектор (привести к единичной длине)
def normalize_vector(vector):
norm_v = np.linalg.norm(vector)
if norm_v != 0:
return vector / norm_v
else:
return vector
# Исходные данные задачи (2 конца отрезка)
x = np.array([0,0,0])
y = np.array([1,1,1])
#нормализуем вектора
x = normalize_vector(x)
y = normalize_vector(y)
# необходимые вектора для решения задачи
s = np.array([y[0] - x[0],y[1] - x[1],y[2] - x[2]])
t = np.array([0,1,0])
a = np.cross(s,t)
#нормализуем вектора
s = normalize_vector(s)
t = normalize_vector(t)
a = normalize_vector(a)
# матрицы
S = np.array([s, a, np.cross(s,a)])
T = np.array([t, a, np.cross(t,a)])
#транспонированная S
S_t = np.transpose(S)
# получаем решение задачи
solution = np.dot(S_t, T)
# тестируем, пробуем получить повернутый отрезок
x = np.array([[0,0,0]])
y = np.array([[1,1,1]])
x = np.dot(x, solution)
y = np.dot(y, solution)
x = np.round(x, decimals=2)
y = np.round(y, decimals=2)
print(x, y)
将平移矩阵应用到
(-A1.x, -A1.y, -A1.z)
原点处的 Now A1
我们应用围绕 OZ 轴一定角度的旋转矩阵。
f=atan2(A1.y-A2.y,A1.x-A2.x)
现在向量位于 OXZ 平面中
应用绕 OY 轴一定角度的旋转矩阵。
t=acos((A1.z-A2.z)/Len(A))
现在向量共线 OZ如有需要,请转回
(A1.x, A1.y, A1.z)
(检查角度标志,我可能犯了一个错误)
所有向量进一步减少到单位长度。这很重要。
我们引入向量s = (x 2 - x 1 , y 2 - y 1 , z 2 - z 1 )。
向量t = (0, 1, 0)。矢量a = s × t - 矢量积(这将是旋转轴)。
我们将根据向量组装两个矩阵: S = (s, a, s × a)和T = (t, a, t × a)。“让我们收集”意味着第一个向量成为矩阵的第一列,第二个向量成为第二列,第三个向量成为第三列。
您需要的旋转矩阵是S -1 ·T。
PS代数是在向量为行向量的假设下编写的,即向量乘以矩阵计算为v·M。如果向量是列向量,则矩阵的“组合”从列变为行,最后的乘积的形式为:T·S -1。
PPS如果归一化前向量a的长度接近于零,则向量s已经几乎是垂直的。你不必标准化,你可以立即返回单位矩阵。
PPPS解决此类问题的一般方法:为初始位置和最终位置提出两个正交基。从底创建两个矩阵。反转第一个并乘以第二个 - 您将得到基数之间的转换矩阵,这就是您所需要的。
PPPPS问题可以通过多种方式解决,这种解决方案是周转最短的。
PPPPS演示: