关于vla最小包围盒问题的求助
好久没有发言了,最近一直在学习高飞鸟的最小包围盒代码,对于连续尺寸标注对象,我用(vlax-invoke-method obj 'GetBoundingBox 'llp 'urp)为什么非正交的对齐标注生成的包围盒会比正交的大一圈,我参考了leemac的包围盒函数,他是用复制对象旋转与轴对齐之后再求包围盒,这样的画执行效率太慢,能否有大神给解决下,为什么带角度的标注包围盒会变大,代码我免费贡献出来了;
; 获取标注对象的基准点和方向向量
(defun dim-basepoints (ent / dxf pt1 pt2 vec)
(setq dxf (entget ent)
pt1 (cdr (assoc 10 dxf)); 标注起点
pt2 (cdr (assoc 14 dxf)); 标注终点
vec (mapcar '- pt2 pt1) ; 方向向量
)
(list pt1 pt2 vec); 返回起点、终点和方向向量
)
;; 点集包围盒计算
;; 参数: pts - 点列表 [(x1 y1) (x2 y2) ...]
;; 返回: 包含左下角和右上角点的列表 [ ]
(defun Dim:pointsetboundingbox ( pts / minx miny maxx maxy pt )
(setq minx (car (car pts))
miny (cadr (car pts))
maxx minx
maxy miny
)
(foreach pt pts
(setq minx (min minx (car pt))
miny (min miny (cadr pt))
maxx (max maxx (car pt))
maxy (max maxy (cadr pt))
)
)
(list (list minx miny) (list maxx maxy))
)
;; 旋转点集
;; 参数: lst - 点列表, bpt - 旋转基点, ang - 旋转角度(弧度)
;; 返回: 旋转后的点列表
(defun Dim:rotatepoints ( lst bpt ang / mat vec )
(setq mat
(list
(list (cos ang) (sin (- ang)) 0.0)
(list (sin ang) (cos ang) 0.0)
'(0.0 0.0 1.0)
)
)
(setq vec (mapcar '- bpt (mxv mat bpt)))
(mapcar '(lambda ( x ) (mapcar '+ (mxv mat x) vec)) lst)
)
;; 矩阵与向量乘法
(defun mxv ( m v )
(mapcar '(lambda ( r ) (apply '+ (mapcar '* r v))) m)
)
;; 计算与标注基线对齐的最小包围盒
;; 参数: ss - 选择集
;; 返回: 最小包围盒的四个顶点坐标列表 ((x1 y1) (x2 y2) (x3 y3) (x4 y4))
(defun CalculateAlignedDimensionBoundingBox (ss / allPoints basePoints baseVectors baseAngle minBox i e obj ll ur llp urp basePts avgVec rotMat invRotMat)
(if (eq 'pickset (type ss))
(progn
(setq allPoints nil
basePoints nil
baseVectors nil)
;; 收集所有标注对象的点和基线
(repeat (setq i (sslength ss))
(setq e (ssname ss (setq i (1- i))))
(setq obj (vlax-ename->vla-object e))
;; 检查是否为标注对象
(if (wcmatch (strcase (vla-get-objectname obj)) "*DIMENSION")
(progn
;; 获取标注的基准点和方向向量
(setq basePts (dim-basepoints e))
(setq basePoints (append basePoints (list (car basePts) (cadr basePts))))
(setq baseVectors (append baseVectors (list (caddr basePts))))
;; 获取标注对象的包围盒点
(vl-catch-all-apply
'(lambda ()
(vlax-invoke-method obj 'GetBoundingBox 'llp 'urp)
)
)
(if llp
(progn
(setq ll (vlax-safearray->list llp))
(setq ur (vlax-safearray->list urp))
;; 添加包围盒的四个角点
(setq allPoints (append allPoints
(list
(list (car ll) (cadr ll)) ; 左下角
(list (car ur) (cadr ll)) ; 右下角
(list (car ur) (cadr ur)) ; 右上角
(list (car ll) (cadr ur)) ; 左上角
)
))
)
)
)
)
)
(if allPoints
(progn
;; 计算所有标注的平均方向向量
(if (and baseVectors (> (length baseVectors) 0))
(progn
;; 计算平均向量
(setq avgVec (mapcar '(lambda (coord) (/ (apply '+ coord) (length baseVectors))) (transpose baseVectors)))
;; 计算平均向量的角度
(setq baseAngle (angle '(0 0) (list (car avgVec) (cadr avgVec))))
)
(setq baseAngle 0.0); 默认角度
)
;; 计算所有点的中心点
(setq cen (mapcar '(lambda (coords) (/ (apply '+ coords) (length coords))) (transpose allPoints)))
;; 创建旋转矩阵 (将点集旋转到与基线对齐)
(setq rotMat
(list
(list (cos baseAngle) (sin baseAngle) 0.0)
(list (- (sin baseAngle)) (cos baseAngle) 0.0)
'(0.0 0.0 1.0)
)
)
;; 旋转点集使其与基线对齐
(setq rotatedPoints
(mapcar
'(lambda (pt)
(mxv rotMat (mapcar '- pt cen))
)
allPoints
)
)
;; 将旋转后的点移回中心点
(setq rotatedPoints
(mapcar
'(lambda (pt)
(mapcar '+ pt cen)
)
rotatedPoints
)
)
;; 计算旋转后点集的包围盒
(setq box (Dim:pointsetboundingbox rotatedPoints))
;; 创建包围盒的四个顶点
(setq boxPoints (list
(car box) ; 左下角
(list (cadr (cadr box)) (cadr (car box))); 右下角
(cadr box) ; 右上角
(list (car (car box)) (cadr (cadr box))); 左上角
))
;; 修正包围盒顶点顺序,确保正确闭合
(setq boxPoints (list
(list (car (car box)) (cadr (car box))); 左下角
(list (car (cadr box)) (cadr (car box))); 右下角
(list (car (cadr box)) (cadr (cadr box))); 右上角
(list (car (car box)) (cadr (cadr box))); 左上角
))
;; 创建反向旋转矩阵
(setq invRotMat
(list
(list (cos (- baseAngle)) (sin (- baseAngle)) 0.0)
(list (- (sin (- baseAngle))) (cos (- baseAngle)) 0.0)
'(0.0 0.0 1.0)
)
)
;; 将包围盒旋转回原始角度
(setq minBox
(mapcar
'(lambda (pt)
(mapcar '+ (mxv invRotMat (mapcar '- pt cen)) cen)
)
boxPoints
)
)
minBox
)
(progn
(princ "\n未找到标注对象。")
nil
)
)
)
(
(princ "\n参数错误: 请提供有效的选择集。")
nil
)
)
)
;; 矩阵转置
(defun transpose ( lst )
(apply 'mapcar (cons 'list lst))
)
;; 测试函数: 创建选择集并计算标注对象的最小包围盒
(defun c:tt (/ ss bbox)
(princ "\n请选择要计算最小包围盒的标注对象...")
(setq ss (ssget '((0 . "*DIMENSION"))));; 只选择标注对象
(if ss
(progn
(setq bbox (CalculateAlignedDimensionBoundingBox ss))
(if bbox
(progn
(princ (strcat "\n最小包围盒顶点: " (vl-princ-to-string bbox)))
;; 绘制包围盒
(entmake
(append
'(
(000 . "LWPOLYLINE")
(100 . "AcDbEntity")
(100 . "AcDbPolyline")
(090 . 4)
(070 . 1)
)
(mapcar '(lambda ( p ) (cons 10 p)) bbox)
)
)
bbox
)
)
)
)
(princ)
)
(defun boundingbox (sel / idx obj dim-ent base-pts base-vec rot_angle base-pt llp urp min-pt max-pt bbox-pts)
(if (> (sslength sel) 0)
(progn
(setq dim-ent (ssname sel 0));; 步骤1: 获取首个标注对象的尺寸基线
(setq base-pts (dim-basepoints dim-ent)) ; 返回基点列表 (基点 pt4 起点 pt1)
;; 步骤2: 计算基线与X轴的夹角和向量
(setq base-vec (mapcar '- (cadr base-pts) (car base-pts))) ; 基线向量
(setq rot_angle (atan (cadr base-vec) (car base-vec))) ; 与X轴的夹角
;; 设置旋转基点
(setq base-pt (car base-pts))
;; 步骤3: 判断是否需要旋转(检查是否为正交角度)
(setq need-rotate
(not (or
(equal rot_angle 0.0 1e-6) ; 0度
(equal rot_angle (/ pi 2) 1e-6) ; 90度
(equal rot_angle pi 1e-6) ; 180度
(equal rot_angle (* 3 (/ pi 2)) 1e-6) ; 270度
(equal rot_angle (* 2 pi) 1e-6) ; 360度
)))
;; 步骤4: 如果需要,将所有对象旋转至与X轴对齐
(if need-rotate
(repeat (setq idx (sslength sel))
(setq obj (vlax-ename->vla-object (ssname sel (setq idx (1- idx)))))
(vla-rotate obj (vlax-3d-point base-pt) (- rot_angle))
)
)
;; 步骤5: 计算选择集整体包围盒
(repeat (setq idx (sslength sel))
(setq obj (vlax-ename->vla-object (ssname sel (setq idx (1- idx)))))
(if (and (vlax-method-applicable-p obj 'getboundingbox)
(not (vl-catch-all-error-p (vl-catch-all-apply 'vla-getboundingbox (list obj 'llp 'urp)))))
(progn
(setq current-llp (vlax-safearray->list llp))
(setq current-urp (vlax-safearray->list urp))
;; 更新整体包围盒的最小和最大点
(if (not min-pt)
(setq min-pt current-llp max-pt current-urp)
(progn
(setq min-pt (mapcar 'min min-pt current-llp))
(setq max-pt (mapcar 'max max-pt current-urp))
)
)
)
)
)
;; 步骤6: 使用辅助函数计算四点包围盒
(setq bbox-pts (hc-pt2-to-pt4 min-pt max-pt))
;; 步骤7: 如果旋转过,将所有对象恢复至初始状态
(if need-rotate
(repeat (setq idx (sslength sel))
(setq obj (vlax-ename->vla-object (ssname sel (setq idx (1- idx)))))
(vla-rotate obj (vlax-3d-point base-pt) rot_angle)
)
)
;; 步骤8: 将包围盒角点旋转回原始位置(如果需要)
(if need-rotate
(setq bbox-pts (hc-pts-rotate bbox-pts base-pt rot_angle))
)
;; 返回选择集的整体包围盒
bbox-pts
)
nil ; 如果选择集为空,返回nil
)
)
(defun dim-basepoints (ent / entls pt1 pt2 pt3 pt4 ang pt1a pt3a);获得Align/Rotate尺寸的基线--02
(setq entls (entget ent)
pt1 (cdr (assoc 10 (entget ent)));(setq ent (car (entsel)))
pt2 (cdr (assoc 14 (entget ent)))
pt3 (cdr (assoc 13 (entget ent)))
ang(angle pt1 pt2)
pt1a (polar pt1 (+ ang (* pi 0.5)) 2)
pt3a (polar pt3 ang 2)
pt4 (inters pt1 pt1a pt3 pt3a nil)
)(list pt4 pt1))
;;取两点的中点(二维)
(defun hc-mid(p1 p2)(mapcar '(lambda (x y) (* 0.5 (+ x y))) p1 p2))
;;pt点围绕p0点旋转ang弧度
(defun hc-pt-rotate (pt p0 ang)(polar p0 (+ (angle p0 pt) ang) (distance pt p0)))
;;点表围绕p0点旋转ang弧度
(defun hc-pts-rotate(lst p0 ang)(mapcar '(lambda(x)(hc-pt-rotate x p0 ang))lst))
;;根据两点坐标返回4个点坐标
(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))))
;; 测试函数 - 命令名为TT
(defun c:TT (/ sel bbox-pts pt1 pt2 pt3 pt4)
"测试boundingbox函数的命令\n调用方式: 在AutoCAD命令行输入TT,然后选择要测试的标注对象"
;; 提示用户选择对象
(prompt "\n选择要计算包围盒的标注对象: ")
(setq sel (ssget))
(if sel
(progn
;; 调用boundingbox函数
(setq bbox-pts (boundingbox sel))
(if bbox-pts
(progn
;; 提取四个角点
(setq pt1 (nth 0 bbox-pts))
(setq pt2 (nth 1 bbox-pts))
(setq pt3 (nth 2 bbox-pts))
(setq pt4 (nth 3 bbox-pts))
;; 创建多段线来显示包围盒
(entmake (list
(cons 0 "LWPOLYLINE")
(cons 100 "AcDbEntity")
(cons 100 "AcDbPolyline")
(cons 62 1)
(cons 90 4); 4个顶点
(cons 70 1); 闭合
(cons 10 pt1)
(cons 10 pt2)
(cons 10 pt3)
(cons 10 pt4)
))
(prompt (strcat "\n包围盒已绘制,角点坐标: "
"\n1: (" (rtos (car pt1)) ", " (rtos (cadr pt1)) ")"
"\n2: (" (rtos (car pt2)) ", " (rtos (cadr pt2)) ")"
"\n3: (" (rtos (car pt3)) ", " (rtos (cadr pt3)) ")"
"\n4: (" (rtos (car pt4)) ", " (rtos (cadr pt4)) ")"
))
)
(prompt "\n无法计算包围盒,请确保选择了有效的标注对象。")
)
)
(prompt "\n未选择任何对象。")
)
(princ)
)
我能想到的办法就只有旋转对象了,其他方法我测试完就是不好使 不是尺寸的对象,你测试过没?
你仔细看看尺寸的,是不是尺寸的定义点在外面,包围盒要计算到定义点,而不是线 XDSoft 发表于 2025-8-6 05:21
不是尺寸的对象,你测试过没?
你仔细看看尺寸的,是不是尺寸的定义点在外面,包围盒要计算到定义点,而不 ...
别的我测试是没问题的,主要是大出去的那一圈我也没看明白是啥原因大的,也不像扩出去的点,就是被vla放大了。我用笨办法解决了,纯数学算的,取出标注的基点再根据界线和文字包围盒偏移 在wcs返回平行于尺寸标注方向的包围盒
晓东API(CAD尺寸标注有效,天正尺寸标注,达不到预期效果)
(setq ss(ssget)
dir (Xdrx_Entity_direction (ssname ss 0))
)
(setq bwh (Xdrx_Entity_Box ss dir)) pxt2015 发表于 2025-8-6 10:24
在wcs返回平行于尺寸标注方向的包围盒
晓东API(CAD尺寸标注有效,天正尺寸标注,达不到预期效果)
(setq s ...
我现在用的就是api 只不过想研习一下 尺寸标注的包围盒 本帖最后由 统一网名 于 2025-8-25 11:11 编辑
a117034423 发表于 2025-8-4 12:52
我能想到的办法就只有旋转对象了,其他方法我测试完就是不好使
页:
[1]