在CAD文件中存储扩展数据

news/2024/12/25 15:52:19/文章来源:https://www.cnblogs.com/yyy2023/p/18588915

基础知识:

  根据CAD官方的资料看来,Database作为一个CAD文件数据库的根对象,其包含10个子对象:九大符号表(SymbolTable)和命名对象词典(NamedObjectsDictionary)。

   这10个子对象属于整个数据库内的最高层级,直属于Database。除这10个子对象以外,所有DBObject对象都必须有一个所有者(Owner),这个所有者可以是其它的DBObject,或者是这10个子对象之一。因此,整个数据库是一个树形结构,存在于数据库中的对象都直接或间接地属于这10个子对象。

  根据数据库的树形结构,所有DBObject对象根据其自身类别,分别属于不同对象。比如:BlockTable中包含多个BlockTableRecord,某个BlockTableRecord又包含多个Entity,其中每个Entity的存在都依赖于其BlockTableRecord的存在。各种信息就是这样分门别类地存储在数据库中。内存中New()生成的对象要加入数据库中,需要调用数据库中已存在的某个对象对应的方法才行,比如;blockTableRecord.AppendEntity(Entity entity);加入后要使用Database.AddNewlyCreatedDBObject(DBObject obj,bool add)方法进行确认。

存储扩展数据的方式:

  为便于扩展,Autodesk设计了多种方式存储用户自定义的数据。“这些数据由开发者自己进行解释 ,CAD不管其含义,扩展数据以吸附物的形式吸附在实体上”。其中资料最多的是XData形式,其次有XRecord和DataTable。几种方式各有异同。

  在了解这三种方法之前,先要了解两个基础知识:ResultBuffer类和DBDictionary类。

  ResultBuffer是一个键值对集合,key是一个DxfCode(short),value是对应的某个类型的object,其本质就是一个Dxf组码表,其中的数据必须按照Dxf组码类型表进行存储。一个ResultBuffer对象最高存储128K的数据。

  DBDictionary也是一个键值对集合,key是一个开发者自行指定的string,value是一个DBObject实例。

  DBDictionary可以作为附加数据依附在一个DBObject实例上,存储和这个DBObject相关的数据,访问方式为DBObject.ExtensionDictionary。依附于一个DBObject的DBDictionary会随着这个DBObject的删除而删除。类似的,DBDictionary也可以依附于Database存储全局数据;访问方式为Database.NamedObjectsDictionaryId。

  由于九大符号表无法满足所有的数据存储需求,特别是新版本增加功能的同时还要保证向下兼容,很多数据存储是借助于Database的命名对象词典完成的,可以自行遍历求证。

  所有的Entity只能存储在BlockTableRecord下,因此Entity不能直接存入DBDictionary。

  不可以把已经添加到Database中的DBObcect添加进DBDictionary,添加操作完成后要使用Database.AddNewlyCreatedDBObject(DBObject obj,bool add)方法进行确认。

