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

如何通过代码识别绿色节点与对应蓝色节点对的关联关系

解决方案:识别绿色节点与蓝色节点对的关联关系

核心思路

要判断绿色节点是否位于一对蓝色节点的连线"之间",需要结合两个关键条件:

  1. 绿色节点落在这对蓝色节点组成线段的包围盒内(确保x、y坐标处于两个蓝节点的极值范围附近)
  2. 绿色节点到这条线段的垂直距离小于设定阈值(过滤掉包围盒内但离线段过远的点)

具体实现步骤

1. 定义基础几何计算函数

先实现两个核心工具函数,用于包围盒计算和点到线段的距离计算:

import math

def get_bounding_box(node_a, node_b):
    """获取两个节点组成线段的包围盒范围"""
    return {
        'min_x': min(node_a['x'], node_b['x']),
        'max_x': max(node_a['x'], node_b['x']),
        'min_y': min(node_a['y'], node_b['y']),
        'max_y': max(node_a['y'], node_b['y'])
    }

def point_to_segment_distance(point, seg_node_a, seg_node_b):
    """计算点到线段的垂直距离(仅当投影在线段上时取垂直距离,否则取到端点的距离)"""
    # 线段向量
    seg_vec_x = seg_node_b['x'] - seg_node_a['x']
    seg_vec_y = seg_node_b['y'] - seg_node_a['y']
    # 点到线段起点的向量
    point_vec_x = point['x'] - seg_node_a['x']
    point_vec_y = point['y'] - seg_node_a['y']
    
    seg_length_sq = seg_vec_x**2 + seg_vec_y**2
    if seg_length_sq == 0:
        # 两个蓝节点重合,直接返回点到节点的直线距离
        return math.hypot(point_vec_x, point_vec_y)
    
    # 计算投影系数t,t∈[0,1]表示投影点在线段上
    t = max(0, min(1, (point_vec_x * seg_vec_x + point_vec_y * seg_vec_y) / seg_length_sq))
    # 计算投影点坐标
    proj_x = seg_node_a['x'] + t * seg_vec_x
    proj_y = seg_node_a['y'] + t * seg_vec_y
    
    # 返回点到投影点的距离
    return math.hypot(point['x'] - proj_x, point['y'] - proj_y)

2. 遍历匹配节点对

遍历所有蓝色节点对,对每个绿色节点检查是否满足匹配条件,可根据实际图形调整距离阈值:

# 你的节点数据
blue_nodes = [
    {"name": 0, "x": 30, "y": 24},
    {"name": 1, "x": 305, "y": 26},
    {"name": 2, "x": 584, "y": 25},
    {"name": 3, "x": 589, "y": 308},
    {"name": 4, "x": 584, "y": 585},
    {"name": 5, "x": 307, "y": 587},
    {"name": 6, "x": 29, "y": 584},
    {"name": 7, "x": 29, "y": 309},
    {"name": 8, "x": 306, "y": 307}
]

green_nodes = [
    {"name": 0, "x": 105, "y": 9},
    {"name": 1, "x": 230, "y": 36},
    {"name": 2, "x": 390, "y": 13},
    {"name": 3, "x": 501, "y": 34},
    {"name": 4, "x": 596, "y": 89},
    {"name": 5, "x": 572, "y": 223},
    {"name": 6, "x": 600, "y": 348},
    {"name": 7, "x": 577, "y": 468},
    {"name": 8, "x": 513, "y": 593},
    {"name": 9, "x": 360, "y": 570},
    {"name": 10, "x": 233, "y": 590},
    {"name": 11, "x": 99, "y": 569},
    {"name": 12, "x": 12, "y": 508},
    {"name": 13, "x": 36, "y": 386},
    {"name": 14, "x": 18, "y": 228},
    {"name": 15, "x": 35, "y": 102},
    {"name": 16, "x": 115, "y": 295},
    {"name": 17, "x": 225, "y": 314},
    {"name": 18, "x": 295, "y": 232},
    {"name": 19, "x": 316, "y": 99},
    {"name": 20, "x": 381, "y": 296},
    {"name": 21, "x": 507, "y": 313},
    {"name": 22, "x": 317, "y": 374},
    {"name": 23, "x": 295, "y": 504}
]

# 距离阈值,根据图形精度调整
distance_threshold = 10

# 存储匹配结果:key为绿色节点编号,value为对应的蓝色节点对
match_results = {}

# 遍历所有绿色节点
for green in green_nodes:
    matched_pairs = []
    # 遍历所有不重复的蓝色节点对
    for i in range(len(blue_nodes)):
        for j in range(i+1, len(blue_nodes)):
            blue_a = blue_nodes[i]
            blue_b = blue_nodes[j]
            # 先检查是否在包围盒附近(预留阈值缓冲)
            bbox = get_bounding_box(blue_a, blue_b)
            if (bbox['min_x'] - distance_threshold <= green['x'] <= bbox['max_x'] + distance_threshold and
                bbox['min_y'] - distance_threshold <= green['y'] <= bbox['max_y'] + distance_threshold):
                # 计算到线段的距离
                dist = point_to_segment_distance(green, blue_a, blue_b)
                if dist <= distance_threshold:
                    matched_pairs.append((blue_a['name'], blue_b['name']))
    match_results[green['name']] = matched_pairs

# 输出匹配结果
for green_name, pairs in match_results.items():
    print(f"绿色节点{green_name}关联的蓝色节点对:{pairs}")

3. 结果验证

运行代码后,绿色节点2、3会匹配到蓝色节点对(1,2),与你描述的场景一致。

优化建议

  • 如果蓝色节点是结构化网络(如环形、网格),可先预定义有效相邻节点对,减少无效遍历,提升效率。
  • 距离阈值可根据节点坐标的精度、图形比例动态调整,避免误判或漏判。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 12:17:02