找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 247|回复: 6

[求助] 关于vla最小包围盒问题的求助

[复制链接]

已领礼包: 212个

财富等级: 日进斗金

发表于 2025-8-3 17:56:41 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
好久没有发言了,最近一直在学习高飞鸟的最小包围盒代码,对于连续尺寸标注对象,我用(vlax-invoke-method obj 'GetBoundingBox 'llp 'urp)为什么非正交的对齐标注生成的包围盒会比正交的大一圈,我参考了leemac的包围盒函数,他是用复制对象旋转与轴对齐之后再求包围盒,这样的画执行效率太慢,能否有大神给解决下,为什么带角度的标注包围盒会变大,代码我免费贡献出来了

;
  1. ; 获取标注对象的基准点和方向向量
  2. (defun dim-basepoints (ent / dxf pt1 pt2 vec)
  3.   (setq dxf (entget ent)
  4.         pt1 (cdr (assoc 10 dxf))  ; 标注起点
  5.         pt2 (cdr (assoc 14 dxf))  ; 标注终点
  6.         vec (mapcar '- pt2 pt1)   ; 方向向量
  7.   )  
  8.   (list pt1 pt2 vec)  ; 返回起点、终点和方向向量
  9. )

  10. ;; 点集包围盒计算
  11. ;; 参数: pts - 点列表 [(x1 y1) (x2 y2) ...]
  12. ;; 返回: 包含左下角和右上角点的列表 [[min_x min_y] [max_x max_y]]
  13. (defun Dim:pointsetboundingbox ( pts / minx miny maxx maxy pt )
  14.     (setq minx (car (car pts))
  15.           miny (cadr (car pts))
  16.           maxx minx
  17.           maxy miny
  18.     )
  19.     (foreach pt pts
  20.         (setq minx (min minx (car pt))
  21.               miny (min miny (cadr pt))
  22.               maxx (max maxx (car pt))
  23.               maxy (max maxy (cadr pt))
  24.         )
  25.     )
  26.     (list (list minx miny) (list maxx maxy))
  27. )

  28. ;; 旋转点集
  29. ;; 参数: lst - 点列表, bpt - 旋转基点, ang - 旋转角度(弧度)
  30. ;; 返回: 旋转后的点列表
  31. (defun Dim:rotatepoints ( lst bpt ang / mat vec )
  32.     (setq mat
  33.         (list
  34.             (list (cos ang) (sin (- ang)) 0.0)
  35.             (list (sin ang) (cos ang)     0.0)
  36.            '(0.0 0.0 1.0)
  37.         )
  38.     )
  39.     (setq vec (mapcar '- bpt (mxv mat bpt)))
  40.     (mapcar '(lambda ( x ) (mapcar '+ (mxv mat x) vec)) lst)
  41. )

  42. ;; 矩阵与向量乘法
  43. (defun mxv ( m v )
  44.     (mapcar '(lambda ( r ) (apply '+ (mapcar '* r v))) m)
  45. )

  46. ;; 计算与标注基线对齐的最小包围盒
  47. ;; 参数: ss - 选择集
  48. ;; 返回: 最小包围盒的四个顶点坐标列表 ((x1 y1) (x2 y2) (x3 y3) (x4 y4))
  49. (defun CalculateAlignedDimensionBoundingBox (ss / allPoints basePoints baseVectors baseAngle minBox i e obj ll ur llp urp basePts avgVec rotMat invRotMat)
  50.     (if (eq 'pickset (type ss))
  51.         (progn
  52.             (setq allPoints nil
  53.                   basePoints nil
  54.                   baseVectors nil)
  55.             
  56.             ;; 收集所有标注对象的点和基线
  57.             (repeat (setq i (sslength ss))
  58.                 (setq e (ssname ss (setq i (1- i))))
  59.                 (setq obj (vlax-ename->vla-object e))
  60.                
  61.                 ;; 检查是否为标注对象
  62.                 (if (wcmatch (strcase (vla-get-objectname obj)) "*DIMENSION")
  63.                     (progn
  64.                         ;; 获取标注的基准点和方向向量
  65.                         (setq basePts (dim-basepoints e))
  66.                         (setq basePoints (append basePoints (list (car basePts) (cadr basePts))))
  67.                         (setq baseVectors (append baseVectors (list (caddr basePts))))
  68.                         
  69.                         ;; 获取标注对象的包围盒点
  70.                         (vl-catch-all-apply
  71.                            '(lambda ()
  72.                                 (vlax-invoke-method obj 'GetBoundingBox 'llp 'urp)
  73.                             )
  74.                         )
  75.                         
  76.                         (if llp
  77.                             (progn
  78.                                 (setq ll (vlax-safearray->list llp))
  79.                                 (setq ur (vlax-safearray->list urp))
  80.                                 
  81.                                 ;; 添加包围盒的四个角点
  82.                                 (setq allPoints (append allPoints
  83.                                     (list
  84.                                         (list (car ll) (cadr ll))    ; 左下角
  85.                                         (list (car ur) (cadr ll))    ; 右下角
  86.                                         (list (car ur) (cadr ur))    ; 右上角
  87.                                         (list (car ll) (cadr ur))    ; 左上角
  88.                                     )
  89.                                 ))
  90.                             )
  91.                         )
  92.                     )
  93.                 )
  94.             )
  95.             
  96.             (if allPoints
  97.                 (progn
  98.                     ;; 计算所有标注的平均方向向量
  99.                     (if (and baseVectors (> (length baseVectors) 0))
  100.                         (progn
  101.                             ;; 计算平均向量
  102.                             (setq avgVec (mapcar '(lambda (coord) (/ (apply '+ coord) (length baseVectors))) (transpose baseVectors)))
  103.                             ;; 计算平均向量的角度
  104.                             (setq baseAngle (angle '(0 0) (list (car avgVec) (cadr avgVec))))
  105.                         )
  106.                         (setq baseAngle 0.0)  ; 默认角度
  107.                     )
  108.                     
  109.                     ;; 计算所有点的中心点
  110.                     (setq cen (mapcar '(lambda (coords) (/ (apply '+ coords) (length coords))) (transpose allPoints)))
  111.                     
  112.                     ;; 创建旋转矩阵 (将点集旋转到与基线对齐)
  113.                     (setq rotMat
  114.                         (list
  115.                             (list (cos baseAngle) (sin baseAngle) 0.0)
  116.                             (list (- (sin baseAngle)) (cos baseAngle) 0.0)
  117.                             '(0.0 0.0 1.0)
  118.                         )
  119.                     )
  120.                      
  121.                     ;; 旋转点集使其与基线对齐
  122.                     (setq rotatedPoints
  123.                         (mapcar
  124.                             '(lambda (pt)
  125.                                 (mxv rotMat (mapcar '- pt cen))
  126.                              )
  127.                             allPoints
  128.                         )
  129.                     )
  130.                      
  131.                     ;; 将旋转后的点移回中心点
  132.                     (setq rotatedPoints
  133.                         (mapcar
  134.                             '(lambda (pt)
  135.                                 (mapcar '+ pt cen)
  136.                              )
  137.                             rotatedPoints
  138.                         )
  139.                     )
  140.                     
  141.                     ;; 计算旋转后点集的包围盒
  142.                     (setq box (Dim:pointsetboundingbox rotatedPoints))
  143.                     
  144.                     ;; 创建包围盒的四个顶点
  145.                     (setq boxPoints (list
  146.                         (car box)                          ; 左下角
  147.                         (list (cadr (cadr box)) (cadr (car box)))  ; 右下角
  148.                         (cadr box)                          ; 右上角
  149.                         (list (car (car box)) (cadr (cadr box)))  ; 左上角
  150.                     ))

  151.                     ;; 修正包围盒顶点顺序,确保正确闭合
  152.                     (setq boxPoints (list
  153.                         (list (car (car box)) (cadr (car box)))  ; 左下角
  154.                         (list (car (cadr box)) (cadr (car box)))  ; 右下角
  155.                         (list (car (cadr box)) (cadr (cadr box)))  ; 右上角
  156.                         (list (car (car box)) (cadr (cadr box)))  ; 左上角
  157.                     ))
  158.                     
  159.                     ;; 创建反向旋转矩阵
  160.                     (setq invRotMat
  161.                         (list
  162.                             (list (cos (- baseAngle)) (sin (- baseAngle)) 0.0)
  163.                             (list (- (sin (- baseAngle))) (cos (- baseAngle)) 0.0)
  164.                             '(0.0 0.0 1.0)
  165.                         )
  166.                     )
  167.                      
  168.                     ;; 将包围盒旋转回原始角度
  169.                     (setq minBox
  170.                         (mapcar
  171.                             '(lambda (pt)
  172.                                 (mapcar '+ (mxv invRotMat (mapcar '- pt cen)) cen)
  173.                              )
  174.                             boxPoints
  175.                         )
  176.                     )
  177.                     
  178.                     minBox
  179.                 )
  180.                 (progn
  181.                     (princ "\n未找到标注对象。")
  182.                     nil
  183.                 )
  184.             )
  185.         )
  186.         (
  187.             (princ "\n参数错误: 请提供有效的选择集。")
  188.             nil
  189.         )
  190.     )
  191. )

  192. ;; 矩阵转置
  193. (defun transpose ( lst )
  194.     (apply 'mapcar (cons 'list lst))
  195. )

  196. ;; 测试函数: 创建选择集并计算标注对象的最小包围盒
  197. (defun c:tt (/ ss bbox)
  198.     (princ "\n请选择要计算最小包围盒的标注对象...")
  199.     (setq ss (ssget '((0 . "*DIMENSION"))))  ;; 只选择标注对象
  200.    
  201.     (if ss
  202.         (progn
  203.             (setq bbox (CalculateAlignedDimensionBoundingBox ss))
  204.             
  205.             (if bbox
  206.                 (progn
  207.                     (princ (strcat "\n最小包围盒顶点: " (vl-princ-to-string bbox)))
  208.                     
  209.                     ;; 绘制包围盒
  210.                     (entmake
  211.             (append
  212.                '(
  213.                     (000 . "LWPOLYLINE")
  214.                     (100 . "AcDbEntity")
  215.                     (100 . "AcDbPolyline")
  216.                     (090 . 4)
  217.                     (070 . 1)
  218.                 )
  219.                 (mapcar '(lambda ( p ) (cons 10 p)) bbox)
  220.             )
  221.         )
  222.                     bbox
  223.                 )
  224.             )
  225.         )
  226.     )
  227.     (princ)
  228. )


360截图178912317692119.png

论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 212个

财富等级: 日进斗金

 楼主| 发表于 2025-8-4 12:52:45 | 显示全部楼层
  1. (defun boundingbox (sel / idx obj dim-ent base-pts base-vec rot_angle base-pt llp urp min-pt max-pt bbox-pts)
  2.     (if (> (sslength sel) 0)
  3.     (progn
  4.       (setq dim-ent (ssname sel 0));; 步骤1: 获取首个标注对象的尺寸基线
  5.       (setq base-pts (dim-basepoints dim-ent)) ; 返回基点列表 (基点 pt4 起点 pt1)
  6.       ;; 步骤2: 计算基线与X轴的夹角和向量
  7.       (setq base-vec (mapcar '- (cadr base-pts) (car base-pts))) ; 基线向量
  8.       (setq rot_angle (atan (cadr base-vec) (car base-vec))) ; 与X轴的夹角
  9.       ;; 设置旋转基点
  10.       (setq base-pt (car base-pts))
  11.       ;; 步骤3: 判断是否需要旋转(检查是否为正交角度)
  12.       (setq need-rotate
  13.         (not (or
  14.           (equal rot_angle 0.0 1e-6)              ; 0度
  15.           (equal rot_angle (/ pi 2) 1e-6)         ; 90度
  16.           (equal rot_angle pi 1e-6)               ; 180度
  17.           (equal rot_angle (* 3 (/ pi 2)) 1e-6)   ; 270度
  18.           (equal rot_angle (* 2 pi) 1e-6)         ; 360度
  19.         )))
  20.       ;; 步骤4: 如果需要,将所有对象旋转至与X轴对齐
  21.       (if need-rotate
  22.         (repeat (setq idx (sslength sel))
  23.           (setq obj (vlax-ename->vla-object (ssname sel (setq idx (1- idx)))))        
  24.           (vla-rotate obj (vlax-3d-point base-pt) (- rot_angle))
  25.         )
  26.       )
  27.       ;; 步骤5: 计算选择集整体包围盒
  28.       (repeat (setq idx (sslength sel))
  29.         (setq obj (vlax-ename->vla-object (ssname sel (setq idx (1- idx)))))        
  30.         (if (and (vlax-method-applicable-p obj 'getboundingbox)
  31.                  (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-getboundingbox (list obj 'llp 'urp)))))        
  32.           (progn
  33.             (setq current-llp (vlax-safearray->list llp))
  34.             (setq current-urp (vlax-safearray->list urp))
  35.             
  36.             ;; 更新整体包围盒的最小和最大点
  37.             (if (not min-pt)
  38.               (setq min-pt current-llp max-pt current-urp)
  39.               (progn
  40.                 (setq min-pt (mapcar 'min min-pt current-llp))
  41.                 (setq max-pt (mapcar 'max max-pt current-urp))
  42.               )
  43.             )
  44.           )
  45.         )
  46.       )
  47.       ;; 步骤6: 使用辅助函数计算四点包围盒
  48.       (setq bbox-pts (hc-pt2-to-pt4 min-pt max-pt))
  49.       
  50.       ;; 步骤7: 如果旋转过,将所有对象恢复至初始状态
  51.       (if need-rotate
  52.         (repeat (setq idx (sslength sel))
  53.           (setq obj (vlax-ename->vla-object (ssname sel (setq idx (1- idx)))))        
  54.           (vla-rotate obj (vlax-3d-point base-pt) rot_angle)
  55.         )
  56.       )
  57.       ;; 步骤8: 将包围盒角点旋转回原始位置(如果需要)
  58.       (if need-rotate
  59.         (setq bbox-pts (hc-pts-rotate bbox-pts base-pt rot_angle))
  60.       )
  61.       
  62.       ;; 返回选择集的整体包围盒
  63.       bbox-pts
  64.     )
  65.     nil ; 如果选择集为空,返回nil
  66.   )
  67. )
  68. (defun dim-basepoints (ent / entls pt1 pt2 pt3 pt4 ang pt1a pt3a);获得Align/Rotate尺寸的基线--02
  69.   (setq entls (entget ent)
  70.         pt1 (cdr (assoc 10 (entget ent)));(setq ent (car (entsel)))
  71.         pt2 (cdr (assoc 14 (entget ent)))
  72.         pt3 (cdr (assoc 13 (entget ent)))
  73.         ang  (angle pt1 pt2)
  74.         pt1a (polar pt1 (+ ang (* pi 0.5)) 2)
  75.         pt3a (polar pt3 ang 2)
  76.         pt4 (inters pt1 pt1a pt3 pt3a nil)
  77.         )  (list pt4 pt1))
  78. ;;取两点的中点(二维)
  79. (defun hc-mid(p1 p2)(mapcar '(lambda (x y) (* 0.5 (+ x y))) p1 p2))
  80. ;;pt点围绕p0点旋转ang弧度
  81. (defun hc-pt-rotate (pt p0 ang)(polar p0 (+ (angle p0 pt) ang) (distance pt p0)))
  82. ;;点表围绕p0点旋转ang弧度
  83. (defun hc-pts-rotate(lst p0 ang)(mapcar '(lambda(x)(hc-pt-rotate x p0 ang))lst))
  84. ;;根据两点坐标返回4个点坐标
  85. (defun hc-pt2-to-pt4 (pt1 pt2)(list (list (car pt1)(cadr pt1)) (list(car pt2)(cadr pt1))(list (car pt2)(cadr pt2))(list (car pt1)(cadr pt2))))
  86. ;; 测试函数 - 命令名为TT
  87. (defun c:TT (/ sel bbox-pts pt1 pt2 pt3 pt4)
  88.   "测试boundingbox函数的命令\n调用方式: 在AutoCAD命令行输入TT,然后选择要测试的标注对象"
  89.   ;; 提示用户选择对象
  90.   (prompt "\n选择要计算包围盒的标注对象: ")
  91.   (setq sel (ssget))
  92.   
  93.   (if sel
  94.     (progn
  95.       ;; 调用boundingbox函数
  96.       (setq bbox-pts (boundingbox sel))
  97.       
  98.       (if bbox-pts
  99.         (progn
  100.           ;; 提取四个角点
  101.           (setq pt1 (nth 0 bbox-pts))
  102.           (setq pt2 (nth 1 bbox-pts))
  103.           (setq pt3 (nth 2 bbox-pts))
  104.           (setq pt4 (nth 3 bbox-pts))
  105.          
  106.           ;; 创建多段线来显示包围盒
  107.           (entmake (list
  108.             (cons 0 "LWPOLYLINE")
  109.             (cons 100 "AcDbEntity")
  110.             (cons 100 "AcDbPolyline")
  111.             (cons 62 1)
  112.             (cons 90 4)  ; 4个顶点
  113.             (cons 70 1)  ; 闭合
  114.             (cons 10 pt1)
  115.             (cons 10 pt2)
  116.             (cons 10 pt3)
  117.             (cons 10 pt4)
  118.           ))
  119.          
  120.           (prompt (strcat "\n包围盒已绘制,角点坐标: "
  121.                           "\n1: (" (rtos (car pt1)) ", " (rtos (cadr pt1)) ")"
  122.                           "\n2: (" (rtos (car pt2)) ", " (rtos (cadr pt2)) ")"
  123.                           "\n3: (" (rtos (car pt3)) ", " (rtos (cadr pt3)) ")"
  124.                           "\n4: (" (rtos (car pt4)) ", " (rtos (cadr pt4)) ")"
  125.                   ))
  126.         )
  127.         (prompt "\n无法计算包围盒,请确保选择了有效的标注对象。")
  128.       )
  129.     )
  130.     (prompt "\n未选择任何对象。")
  131.   )
  132.   (princ)
  133. )
我能想到的办法就只有旋转对象了,其他方法我测试完就是不好使

点评

[attachimg]109300[/attachimg]  详情 回复 发表于 2025-8-25 11:09
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 145个

财富等级: 日进斗金

发表于 2025-8-6 05:21:12 | 显示全部楼层
不是尺寸的对象,你测试过没?
你仔细看看尺寸的,是不是尺寸的定义点在外面,包围盒要计算到定义点,而不是线

点评

别的我测试是没问题的,主要是大出去的那一圈我也没看明白是啥原因大的,也不像扩出去的点,就是被vla放大了。我用笨办法解决了,纯数学算的,取出标注的基点再根据界线和文字包围盒偏移  详情 回复 发表于 2025-8-6 10:03
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 212个

财富等级: 日进斗金

 楼主| 发表于 2025-8-6 10:03:19 | 显示全部楼层
XDSoft 发表于 2025-8-6 05:21
不是尺寸的对象,你测试过没?
你仔细看看尺寸的,是不是尺寸的定义点在外面,包围盒要计算到定义点,而不 ...

别的我测试是没问题的,主要是大出去的那一圈我也没看明白是啥原因大的,也不像扩出去的点,就是被vla放大了。我用笨办法解决了,纯数学算的,取出标注的基点再根据界线和文字包围盒偏移
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 48个

财富等级: 招财进宝

发表于 2025-8-6 10:24:45 | 显示全部楼层
在wcs返回平行于尺寸标注方向的包围盒
晓东API(CAD尺寸标注有效,天正尺寸标注,达不到预期效果)
(setq ss  (ssget)
      dir (Xdrx_Entity_direction (ssname ss 0))
)
(setq bwh (Xdrx_Entity_Box ss dir))

点评

我现在用的就是api 只不过想研习一下 尺寸标注的包围盒  详情 回复 发表于 2025-8-6 11:22
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 212个

财富等级: 日进斗金

 楼主| 发表于 2025-8-6 11:22:23 | 显示全部楼层
pxt2015 发表于 2025-8-6 10:24
在wcs返回平行于尺寸标注方向的包围盒
晓东API(CAD尺寸标注有效,天正尺寸标注,达不到预期效果)
(setq s ...

我现在用的就是api 只不过想研习一下 尺寸标注的包围盒
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2025-8-25 11:09:45 | 显示全部楼层
本帖最后由 统一网名 于 2025-8-25 11:11 编辑
a117034423 发表于 2025-8-4 12:52
我能想到的办法就只有旋转对象了,其他方法我测试完就是不好使

wechat_2025-08-25_110703_869.png
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2025-9-22 06:46 , Processed in 0.380911 second(s), 45 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表