Book Image

Instant Autodesk AutoCAD 2014 Customization with .NET

By : Tom Nelson
Book Image

Instant Autodesk AutoCAD 2014 Customization with .NET

By: Tom Nelson

Overview of this book

<p>AutoCAD's .NET API can be used to create small but powerful applications that help CAD users achieve productivity gains and improve quality. CAD users can accelerate drafting and design processes, improve drawing accuracy, minimize time spent on repetitive or demanding tasks, and reduce errors. In short, users can deliver better drawings faster with customized CAD tools.</p> <p>Learn how to use AutoCAD's .NET API to create your own high-powered, custom applications for AutoCAD. This book is a toolbox of small projects for handling common AutoCAD tasks. You can add to these recipes to develop your own specialized AutoCAD program library. Clear, step-by-step instructions and complete code examples illustrate the process, making it easy to develop your own custom AutoCAD tools.</p> <p><br />Giving you the building blocks of AutoCAD application development, you&rsquo;ll learn to create compact user interfaces for your AutoCAD plugins and add command buttons to the ribbon interface. Next, you&rsquo;ll create programs to insert and modify AutoCAD block and attribute references, as well as working with custom data stored on AutoCAD objects. Learn how to publish layouts from external drawings in multi-sheet PDF files, export AutoCAD data to MS Excel for processing, and respond to AutoCAD event notifications (such as when an object is selected). With the tools presented in this book, you can develop and implement new functionality to address your specialized business needs.</p>
Table of Contents (7 chapters)

Reading and writing extended data (Should know)


CAD data is not limited to layers, linetypes, and point coordinates. Let's make an application that reads and manipulates data that you store in AutoCAD objects. While our example is simple, in the real world this data could represent material type, weight, cost, inventory, supplier data, and more. We saw how we can attach attributes (text data) to block references in AutoCAD drawings. However, we work with other AutoCAD object types in addition to blocks, and we may also wish to represent data using other data types (integers, reals, 2D and 3D points, and more). We can accomplish this by using extended entity data, or xdata for short.

Getting ready

In this project, which can be used with virtually any AutoCAD drawing, we will create commands which add (attach) xdata to an AutoCAD object, read and display xdata found on an object, and also remove specific xdata from an object.

