明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 955|回复: 9

[提问] 查找多层嵌套块内文本对象,并正确绘制圆形标记

[复制链接]
发表于 2025-2-27 18:36:36 | 显示全部楼层 |阅读模式
50明经币
主要目的在于检索当前dwg文件中的某些字符,并在其上绘制圆形便于查看标记。
目前我能成功在单行文本、多行文本、以及单层块内实现这个目的,但是无法在多层嵌套块中正确位置绘制圆形。而且每次多层嵌套块绘制出来的圆形都在图纸原点,我很q


  1. (defun c:DrawCircleAtBlockText (/ *error* main acadDoc blks str dia)
  2.   (vl-load-com)
  3.   (setq foundCount 0)  ; 设置计数器为全局变量
  4.   
  5.   ;; 错误处理函数
  6.   (defun *error* (msg)
  7.     (if acadDoc (vla-EndUndoMark acadDoc))
  8.     (princ (strcat "\n[DEBUG] 错误: " msg))
  9.     (princ)
  10.   )
  11.   
  12.   ;; 创建或获取图层
  13.   (defun setup-layer (layerName colorIndex / layerObj layers)
  14.     (setq layers (vla-get-Layers
  15.                    (vla-get-ActiveDocument
  16.                      (vlax-get-acad-object))))
  17.    
  18.     ;; 尝试获取已存在的图层
  19.     (if (not (vl-catch-all-error-p
  20.                (setq layerObj (vl-catch-all-apply 'vla-item
  21.                                                  (list layers layerName)))))
  22.       layerObj
  23.       ;; 如果图层不存在,创建新图层
  24.       (setq layerObj (vla-add layers layerName))
  25.     )
  26.    
  27.     ;; 设置图层颜色
  28.     (vla-put-Color layerObj colorIndex)
  29.     layerName
  30.   )
  31.   
  32.   ;; 计算总块数
  33.   (defun count-total-blocks (blks / count)
  34.     (setq count 0)
  35.     (vlax-for blk blks
  36.       (setq count (1+ count))
  37.     )
  38.     count
  39.   )
  40.   
  41.   ;; 更新进度条
  42.   (defun update-progress (current total / percent)
  43.     (setq percent (fix (* (/ current total) 100.0)))
  44.     (princ (strcat "\r处理进度: " (itoa percent) "%"))
  45.     (if (= current total) (princ "\n"))
  46.   )
  47.   
  48.   ;; 主处理函数
  49.   (defun main ()
  50.     (setq acadDoc (vla-get-ActiveDocument (vlax-get-acad-object))
  51.           blks (vla-get-Blocks acadDoc))
  52.    
  53.     ;; 处理图层
  54.     (setup-layer "M-0-E" 6)
  55.    
  56.     ;; 获取并验证文字输入
  57.     (while (not str)
  58.       (setq str (getstring "\n请输入需要查找的文字内容: "))
  59.       (cond
  60.         ((= str "")
  61.           (setq str nil)
  62.           (princ "\n[DEBUG] 错误: 文字内容不能为空,请重新输入")
  63.         )
  64.         ((= str nil)
  65.           (exit)
  66.         )
  67.       )
  68.     )
  69.    
  70.     ;; 获取并验证直径输入
  71.     (while (not dia)
  72.       (setq dia (getdist "\n请输入圆形直径: "))
  73.       (cond
  74.         ((and dia (<= dia 0.0))
  75.           (setq dia nil)
  76.           (princ "\n[DEBUG] 错误: 直径必须大于0,请重新输入")
  77.         )
  78.         ((= dia nil)
  79.           (exit)
  80.         )
  81.       )
  82.     )
  83.    
  84.     (vla-StartUndoMark acadDoc)
  85.    
  86.     (if (and str dia)
  87.       (progn
  88.         (setq totalBlocks (count-total-blocks blks)
  89.               currentBlock 0)
  90.         (princ "\n[DEBUG] 开始处理,总块数: ")
  91.         (princ totalBlocks)
  92.         (vlax-for blkDef blks
  93.           (setq currentBlock (1+ currentBlock))
  94.           (update-progress currentBlock totalBlocks)
  95.           (process-block-def blkDef str dia)
  96.         )
  97.         (princ (strcat "\n[DEBUG] 已成功创建 " (itoa foundCount) " 个圆形"))
  98.       )
  99.       (princ "\n[DEBUG] 操作已取消")
  100.     )
  101.     (vla-EndUndoMark acadDoc)
  102.   )
  103.   
  104.        ;; 块定义处理
  105.     (defun process-block-def (blkDef str dia / found)
  106.       (princ (strcat "\n[DEBUG] 正在处理块定义: " (vla-get-Name blkDef)))
  107.       
  108.       ;; 首先处理普通文本对象
  109.       (vlax-for obj blkDef
  110.         (cond
  111.           ((or (= (vla-get-ObjectName obj) "AcDbText")
  112.                (= (vla-get-ObjectName obj) "AcDbMText"))
  113.            (princ (strcat "\n[DEBUG] 找到文本对象,内容: " (vla-get-TextString obj)))
  114.            (if (= (strcase (vla-get-TextString obj)) (strcase str))
  115.              (progn
  116.                (princ "\n[DEBUG] 文本内容匹配成功")
  117.                (create-circle-at-text obj dia)
  118.                (setq found t)
  119.              )
  120.            ))
  121.           ;; 处理块参照
  122.           ((= (vla-get-ObjectName obj) "AcDbBlockReference")
  123.            (princ "\n[DEBUG] 找到块参照")
  124.            (if (process-block-reference obj str dia)
  125.              (setq found t)
  126.            ))
  127.         )
  128.       )
  129.       found
  130.     )

  131.     ;; 在普通文本位置创建圆
  132.     (defun create-circle-at-text (textObj dia / textPt)
  133.       (setq textPt (vlax-get textObj 'InsertionPoint))
  134.       (princ (strcat "\n[DEBUG] 文本坐标: " (vl-princ-to-string textPt)))
  135.       
  136.       (if (entmakex
  137.             (list
  138.               '(0 . "CIRCLE")
  139.               '(8 . "M-0-E")
  140.               (cons 10 textPt)
  141.               (cons 40 (/ dia 2.0))
  142.             )
  143.           )
  144.         (progn
  145.           (setq foundCount (1+ foundCount))
  146.           (princ "\n[DEBUG] 创建圆形成功"))
  147.         (princ "\n[DEBUG] 创建圆形失败"))
  148.     )
  149.    
  150.     ;; 处理块参照中的文本
  151.     (defun process-block-reference (blkRef str dia / blkDef found)
  152.       (if (setq blkDef (vla-item blks (vla-get-Name blkRef)))
  153.         (progn
  154.           (princ (strcat "\n[DEBUG] 处理块参照: " (vla-get-Name blkRef)))
  155.           (vlax-for obj blkDef
  156.             (cond
  157.               ;; 处理块中的文本
  158.               ((or (= (vla-get-ObjectName obj) "AcDbText")
  159.                    (= (vla-get-ObjectName obj) "AcDbMText"))
  160.                (princ (strcat "\n[DEBUG] 块中找到文本,内容: " (vla-get-TextString obj)))
  161.                (if (= (strcase (vla-get-TextString obj)) (strcase str))
  162.                  (progn
  163.                    (princ "\n[DEBUG] 块中文本匹配成功")
  164.                    (create-circle-at-block-text obj blkRef dia)
  165.                    (setq found t)
  166.                  )
  167.                ))
  168.               ;; 处理嵌套块
  169.               ((= (vla-get-ObjectName obj) "AcDbBlockReference")
  170.                (if (process-block-reference obj str dia)
  171.                  (setq found t)
  172.                ))
  173.             )
  174.           )
  175.         )
  176.       )
  177.       found
  178.     )
  179.    
  180.     ;; 在块参照中的文本位置创建圆
  181.     (defun create-circle-at-block-text (textObj blkRef dia / textPt mat worldPt)
  182.       (setq textPt (vlax-get textObj 'InsertionPoint))
  183.       (princ (strcat "\n[DEBUG] 块中文本局部坐标: " (vl-princ-to-string textPt)))
  184.       
  185.       ;; 获取块的变换矩阵
  186.       (setq mat (get-cumulative-matrix blkRef))
  187.       (setq worldPt (apply-matrix textPt mat))
  188.       (princ (strcat "\n[DEBUG] 转换后的世界坐标: " (vl-princ-to-string worldPt)))
  189.       
  190.       (if (entmakex
  191.             (list
  192.               '(0 . "CIRCLE")
  193.               '(8 . "M-0-E")
  194.               (cons 10 worldPt)
  195.               (cons 40 (/ dia 2.0))
  196.             )
  197.           )
  198.         (progn
  199.           (setq foundCount (1+ foundCount))
  200.           (princ "\n[DEBUG] 创建圆形成功"))
  201.         (princ "\n[DEBUG] 创建圆形失败"))
  202.     )
  203.    
  204.     ;; 实例处理(用于块参照中的文本对象)
  205.     ;; 将未使用的函数转换为注释
  206.     ;; ===== 以下为未使用的函数,已注释 =====
  207.     ;; process-block-instances 函数定义
  208.     #|
  209.     (defun process-block-instances (blkDef textObj dia / ss refID mat textPtWorld)
  210.       (princ (strcat "\n[DEBUG] 处理块实例: " (vla-get-Name blkDef)))
  211.       ;; 获取文本在块定义中的局部坐标
  212.       (setq textPt (vlax-get textObj 'InsertionPoint))
  213.       (princ (strcat "\n[DEBUG] 文本局部坐标: " (vl-princ-to-string textPt)))
  214.       
  215.       ;; 处理所有块实例
  216.       (setq blkName (vla-get-Name blkDef)
  217.             ss (ssget "_X" (list '(0 . "INSERT") (cons 2 blkName))))
  218.       
  219.       (if ss
  220.         (progn
  221.           (princ (strcat "\n[DEBUG] 找到 " (itoa (sslength ss)) " 个块实例"))
  222.           (repeat (setq cnt (sslength ss))
  223.             (setq refID (ssname ss (setq cnt (1- cnt))))
  224.             
  225.             ;; 转换为VLA对象并应用变换
  226.             (if (setq refID (vlax-ename->vla-object refID))
  227.               (progn
  228.                 (setq mat (get-cumulative-matrix refID))
  229.                 (setq textPtWorld (apply-matrix textPt mat))
  230.                 (princ (strcat "\n[DEBUG] 转换后的世界坐标: " (vl-princ-to-string textPtWorld)))
  231.                
  232.                 ;; 创建圆
  233.                 (if (entmakex
  234.                       (list
  235.                         '(0 . "CIRCLE")
  236.                         '(8 . "M-0-E")
  237.                         (cons 10 textPtWorld)
  238.                         (cons 40 (/ dia 2.0))
  239.                       )
  240.                     )
  241.                   (progn
  242.                     (setq foundCount (1+ foundCount))
  243.                     (princ "\n[DEBUG] 创建圆形成功"))
  244.                   (princ "\n[DEBUG] 创建圆形失败"))
  245.               )
  246.             )
  247.           )
  248.         )
  249.         (princ "\n[DEBUG] 未找到块实例")
  250.       )
  251.     )
  252.    |#
  253.     ;; 获取累积变换矩阵(递归处理嵌套块)
  254.     (defun get-cumulative-matrix (blkRef / parentMatrix parentEnt)
  255.       (setq parentMatrix (get-block-transform blkRef))
  256.       
  257.       ;; 获取当前块参照的所有者(父块)
  258.       (if (and blkRef
  259.                (setq parentEnt (vlax-vla-object->ename blkRef))
  260.                (setq parentEnt (entnext parentEnt))
  261.                (= "INSERT" (cdr (assoc 0 (entget parentEnt)))))
  262.         ;; 如果还在嵌套块中,继续向上递归
  263.         (if (setq parentObj (vlax-ename->vla-object parentEnt))
  264.           (setq parentMatrix (multiply-matrices
  265.                               (get-cumulative-matrix parentObj)
  266.                               parentMatrix))
  267.         )
  268.       )
  269.       parentMatrix
  270.     )
  271.    
  272.     ;; 获取单个块的变换矩阵(平移、旋转、缩放)
  273.     (defun get-block-transform (blkRef / insPt scaleX scaleY rotAng mat)
  274.       (setq insPt  (vlax-get blkRef 'InsertionPoint)
  275.             scaleX (vla-get-XScaleFactor blkRef)
  276.             scaleY (vla-get-YScaleFactor blkRef)
  277.             rotAng (vla-get-Rotation blkRef))
  278.       
  279.       ;; 构建变换矩阵(4x4齐次矩阵)
  280.       (setq mat (list
  281.                  (list (* scaleX (cos rotAng)) (* (- scaleY) (sin rotAng)) 0.0 (car insPt))
  282.                  (list (* scaleX (sin rotAng)) (* scaleY (cos rotAng)) 0.0 (cadr insPt))
  283.                  (list 0.0 0.0 1.0 (if (caddr insPt) (caddr insPt) 0.0))
  284.                  (list 0.0 0.0 0.0 1.0)))
  285.       mat
  286.     )
  287.    
  288.     ;; 矩阵乘法(合并嵌套变换)
  289.     (defun multiply-matrices (mat1 mat2 / result)
  290.       (setq result (mapcar '(lambda (row)
  291.                               (mapcar '(lambda (col)
  292.                                         (apply '+ (mapcar '* row col)))
  293.                               (apply 'mapcar (cons 'list mat2))))
  294.                           mat1))
  295.       result
  296.     )
  297.     ;; 应用矩阵变换到点
  298.         (defun apply-matrix (pt mat / x y z)
  299.           (setq x (car pt)
  300.                 y (cadr pt)
  301.                 z (caddr pt))
  302.           (list
  303.             (+ (* x (caar mat)) (* y (cadar mat)) (* z (caddar mat)) (cadddr (car mat)))
  304.             (+ (* x (caadr mat)) (* y (cadadr mat)) (* z (caddr (cadr mat))) (cadddr (cadr mat)))
  305.             (+ (* x (caaddr mat)) (* y (cadadr mat)) (* z (caddr (caddr mat))) (cadddr (caddr mat))))
  306.         )
  307.     #|
  308.     ;; 增强嵌套块处理(递归遍历所有层级)
  309.     (defun process-nested-block (blkDef str dia / obj)
  310.       (vlax-for obj blkDef
  311.         (cond
  312.           ((= (vla-get-ObjectName obj) "AcDbBlockReference")
  313.             (process-block-def
  314.               (vla-item (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-acad-object)))
  315.               (vla-get-Name obj))
  316.               str dia)
  317.           )
  318.         )
  319.       )
  320.     )
  321.     |#
  322.     (main)
  323.     (princ)
  324. )

附件: 您需要 登录 才可以下载或查看,没有账号?注册
回复

使用道具 举报

发表于 2025-2-27 18:36:37 | 显示全部楼层

本帖子中包含更多资源

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

x
回复

使用道具 举报

发表于 2025-2-28 11:42:24 | 显示全部楼层
本帖最后由 ssyfeng 于 2025-3-1 11:08 编辑

转换一下坐标应该就可以

本帖子中包含更多资源

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

x
回复

使用道具 举报

发表于 2025-2-28 11:44:39 | 显示全部楼层
嵌套块要不停地计算嵌套矩阵再转换。比较简单的方式是将图块弄到DBX中,逐层分解到没有图块,然后过滤全图找到需要标记的文本,再根据文本位置在DWG中创建圆。
回复

使用道具 举报

 楼主| 发表于 2025-2-28 14:28:46 | 显示全部楼层
ssyfeng 发表于 2025-2-28 11:42
转换一下坐标应该就可以

我试了坐标转换,单层块没问题 多层嵌套块坐标转换画出来的圆形还是不在其位,会偏离,昨天弄了半天也没有解决。
回复

使用道具 举报

 楼主| 发表于 2025-2-28 14:29:51 | 显示全部楼层
kozmosovia 发表于 2025-2-28 11:44
嵌套块要不停地计算嵌套矩阵再转换。比较简单的方式是将图块弄到DBX中,逐层分解到没有图块,然后过滤全图 ...

哎,这不是我想要的结果,会破坏原图的完整性。但这确实是最简单的做法。
回复

使用道具 举报

发表于 2025-2-28 14:32:11 | 显示全部楼层
jezli 发表于 2025-2-28 14:29
哎,这不是我想要的结果,会破坏原图的完整性。但这确实是最简单的做法。

不需要破坏DWG,explode是在DBX中进行的,对DWG没有任何影响
回复

使用道具 举报

发表于 2025-2-28 14:56:15 | 显示全部楼层
楼主搞得过于复杂,实际上不存在嵌套块的处理

帮你修改了一下
  1. (defun c:DrawCircleAtBlockText (/       ACADDOC    BLKS
  2.         CIRCLE       DIA    FOUNDCOUNT
  3.         STR       TEXTPT    TOTALBLOCKS
  4.         *error*       process-block-def
  5.              )
  6.   (vl-load-com)

  7.   ;; 错误处理函数
  8.   (defun *error* (msg)
  9.     (if  acadDoc
  10.       (vla-EndUndoMark acadDoc)
  11.     )
  12.     (princ (strcat "\n[DEBUG] 错误: " msg))
  13.     (princ)
  14.   )
  15.   ;; 块定义处理
  16.   (defun process-block-def (blkDef str dia / found)
  17.     (setq found 0)
  18.     (vlax-for obj blkDef
  19.       (if (and (or (= (vla-get-ObjectName obj) "AcDbText")
  20.        (= (vla-get-ObjectName obj) "AcDbMText")
  21.          )
  22.          (= (strcase (vla-get-TextString obj)) (strcase str))
  23.     )
  24.   (progn
  25.     (setq found (1+ found))
  26.     (setq textPt (vla-get-InsertionPoint obj))
  27.     (setq circle (vla-addcircle blkDef textPt (* dia 0.5)))
  28.     (vla-put-layer circle "M-0-E")
  29.   )
  30.       )
  31.     )
  32.     found
  33.   )


  34.   (setq foundCount 0)      ; 设置计数器为全局变量
  35.   (setq  acadDoc  (vla-get-ActiveDocument (vlax-get-acad-object))
  36.   blks  (vla-get-Blocks acadDoc)
  37.   )

  38.   ;; 处理图层
  39.   (if (not (tblsearch "layer" "M-0-E"))
  40.     (entmake '((0 . "LAYER")
  41.          (100 . "AcDbSymbolTableRecord")
  42.          (100 . "AcDbLayerTableRecord")
  43.          (70 . 0)
  44.          (6 . "Continuous")
  45.          (2 . "M-0-E")
  46.          (62 . 6)
  47.         )
  48.     )
  49.   )
  50.   ;; 获取并验证文字输入
  51.   (while (= (setq str (getstring "\n请输入需要查找的文字内容: ")) "")
  52.     (princ "\n[DEBUG] 错误: 文字内容不能为空,请重新输入")
  53.   )

  54.   ;; 获取并验证直径输入
  55.   (while (<= (setq dia (getdist "\n请输入圆形直径: ")) 0.0)
  56.     (princ "\n[DEBUG] 错误: 直径必须大于0,请重新输入")
  57.   )

  58.   (vla-StartUndoMark acadDoc)
  59.   (setq totalBlocks (vla-get-count blks))
  60.   (acet-ui-progress "开始处理..." totalBlocks)
  61.   (vlax-for blkDef blks
  62.     (acet-ui-progress -1)
  63.     (setq foundCount
  64.      (+ foundCount (process-block-def blkDef str dia))
  65.     )
  66.   )
  67.   (acet-ui-progress)
  68.   (princ
  69.     (strcat "\n[DEBUG] 已成功创建 " (itoa foundCount) " 个圆形")
  70.   )
  71.   (vla-EndUndoMark acadDoc)
  72.   (vla-Regen acadDoc acActiveViewport)
  73.   (princ)
  74. )


点评

把圆画到块里面去了。。。。他需要圆在块外面。  发表于 2025-2-28 15:11
回复

使用道具 举报

 楼主| 发表于 2025-3-3 22:22:52 | 显示全部楼层

求大佬赐教 点播
回复

使用道具 举报

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

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-4-19 05:56 , Processed in 0.218478 second(s), 33 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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