XData:

  XData是最简便的附加自定义数据的方式,使用的是ResultBuffer数据类型。

  一个DBObject附加的XData最多只能存储16K的数据,不同的DxfCode对应的存储空间也有最大值限制。

  XData中存储的某些数据可以跟随CAD环境或者Entity进行变化而无需开发者参与,其它语言也能轻松访问,这是使用XData的优势。

  由于存储量的限制,XData方式只适合存储少量数据;并且其中Value的类型必须和DxfCode相对应,限制了它的灵活性。

  大致流程如下:

  1、new一个ResultBuffer,然后调用其Add(new TypedValue((int)code, Value))方法添加键值对。

  2、写模式打开DBObject,赋值Obj.XData = ResultBuffer。

  3、读:ResultBuffer resultBuffer=Obj.XData。

  注意点如下:

  1、为区分不同的用户(开发者),对于DBObject.XData赋值的时候要求:写入的ResultBuffer第一个键值对须使用new TypedValue((int)DxfCode.ExtendedDataRegAppName, AppName),以此来区分不同的用户(开发者);具有不同AppName开始的ResultBuffer在赋值的时候不会相互覆盖。需要读数据时,使用Obj.GetXDataForApplication(AppName)可以只读自己写入的那一段。

  2、写入带有DxfCode.ExtendedDataRegAppName键值对的ResultBuffer的时候,要求AppName在Database中是注册过的。因此,在写入带AppName的ResultBuffer之前,应进行两个操作:将DBObject加入Database,在Database的RegAppTable中注册AppName。

  3、写入的键值对要求DxfCode不小于DxfCode.ExtendedDataAsciiString(1000),可以去查看Dxf组码类型表,小于DxfCode.ExtendedDataAsciiString(1000)的是属于“原生”的组码,这些组码在CAD中有其专有用途,因此不对XData开放。大于等于的是属于“扩展”的,用于存储二次开发的信息。

  4、除DxfCode.ExtendedDataRegAppName外,ResultBuffer中允许连续或间断写入相同的Dxf组码的内容。

  5、写入的部分数据会跟随Entity的Transform而发生改变。利用这个设定,可以达到一些特定的目的,比如将Entity上的特殊点以XData的形式记录在Entity上,当客户利用CAD原生的Move、Rotate等命令操作此Entity时,这些点将跟随同步变化;再如,通过判断Scale是否发生改变来判断客户是否对该实体进行过缩放操作。需要注意的是,这些数据只对Entity整体的Transform敏感,客户的某些操作不会触发Transform操作,因此这些操作不会导致XData发生变化,比如客户使用STRETCH命令拉伸了多段线的部分节点。

  6、XData的数据在写入和读出的时候可能发生类型转换,这很容易导致在验证之前存入的数据时发生意料之外的情况,具体可自行测试。

  具体可参考如下代码:

  

  1 namespace MichSpace.Tests
  2 {
  3     public static class XDataDemo
  4     {
  5         static string AppName = "XDataDemoAppName";
  6         public static void WriteXDataDemo()
  7         {
  8             var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.CurrentDocument;
  9             if (doc == null) return;
 10             var db = doc.Database;
 11             var ed = doc.Editor;
 12             var pResult = ed.GetEntity("选择一个Entity"+"\n");
 13             if (pResult.Status!= Autodesk.AutoCAD.EditorInput.PromptStatus.OK) { ed.WriteMessage("选择Entity失败,退出"+"\n"); return; }
 14             RegisterAppName(db, AppName);
 15             RegisterAppName(db, AppName+"2");
 16             var xData = CreatNewXData();
 17             var xData2 = CreatNewXData2();
 18             using (var trans = db.TransactionManager.StartTransaction())
 19             {
 20                 var ent = trans.GetObject(pResult.ObjectId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite);
 21                 ent.XData = xData;//此处使用的赋值语句
 22                                   //CAD内部好像进行了额外的处理
 23                                   //比如验证AppName是否已注册、验证该实体的XData中是否已有相同的AppName的XData
 24                 ent.XData = xData2;//第二次赋值不会覆盖第一次的赋值,因为两个XData的AppName不相同
 25                 ed.WriteMessage("写入XData成功"+"\n");
 26                 trans.Commit();
 27             }
 28         }
 29         public static void ReadXDataDemo()
 30         {
 31             var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.CurrentDocument;
 32             if (doc == null) return;
 33             var db = doc.Database;
 34             var ed = doc.Editor;
 35             var pResult = ed.GetEntity("选择一个Entity"+"\n");
 36             if (pResult.Status!= Autodesk.AutoCAD.EditorInput.PromptStatus.OK) { ed.WriteMessage("选择Entity失败,退出"+"\n"); return; }
 37             using (var trans = db.TransactionManager.StartTransaction())
 38             {
 39                 var ent = trans.GetObject(pResult.ObjectId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite);
 40                 var xData = ent.XData;//获取全部XData
 41                                       //     xData=ent.GetXDataForApplication(AppName);//获取指定应用的XData
 42                 PrintXData(xData, ed);
 43             }
 44         }
 45         public static void ClearXDataDemo()
 46         {
 47             var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.CurrentDocument;
 48             if (doc == null) return;
 49             var db = doc.Database;
 50             var ed = doc.Editor;
 51             var pResult = ed.GetEntity("选择一个Entity"+"\n");
 52             if (pResult.Status!= Autodesk.AutoCAD.EditorInput.PromptStatus.OK) { ed.WriteMessage("选择Entity失败,退出"+"\n"); return; }
 53             RegisterAppName(db, AppName);
 54            
 55             using (var trans = db.TransactionManager.StartTransaction())
 56             {
 57                 var ent = trans.GetObject(pResult.ObjectId, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite);
 58                 //这两种方法不能清除XData
 59                 //ent.XData=null;
 60                 //ent.XData=new ResultBuffer();
 61                 //测试通过的方法如下:
 62                 var xData = new ResultBuffer();
 63                 xData.Add(new TypedValue((int)DxfCode.ExtendedDataRegAppName, AppName));
 64                 //只能清除指定AppName的XData
 65                 //要清除全部XData,需要遍历所有AppName,并删除对应XData
 66                 ent.XData = xData;
 67                 ed.WriteMessage("清除XData成功。"+"\n");
 68                 trans.Commit();
 69             }
 70         }
 71         private static void RegisterAppName(Database db, string appName)
 72         {
 73             using (var trans = db.TransactionManager.StartTransaction())
 74             {
 75                 var regAppTable = trans.GetObject(db.RegAppTableId, OpenMode.ForRead) as RegAppTable;
 76                 if (!regAppTable.Has(appName))
 77                 {
 78                     regAppTable.UpgradeOpen();
 79                     var regAppTableRecord = new RegAppTableRecord();
 80                     regAppTableRecord.Name = appName;
 81                     regAppTable.Add(regAppTableRecord);
 82                     trans.AddNewlyCreatedDBObject(regAppTableRecord, true);
 83                     trans.Commit();
 84                 }
 85             }
 86         }
 87         private static ResultBuffer CreatNewXData()
 88         {
 89             var xData = new ResultBuffer();
 90             //插入了注册的应用名称,用于区分不同应用的XData
 91             xData.Add(new TypedValue((int)DxfCode.ExtendedDataRegAppName, AppName));
 92             //插入了一个字符串,用于记录需要的信息
 93             xData.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, "Point_1"));
 94             //插入了一个点的坐标,Entity发生Transform时,点的坐标也会发生变化
 95             xData.Add(new TypedValue((int)DxfCode.ExtendedDataWorldXCoordinate, new Point3d(100, 200, 300)));
 96             xData.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, "Point_2"));
 97             //使用相同的DxfCode插入了第二个点,两次插入的数据都会被保存在ResultBuffer中
 98             xData.Add(new TypedValue((int)DxfCode.ExtendedDataWorldXCoordinate, new Point3d(400, 500, 600)));
 99             xData.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, "Vector_1"));