How to do it...

  1. Create a new command, AddXD. Get the current drawing's Database and Editor objects:

    [CommandMethod("AddXD")]
    static public void AddXD() {
       //Get the curr dwg database
       Database db = 
          Application.DocumentManager.MdiActiveDocument.Database;
      //Begin a transaction
      using (Transaction trans =   
         db.TransactionManager.StartTransaction()) {
         //Get the Editor object of current drawing
      Editor ed = 
         Application.DocumentManager.MdiActiveDocument.Editor;
  2. Add code to prompt the user to select an object on screen (configure the options to exit the command if the user right-clicks on or presses ENTER):

    //Select an object on screen
    PromptEntityOptions prEntOpts = new PromptEntityOptions(
       "Select object");
    prEntOpts.AllowNone = true; //Allow Enter key/Right-click as input
    PromptEntityResult prEntRes = ed.GetEntity(prEntOpts);
    if (prEntRes.Status != PromptStatus.OK) {
       ed.WriteMessage("Done.");
       return;
    }
  3. Open the selected object for read. Retrieve the handle of the object, as well as the object's layer name. Now, upgrade the OpenMode to ForWrite, since we will be writing xdata to the object:

    //Open the selected object for read
    Entity acEnt = (Entity)trans.GetObject(prEntRes.ObjectId, 
       OpenMode.ForRead);
    //Get the handle for the selected object
    Handle acHndl = acEnt.Handle;
    //Get the layer name for the selected object
    string lyrName = acEnt.Layer.ToString();
    acEnt.UpgradeOpen();
  4. Open the regapp table and check for your appid (a unique identifier for accessing this set of data). I suggest changing it from TEST to something more original. If your appid is not found, upgrade the regapp table's OpenMode to ForWrite, create a new regapp table record and then add your appid:

    RegAppTable regTbl = (RegAppTable)trans.GetObject(db.RegAppTableId, OpenMode.ForRead);
    if (!regTbl.Has("TEST")) {  
       regTbl.UpgradeOpen(); 
       RegAppTableRecord regTblRec = new RegAppTableRecord();
       regTblRec.Name = "TEST";
       regTbl.Add(regTblRec);
       trans.AddNewlyCreatedDBObject(regTblRec, true);
    }
  5. Finally, attach a variety of xdata types to the selected AutoCAD object. Add the xdata to a ResultBuffer and set the object's xdata property to the contents of the buffer. Once the xdata is attached, dispose of the ResultBuffer:

       ResultBuffer resBuf = 
          new ResultBuffer(new TypedValue(1001, "TEST"), 
          new TypedValue(1000, "An integer:"), 
          new TypedValue(1070, 0521),
          new TypedValue(1000, "Handle of selected object:"),
          //Handle of the object you picked
          new TypedValue(1005, acHndl),
          new TypedValue(1000, "Open bracket:"),
          //'Opening' control bracket for nested xdata
          new TypedValue(1002, "{"),
          new TypedValue(1000, "Layer of selected object:"),
          new TypedValue(1003, acEnt.Layer.ToString()),
          new TypedValue(1000, "Close bracket"),
          //'Closing' control bracket for nested xdata
          new TypedValue(1002, "}"));
       acEnt.XData = resBuf;
       resBuf.Dispose(); 
       trans.Commit();                 
    } //end transaction
  6. Create another command, ReadXD. As before, get the Database and Editor objects, and prompt the user to select an object. Also, check the regapp table for your appid:

    [CommandMethod("ReadXD")]
    static public void ReadXD() {
      //Get the curr dwg database
      Database db = 
        Application.DocumentManager.MdiActiveDocument.Database;
      //Begin a transaction
       using (Transaction trans = 
          db.TransactionManager.StartTransaction()) {
          //Get the Editor object of current drawing
          Editor ed = 
             Application.DocumentManager.MdiActiveDocument.Editor;
          //Select an object on screen
          PromptEntityOptions prEntOpts = new
             PromptEntityOptions("Select object");
          prEntOpts.AllowNone = true; //Allow Enter key/Right-click 
          PromptEntityResult prEntRes = ed.GetEntity(prEntOpts);
          if (prEntRes.Status != PromptStatus.OK) {
             ed.WriteMessage("Done.");
             return;
          }
          //Open the selected object for read
          Entity acEnt = (Entity)trans.GetObject(prEntRes.ObjectId, 
             	OpenMode.ForRead);
    
          //Open the regapp table and check for your appid
          RegAppTable regTable = 
            (RegAppTable)trans.GetObject(db.RegAppTableId, 
             OpenMode.ForRead);
  7. If your appid exists in the table, retrieve the xdata from the selected object. Use a ResultBuffer to capture the xdata. Loop through the buffer, testing each item for its xdata type code. Display the xdata (adding some descriptive information) in AutoCAD's textscreen (press the F2 key to toggle the textscreen visibility):

    if (regTable.Has("TEST")) { //Replace "TEST" with your own appid 
       //If the appid exists in the regapp table, attempt to read the 
       //object's xdata from the table
       ResultBuffer resBuf = acEnt.GetXDataForApplication("TEST");
       if (resBuf != null) {
          TypedValue[] resBufArray = resBuf.AsArray();
          foreach (TypedValue val in resBufArray) {
             switch ((DxfCode)val.TypeCode) {
                //Appid type xdata
                case DxfCode.ExtendedDataRegAppName:
                   string appid = (string)val.Value;
                   ed.WriteMessage(System.Environment.NewLine 
                       + "1001 AppId: {0}", appid);
                   break;
                //String type xdata
                case DxfCode.ExtendedDataAsciiString:
                   string strng = (string)val.Value;
                   ed.WriteMessage(System.Environment.NewLine 
                       + "1000 String: {0}", strng);
                   break;
                //LayerName type xdata
                case DxfCode.ExtendedDataLayerName:
                   string laynam = (string)val.Value;
                   ed.WriteMessage(System.Environment.NewLine 
                       + "1003 Layer: {0}", laynam);
                   break;
                //Handle type xdata
                case DxfCode.ExtendedDataHandle:
                   ed.WriteMessage(System.Environment.NewLine 
                      + "1005 Handle: {0}", val.Value);
                   break;
                //Control type xdata
                case DxfCode.ExtendedDataControlString:
                   string brkt = (string)val.Value;
                   ed.WriteMessage(System.Environment.NewLine
                      + "1002 Control: {0}", brkt);
                   break;
                //Integer type xdata
                case DxfCode.ExtendedDataInteger16:
                   Int16 intgr = (short)val.Value;
                   ed.WriteMessage(System.Environment.NewLine 
                       + "1070 Integer: {0}", intgr);
                   break;
                default:
                   ed.WriteMessage(System.Environment.NewLine 
                       + "Unknown type: {0}", val.Value);
                   break;
             }//switch
          }//foreach
       }
       else {
          ed.WriteMessage(System.Environment.NewLine 
             + "No xdata found for appid: TEST");
       }
       trans.Commit();                     
    }
    else {
       ed.WriteMessage(System.Environment.NewLine
          + "No xdata found for appid: TEST");
    }
  8. Create a command named RemXD to remove xdata associated with a particular appid. Add code, as in the other two commands, to prompt the user to select an object:

    [CommandMethod("RemXD")]
    static public void RemXD() {
       //Get the curr dwg database
       Database db =  
          Application.DocumentManager.MdiActiveDocument.Database;
       //Begin a transaction
       using (Transaction trans = 
          db.TransactionManager.StartTransaction()) {
          Editor ed = 
             Application.DocumentManager.MdiActiveDocument.Editor;
          //Select an object on screen
          PromptEntityOptions prEntOpts = new  
             PromptEntityOptions("Select object");
          prEntOpts.AllowNone = true; //Allow Enter key/Right-click
          PromptEntityResult prEntRes = ed.GetEntity(prEntOpts);
          if (prEntRes.Status != PromptStatus.OK) {
             ed.WriteMessage("Done.");
             return;
          }
          //Open the selected object for read
          Entity acEnt = (Entity)trans.GetObject(prEntRes.ObjectId, 
             OpenMode.ForRead);
          ResultBuffer resBuf = acEnt.GetXDataForApplication("TEST");
  9. If there is xdata associated with your appid, remove it by setting the object's XData property to an empty ResultBuffer (empty, except for your appid):

       if (resBuf != null) {
          acEnt.UpgradeOpen();
          acEnt.XData = new ResultBuffer(new TypedValue(1001,"TEST"));
          resBuf.Dispose();
       }
       trans.Commit();                 
    }

How it works...

AutoCAD maintains a regapp table which contains a regapp table record for every appid. Xdata persists with an object (entity) between drawing sessions. You can have more than one appid associated with an object, but you can only retrieve the xdata associated with a particular appid. There is also an xdata command for end users to specify an appid and add XData to an object. The main disadvantage of xdata is its size limitation. It is recommended to have no more than 1 KB of xdata attached to any one AutoCAD object.

There's more...

If you require more data per object, AutoCAD has an alternative to xdata called the xrecord, which lives either in the drawing's NamedObject Dictionary (NOD) or in a specific object's extension dictionary. Unlike xdata, xrecords are not subject to the 1 KB size limitation and hold much more data than xdata. Working with xrecords is outside the scope of this book.