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

复杂不规则2D形状的轮廓路径计算问题求助

复杂2D轮廓点集的路径寻路问题

数据集说明

拥有多组不规则2D形状数据集,包含构成形状轮廓的无序点,部分数据存在环结构或点岛。示例形状如下:

图1:示例复杂2D形状

该示例的坐标数据需复制到代码的points =行中。

研究目的

计算这些形状的连续轮廓线,测量其周长,并最终计算轮廓上两点间的距离。

现存问题

对于含环结构的复杂形状,当前路径寻路方法无法生成合理轮廓:

  • 已通过忽略远超最近点平均距离的连接解决点岛问题,但环结构的处理仍未突破
  • 当前方法在环区域选择错误初始路径后会失效,出现跳转至未连接点、折返遗漏点后因距离阈值限制陷入停滞的情况,错误结果如下:

图2:当前路径寻路的错误结果(蓝色起点,红色终点,最后一点始终与起点相连)

需求目标

改进现有路径寻路方法,使其能稳定处理复杂环结构,或找到适用于该问题的替代路径寻路方法。

测试代码

需将示例坐标数据复制到points =行:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import scipy.spatial
import sys
import os
import numpy as np
import pandas as pd
import re
from scipy.interpolate import CubicSpline
from scipy.signal import savgol_filter
from matplotlib.collections import LineCollection


def calculate_path_length(path):
    """
    Calculate the path length.

    Parameters:
    path (array): An array of 2D points in the path.

    Returns:
    float: The total length of the path.
    """
    return np.sum(np.sqrt(np.sum(np.diff(path, axis=0)**2, axis=1)))


def get_shortest_path(full_path, start_point, end_point):
    """
    Get the shortest path between start and end points in a circular path.

    Parameters:
    full_path (array): An array of 2D points in the circular path.
    start_point (array): The start point.
    end_point (array): The end point.

    Returns:
    array: The shortest path.
    """
    # Get the indices of the start and end points in the full path
    start_index = np.where((full_path == start_point).all(axis=1))[0][0]
    end_index = np.where((full_path == end_point).all(axis=1))[0][0]

    # Calculate the paths
    if start_index < end_index:
        direct_path = full_path[start_index:end_index + 1]
        indirect_path = np.concatenate((full_path[end_index:], full_path[:start_index + 1]))
    else:
        direct_path = full_path[end_index:start_index + 1]
        indirect_path = np.concatenate((full_path[:end_index + 1], full_path[start_index:]))

    # Calculate the lengths of the paths
    direct_path_length = calculate_path_length(direct_path)
    indirect_path_length = calculate_path_length(indirect_path)

    # Return the shortest path
    print(direct_path_length, indirect_path_length)
    if direct_path_length < indirect_path_length:
        return direct_path
    else:
        return indirect_path


def GetPointDistance(p1, p2):
    return np.sqrt( ((p2[0] - p1[0])**2) + ((p2[1] - p1[1])**2) )


def AverageDistanceWithBuffer(points, buffer_size=20):
    """
    Calculate the average distance of a group of points and add buffer_size standard deviations to 
    add a large ceiling for distance variances. This should still be able to exclude extremely 
    large deviations that occur when outliers are present.

    Parameters:
    points (list): 2D list of 2xN points.
    buffer_size (int): Padding multiplier to use for outlier rejection.

    Returns:
    float: The average distance with buffer.
    """
    distances = []
    for i, point in enumerate(points):
        if i != len(points) - 1:
            distances.append(GetPointDistance(point, points[i+1]))
    return np.mean(distances) + buffer_size * np.std(distances)
    

def random_downsample(arr, percentage):
    """
    Randomly downsample an array by the given percentage.

    Parameters:
    arr (array): The input array.
    percentage (float): The percentage of data to retain.

    Returns:
    array: The downsampled array.
    """
    if percentage <= 0 or percentage > 100:
        raise ValueError("Percentage should be between 0 and 100 (inclusive).")

    sample_size = int(len(arr) * percentage / 100)
    random_indices = np.random.choice(len(arr), sample_size, replace=False)
    sampled_arr = arr[random_indices]

    return sampled_arr



def shortest_path(points, start_point, end_point):
    """
    Find the shortest path between start and end points.

    Parameters:
    points (array): An array of 2D points.
    start_point (array): The start point.
    end_point (array): The end point.

    Returns:
    array: The full path.
    array: The shortest path between the start and end points.
    """
    points = points.tolist()
    start_point = start_point.tolist()
    end_point = end_point.tolist()
    points = points + [start_point, end_point]
    current_point = start_point
    full_path = [current_point]
    points.remove(current_point)

    use_cutoff = False
    while points:
        if len(full_path) == 1000:
            buffered_avg_dist = AverageDistanceWithBuffer(full_path)
            use_cutoff = True

        if len(points) == 1 and points[0] == end_point:
            full_path.append(end_point)
            points.remove(end_point)
        else:
            closest_point = min(points, key=lambda x: np.linalg.norm(np.array(current_point) - np.array(x)))
            closest_point_dist = GetPointDistance(current_point, closest_point)
            if use_cutoff:
                if closest_point_dist < buffered_avg_dist:
                    full_path.append(closest_point)
                    current_point = closest_point
            else:
                full_path.append(closest_point)
                current_point = closest_point
            points.remove(closest_point)
        

    # To form a closed loop for the full perimeter path
    full_path.append(start_point)

    # Shortest path from start to end
    shortest_path = get_shortest_path(np.array(full_path), start_point, end_point)

    plt.scatter(shortest_path[:, 0], shortest_path[:, 1], c=range(len(shortest_path)), cmap='inferno')
    plt.close()

    # Convert lists into numpy arrays
    full_path = np.array(full_path)
    shortest_path = np.array(shortest_path)

    return full_path, shortest_path


points = # 复制示例坐标数据到此处
points = np.array(points)

# 返回完整路径及起止点间的最短路径
full, shortest = shortest_path(points, points[48], points[int(len(points)/2)])  # 自定义起止点

# 绘制轮廓
plt.scatter(points[0, 0], points[0, 1], s=200, facecolor='red', zorder=1000)  # 绘制起点
plt.scatter(points[int(len(points)/2), 0], points[int(len(points)/2), 1], s=200, facecolor='green', zorder=1000)  # 绘制终点
plt.scatter(points[:, 0], points[:, 1])  # 绘制所有点
plt.plot(full[:, 0], full[:, 1], color='k')  # 绘制路径线
plt.axis('equal')
plt.show()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 02:47:07