明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
123
返回列表 发新帖
楼主: ynhh

[源码] 批量合并图纸又快又避免同名块影响,AI编写的

  [复制链接]
发表于 昨天 17:22 | 显示全部楼层

在CAD图纸里有多个布局和一个模型空间,每个布局的图框和位置基本上是一致的。

目标:
1、把多个布局合并到一个布局里
2、可选需要合并的布局数量和合并后的布局
3、是否删除旧的布局,建议默认删除
4、保持合并后的布局排版,建议横向排列,图框间距 50~100mm

是否可以用lisp语言实现这些功能

用国内免费的ai 测试了几个 运行中均出现错误

回复 支持 反对

使用道具 举报

发表于 昨天 18:08 | 显示全部楼层
ai的代码 还有不少问题 排版还是有问题



  1. ;;; MergeLayouts.lsp
  2. ;;; 功能:合并多个布局到一个布局(支持块图框 + 多视口)
  3. ;;; 兼容 AutoCAD 2012 – 2024 标准版(无需 DCL,无 vl-choice-list)

  4. (vl-load-com)
  5. ; 快捷命令
  6. (defun c:tt2 () (c:MergeLayouts))
  7. (defun c:tr2 () (c:MergeLayouts))

  8. (princ "\n命令已加载,输入 SIDECUT 或 tt2 启动")
  9. (princ)

  10. ;;; MergeLayouts.lsp
  11. ;;; 功能:合并多个布局到一个布局(支持块图框 + 多视口)
  12. ;;; 兼容 AutoCAD 2012 – 2024 标准版 | 无 DCL | 无第三方依赖

  13. ;;; MergeLayouts.lsp
  14. ;;; 功能:合并多个布局到一个布局(支持块图框 + 多视口)
  15. ;;; 兼容 AutoCAD 2012 – 2024 标准版 | 无 DCL | 自动创建视口

  16. (vl-load-com)

  17. (defun c:MergeLayouts (/ doc layouts allLayoutNames srcNames tgtName
  18.                         delSrc? cols row col basePt offsetVec
  19.                         entsToCopy bbox width height newInsertPt layoutObj
  20.                         input indices)

  21.   (setq doc (vla-get-ActiveDocument (vlax-get-acad-object)))
  22.   (setq layouts (vla-get-Layouts doc))

  23.   ;; 获取所有非 Model 布局名称
  24.   (setq allLayoutNames '())
  25.   (vlax-for layout layouts
  26.     (setq layName (vla-get-Name layout))
  27.     (if (/= (strcase layName) "MODEL")
  28.       (setq allLayoutNames (cons layName allLayoutNames))
  29.     )
  30.   )
  31.   (setq allLayoutNames (reverse allLayoutNames))

  32.   ;; 检查布局数量
  33.   (if (< (length allLayoutNames) 2)
  34.     (progn
  35.       (alert "至少需要两个布局(不含 Model)才能合并!")
  36.       (princ)
  37.       (exit)
  38.     )
  39.   )

  40.   ;; ========== 选择源布局(编号多选)==========
  41.   (princ "\n可用布局列表:")
  42.   (setq i 0)
  43.   (foreach name allLayoutNames
  44.     (princ (strcat "\n  [" (itoa (setq i (1+ i))) "] " name))
  45.   )
  46.   (princ "\n\n请输入要合并的源布局编号(空格分隔,例如: 1 3 4): ")
  47.   (setq input (getstring T))
  48.   (if (= input "") (exit))

  49.   ;; 安全解析输入
  50.   (if (wcmatch (strcat " " input " ") "*[~ 0-9 ]*")
  51.     (progn
  52.       (alert "输入格式错误!\n请只输入数字,用空格分隔(如: 1 2 3)。")
  53.       (exit)
  54.     )
  55.   )

  56.   (setq indices (read (strcat "(" (vl-string-trim " " input) ")")))
  57.   (if (atom indices) (setq indices (list indices)))

  58.   (setq srcNames
  59.     (vl-remove-if-not
  60.       '(lambda (idx) (and (>= idx 1) (<= idx (length allLayoutNames))))
  61.       indices
  62.     )
  63.   )
  64.   (if (null srcNames)
  65.     (progn (alert "未选择任何有效布局!") (exit))
  66.   )
  67.   (setq srcNames
  68.     (mapcar '(lambda (i) (nth (1- i) allLayoutNames)) srcNames)
  69.   )
  70.   ;; ========== 源布局选择结束 ==========

  71.   ;; ========== 选择目标布局 ==========
  72.   (setq candidates (vl-remove-if '(lambda (x) (member x srcNames)) allLayoutNames))
  73.   (cond
  74.     (candidates
  75.       (princ "\n可选目标布局:")
  76.       (setq i 0)
  77.       (foreach name candidates
  78.         (princ (strcat "\n  [" (itoa (setq i (1+ i))) "] " name))
  79.       )
  80.       (princ "\n\n输入目标布局编号,或直接回车新建布局: ")
  81.       (setq input (getstring T))
  82.       (if (= input "")
  83.         (setq tgtName (getstring "\n输入新布局名称 <Merged_Layout>: "))
  84.         (progn
  85.           (if (wcmatch input "*[~0-9]*")
  86.             (setq tgtName "Merged_Layout")
  87.             (progn
  88.               (setq idx (atoi input))
  89.               (if (and (>= idx 1) (<= idx (length candidates)))
  90.                 (setq tgtName (nth (1- idx) candidates))
  91.                 (setq tgtName "Merged_Layout")
  92.               )
  93.             )
  94.           )
  95.         )
  96.       )
  97.     )
  98.     (T
  99.       (setq tgtName (getstring "\n输入新布局名称 <Merged_Layout>: "))
  100.     )
  101.   )
  102.   (if (= tgtName "") (setq tgtName "Merged_Layout"))

  103.   ;; 创建目标布局(如果不存在)
  104.   (if (not (member tgtName allLayoutNames))
  105.     (vla-Add layouts tgtName)
  106.   )

  107.   ;; &#9989; 关键修正:确保目标布局有活动视口
  108.   (EnsureActiveViewport tgtName)

  109.   ;; 是否删除源布局?
  110.   (initget "是 否")
  111.   (setq delSrc?
  112.     (= (getkword "\n是否删除源布局?[是/否] <否>: ") "是")
  113.   )

  114.   ;; 清空目标布局(保留一个视口)
  115.   (ClearLayout tgtName)

  116.   ;; ========== 合并处理 ==========
  117.   (setq cols 2) ; 每行布局数量
  118.   (setq row 0)
  119.   (setq col 0)

  120.   (foreach layName srcNames
  121.     (princ (strcat "\n正在处理布局: " layName))
  122.     (setq layoutObj (vla-Item layouts layName))
  123.     (setq entsToCopy (ssget "_X" (list (cons 410 layName))))

  124.     (if entsToCopy
  125.       (progn
  126.         (setq basePt (GetFrameBasePoint entsToCopy))
  127.         (if (null basePt) (setq basePt '(0.0 0.0 0.0)))

  128.         (setq bbox (GetLayoutBoundingBox entsToCopy))
  129.         (if bbox
  130.           (progn
  131.             (setq width (- (car (cadr bbox)) (car (car bbox))))
  132.             (setq height (- (cadr (cadr bbox)) (cadr (car bbox))))
  133.           )
  134.           (progn
  135.             (setq width 1189.0) ; A3 宽 (mm)
  136.             (setq height 841.0) ; A3 高 (mm)
  137.           )
  138.         )

  139.         (setq newInsertPt
  140.           (list
  141.             (+ (* col (+ width 20.0)) 10.0)
  142.             (- (* row (+ height 20.0)) 10.0)
  143.             0.0
  144.           )
  145.         )
  146.         (setq offsetVec (mapcar '- newInsertPt basePt))
  147.         (CopyAndMoveEntities entsToCopy tgtName offsetVec)
  148.       )
  149.     )

  150.     (setq col (1+ col))
  151.     (if (>= col cols) (setq col 0 row (1+ row)))

  152.     (if delSrc? (vla-Delete layoutObj))
  153.   )

  154.   (setvar "CTAB" tgtName)
  155.   (princ (strcat "\n&#9989; 合并完成!目标布局: " tgtName))
  156.   (princ)
  157. )

  158. ;; ========== 确保布局有活动视口 ==========
  159. (defun EnsureActiveViewport (layName / doc layouts)
  160.   (setq doc (vla-get-ActiveDocument (vlax-get-acad-object)))
  161.   (setq layouts (vla-get-Layouts doc))
  162.   
  163.   ;; 切换到目标布局
  164.   (setvar "CTAB" layName)
  165.   
  166.   ;; 检查是否存在视口
  167.   (setq hasViewport nil)
  168.   (vlax-for obj (vla-get-Block (vla-Item layouts layName))
  169.     (if (= (vla-get-ObjectName obj) "AcDbViewport")
  170.       (setq hasViewport T)
  171.     )
  172.   )
  173.   
  174.   ;; 如果没有视口,创建默认视口
  175.   (if (not hasViewport)
  176.     (progn
  177.       (princ (strcat "\n  &#9888;&#65039; 布局 " layName " 无视口,正在创建默认视口..."))
  178.       (command "_.MVIEW" "_FIT")
  179.       ;; 等待命令完成
  180.       (while (> (getvar "CMDACTIVE") 0)
  181.         (command)
  182.       )
  183.     )
  184.   )
  185. )

  186. ;; ========== 安全获取点坐标 ==========
  187. (defun GetPointSafe (obj prop / pt)
  188.   (setq pt (vlax-get obj prop))
  189.   (cond
  190.     ((listp pt) pt)
  191.     ((= (type pt) 'variant)
  192.       (vlax-safearray->list (vlax-variant-value pt))
  193.     )
  194.     (T nil)
  195.   )
  196. )

  197. ;; ========== 获取图框块插入点 ==========
  198. (defun GetFrameBasePoint (ss / i ent obj pt)
  199.   (setq i 0 pt nil)
  200.   (repeat (sslength ss)
  201.     (if (null pt)
  202.       (progn
  203.         (setq ent (ssname ss i))
  204.         (setq obj (vlax-ename->vla-object ent))
  205.         (if (= (vla-get-ObjectName obj) "AcDbBlockReference")
  206.           (setq pt (GetPointSafe obj 'InsertionPoint))
  207.         )
  208.       )
  209.     )
  210.     (setq i (1+ i))
  211.   )
  212.   pt
  213. )

  214. ;; ========== 获取布局包围盒 ==========
  215. (defun GetLayoutBoundingBox (ss / minPt maxPt globalMin globalMax i ent obj)
  216.   (setq i 0 globalMin nil globalMax nil)
  217.   (repeat (sslength ss)
  218.     (setq ent (ssname ss i))
  219.     (setq obj (vlax-ename->vla-object ent))
  220.     (if (not (wcmatch (vla-get-ObjectName obj) "*Viewport"))
  221.       (progn
  222.         (vla-GetBoundingBox obj 'minPt 'maxPt)
  223.         (if (null globalMin)
  224.           (setq globalMin minPt globalMax maxPt)
  225.           (progn
  226.             (setq globalMin (MapMinMax globalMin minPt 'min))
  227.             (setq globalMax (MapMinMax globalMax maxPt 'max))
  228.           )
  229.         )
  230.       )
  231.     )
  232.     (setq i (1+ i))
  233.   )
  234.   (if globalMin
  235.     (list
  236.       (vlax-safearray->list globalMin)
  237.       (vlax-safearray->list globalMax)
  238.     )
  239.   )
  240. )

  241. ;; ========== 向量 min/max ==========
  242. (defun MapMinMax (v1 v2 op / x1 y1 z1 x2 y2 z2)
  243.   (setq x1 (vlax-safearray-get-element v1 0)
  244.         y1 (vlax-safearray-get-element v1 1)
  245.         z1 (vlax-safearray-get-element v1 2)
  246.         x2 (vlax-safearray-get-element v2 0)
  247.         y2 (vlax-safearray-get-element v2 1)
  248.         z2 (vlax-safearray-get-element v2 2)
  249.   )
  250.   (vlax-safearray-fill
  251.     (vlax-make-safearray vlax-vbDouble '(0 . 2))
  252.     (list
  253.       ((if (= op 'min) min max) x1 x2)
  254.       ((if (= op 'min) min max) y1 y2)
  255.       ((if (= op 'min) min max) z1 z2)
  256.     )
  257.   )
  258. )

  259. ;; ========== 复制并移动实体 ==========
  260. (defun CopyAndMoveEntities (ss tgtLayoutName offset / oldCTAB i ent obj newEnt doc)
  261.   (setq doc (vla-get-ActiveDocument (vlax-get-acad-object)))
  262.   (setq oldCTAB (getvar "CTAB"))
  263.   (setvar "CTAB" tgtLayoutName)

  264.   (setq i 0)
  265.   (repeat (sslength ss)
  266.     (setq ent (ssname ss i))
  267.     (setq obj (vlax-ename->vla-object ent))
  268.     ;; 跳过主视口:保留第一个视口(由 ClearLayout 保证存在)
  269.     (if (/= (vla-get-ObjectName obj) "AcDbViewport")
  270.       (progn
  271.         (setq newEnt (vla-Copy obj))
  272.         (vla-Move newEnt (vlax-3d-point '(0 0 0)) (vlax-3d-point offset))
  273.       )
  274.       ;; 视口也复制(但 ClearLayout 已清空,所以这里不会重复)
  275.       (progn
  276.         (setq newEnt (vla-Copy obj))
  277.         (vla-Move newEnt (vlax-3d-point '(0 0 0)) (vlax-3d-point offset))
  278.       )
  279.     )
  280.     (setq i (1+ i))
  281.   )

  282.   (setvar "CTAB" oldCTAB)
  283. )

  284. ;; ========== 清空布局(保留第一个视口)==========
  285. (defun ClearLayout (layName / oldCTAB doc layoutObj firstVP ss i ent obj)
  286.   (setq doc (vla-get-ActiveDocument (vlax-get-acad-object)))
  287.   (setq oldCTAB (getvar "CTAB"))
  288.   (setvar "CTAB" layName)
  289.   (setq layoutObj (vla-Item (vla-get-Layouts doc) layName))

  290.   ;; 找到第一个视口(用于保留)
  291.   (setq firstVP nil)
  292.   (vlax-for obj (vla-get-Block layoutObj)
  293.     (if (and (= (vla-get-ObjectName obj) "AcDbViewport") (null firstVP))
  294.       (setq firstVP obj)
  295.     )
  296.   )

  297.   ;; 删除所有实体,除了第一个视口
  298.   (setq ss (ssget "_X" (list (cons 410 layName))))
  299.   (if ss
  300.     (progn
  301.       (setq i 0)
  302.       (repeat (sslength ss)
  303.         (setq ent (ssname ss i))
  304.         (setq obj (vlax-ename->vla-object ent))
  305.         (if (or (/= (vla-get-ObjectName obj) "AcDbViewport")
  306.                 (/= obj firstVP))
  307.           (vla-delete obj)
  308.         )
  309.         (setq i (1+ i))
  310.       )
  311.     )
  312.   )

  313.   (setvar "CTAB" oldCTAB)
  314. )

  315. ;; ========== 字符串工具 ==========
  316. (defun vl-string-trim (chars str / len)
  317.   (while (and (> (strlen str) 0) (vl-position (ascii (substr str 1 1)) (vl-string->list chars)))
  318.     (setq str (substr str 2))
  319.   )
  320.   (while (and (> (strlen str) 0) (vl-position (ascii (substr str (strlen str) 1)) (vl-string->list chars)))
  321.     (setq str (substr str 1 (1- (strlen str))))
  322.   )
  323.   str
  324. )

  325. (defun vl-string->list (str / i lst)
  326.   (setq i 0 lst '())
  327.   (while (< i (strlen str))
  328.     (setq lst (cons (ascii (substr str (setq i (1+ i)) 1)) lst))
  329.   )
  330.   (reverse lst)
  331. )

  332. (princ "\n命令 MERGELAYOUTS 已加载。")
  333. (princ "\n&#9989; 支持:块图框 + 多视口 + 自动创建默认视口")
  334. (princ "\n&#9989; 兼容 AutoCAD 2012 – 2024 标准版")
  335. (princ "\n&#128204; 使用方法:输入 MERGELAYOUTS,按编号选择布局。")
  336. (princ)


回复 支持 反对

使用道具 举报

发表于 昨天 18:09 | 显示全部楼层
qifeifei 发表于 2025-11-1 13:48
DCL和LSP源码文件在此,程序非常好用,但有几个小问题:
1、程序在每打开的一幅图中只能用一次,再次用就 ...

刘明,明天再来下载
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-11-3 07:38 , Processed in 0.165508 second(s), 20 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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