如何在AutoCAD或Python中获取绘图闭合区域的边界坐标?
提取闭合对象边界坐标的AutoCAD与Python实现方案
给定线条坐标列表(格式为coordinates_list = [[x, y, z, x1, y1, z1], ...]),需从对应绘图中提取全部15个闭合对象的边界坐标,针对你遇到的_-BOUNDARY命令无法直接读取坐标、DFS算法识别不全的问题,以下是两种可行方案:
一、AutoCAD 实现方案
步骤1:将坐标列表导入AutoCAD生成线条
_-BOUNDARY命令依赖AutoCAD中的图元对象,需先把坐标批量转换成直线图元,可通过以下两种方式实现:
- AutoLISP 批量创建直线:
(defun c:importlines (/ coords lst) ; 替换为你的坐标列表,格式为((x y z x1 y1 z1) (x2 y2 z2 x3 y3 z3) ...) (setq coords '((0 0 0 1 0 0) (1 0 0 1 1 0) ...)) (foreach lst coords (command "LINE" (list (car lst) (cadr lst) (caddr lst)) (list (cadddr lst) (cadddr (cdr lst)) (cadddr (cddr lst))) "") ) ) - Python pyautocad 库批量创建直线:
from pyautocad import Autocad, APoint acad = Autocad(create_if_not_exists=True) coordinates_list = [[0,0,0,1,0,0], [1,0,0,1,1,0], ...] # 你的坐标数据 for line in coordinates_list: start = APoint(line[0], line[1], line[2]) end = APoint(line[3], line[4], line[5]) acad.model.AddLine(start, end)
步骤2:生成闭合边界
线条导入完成后,执行_-BOUNDARY命令:
- 输入
_-BOUNDARY回车,设置创建对象为多段线(_O选项选择_M); - 依次拾取每个闭合区域的内部点,AutoCAD会自动生成对应闭合多段线;
- 若需批量处理,可提前准备15个闭合区域的内部点坐标,用AutoLISP循环执行命令:
(defun c:batchboundary (/ pts) ; 替换为15个闭合区域的内部点坐标列表 (setq pts '((0.5 0.5 0) (2.5 0.5 0) ...)) (foreach pt pts (command "_-BOUNDARY" "_O" "_M" pt "") ) )
步骤3:导出闭合边界坐标
选中生成的多段线,用以下方式提取坐标:
- 执行
LIST命令,直接查看多段线顶点坐标; - 用AutoLISP批量导出到文本文件:
(defun c:exportboundcoords (/ ent coords f) (setq ent (car (entsel "\n选择闭合多段线:"))) (setq coords (entget ent)) (setq f (open "boundary_coords.txt" "w")) (foreach item coords (if (= (car item) 10) ; 提取顶点坐标 (write-line (strcat (rtos (cadr item)) "," (rtos (caddr item)) "," (rtos (cadddr item))) f) ) ) (close f) )
二、Python 实现方案
你之前用DFS识别不全,大概率是未处理浮点精度误差、未做去重逻辑导致的,以下是优化后的实现:
核心逻辑
将线条的端点作为节点构建无向图,通过DFS查找所有环(闭合路径),同时处理浮点精度、排除重复环。
完整代码
import math from collections import defaultdict # 浮点精度阈值,解决坐标微小误差问题 EPS = 1e-6 def is_close(p1, p2): """判断两个点是否重合(考虑浮点精度)""" return math.hypot(p1[0]-p2[0], p1[1]-p2[1], p1[2]-p2[2]) < EPS def get_closed_boundaries(coordinates_list): # 构建无向图:键为点元组,值为相连的点列表 graph = defaultdict(list) # 存储已处理的线条,避免重复添加边 processed_lines = set() for line in coordinates_list: p1 = (line[0], line[1], line[2]) p2 = (line[3], line[4], line[5]) # 用排序后的点对标识线条,避免重复存储 line_key = tuple(sorted([p1, p2], key=lambda x: (x[0], x[1], x[2]))) if line_key not in processed_lines: processed_lines.add(line_key) graph[p1].append(p2) graph[p2].append(p1) closed_boundaries = [] visited_lines = set() def dfs(current_point, start_point, path, visited_points): # 回到起点且路径长度≥3,判定为有效闭合环 if is_close(current_point, start_point) and len(path) >= 3: # 生成唯一标识去重(避免顺时针/逆时针的同一环被重复记录) boundary_key = tuple(sorted(path, key=lambda x: (x[0], x[1], x[2]))) if boundary_key not in [tuple(sorted(b, key=lambda x: (x[0], x[1], x[2]))) for b in closed_boundaries]: closed_boundaries.append(path.copy()) return for neighbor in graph[current_point]: line_key = tuple(sorted([current_point, neighbor], key=lambda x: (x[0], x[1], x[2]))) # 避免重复走同一条线,且排除直接返回起点的无效路径(除了初始步骤) if line_key not in visited_lines and (not is_close(neighbor, start_point) or len(path) == 1): visited_lines.add(line_key) visited_points.add(neighbor) path.append(neighbor) dfs(neighbor, start_point, path, visited_points) # 回溯 path.pop() visited_points.remove(neighbor) visited_lines.remove(line_key) # 遍历所有点作为起点查找闭合环 for point in graph: dfs(point, point, [point], set([point])) # 最终去重:排除从不同起点识别的同一环 unique_boundaries = [] seen_keys = set() for boundary in closed_boundaries: key = tuple(sorted(boundary, key=lambda x: (x[0], x[1], x[2]))) if key not in seen_keys: seen_keys.add(key) unique_boundaries.append(boundary) return unique_boundaries # 示例调用 coordinates_list = [[0,0,0,1,0,0], [1,0,0,1,1,0], [1,1,0,0,1,0], [0,1,0,0,0,0], ...] boundaries = get_closed_boundaries(coordinates_list) print(f"识别到的闭合对象数量:{len(boundaries)}") for idx, boundary in enumerate(boundaries): print(f"闭合对象 {idx+1} 的坐标:{boundary}")
关键优化说明
- 浮点精度处理:通过
is_close函数判断点是否重合,解决坐标微小误差导致的节点匹配失败; - 去重机制:对线条和闭合路径的点进行排序,排除同一闭合环的不同遍历方向或起点的重复记录;
- DFS终止条件:要求路径长度≥3,避免将两点往返误判为闭合环。
内容的提问来源于stack exchange,提问作者Bobby Lith
相关产品推荐
相关产品推荐