100             //插入了一个向量,此处需要将向量转化为Point3d数据类型
101             //向量对旋转的Transform敏感,对平移和缩放不敏感
102             xData.Add(new TypedValue((int)DxfCode.ExtendedDataWorldXDir, new Point3d(100, 0, 0)));
103             xData.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, "scale"));
104             //插入了一个缩放因子,对平移和旋转不敏感
105             xData.Add(new TypedValue((int)DxfCode.ExtendedDataScale, 1.0));
106             xData.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, "Vector_2"));
107             xData.Add(new TypedValue((int)DxfCode.ExtendedDataWorldXDir, new Point3d(0, 200, 0)));
108             xData.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, "RealNumber"));
109             //插入了一个实数,不跟随Entity的Transform变化
110             xData.Add(new TypedValue((int)DxfCode.ExtendedDataReal, 1.0));
111             return xData;
112         }
113         private static ResultBuffer CreatNewXData2()
114         {
115             var xData = new ResultBuffer();
116             xData.Add(new TypedValue((int)DxfCode.ExtendedDataRegAppName, AppName+"2"));
117             xData.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, "APP2_Point_1"));
118             xData.Add(new TypedValue((int)DxfCode.ExtendedDataWorldXCoordinate, new Point3d(100, 200, 300)));
119             xData.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, "APP2_Point_2"));
120             return xData;
121         }
122         private static void PrintXData(ResultBuffer xData, Editor ed)
123         {
124             if (ed==null) return;
125             if (xData == null) { ed.WriteMessage("没有XData"+"\n"); return; }
126             ed.WriteMessage("XData内容:"+"\n");
127             foreach (TypedValue tv in xData)
128             {
129                 string s = "";
130                 s+=string.Format("{0,-8}", $"[{tv.TypeCode.ToString()}]");
131                 s+=string.Format("{0,-40}", $"[{tv.Value.GetType().ToString()}]");
132                 s+=string.Format("{0,-60}", $"[{tv.Value.ToString()}]");
133                 s+="\n";
134                 ed.WriteMessage(s);
135             }
136             //打印内容如下:
137             //[1001]  [System.String]                         [XDataDemoAppName]
138             //[1000]  [System.String]                         [Point_1]
139             //[1011]  [Autodesk.AutoCAD.Geometry.Point3d]     [(100,200,300)]
140             //[1000]  [System.String]                         [Point_2]
141             //[1011]  [Autodesk.AutoCAD.Geometry.Point3d]     [(400,500,600)]
142             //[1000]  [System.String]                         [Vector_1]
143             //[1013]  [Autodesk.AutoCAD.Geometry.Point3d]     [(100,0,0)]
144             //[1000]  [System.String]                         [scale]
145             //[1042]  [System.Double]                         [1]
146             //[1000]  [System.String]                         [Vector_2]
147             //[1013]  [Autodesk.AutoCAD.Geometry.Point3d]     [(0,200,0)]
148             //[1000]  [System.String]                         [RealNumber]
149             //[1040]  [System.Double]                         [1]
150             //[1001]  [System.String]                         [XDataDemoAppName2]
151             //[1000]  [System.String]                         [APP2_Point_1]
152             //[1011]  [Autodesk.AutoCAD.Geometry.Point3d]     [(100,200,300)]
153             //[1000]  [System.String]                         [APP2_Point_2]
154         }
155     }
156 }
View Code

