September 2014

Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30        








« Using the Microsoft Kinect SDK to sweep segmented solids inside AutoCAD | Main | Recorded AutoCAD .NET training available for download »

October 27, 2011

Creating a legend of AutoCAD drawings using .NET

This interesting question came up in our discussion forums:

Does anyone have a routine that will insert all the drawings from a single folder into one drawing to create a legend sheet? I'm trying to document the company's various blocks and details for dissemination amongst several offices.

The simplest – and most elegant, in my opinion – approach for addressing this requirement is via the Table object, which allows you to include block thumbnails in each of its cells. So we would need to import the various drawings into the current drawing as blocks, and then point the various cells of the table object at each of them, in turn. Thankfully I could borrow a good amount of the code to do this from these previous posts.

Here’s the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Windows;

using System.IO;

using System.Linq;

 

namespace MythsAndLegends

{

  public class Commands

  {

    [CommandMethod("LEGEND")]

    public void CreateLegend()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

 

      // Ask the user to select the drawings to list in the table

 

      OpenFileDialog ofd =

        new OpenFileDialog(

          "Select drawings to add to legend",

          null,

          "dwg",

          "DrawingsToImport",

          OpenFileDialog.OpenFileDialogFlags.AllowMultiple

        );

 

      System.Windows.Forms.DialogResult dr = ofd.ShowDialog();

 

      if (dr != System.Windows.Forms.DialogResult.OK)

        return;

 

      // Get the list of filenames and say how many were selected

 

      string[] names = ofd.GetFilenames();

      ed.WriteMessage(

        "\n{0} files selected.", names.Length

      );

 

      // If we have some selected, we'll create a table

 

      if (names.Length > 0)

