明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1085|回复: 12

[讨论] 代码求助-采用lisp统计CAD图中不同名称块的数量

[复制链接]
发表于 2024-6-5 14:26:40 | 显示全部楼层 |阅读模式
写了一段AutoLISP代码用来统计AutoCAD中所有图块的数量,并根据图块名称进行分类统计。但是运行一直报错错误: 参数类型错误: numberp: nil,,请高人指点怎么调试,谢谢了。

  1. (defun c:count-blocks-by-name ()
  2.   (setq ss (ssget "X" '((0 . "INSERT"))))
  3.   (if (not ss)
  4.     (alert "没有找到图块。")
  5.     (progn
  6.       (setq block-count (list)) ; 初始化一个空的列表来存储图块名称和计数
  7.       (repeat (sslength ss)
  8.         (setq ent (ssname ss i))
  9.         (setq obj (entget ent))
  10.         (if obj ; 确保 obj 不是 nil
  11.           (progn
  12.             (setq block-name (cdr (assoc 2 obj))) ; 获取图块名称
  13.             ;; 检查 block-name 是否为文字类型,如果是,则直接使用
  14.             ;; AutoLISP 中字符串默认为文字类型,不需要额外转换
  15.             (setq found nil)
  16.             (foreach b block-count
  17.               (if (and b (= (cdr b) block-name))
  18.                 (progn
  19.                   (setq found t)
  20.                   (setq count (car b))
  21.                   (setq new-count (+ count 1))
  22.                   (setcar b new-count)
  23.                 )
  24.               )
  25.             )
  26.             (if (not found)
  27.               ;; 添加新图块名称和计数,初始化计数为1
  28.               (setq block-count (cons (cons 1 block-name) block-count))
  29.             )
  30.           )
  31.         )
  32.       )
  33.       ;; 对列表进行排序,这里使用长度排序
  34.       (setq block-count (sort block-count '(lambda (a b) (> (car a) (car b)))))
  35.       (setq total-count 0)
  36.       (foreach b block-count
  37.         (setq count (car b))
  38.         (setq block-name (cdr b))
  39.         (setq total-count (+ total-count count))
  40.         (alert (strcat "图块 '" block-name "' 的数量: " (itoa count)))
  41.       )
  42.       (alert (strcat "总图块数量: " (itoa total-count)))
  43.     )
  44.   )
  45.   (princ)
  46. )

发表于 2024-6-6 19:05:43 | 显示全部楼层
本帖最后由 你有种再说一遍 于 2024-6-6 19:54 编辑

给你一个c#代码看看,主要这个map在lisp上面实现困难,所以不建议用lisp做这个功能...
这里的代码还有两个优化的地方.
一个缺少并行.
一个如果在画图的时候就加入集合,岂不是0秒获取.


  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Diagnostics;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading.Tasks;

  11. namespace 统计块参照分类
  12. {
  13.     public class Class1
  14.     {
  15.         
  16.         [CommandMethod("test2")]
  17.         public void BlkRefCount2()
  18.         {
  19.             var doc = Application.DocumentManager.MdiActiveDocument;
  20.             var acDocEd = doc.Editor;
  21.             var db = doc.Database;
  22.             Dictionary<string, int> map = new Dictionary<string, int>();
  23.             Stopwatch stopwatch = new Stopwatch();
  24.             stopwatch.Start();
  25.             using (Transaction trans = db.TransactionManager.StartTransaction())
  26.             {
  27.                 BlockTable bt = (BlockTable)trans.GetObject(db.BlockTableId, OpenMode.ForRead);//BlockTableId 一定是ok
  28.                 foreach (ObjectId btrObjId in bt)//遍历所有的块表记录,不是当前块表 db.CurrentSpaceId,因为布局中也可能会有块
  29.                 {
  30.                     if (!btrObjId.IsOk()) continue;
  31.                     BlockTableRecord btr = (BlockTableRecord)trans.GetObject(btrObjId, OpenMode.ForRead);
  32.                     foreach (ObjectId obj in btr)
  33.                     {
  34.                         if (!obj.IsOk()) continue;
  35.                         Entity ent = (Entity)trans.GetObject(obj, OpenMode.ForRead);
  36.                         if (ent is BlockReference blkref)
  37.                         {
  38.                             var name = blkref.GetBlockName();
  39.                             if (!map.ContainsKey(name))
  40.                             {
  41.                                 map.Add(name, 0);
  42.                             }
  43.                             map[name]++;
  44.                         }
  45.                     }
  46.                 }
  47.             }
  48.             stopwatch.Stop();
  49.             TimeSpan elapsed = stopwatch.Elapsed;
  50.             double elapsedMillisecondsDouble = stopwatch.ElapsedMilliseconds;
  51.             double microsecondsFraction = (elapsedMillisecondsDouble - Math.Truncate(elapsedMillisecondsDouble)) * 1000; // 获取毫秒的小数部分并转换为微秒  
  52.             acDocEd.WriteMessage($"程序运行了 {stopwatch.Elapsed.Hours:00}:{stopwatch.Elapsed.Minutes:00}:{stopwatch.Elapsed.Seconds:00}.{elapsedMillisecondsDouble:0.000} 秒\n");
  53.             foreach (var pair in map)
  54.             {
  55.                 acDocEd.WriteMessage($"Name: {pair.Key}, Count: {pair.Value}\n");
  56.             }
  57.         }
  58.     }
  59.     public static partial class BlockHelper
  60.     {
  61.         /// <summary>
  62.         /// 动态块真实块名获取
  63.         /// </summary>
  64.         /// <param name="brRec">块参照</param>
  65.         /// <returns>成功返回:块的真实名称,失败返回:null</returns>
  66.         // 1.块的Z比例是0就会令动态块变成普通块,那么导致判断动态块失效
  67.         // 2.brRec.IsDynamicBlock 如果是动态块这句会报错:eInvalidObjectId
  68.         //   重复空格执行上次报这个错误,应该在所有GetObject位置写.Dispose();
  69.         public static string GetBlockName(this BlockReference blkref)
  70.         {
  71.             string blockName = string.Empty;
  72.             if (blkref.DynamicBlockTableRecord.IsOk())
  73.             {
  74.                 // 动态块表记录可以获取 动态块名 也可以获取 普通块名
  75.                 var btRec = blkref.DynamicBlockTableRecord.GetObject(OpenMode.ForRead) as BlockTableRecord;
  76.                 blockName = btRec.Name;
  77.                 btRec.Dispose();
  78.             }
  79.             return blockName;
  80.         }
  81.     }
  82.     public static partial class EntityEdit
  83.     {
  84.         /// <summary>
  85.         /// id有效,未被删除
  86.         /// </summary>
  87.         /// <param name="id"></param>
  88.         /// <returns></returns>
  89.         public static bool IsOk(this ObjectId id)
  90.         {
  91.             return !id.IsNull && id.IsValid && !id.IsErased && !id.IsEffectivelyErased && id.IsResident;
  92.         }
  93.     }
  94. }


 楼主| 发表于 2024-6-7 13:14:58 | 显示全部楼层
你有种再说一遍 发表于 2024-6-6 19:05
给你一个c#代码看看,主要这个map在lisp上面实现困难,所以不建议用lisp做这个功能...
这里的代码还有两个优 ...

谢谢大佬。这个可以直接在CAD里面调用吗,改成lisp直接调用。
 楼主| 发表于 2024-6-5 22:51:31 | 显示全部楼层
你有种再说一遍 发表于 2024-6-5 20:18
但是这个题目很有意思啊,至于为什么,可能你感觉不到,我之后再来告诉你

大佬,看了你的连载文章,我是完全看不懂,但是感觉说的深度不是一般人能够企及的。膜拜下
发表于 2024-6-5 16:12:50 | 显示全部楼层
还缺函数呀
发表于 2024-6-5 16:22:29 | 显示全部楼层
扣莲哦,怎么写不出呢
发表于 2024-6-5 16:46:56 | 显示全部楼层
BCOUNT命令就能干的事,何必自己撸代码
 楼主| 发表于 2024-6-5 18:08:26 | 显示全部楼层
kozmosovia 发表于 2024-6-5 16:46
BCOUNT命令就能干的事,何必自己撸代码

我用的是autocad 2020,  好像CAD2022 以上有count命令可以统计
 楼主| 发表于 2024-6-5 18:09:52 | 显示全部楼层
kozmosovia 发表于 2024-6-5 16:46
BCOUNT命令就能干的事,何必自己撸代码

YYDS,试了下Bcount命令,低版本CAD也可以统计,谢谢大哥
发表于 2024-6-5 20:18:10 | 显示全部楼层
yimiyangguang55 发表于 2024-6-5 18:09
YYDS,试了下Bcount命令,低版本CAD也可以统计,谢谢大哥

但是这个题目很有意思啊,至于为什么,可能你感觉不到,我之后再来告诉你
发表于 2024-6-6 12:28:21 | 显示全部楼层
CAD2024自带这个功能,自动生成数量统计表格,删除块数量也会改。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-11-25 15:45 , Processed in 0.197609 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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