查找最近多段线的LISP实现

核心逻辑与实现方案

在 AutoCAD 中判断哪条多段线离指定点最近及次近,核心在于遍历选择集中的所有多段线对象,利用 ActiveX 方法 vlax-curve-getClosestPointTo 获取该点在每条多段线上的投影点(最近点),计算两点间的欧几里得距离,最后对距离列表进行排序提取前两名 。

以下是完整的 AutoLISP 代码实现,包含详细的中文注释和逻辑封装:

lisp 复制代码
(defun c:FindNearestPolylines (/ ss pickPt i ent obj closestPt distVal distList result first second)
  ;; 1. 获取用户选择的点
  (setq pickPt (getpoint "
请指定参考点: "))
  (if (null pickPt)    (progn (princ "
未指定点,命令取消。") (exit))
  )

  ;; 2. 选择多段线集合 (支持轻量多段线和普通多段线)
  ;; 使用 ssget 过滤选择集,代码 -4 表示逻辑与,0 表示实体类型
  (princ "
请选择要比较的多段线集合: ")
  (setq ss (ssget '((0 . "LWPOLYLINE,POLYLINE"))))
  
  (if (null ss)
    (progn (princ "
未选择任何多段线。") (exit))
  )

  ;; 3. 初始化变量
  (setq i 0) (setq distList '()) ; 用于存储 ((距离 . 实体名) ...) 的列表  (setq totalCount (sslength ss))

  ;; 4. 遍历选择集计算距离
  (repeat totalCount
    (setq ent (ssname ss i)) ; 获取第 i 个实体名
    (setq obj (vlax-ename->vla-object ent)) ; 转换为 VLA 对象以调用 ActiveX 方法
    
    ;; 关键步骤:获取曲线上离指定点最近的点
    ;; vlax-curve-getClosestPointTo 返回 WCS 坐标列表 (x y z)
    (setq closestPt (vlax-curve-getClosestPointTo obj (vlax-3d-point pickPt)))
    
    (if closestPt
      (progn
        ;; 计算欧几里得距离:sqrt((x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2)
        (setq distVal (distance pickPt closestPt))
        ;; 将 (距离 . 实体名) 加入列表 (setq distList (cons (cons distVal ent) distList))
      )
    )
    (setq i (1+ i))
  )

  ;; 5. 排序并提取结果
 ;; 按距离从小到大排序 (car 是距离)
  (setq distList (vl-sort distList '(lambda (a b) (< (car a) (car b)))))

  ;;检查是否有足够的结果
  (if (< (length distList) 2)
    (progn 
      (princ "
有效多段线数量不足 2 条,无法判断次近。")
      (if (= (length distList) 1)
        (progn
          (setq first (car distList))
          (princ (strcat "
最近的多段线句柄:<" (rtos (car first) 2 4) ">"))
          (sssetfirst nil (ssadd (cdr first))) ; 高亮显示
        )
 )
      (exit)
    )
  )

  ;; 提取第一名和第二名
  (setq first (car distList))
  (setq second (cadr distList))

  ;; 6. 输出结果并高亮显示
  (princ (strcat "
=== 计算结果 ==="
                 "
参考点坐标: " (rtos (car pickPt) 22) ", " (rtos (cadr pickPt) 2 2)
                 "
[最近] 距离: " (rtos (car first) 2 4) " | 实体句柄: " (itoa (cdr first))
                 "
[次近] 距离: " (rtos (car second) 2 4) " | 实体句柄: " (itoa (cdr second))
  ))
  
  ;; 创建临时选择集高亮显示这两条线
  (setq result (ssadd)) (ssadd (cdr first) result)
  (ssadd (cdr second) result)
  (sssetfirst nil result) ; 在 CAD 界面中高亮
  
  (princ "
已高亮显示最近和次近的多段线。")
  (princ)
)

;; 辅助说明:
;; 1. vlax-curve-getClosestPointTo是计算点到曲线最短距离的核心 API,它自动处理直线段和圆弧段的几何投影 。
;; 2. 对于包含大量实体的场景,此算法复杂度为 O(N),效率较高。
;; 3. 若需排除特定图层或颜色的多段线,可在 ssget 的过滤表中增加额外条件 (如 (8 . "LayerName"))。

关键技术解析

技术环节 核心函数/逻辑 作用说明
最近点计算 vlax-curve-getClosestPointTo 这是解决此类问题的标准方法。它不仅能处理直线段,还能精确计算点到圆弧、样条曲线的垂足位置,比手动遍历顶点更精准 。
距离度量 (distance pt1 pt2) AutoLISP 内置函数,直接计算三维空间中两点的直线距离,用于量化"远近"关系。
数据排序 vl-sort + Lambda 将计算出的 (距离 . 实体名) 点对列表按距离值(CAR部分)进行升序排列,从而轻松提取第一个(最近)和第二个(次近)元素。
对象过滤 ssget 过滤码 使用 '((0 . "LWPOLYLINE,POLYLINE")) 确保只处理多段线对象,避免误选直线、圆或其他实体干扰计算结果。

操作与应用场景

  1. 运行命令 :在 CAD 命令行输入 FindNearestPolylines (或简写 c:FindNearestPolylines 加载后)。
  2. 交互流程 :
    • 首先点击屏幕上的任意一点作为参考基准点。
    • 框选或点选一组需要比较的多段线。
  3. 结果反馈 :
    • 命令行会打印具体的距离数值。
    • 图形界面会自动高亮显示 找到的最近和次近两条多段线,方便用户直观确认。4. 扩展应用:此逻辑常用于管线碰撞检测前的预筛选、自动标注最近标高线 ,或在批量加工路径规划中寻找相邻轮廓。

参考来源

相关推荐
吴可可12314 小时前
Lisp函数定义四法详解
lisp
aluluka16 小时前
《elisp 每日一练》——Emacs的启动加速
emacs·lisp·elisp
吴可可1232 天前
LISP实现多段线精准三段打断
lisp
aluluka9 天前
《elisp 每日一练》——定时器与进程调用综合练习
emacs·lisp·elisp
aluluka10 天前
《elisp 每日一练》——Process Sentinel 与 json集成
json·emacs·lisp·elisp
aluluka14 天前
《elisp 每日一练》——定时器机制
emacs·lisp·elisp
aluluka15 天前
《elisp 每日一练》——hook 与 advice 综合练习
emacs·lisp·elisp
aluluka24 天前
《elisp 每日一练》—— syntax table 与 font lock
emacs·lisp·elisp
aluluka2 个月前
《elisp 每日一练》——状态栏显示管理与modeline 动态更新
emacs·lisp·elisp