      {

        int numRows, numCols;

 

        // If only one was selected, we know the table will

        // be 1x1

 

        if (names.Length == 1)

        {

          numRows = 1;

          numCols = 1;

        }

        else

        {

          // Otherwise we prompt for the number of columns

 

          PromptIntegerOptions opts =

            new PromptIntegerOptions(

              "\nEnter number of columns: "

            );

 

          opts.LowerLimit = 1;

          opts.UpperLimit = names.Length;

          opts.DefaultValue = 1;

          opts.UseDefaultValue = true;

 

          PromptIntegerResult pir = ed.GetInteger(opts);

 

          if (pir.Status != PromptStatus.OK)

            return;

 

          // Get whether to start at the top or the bottom

 

          PromptKeywordOptions pko =

            new PromptKeywordOptions(

              "\nPopulate from the top or from the bottom?"

            );

          pko.AllowNone = true;

          pko.Keywords.Add("Top");

          pko.Keywords.Add("Bottom");

          pko.Keywords.Default = "Top";

 

          PromptResult pkr = ed.GetKeywords(pko);

 

          bool fromTop = (pkr.StringResult == "Top");

 

          // Get whether to start at the top or the bottom

 

          pko =

            new PromptKeywordOptions(

              "\nList alphabetically or in selected order?"

            );

          pko.AllowNone = true;

          pko.Keywords.Add("Alphabetically");

          pko.Keywords.Add("Selected");

          pko.Keywords.Default = "Alphabetically";

 

          pkr = ed.GetKeywords(pko);

 

          bool sort = (pkr.StringResult == "Alphabetically");

 

          // And the insertion point of the table

 

          PromptPointResult pr =

            ed.GetPoint("\nEnter table insertion point: ");

 

          if (pr.Status == PromptStatus.OK)

          {

            Transaction tr =

              doc.TransactionManager.StartTransaction();

 

            using (tr)

            {

              // Use constants for the cell dimensions

 

              const int cellWidth = 3;

              const int cellHeight = 3;

 

              // Create the table

 

              Table tb = new Table();

              tb.TableStyle = db.Tablestyle;

 

              // We can calculate the number of rows based on

              // the number of cells and the number of columns

 

              numCols = pir.Value;

              numRows = (names.Length / numCols) + 1;

 

              // We'll add in our custom columns and rows

 

              if (numCols > 0)

              {

                tb.InsertColumns(1, cellWidth, numCols);

              }

              if (numRows > 0)

              {

                tb.InsertRows(1, cellHeight, numRows);

              }

 

              // And then delete the original row/column

              // that comes with the blank table

 

              tb.DeleteRows(0, 1);

              tb.DeleteColumns(0, 1);

 

              tb.Position = pr.Value;

 

              if (sort)

              {

                names = names.OrderBy(x => x).ToArray<string>();

              }

 

              // Loop through the names, adding them to the table

 

              for (int i = 0; i < names.Length; i++)

              {

                string blockName = "";

 

                try

                {

                  // Use a Database to insert a block for each

                  // drawing into the current drawing

 

                  using (Database src = new Database(false, true))

                  {

                    // First we read in the DWG

 

                    src.ReadDwgFile(

                      names[i], FileShare.Read, true, ""

                    );

 

                    // Take the name of the file without the

                    // extension

 

                    blockName =

                      Path.GetFileNameWithoutExtension(names[i]);

 

                    // Check whether it works as a symbol table

                    // name (will thrown an exception if not)

 

                    SymbolUtilityServices.ValidateSymbolName(

                      blockName, false

                    );

 

                    // Insert our drawing as a block (which

                    // will take the modelspace)

 

                    ObjectId blockId =

                      db.Insert(blockName, src, false);

 

                    // Calculate the row and column for this item

                    // If from the top: we just divide by the

                    // number of columns to get the row

                    // If from the bottom, subtract from

                    // the total rows

 

                    int row =

                      (fromTop ?

                        i / numCols :

                        numRows - (i / numCols + 1)

                      );

 

                    // The column is just the modulus remainder

 

                    int col = i % numCols;

 

                    // Insert the block as the contents of our cell

 

                    Cell cell = tb.Cells[row, col];

                    cell.Contents.InsertAt(0);

                    cell.Contents[0].BlockTableRecordId =

                       blockId;

                  }

                }

                catch (System.Exception ex)

                {

                  ed.WriteMessage(

                    "\nCould not add \"{0}\": {1}",

                    blockName, ex.Message

                  );

                }

              }

              tb.GenerateLayout();

 

              // Finally we add our table to modelspace

 

              BlockTable bt =

                (BlockTable)tr.GetObject(

                  doc.Database.BlockTableId,

                  OpenMode.ForRead

                );

 

              BlockTableRecord btr =

                (BlockTableRecord)tr.GetObject(

                  bt[BlockTableRecord.ModelSpace],

                  OpenMode.ForWrite

                );

              btr.AppendEntity(tb);

              tr.AddNewlyCreatedDBObject(tb, true);

              tr.Commit();

            }

          }

        }

      }

    }

  }

}

When we run the LEGEND command, we get asked to select some drawings:

Selecting a set of drawing files

We then get prompted with the number of drawings selected and get asked to provide some additional information to determine how the table gets created. We’ll run the command twice, selecting the same set of AutoCAD sample drawings but using 3 and 4 columns, populating the two tables from the top and the bottom respectively.

Command: LEGEND

13 files selected.

Enter number of columns <1>: 3

Populate from the top or from the bottom? [Top/Bottom] <Top>: Top

List alphabetically or in selected order? [Alphabetically/Selected]

<Alphabetically>: Alphabetically

Enter table insertion point:

 

[Dump of block imports deleted...]

 

Command: LEGEND

13 files selected.

Enter number of columns <1>: 4

Populate from the top or from the bottom? [Top/Bottom] <Top>: Bottom

List alphabetically or in selected order? [Alphabetically/Selected]

<Alphabetically>: Alphabetically

Enter table insertion point:

 

[Dump of block imports deleted...]

We can see that the tables contain the same order of blocks, but the first is wider and was populated from the top-left rather than the bottom-left:Two legend tables created from a folder of drawings

blog comments powered by Disqus

Feed/Share

10 Random Posts