You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对非凸形状的GPS点进行顺时针排序以生成赛车线

高度非凸赛道边界GPS点的顺时针排序方案

我需要为某高度非凸的赛道生成赛车线,但手里只有无顺序的边界GPS点。想把这些点按顺时针方向排序,让车辆能循迹。尝试过基于重心的旋转排序函数,但对非凸形状无效,函数代码如下:

def rotational_sort(list_of_xy_coords):
    cx, cy = list_of_xy_coords.mean(0)
    x, y = list_of_xy_coords.T
    angles = np.arctan2(x-cx, y-cy)
    indices = np.argsort(angles)
    return list_of_xy_coords[indices]

问题原因

基于重心的旋转排序仅适用于凸多边形:它依赖所有点相对于重心的角度单调变化,非凸赛道会存在部分点的角度交叉,导致排序后点的顺序混乱,无法形成连续边界。

解决方案:基于Delaunay三角剖分的边界提取与排序

通过三角剖分找到点的邻接关系,提取边界边后构建连续序列,最后调整为顺时针方向:

1. 构建Delaunay三角剖分

利用三角剖分建立点之间的拓扑关系,为后续提取边界做准备:

from scipy.spatial import Delaunay
import numpy as np
from collections import defaultdict

# 替换为你的GPS点数组(N×2的numpy数组)
points = np.array(your_gps_points)
tri = Delaunay(points)

2. 筛选边界边

Delaunay三角剖分中,仅出现在单个三角形内的边即为边界边:

edge_count = defaultdict(int)
edges = []

# 遍历所有三角形的边,统计出现次数
for simplex in tri.simplices:
    for i in range(3):
        p1, p2 = simplex[i], simplex[(i+1)%3]
        # 按点索引排序存储,避免重复统计
        edge_key = tuple(sorted((p1, p2)))
        edge_count[edge_key] += 1
        edges.append((p1, p2))

# 提取仅出现一次的边界边
boundary_edges = [edge for edge in edges if edge_count[tuple(sorted(edge))] == 1]

3. 构建连续的边界点序列

从任意边界点出发,沿着边界边依次连接,形成闭合的边界点序列:

# 构建边界点的邻接表
adj = defaultdict(list)
for p1, p2 in boundary_edges:
    adj[p1].append(p2)
    adj[p2].append(p1)

# 生成闭合边界序列
start_point = boundary_edges[0][0]
current_point = start_point
prev_point = None
boundary_sequence = [current_point]

while True:
    # 获取下一个邻接点(排除前一个点)
    neighbors = adj[current_point]
    next_point = neighbors[0] if neighbors[0] != prev_point else neighbors[1]
    if next_point == start_point:
        break
    boundary_sequence.append(next_point)
    prev_point = current_point
    current_point = next_point

# 得到初步排序的边界点
sorted_points = points[boundary_sequence]

4. 调整为顺时针方向

通过多边形面积的符号判断当前序列方向,若为逆时针则反转序列:

def is_clockwise(points):
    x, y = points.T
    # 计算多边形有向面积,面积为负表示顺时针
    signed_area = np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1))
    return signed_area < 0

# 若当前为逆时针,反转序列得到顺时针
if not is_clockwise(sorted_points):
    sorted_points = sorted_points[::-1]

内容的提问来源于stack exchange,提问作者Jiqian Dong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 06:47:28