zoukankan      html  css  js  c++  java
  • AutoCAD.NET二次开发:扩展数据之XData

    结果缓存——ResultBuffer

      结果缓存即 Autodesk.AutoCAD.DatabaseServices.ResultBuffer 类型,使用 ResultBuffer 对象时需要提供一个数据对,每个数据对包含一个数据类型描述和一个值,这些数据对是 Autodesk.AutoCAD.DatabaseServices.TypedValue 类的实例。

      TypedValue.TypeCode 属性是一个16位整型数据,它指明 TypedValue.Value 属性的数据类型,可接受的 TypeCode 值取决于 ResultBuffer 实例的使用范围,例如,适用于扩展记录定义的 TypeCode 值就不适合于 XData。而Autodesk.AutoCAD.DatabaseServices.DxfCode 枚举类型定义的码值则描述了 ResultBuffer 可能的数据类型。

      TypedValue.Value 属性是一个 System.Object 的实例,它可以包含任何类型的数据;但是,Value 的数据必须符合由 TypeCode 指明的类型。

      创建 ResultBuffer 方法有两种:

      一种是使用构造函数创建,即在声明 ResultBuffer 时将一个 TypedValue 作用参数传给 ResultBuffer:

    ResultBuffer  resBuf = new ResultBuffer(new TypedValue((int)DxfCode.Text, "我的扩展数据"));

      另一种是使用 ResultBuffer.Add() 方法来添加 TypedValue,可以添加多个TypedValue,但总数据大小不能超过128K:

    ResultBuffer resBuf = new ResultBuffer (); 
    resBuf.Add(new TypedValue ((int)DxfCode.Text, "我的扩展数据")); 
    resBuf.Add(new TypedValue ((int)DxfCode.Real, 20.0)); 
    resBuf.Add(new TypedValue((int)DxfCode.Int32, 5));

    扩展数据——XData

      AutoCAD 数据库对象都可以灵活的添加一定数量的自定义数据,供开发者使用,这些数据的含义由开发者自行解释,AutoCAD 只维护这些数据而不管其具体的含义,这些数据被称为扩展数据(XData),扩展数据以结果缓存形式附加在实体上,因此,能够有效的利用存储空间,对于添加轻量的数据非常方便的。

      可以通过实体 DBObject 类及其派生类的 XData 属性获取或设置扩展数据。实体的扩展数据由应用程序创建, 附着在实体的扩展数据可以包含一个或多个组。每一组均以一个互不相同的注册应用程序名开头,扩展数据 XData 所支持的TypedValue.TypeCode 属性值(DXF 组码)只能采用 1000~1071 之间的组码值,不同组码对应不同类型的信息,各个组码的说明如下表所示:

    DXF 组码值  扩展数据内容
    1000~1009

    字符串 (最多不超过 255 个字
    符)

    1001  Xdata 的应用程序名
    1002  Xdata 的控制字符串
    1003 图层名
    1004 二进制数据
    1005 数据库对象句柄
    1010~1059  浮点数
    1010,1020,1030  三维点(x, y , z)
    1011,1021,1031  三维空间位置
    1012,1022,1032  三维空间距离
    1013,1023,1033  三维空间方向
    1040  Xdata 中的浮点数
    1041  Xdata 中的距离值
    1042 Xdata 中的比例系数
    1060~1070  16 位整数
    1071  32 位整数

      由于每个数据库对象可以附加多个应用程序的数据,所以在 ResultBuffer 中,应用程序名是每段扩展数据的第一个数据,其后的结果缓冲数据都归此应用程序名所有。(也可以使用其他的特殊标识作为第一个数据,总之目的是为了便于区分,方便后期查询此扩展数据)

      AutoCAD 将注册的应用程序名称保存于数据库中的 RegAppTable 表中,在使用之前,必须首先检测是否已经存在 RegAppTable 表中,如果没有则需要注册,也就是创建一个 RegAppTableRecord 表记录, 注册程序的名字最长可达 31 个字符,以下代码完成 RegAppTableRecord 表记录的创建:

    RegAppTable appTbl = trans.GetObject(db.RegAppTableId, OpenMode.ForWrite) as RegAppTable ; 
    if (!appTbl.Has("MyAppName")) 
    { 
      RegAppTableRecord appTblRcd = new RegAppTableRecord(); 
      appTblRcd.Name ="MyAppName"; 
      appTbl.Add(appTblRcd); 
      trans.AddNewlyCreatedDBObject(appTblRcd, true); 
    } 

      

      添加扩展数据到数据库对象上,首先需要获取数据注册应用程序名,然后通过 DBObject 类及其派生类的 XData 属性设置扩展数据,如以下代码所示: 

    public void AddXData() 
    { 
      Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; 
      ed.WriteMessage("添加扩充数据 XDATA
    "); 
      PromptEntityOptions entOps = new PromptEntityOptions("选择实体对象"); 
      PromptEntityResult entRes; 
      entRes = ed.GetEntity(entOps); 
      if (entRes.Status != PromptStatus.OK) 
      { 
        ed.WriteMessage("选择对象失败,退出"); 
        return; 
      } 
      ObjectId objId = entRes.ObjectId; 
      Database db = HostApplicationServices.WorkingDatabase; 
      using (Transaction trans = db.TransactionManager.StartTransaction()) 
      { 
        Entity ent = trans.GetObject(objId, OpenMode.ForWrite) as Entity ; 
        ent.ColorIndex =1; 
        RegAppTable appTbl = trans.GetObject(db.RegAppTableId, OpenMode.ForWrite) as RegAppTable ; 
        if (!appTbl.Has("MyAppName")) 
        { 
          RegAppTableRecord appTblRcd = new 
          RegAppTableRecord(); 
          appTblRcd.Name ="MyAppName"; 
          appTbl.Add(appTblRcd); 
          trans.AddNewlyCreatedDBObject(appTblRcd, true); 
        } 
        ResultBuffer resBuf = new ResultBuffer();
        resBuf.Add(new TypedValue(1001, "我的扩展数据应用程序"));
        resBuf.Add(new TypedValue(1000, "作者:王"));
        ent.XData = resBuf; 
        trans.Commit(); 
      } 
    } 

      从指定的对象返回所附着的扩展数据也需要通过 DBObject 类及其派生类的XData 属性,返回的结果为 ResultBuffer,可以用.AsArray()方法将其转换为一个TypedValue[]数组,或者借助遍历器 IEnumerator(在 System.Collections 命名空间中),同时根据 DXF 的组码值判断所添加的数据,这些数据的含义由开发者自行解释。

      使用自带方法转为数组:

    TypedValue[] tvs = rb.AsArray();

      使用IEnumerator遍历:

    public void GETXDATA() 
    { 
      Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; 
      ed.WriteMessage("获取扩充数据 XDATA
    "); 
      PromptEntityOptions entOps = new PromptEntityOptions("选择实体对象"); 
      PromptEntityResult entRes = ed.GetEntity(pr); 
      if (entRes.Status != PromptStatus.OK) 
      { 
        ed.WriteMessage("选择对象失败,退出"); 
        return; 
      } 
      Database db = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database; 
      using (Transaction tr = db.TransactionManager.StartTransaction()) 
      { 
        Entity ent = (Entity)tr.GetObject(res.ObjectId, OpenMode.ForRead); 
        ResultBuffer resBuf = ent.XData; 
        if (resBuf ! = null) 
        { 
          IEnumerator iter = resBuf.GetEnumerator(); 
          while (iter.MoveNext()) 
          { 
            TypedValue tmpVal = (TypedValue)iter.Current; 
            ed.WriteMessage(tmpVal.TypeCode.ToString() + ":"); 
            ed.WriteMessage(tmpVal.Value.ToString() +"
    "); 
          } 
        } 
      } 
    } 

      也可以将扩展数据读取到更常用的List<T>中,参考代码如下:

    public List<System.Object> GetXDataList(Entity ent)
    {
      Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
      List<System.Object> objs = new List<System.Object>();
      Database db = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database;
      using (Transaction trans = db.TransactionManager.StartTransaction())
      {
        ent = (Entity)trans.GetObject(ent.ObjectId, OpenMode.ForRead);
        ResultBuffer resBuf = ent.XData;
        if (resBuf != null)
        {
          System.Collections.IEnumerator itor = resBuf.GetEnumerator();
          while (itor.MoveNext())
          {
            TypedValue tmpVal = (TypedValue)itor.Current;
            objs.Add(tmpVal.Value);
              }
        }
        trans.Commit();   }
      return objs; }

      要注意的是,XData是比较特殊的,给实体添加扩展数据,是这样的:

    ResultBuffer rb = new ResultBuffer(
      new TypedValue[]{
            new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc"),
             new TypedValue((int)DxfCode.ExtendedDataAsciiString,"123")
       });
    line.XData = rb;

      但是这里虽然是用等号赋值的,但是它并不一定会覆盖旧的扩展数据,一个实体,只有一个XData属性,但是里面可以记录多个不同应用程序名的扩展数据。

      每次用“=”给实体的XData赋值时,如果XData里还没有这个应用程序的扩展数据,那么新赋的这些值,会被添加到原有的XData结尾去,比如上面已经给line对象添加了应用程序“abc”的扩展数据,这个时候读取line的XData,其内容应该是这样的:

    new TypedValue[]{
        new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc"),
        new TypedValue((int)DxfCode.ExtendedDataAsciiString,"123")
    }

      这时候,再给line添加一个新的应用程序"lc"的扩展数据:

    ResultBuffer rb1 = new ResultBuffer(
    new TypedValue[]{
      new TypedValue((int)DxfCode.ExtendedDataRegAppName,"lc"),
      new TypedValue((int)DxfCode.ExtendedDataAsciiString,"0")
    });
    line.XData = rb1;

      此时,如果再读取line的XData,那么结果就会是:

    new TypedValue[]{
      new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc"),
      new TypedValue((int)DxfCode.ExtendedDataAsciiString,"123"),
      new TypedValue((int)DxfCode.ExtendedDataRegAppName,"lc"),
      new TypedValue((int)DxfCode.ExtendedDataAsciiString,"0")
    }

      这样的话,那如果同一个实体如果有多个应用程序的扩展数据,那我怎么取其中某一个应用程序的扩展数据呢?

      答案是使用:GetXDataForApplication方法,该方法的参数就是应用程序名,比如:

    ResultBuffer res = line.GetXDataForApplication("abc");
    
    这样取到的结果就是:
    new TypedValue[]{
      new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc"),
      new TypedValue((int)DxfCode.ExtendedDataAsciiString,"123")
    }

      如果要修改扩展数据,只需要对XData重新赋值就行,比如现在我们修改应用程序abc的扩展数据:

    line.XData = new ResultBuffer(
    new TypedValue[]{
      new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc"),
      new TypedValue((int)DxfCode.ExtendedDataAsciiString,"1231"),
      new TypedValue((int)DxfCode.ExtendedDataAsciiString,"1")
    });
    
    //对XData重新赋值时,如果XData里已经有了abc的扩展数据,那么会把原有的abc的扩展数据替换掉,如果现在还没有abc的扩展数据,那么就会在XData结尾处添加上新的扩展数据。

      如果要删除扩展数据,操作方式如下:

    //删除应用程序abc的扩展数据,只需要进行一个这样的赋值,新值里只添加一个应用程序名,不添加其他值,这样XData中,原有的abc的扩展数据就会被删除
    line.XData = new ResultBuffer(
      new TypedValue[]{
      new TypedValue((int)DxfCode.ExtendedDataRegAppName,"abc")
    });

      注意:尽量不要直接删除已经在RegAppTable里注册的应用程序名,如果图纸上的实体上添加了此应用程序的扩展数据,那么扩展数据中对应的应用程序名会被删掉,但它下面对应的其他数据值并不会被删除,有可能会引发问题,例如:

    //删除应用程序abc在RegAppTable里的记录
    RegAppTable rat = (RegAppTable)trans.GetObject(db.RegAppTableId, OpenMode.ForWrite);
    if (!rat.Has("abc"))
    {
      RegAppTableRecord ratr = (RegAppTableRecord)rat["abc"].GetObject(OpenMode.ForWrite);
      ratr.Erase();
    }
    
    //这时,读取line的XData,其内容会是这样(假设我们上一步,没有删除line中abc的扩展数据)
    new TypedValue[]{
      new TypedValue((int)DxfCode.ExtendedDataAsciiString,"123"),
      new TypedValue((int)DxfCode.ExtendedDataRegAppName,"lc"),
      new TypedValue((int)DxfCode.ExtendedDataAsciiString,"0")
    }

      所以,个人认为,在删除RegAppTable中的已注册的应用程序名时,应先用过滤选择器选择出添加了此应用程序扩展数据的实体,然后将它们的扩展数据删除,然后再去删除RegAppTable中的应用程序注册信息。

  • 相关阅读:
    在CMD中使用for命令对单行字符串做分割的方法
    关于CMD/DOS中的短文件名规则
    [批处理]全盘搜索批量文件
    [批处理]批量提取MKV资源
    关于CMD中延迟环境变量嵌套的实现方法
    [批处理]自动按日期重命名文件名
    [批处理]手动伪造相机自动编号
    [批处理]简易命令行RAR
    [批处理]Oracle启动助手
    [批处理]强制删除文件及文件夹
  • 原文地址:https://www.cnblogs.com/bomb12138/p/3685577.html
Copyright © 2011-2022 走看看