Accessing the AutoCAD objects referred to by fields using .NET

本文介绍了一种使用C#从AutoCAD的MText对象中提取字段代码的方法,并通过实例演示了如何解析这些代码来获取引用对象的信息。


Thanks to Wolfgang Ruthensteiner for suggesting this excellent topic a comment to this previous post. Here's Wonfgang's question:

How do I read back the field code with C# (from an attribute e.g.)?

I am linking room-label blocks with polylines, using fields inside an attribute to display the polyline's area property.

Later I want to find out programatically, which polyline a certain block is linked to by evaluating the field in the attribute (extracting the objectId).

This was actually quite tricky, and one I needed the help of our old friend, ArxDbg, to solve (see here for some information on this very useful ObjectARX sample). I should say up-front that there may well be a simpler way to access the information - the below technique is to some degree relying on the database structure (which might be considered an implementation detail). I may be missing a higher-level API providing a simpler way to access the information, but there you have it.

The full text of the field expression is stored in an AcDbField object (which is accesible through the Autodesk.AutoCAD.DatabaseServices.Field) which exists inside a field dictionary in the text object's (or attribute's) extension dictionary. So here's what needs to happen:

  • Select the MText object (I chose to use MText in the below code, as it was a bit more work to allow attribute selection within a block - left as an exercise for the reader :-)
  • Open the MText object's extension dictionary
  • Open the nested field dictionary
  • Access the field object stored therein

At this stage you have your text string with all the uninterpreted field codes. For those of you that are interested, I remember an important decision at the time we implemented fields in AutoCAD: that we should maintain the existing protocol and not return uninterpreted field codes from the standard text access properties/methods. This was largely to avoid migration issues for applications that depended on the data to be returned in its evaluated form. But it clearly means a bit more work if you want to get at the underlying codes.

So once we have our codes, we then want to get back to the "referred" object(s). I implemented a simple function that parses a string for the following sub-string:

%</_ObjId XXX>%

... where XXX is a string representing the ObjectId. The code then uses a conversion function to get an integer from the string, and create an ObjectId from the integer. We return the ID to the calling function, where we can then open it and find out more about it.

So that's the description - here's the C# code implementing it:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using System;


namespace FieldExtraction

{

  public class Commands

  {

    [CommandMethod("GFL")]

    static public void GetFieldLink()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;


      // Ask the user to select an attribute or an mtext

      PromptEntityOptions opt =

        new PromptEntityOptions(

          "/nSelect an MText object containing field(s): "

        );

      opt.SetRejectMessage(

        "/nObject must be MText."

      );

      opt.AddAllowedClass(typeof(MText), false);

      PromptEntityResult res =

        ed.GetEntity(opt);


      if (res.Status == PromptStatus.OK)

      {

        Transaction tr =

          doc.TransactionManager.StartTransaction();

        using (tr)

        {

          // Check the entity is an MText object

          DBObject obj =

            tr.GetObject(

              res.ObjectId,

              OpenMode.ForRead

            );


          MText mt = obj as MText;

          if (mt != null)

          {

            if (!mt.HasFields)

            {

              ed.WriteMessage(

                "/nMText object does not contain fields."

              );

            }

            else

            {

              // Open the extension dictionary

              DBDictionary extDict =

                (DBDictionary)tr.GetObject(

                  mt.ExtensionDictionary,

                  OpenMode.ForRead

                );


              const string fldDictName = "ACAD_FIELD";

              const string fldEntryName = "TEXT";

              // Get the field dictionary

              if (extDict.Contains(fldDictName))

              {

                ObjectId fldDictId =

                  extDict.GetAt(fldDictName);

                if (fldDictId != ObjectId.Null)

                {

                  DBDictionary fldDict =

                    (DBDictionary)tr.GetObject(

                      fldDictId,

                      OpenMode.ForRead

                    );


                  // Get the field itself

                  if (fldDict.Contains(fldEntryName))

                  {

                    ObjectId fldId =

                      fldDict.GetAt(fldEntryName);

                    if (fldId != ObjectId.Null)

                    {

                      obj =

                        tr.GetObject(

                          fldId,

                          OpenMode.ForRead

                        );

                      Field fld = obj as Field;

                      if (fld != null)

                      {

                        // And finally get the string

                        // including the field codes

                        string fldCode = fld.GetFieldCode();

                        ed.WriteMessage(

                          "/nField code: "

                          + fldCode

                        );


                        // Loop, using our helper function

                        // to find the object references

                        do

                        {

                          ObjectId objId;

                          fldCode =

                            FindObjectId(

                              fldCode,

                              out objId

                            );

                          if (fldCode != "")

                          {

                            // Print the ObjectId

                            ed.WriteMessage(

                              "/nFound Object ID: "

                              + objId.ToString()

                            );

                            obj =

                              tr.GetObject(

                                objId,

                                OpenMode.ForRead

                              );

                            // ... and the type of the object

                            ed.WriteMessage(

                              ", which is an object of type "

                              + obj.GetType().ToString()

                            );

                          }

                        } while (fldCode != "");                         

                      }

                    }

                  }

                }

              }

            }

          }

        }

      }

    }


