由于您假设这四个点是共面的,您需要做的就是找到质心,计算从质心到每个点的向量,然后按向量的角度对点进行排序。
import numpy as np
def sort_points(pts):
centroid = np.sum(pts, axis=0) / pts.shape[0]
vector_from_centroid = pts - centroid
vector_angle = np.arctan2(vector_from_centroid[:, 1], vector_from_centroid[:, 0])
sort_order = np.argsort(vector_angle) # Find the indices that give a sorted vector_angle array
# Apply sort_order to original pts array.
# Also returning centroid and angles so I can plot it for illustration.
return (pts[sort_order, :], centroid, vector_angle[sort_order])
这个函数在假设点是二维的情况下计算角度,但是如果你有共面点,那么在公共平面上找到坐标并消除第三个坐标应该很容易。
让我们编写一个快速绘图函数来绘制我们的点:
from matplotlib import pyplot as plt
def plot_points(pts, centroid=None, angles=None, fignum=None):
fig = plt.figure(fignum)
plt.plot(pts[:, 0], pts[:, 1], 'or')
if centroid is not None:
plt.plot(centroid[0], centroid[1], 'ok')
for i in range(pts.shape[0]):
lstr = f"pt{i}"
if angles is not None:
lstr += f" ang: {angles[i]:.3f}"
plt.text(pts[i, 0], pts[i, 1], lstr)
return fig
现在让我们测试一下:
随机点:
pts = np.random.random((4, 2))
spts, centroid, angles = sort_points(pts)
plot_points(spts, centroid, angles)
矩形中的点:
pts = np.array([[0, 0], # pt0
[10, 5], # pt2
[10, 0], # pt1
[0, 5]]) # pt3
spts, centroid, angles = sort_points(pts)
plot_points(spts, centroid, angles)
找到包含我们点的平面的法向量很容易,它只是连接两对点的向量的(归一化)叉积:
plane_normal = np.cross(pts[1, :] - pts[0, :], pts[2, :] - pts[0, :])
plane_normal = plane_normal / np.linalg.norm(plane_normal)
现在,要找到这个平面上所有点的投影,我们需要知道这个平面上新坐标系的“原点”和基础。让我们假设第一个点是原点,x轴连接第一个点到第二个点,由于我们知道z轴(平面法线)和x轴,我们可以计算y轴。
new_origin = pts[0, :]
new_x = pts[1, :] - pts[0, :]
new_x = new_x / np.linalg.norm(new_x)
new_y = np.cross(plane_normal, new_x)
现在,点在新平面上的投影由this answer 给出:
proj_x = np.dot(pts - new_origin, new_x)
proj_y = np.dot(pts - new_origin, new_y)
现在你有了二维点。运行上面的代码对它们进行排序。