首页 > 其他分享 >在CAD文件中存储扩展数据

在CAD文件中存储扩展数据

时间:2024-12-25 15:52:09浏览次数:4  
标签:存储 TypedValue 扩展 xData DxfCode var new CAD XData

基础知识:

  根据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

 

标签:存储,TypedValue,扩展,xData,DxfCode,var,new,CAD,XData
From: https://www.cnblogs.com/yyy2023/p/18588915

相关文章

  • Mysql存储引擎(InnoDB-事务原理)
    1、什么是事务    事务是一组命令的集合,要么全部成功,要么都不成功。事务有四个特征,即原子性、一致性、隔离性、持久性。其中隔离性又有四大隔离级别,分别是读未提交,读已提交、可重复读、串行化,四大隔离级别主要解决三个现象,脏读,不可重复读,幻读。 2、事务的四大特性(A......
  • C语言——整型数据在内存中的存储
    整型数组在内存中的存储一、大小端存储1.大端存储(大端字节序存储)2.小端存储(小端字节序存储)>给大家一个题目,设计一个程序判断当前机器的字节序.二、原码、反码和补码1.*补充2.例题1.2.3.4.5.6.一、大小端存储1.大端存储(大端字节序存储)将一个数据的低位字节内容......
  • CAD图纸显示不全,4大问题、解法汇总!快收藏
    CAD图纸显示不全,4大问题、解法汇总!快收藏你的CAD图纸显示不全?常见的情况有这4种:1.外部参照2.布局/模型切换3.天正及高版本不显示4.ole图片不显示具体表现、判断方法、解决办法,都给大家整理好啦!快来使用CAD快速看图跟着文章一起学习吧~一、外部参照问题情况及......
  • .MUI 文件是 Multilingual User Interface(多语言用户界面)文件的扩展名。它们是 Window
    什么是 .MUI 文件?.MUI文件是MultilingualUserInterface(多语言用户界面)文件的扩展名。它们是Windows操作系统用于支持多语言界面的文件。每个.MUI文件包含了特定语言版本的用户界面资源,如菜单项、对话框文本、按钮标签等,确保操作系统和应用程序能够以不同的语言显示界面......
  • IndexedDB:前端存储新宠,数据库的“特种兵”
    indexedDB是不可靠存储,会在c盘空间不足时,自动清空,极易丢失数据。web的离线功能,就是能存一些数据,包括图片到本地,等可以上网的时候再把这些数据更新到服务器的数据库。IndexedDB具有以下特点IndexedDB数据库是存储键值对的非关系型数据库。IndexedDB内部采用对象仓库(object......
  • 振石股份携手「维智佳创」重塑风电领域CAD智能化设计
    本文由「维智佳创」原创,未经允许请勿直接复制转载!振石股份:成为全球风电材料解决方案的引领者#成立于2000年,是全球领先的玻纤织物制造商,专业从事风电用增强玻纤织物的研发、生产和销售。#开发了上千种新产品,申请或者授权专利百余项,产能规模全球领先,获得第三批制造业单......
  • 存储
    存储每个微信小程序都可以有自己的本地缓存,可以通过wx.setStorage/wx.setStorageSync、wx.getStorage/wx.getStorageSync、wx.clearStorage/wx.clearStorageSync,wx.removeStorage/wx.removeStorageSync对本地缓存进行读写和清理。隔离策略同一个微信用户,同一个小程序storage......
  • 如何使用 PHP 扩展运算符
    数组合并(...)基本概念在PHP中,扩展运算符用于将一个或多个数组的元素合并到另一个数组中。它提供了一种简洁的方式来组合数组,而不是使用传统的循环或array_merge函数。示例代码假设有两个数组$array1和$array2,我们想将它们合并成一个新数组。在这个例子中,...$array1......
  • Windows10系统使用Python查看本机已存储的WiFi密码
    Windows10系统使用Python查看本机已存储的WiFi密码importreimportsubprocessname_list=[]#定义要执行的命令command='netshwlanshowprofiles'#使用subprocess.run执行命令,并捕获输出result=subprocess.run(command,shell=True,text=True,stdout=subpro......
  • 全栈开发中的技术选型决策:快速上线与扩展的平衡
    文章目录摘要引言技术选型的重要性技术选型的关键考虑点项目需求团队技能技术生态性能与扩展性成本与复杂性基于SpringBoot和Vue.js的全栈架构后端代码:SpringBoot示例代码详解:运行原理:前端代码:Vue.js示例代码详解:运行原理:完整运行逻辑改进扩展QA环节为什么......