    // Extract an ObjectId from a field string

    // and return the remainder of the string

    //

    static public string FindObjectId(

      string text,

      out ObjectId objId

    )

    {

      const string prefix = "%<//_ObjId ";

      const string suffix = ">%";


      // Find the location of the prefix string

      int preLoc = text.IndexOf(prefix);

      if (preLoc > 0)

      {

        // Find the location of the ID itself

        int idLoc = preLoc + prefix.Length;


        // Get the remaining string

        string remains = text.Substring(idLoc);


        // Find the location of the suffix

        int sufLoc = remains.IndexOf(suffix);


        // Extract the ID string and get the ObjectId

        string id = remains.Remove(sufLoc);

        objId = new ObjectId(Convert.ToInt32(id));


        // Return the remainder, to allow extraction

        // of any remaining IDs

        return remains.Substring(sufLoc + suffix.Length);

      }

      else

      {

        objId = ObjectId.Null;

        return "";

      }

    }

  }

}

Here's what happens when we run the code. Firstly I went and created a simple, closed polyline and a circle. I then created a single MText object with field codes accessing the other two objects' areas:

Fields_4

I then run the GFL command and select the MText object:

Command: GFL

Select an MText object containing field(s):

Field code: Area of the circle: /AcObjProp Object(%</_ObjId

2130239616>%).Area/P/PArea of the polyline: /AcObjProp Object(%</_ObjId

2130239624>%).Area

Found Object ID: (2130239616), which is an object of type

Autodesk.AutoCAD.DatabaseServices.Circle

Found Object ID: (2130239624), which is an object of type

Autodesk.AutoCAD.DatabaseServices.Polyline

As you can see, we've been able to find and extract information from the objects referred to by fields in an MText object.

July 13, 2007 in AutoCAD, AutoCAD .NET | Permalink

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/t/trackback/876965/20017930

