Python求解N维空间给定两顶点的等边三角形第三顶点
已知条件
给定等边三角形的两个顶点 $A,B \in R^N$,其中空间维度 $N > 1$。
实现目标
求解第三个顶点 $Z \in R^N$,满足三边等长约束:||A-B|| = ||A-Z|| = ||B-Z||。
现有仅支持二维点场景(即$A,B \in R^2$、$Z \in R^2$)计算的Python脚本,代码如下:
import numpy as np def equilateral(A, B): # Computes `x coordinate` of the third vertex. vx = ( A[0] + B[0] + np.sqrt(3) * ( A[1] - B[1] ) ) / 2 # Computes 'y coordinate' of the third vertex. vy = ( A[1] + B[1] + np.sqrt(3) * ( A[0] - B[0] ) ) / 2 z = np.array([vx, vy]) #This point z is the third vertex. return z # Test for 2D vectors: A = np.array([2,0]) B = np.array([5,0]) Z = equilateral(A,B) print(z) # [ 3.5, -2.59807621]
需要扩展上述代码(或设计更优的实现方案),支持N维向量场景下的第三个顶点求解,适配如下测试用例:
N = 5 A = np.random.normal(size=(N, )) B = np.random.normal(size=(N, )) z = equilateral(A, B)
解法思路
N维空间下过A、B两点的等边三角形第三个顶点存在2个合法解,核心逻辑非常清晰:
- 等边三角形AB边的高长度为 $\frac{\sqrt{3}}{2} \cdot ||A-B||$,高的落点恰好是AB的中点
- 只需要在AB的垂直超平面上,找到一个长度等于高的向量,叠加到中点坐标上即可得到第三个顶点
- 垂直向量可以通过Gram-Schmidt正交化快速构造,不需要复杂的矩阵运算
兼容任意N维的实现代码
import numpy as np def equilateral(A, B, return_second_solution: bool = False): A = np.asarray(A, dtype=np.float64) B = np.asarray(B, dtype=np.float64) ab = B - A len_ab = np.linalg.norm(ab) # 计算AB中点坐标 mid_point = (A + B) / 2 # 构造与ab不共线的辅助向量:选取ab分量绝对值最小的维度置1,从根源避免共线问题 min_dim = np.argmin(np.abs(ab)) aux_vec = np.zeros_like(A) aux_vec[min_dim] = 1.0 # Gram-Schmidt正交化,得到严格垂直于ab的向量 perpendicular_vec = aux_vec - (np.dot(aux_vec, ab) / np.dot(ab, ab)) * ab # 将垂直向量归一化后,缩放到等边三角形高的长度 perpendicular_vec = perpendicular_vec / np.linalg.norm(perpendicular_vec) * len_ab * np.sqrt(3) / 2 # AB两侧各有一个合法解,通过参数控制返回哪一个 return mid_point + perpendicular_vec if not return_second_solution else mid_point - perpendicular_vec
正确性校验
不管是二维还是高维场景,都可以通过校验三边长度确认结果符合约束:
# 二维场景对齐原脚本测试 A_2d = np.array([2, 0]) B_2d = np.array([5, 0]) Z_2d = equilateral(A_2d, B_2d, return_second_solution=True) print("二维测试结果:", Z_2d.round(8)) print("二维三边长:", round(np.linalg.norm(A_2d - B_2d), 8), round(np.linalg.norm(A_2d - Z_2d), 8), round(np.linalg.norm(B_2d - Z_2d), 8)) # 五维场景适配测试 N = 5 A_nd = np.random.normal(size=(N, )) B_nd = np.random.normal(size=(N, )) Z_nd = equilateral(A_nd, B_nd) print("\n五维测试三边长:", round(np.linalg.norm(A_nd - B_nd), 8), round(np.linalg.norm(A_nd - Z_nd), 8), round(np.linalg.norm(B_nd - Z_nd), 8))
运行代码可以看到,两种场景下三边长度完全相等,符合等边三角形的约束。如果需要获取AB另一侧的第三个顶点,传入return_second_solution=True即可。
内容的提问来源于stack exchange,提问作者farid
相关产品推荐
相关产品推荐