XRecord:

tobecontinued

DataTable:

tobecontinued

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/858686.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人员聚集监测识别摄像机

人员聚集监测识别摄像机可以通过高清晰度的摄像头和先进的人脸识别技术,准确地识别出人群中的个体,并记录下他们的行踪和行为。在人员密集的场所,如商场、车站、体育场馆等,这种摄像机能够帮助安保人员更好地掌握人员活动的情况,及时发现异常情况,有效应对突发事件。除了…

CS61B srping 2018 lab03 https://sp18.datastructur.es/

Unit Testing with JUnit, Debugging 准备 装好 CS61B插件(emmmmm,不装也没事) 把lab2 的IntList.java 复制到 lab3/IntList 文件夹. 看看关于测试的课程视频 介绍 啊? JUnit是java测试框架,现在要用JUnit进行单元测试,单元Unit就是把程序分成小块的单元,一个单元的功…

摄像机实时接入分析平台视频分析网关:如何评估视频分析系统的性能?

在当今这个数字化、智能化快速发展的时代,视频分析系统已成为安全监控、交通管理、商业智能等多个领域不可或缺的技术支撑。这些系统的性能评估对于确保其有效性和可靠性至关重要。以下是对视频分析系统性能评估的关键指标和方法的详细探讨,这些评估将帮助我们深入了解系统的…

Protocol Buffers 使用笔记

Protocol Buffers 使用笔记created: 2024-03-04T11:11+08:00 modified: 2024-11-26T15:28+08:00 published: 2024-12-25T15:30+08:00 categories: applicationsProtocol Buffers 简称 protobuf 或者 PB,要解决的问题是这样的: 在互联网上传输大量数据,如果使用 json 等类似格…

域名解析平台有哪些

在互联网的广袤世界中,域名解析平台起着至关重要的作用,它们就像是互联网的 “导航仪”,将人们易于记忆的域名转换为计算机能够理解的 IP 地址,从而确保我们能够顺利访问各类网站和在线服务。域名解析的过程就是将域名翻译为对应的 IP 地址,使得浏览器能够准确地找到服务器…

Pycharm2024.3完整的安装教程(附激活,常见问题处理)

卸载老版本 Pycharm 首先,如果小伙伴的电脑上有安装老版本的Pycharm , 需要将其彻底卸载掉,如下所示(没有安装则不用管,直接安装即可): TIP:如果你之前使用过本站提供的 激活到 2025 年版本脚本,需要执行对应卸载脚本 /适用2024版本/JetBrains 2023 最新全家桶/jetbra /…

搭建npm私有仓库——verdaccio

前言Verdaccio 是一个简单的、零配置要求的本地私有 npm 注册表。无需整个数据库即可开始!Verdaccio 开箱即用,带有自己的小型数据库,并且能够代理其他注册表(例如 npmjs.org),并在此过程中缓存下载的模块。对于那些希望扩展其存储功能的人,Verdaccio 支持各种社区制作的…

门店协作的未来:协作文档如何提升客户体验?

汽车销售是一种高竞争、高需求精细化管理的业务形态。门店销售团队不仅需要对接客户,还要实时反馈总部的策略与数据。如果销售流程中协同效率不足,往往会导致商机流失和客户满意度下降。协作文档工具的普及,为车企门店带来了全新解决方案。 车企门店销售面临的核心问题 在车…

功率器件的热设计基础(二)——热阻的串联和并联

功率半导体热设计是实现IGBT、碳化硅SiC高功率密度的基础,只有掌握功率半导体的热设计基础知识,才能完成精确热设计,提高功率器件的利用率,降低系统成本,并保证系统的可靠性。/ 前言 / 功率半导体热设计是实现IGBT、碳化硅SiC高功率密度的基础,只有掌握功率半导体的热设计…

视频分析设备平台EasyCVR关于未来监控系统可能会集成哪些新技术?

随着科技的飞速发展,监控系统正经历着一场革命性的变革。未来的监控系统将不再是单一的观察和记录工具,而是集成了多种前沿技术的智能平台,它们将极大地提高安全性、效率和响应速度。以下是未来监控系统可能集成的一些关键技术。1、人工智能技术 1)监控系统将越来越多地应用…

【亲测能用】专业音乐制作软件Ableton Live Suite v12.1.5 中文版(附安装教程)

软件介绍 在数字音频工作站(DAW)的领域中,Ableton Live以其创新和灵活性脱颖而出,成为全球音乐家和制作人的首选工具。由德国Ableton公司精心打造,这款软件不仅支持无缝的音乐播放和即时编辑,还提供了强大的音频效果和虚拟乐器,让音乐创作变得无限可能。 功能亮点 Ablet…

【测试侧】产品场景用例模板

产品的场景法用例设计的测试场景用例模板