Listed below are links to weblogs that reference Accessing the AutoCAD objects referred to by fields using .NET:

 
打开链接下载源码: https://pan.quark.cn/s/c43e5bd27521 标题中的“AMD and Nvidia GOP update 1.9.6.rar”表示这是一个包含了AMD与Nvidia显卡的GOP(Graphics Output Protocol)驱动程序升级至1.9.6版本的压缩文件。该更新主要针对显卡在UEFI(统一可扩展固件接口)环境下的图形输出性能进行优化,并致力于提升系统的稳定性。在描述中提及“显卡附加UEFI引导工具,最新版”,表明此次更新内含了一个专为UEFI BIOS环境设计的显卡引导工具,或许表现为一个自启动脚本或程序,例如GOPupd.bat。通过这一工具,用户能够在UEFI模式下对显卡进行精确的配置和初始化,从而保障操作系统能够最大化地发挥显卡的效能。必需的组件包括“colorama-0.4.3”,这是一个在Windows平台上用于管理颜色控制序列的Python模块,可能在更新过程中用于生成彩色命令行显示,以增强用户交互的直观性。此外,“Visual C++Redistributable”是微软提供的运行时支持库,旨在确保基于C++编译的应用程序能够正常运行,此处可能用于更新工具或相关依赖模块。标签“uefi bios”突显了该更新与UEFI BIOS系统的紧密关联,暗示其将作用于计算机的启动序列及硬件初始化过程。压缩包内的文件清单如下: 1. GOPupd.bat - 很有可能是负责执行GPU UEFI引导更新的核心脚本。 2. #Nvidia_ROM_Info.bat 和 #AMD_ROM_Info.bat - 这两个文档可能用于采集Nvidia与AMD显卡的ROM数据,以辅助识别显卡型号并执行适配性验证。 3....
代码下载地址: https://pan.quark.cn/s/a2e2c95e6128 意法半导体(STMicroelectronics)研发的STM32H750是一款性能优越的微控制器,属于STM32H7系列,拥有卓越的处理性能以及多元化的外设接口。在此项工作中,我们将研究如何借助STM32H750达成串口空闲中断(IDLE interrupt)的运用、借助DMA完成UART(通用异步收发传输器)的数据传输,并且探究如何运用STM32CubeMX配置并构建MDK5(Keil uVision5)项目。串口空闲中断是串口通信中的一个核心功能,当串口在一段时间内没有进行数据交换时,会引发该中断。这种功能在需要实时监测串口状态的应用场合中非常有价值,比如,在等待特定指令或需要降低能耗的情况下。在STM32H750中,设定串口空闲中断通常包含以下几个环节: 1. 串口设置:在STM32CubeMX中选定相应的UART接口,并激活中断功能。 2. 中断优先级设定:按照应用需求设定中断优先级。 3. 中断服务函数注册:在程序代码中定义中断服务函数以应对中断事件。 4. 启用串口空闲中断:在初始化代码中激活串口的IDLE位,使能中断。 DMA(Direct Memory Access)传输是一种高效的数据传输机制,它允许外设直接与内存进行交互,无需CPU的介入,从而减轻了CPU的工作负担。在STM32H750中,我们可以运用DMA配合UART来接收数据: 1. DMA配置:在STM32CubeMX中为UART选择合适的DMA通道,并设定传输特性。 2. UART配置:将UART设置为DMA模式,并指定接收缓冲区的地址。 3. 中断配置:开启DMA传输完成中断,以便在数据接收完...
源码直接下载地址: https://pan.quark.cn/s/d64de7ee3e36 STM32CubeIDE是由STMicroelectronics(意法半导体)开发的一款集成开发环境,其核心功能是针对STM32系列微控制器进行优化,并集成了包括源代码编写、编译执行、调试检测以及项目参数设置在内的完整开发工具集。该开发平台依托于Eclipse系统框架构建,旨在为编程人员营造一个便捷且生产力高的工作场景。1.9.0版本属于其产品线中的一个成熟版本,通常包含了若干性能增强措施以及新特性的集成。在嵌入式系统的构建过程中,代码的自动完成机制是一项关键的辅助技术,它能够显著提升工作速率并降低操作失误。专门为这一目的设计的STM32CubeIDE 1.9.0自动代码补全组件,能够有效满足开发者的相关需求。通过将压缩文件中的内容部署到STM32CubeIDE安装路径下的`plugins`子目录中,该插件即可被系统自动检测并激活,从而在代码编写阶段,系统能够基于上下文信息智能地预判并展示潜在的函数名称、变量定义或常量值,进而辅助开发者迅速完成输入任务。基于ARM Cortex-M架构的STM32系列微控制器,在物联网装置、工业自动化系统、个人消费类电子设备等领域具有广泛的部署。在这些应用场景中,单片机扮演着核心角色,而STM32凭借卓越的处理性能、多样化的外部接口配置以及出色的能源控制能力,已成为众多开发者的首选方案。STM32CubeIDE所提供的自动代码补全功能,对于初入行业的开发者而言尤为适宜,因为它能够实时呈现API函数的相关信息,涵盖函数标识符、参数的数据类型与数目,乃至函数的返回类型,从而协助开发者精准地运用STM32的固件库。不仅如此,即便对于已经熟练掌握ST...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值