August 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
31            








« Using a jig from .NET to multiply insert AutoCAD blocks | Main | Displaying a progress meter during long operations in AutoCAD using .NET »

May 22, 2007

Using a jig from .NET to multiply insert AutoCAD blocks - Part 2

In the last post we looked at a jig that can be used to add block references to an AutoCAD drawing. This post extends that code to support annotative block definitions (available from AutoCAD 2008) and blocks with attributes. Thanks once again to Holger Steiner for the jig class and to Roland Feletic for posting the code to support annotative blocks.

A comment on the previous post asked about having attributes visible during the jig process: unfortunately that's not currently possible, as the existing managed AttributeCollection implementation wraps the version of the AcDbBlockReference::appendAttribute() ObjectARX function that requires the block reference to already have been added to the drawing. So for now you will need to live with the fact that the attributes don't display during the jig, but do display as soon as the block has been added to the drawing.

Below is the modified C# code, with line numbers. And here's the source file for download.

    1 using Autodesk.AutoCAD.ApplicationServices;

    2 using Autodesk.AutoCAD.DatabaseServices;

    3 using Autodesk.AutoCAD.EditorInput;

    4 using Autodesk.AutoCAD.Runtime;

    5 using Autodesk.AutoCAD.Geometry;

    6 using Autodesk.AutoCAD.Internal;

    7

    8 namespace BlockJigTest

    9 {

   10   class BlockJig : EntityJig

   11   {

   12     Point3d mCenterPt, mActualPoint;

   13

   14     public BlockJig(BlockReference br)

   15       : base(br)

   16     {

   17       mCenterPt = br.Position;

   18     }

   19

   20     protected override SamplerStatus Sampler(JigPrompts prompts)

   21     {

   22       JigPromptPointOptions jigOpts =

   23         new JigPromptPointOptions();

   24       jigOpts.UserInputControls =

   25         (UserInputControls.Accept3dCoordinates

   26         | UserInputControls.NoZeroResponseAccepted

   27         | UserInputControls.NoNegativeResponseAccepted);

   28

   29       jigOpts.Message =

   30         "\nEnter insert point: ";

   31

   32       PromptPointResult dres =

   33         prompts.AcquirePoint(jigOpts);

   34

   35       if (mActualPoint == dres.Value)

   36       {

   37         return SamplerStatus.NoChange;

   38       }

   39       else

   40       {

   41         mActualPoint = dres.Value;

   42       }

   43       return SamplerStatus.OK;

   44     }

   45

   46     protected override bool Update()

   47     {

   48       mCenterPt = mActualPoint;

   49       try

   50       {

   51         ((BlockReference)Entity).Position = mCenterPt;

   52       }

   53       catch (System.Exception)

   54       {

   55         return false;

   56       }

   57       return true;

   58     }

   59

   60     public Entity GetEntity()

   61     {

   62       return Entity;

   63     }

   64   }

   65

   66   public class Commands

   67   {

   68     [CommandMethod("BJIG")]

   69     public void CreateBlockWithJig()

   70     {

   71       Document doc =

   72         Application.DocumentManager.MdiActiveDocument;

   73       Database db = doc.Database;

   74       Editor ed = doc.Editor;

   75

   76       // First let's get the name of the block

   77       PromptStringOptions opts =

   78         new PromptStringOptions("\nEnter block name: ");

   79       PromptResult pr = ed.GetString(opts);

   80       if (pr.Status == PromptStatus.OK)

   81       {

   82         Transaction tr =

   83           doc.TransactionManager.StartTransaction();

   84         using (tr)

   85         {

   86           // Then open the block table and check the

   87           // block definition exists

   88           BlockTable bt =

   89             (BlockTable)tr.GetObject(

   90               db.BlockTableId,

   91               OpenMode.ForRead

   92             );

   93           if (!bt.Has(pr.StringResult))

   94           {

   95             ed.WriteMessage("\nBlock not found.");

   96           }

   97           else

   98           {

   99             ObjectId bdId = bt[pr.StringResult];

  100

  101             // We loop until the jig is cancelled

  102             while (pr.Status == PromptStatus.OK)

  103             {

  104               // Create the block reference and

  105               // add it to the jig

  106               Point3d pt = new Point3d(0, 0, 0);

  107               BlockReference br =

  108                 new BlockReference(pt, bdId);

  109

  110               BlockJig entJig = new BlockJig(br);

  111

  112               // Perform the jig operation

  113               pr = ed.Drag(entJig);

  114               if (pr.Status == PromptStatus.OK)

  115               {

  116                 // If all is OK, let's go and add the

  117                 // entity to the modelspace

  118                 BlockTableRecord ms =

  119                   (BlockTableRecord)tr.GetObject(

  120                     bt[BlockTableRecord.ModelSpace],

  121                     OpenMode.ForWrite

  122                   );

  123                 ms.AppendEntity(

  124                   entJig.GetEntity()

  125                 );

  126                 tr.AddNewlyCreatedDBObject(

  127                   entJig.GetEntity(),

  128                   true

  129                 );

  130

  131                 // Start attrib/annot-scale support code

  132                 BlockTableRecord bd =

  133                   (BlockTableRecord)tr.GetObject(

  134                     bdId,

  135                     OpenMode.ForRead

  136                   );

  137                 if (bd.Annotative == AnnotativeStates.True)

  138                 {

  139                   ObjectContextManager ocm =

  140                     db.ObjectContextManager;

  141                   ObjectContextCollection occ =

  142                     ocm.GetContextCollection(

  143                       "ACDB_ANNOTATIONSCALES"

  144                     );

  145                   ObjectContexts.AddContext(

  146                     br,

  147                     occ.CurrentContext

  148                   );

  149                 }

  150

  151                 // Add the attributes

  152                 foreach (ObjectId attId in bd)

  153                 {

  154                   Entity ent =

  155                     (Entity)tr.GetObject(

  156                       attId,

  157                       OpenMode.ForRead

  158                     );

  159                   if (ent is AttributeDefinition)

  160                   {

  161                     AttributeDefinition ad =

  162                       (AttributeDefinition)ent;

  163                     AttributeReference ar =

  164                       new AttributeReference();

  165                     ar.SetAttributeFromBlock(

  166                       ad,

  167                       br.BlockTransform

  168                     );

  169                     br.AttributeCollection.AppendAttribute(ar);

  170                     tr.AddNewlyCreatedDBObject(ar, true);

  171                   }

  172                 }

  173                 // End attrib/annot-scale support code

  174

  175                 // Call a function to make the graphics display

  176                 // (otherwise it will only do so when we Commit)

  177                 doc.TransactionManager.QueueForGraphicsFlush();

  178               }

  179             }

  180           }

  181           tr.Commit();

  182         }

  183       }

  184     }

  185   }

  186 }

You'll notice the lines in red, from lines 131 to 173, have been added to the previous version of the code. The lines from 137 to 149 will only work with versions since AutoCAD 2008, as they're related to annotation scaling. As mentioned previously, this section of code relies on AcMgdInternal.dll, an unsupported assembly which is liable to change in future releases.

Update:

Subsequent to the comment from Roland, I've modified the above code to attach the annotation scale earlier, before the jig starts. This allows the jig to properly represent the block being placed (as otherwise annotative blocks will not display during the jig operation):

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.Internal;

namespace BlockJigTest

{

  class BlockJig : EntityJig

  {

    Point3d mCenterPt, mActualPoint;

    public BlockJig(BlockReference br)

      : base(br)

    {

      mCenterPt = br.Position;

    }

    protected override SamplerStatus Sampler(JigPrompts prompts)

    {

      JigPromptPointOptions jigOpts =

        new JigPromptPointOptions();

      jigOpts.UserInputControls =

        (UserInputControls.Accept3dCoordinates

        | UserInputControls.NoZeroResponseAccepted

        | UserInputControls.NoNegativeResponseAccepted);

      jigOpts.Message =

        "\nEnter insert point: ";

      PromptPointResult dres =

        prompts.AcquirePoint(jigOpts);

      if (mActualPoint == dres.Value)

      {

        return SamplerStatus.NoChange;

      }

      else

      {

        mActualPoint = dres.Value;

      }

      return SamplerStatus.OK;

    }

    protected override bool Update()

    {

      mCenterPt = mActualPoint;

      try

      {

        ((BlockReference)Entity).Position = mCenterPt;

      }

      catch (System.Exception)

      {

        return false;

      }

      return true;

    }

    public Entity GetEntity()

    {

      return Entity;

    }

  }

  public class Commands

  {

    [CommandMethod("BJIG")]

    public void CreateBlockWithJig()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

      // First let's get the name of the block

      PromptStringOptions opts =

        new PromptStringOptions("\nEnter block name: ");

      PromptResult pr = ed.GetString(opts);

      if (pr.Status == PromptStatus.OK)

      {

        Transaction tr =

          doc.TransactionManager.StartTransaction();

        using (tr)

        {

          // Then open the block table and check the

          // block definition exists

          BlockTable bt =

            (BlockTable)tr.GetObject(

              db.BlockTableId,

              OpenMode.ForRead

            );

          if (!bt.Has(pr.StringResult))

          {

            ed.WriteMessage("\nBlock not found.");

          }

          else

          {

            ObjectId bdId = bt[pr.StringResult];

            // We loop until the jig is cancelled

            while (pr.Status == PromptStatus.OK)

            {

              // Create the block reference and

              // add it to the jig

              Point3d pt = new Point3d(0, 0, 0);

              BlockReference br =

                new BlockReference(pt, bdId);

              // Start annot-scale support code

              BlockTableRecord bd =

                (BlockTableRecord)tr.GetObject(

                  bdId,

                  OpenMode.ForRead

                );

              // Using will dispose of the block definition

              // when no longer needed

              using (bd)

              {

                if (bd.Annotative == AnnotativeStates.True)

                {

                  ObjectContextManager ocm =

                    db.ObjectContextManager;

                  ObjectContextCollection occ =

                    ocm.GetContextCollection(

                      "ACDB_ANNOTATIONSCALES"

                    );

                  ObjectContexts.AddContext(

                    br,

                    occ.CurrentContext

                  );

                }

              }

              // End annot-scale support code

              BlockJig entJig = new BlockJig(br);

              // Perform the jig operation

              pr = ed.Drag(entJig);

              if (pr.Status == PromptStatus.OK)

              {

                // If all is OK, let's go and add the

                // entity to the modelspace

                BlockTableRecord ms =

                  (BlockTableRecord)tr.GetObject(

                    bt[BlockTableRecord.ModelSpace],

                    OpenMode.ForWrite

                  );

                ms.AppendEntity(

                  entJig.GetEntity()

                );

                tr.AddNewlyCreatedDBObject(

                  entJig.GetEntity(),

                  true

                );

                // Start attribute support code

                bd =

                  (BlockTableRecord)tr.GetObject(

                    bdId,

                    OpenMode.ForRead

                  );

                // Add the attributes

                foreach (ObjectId attId in bd)

                {

                  Entity ent =

                    (Entity)tr.GetObject(

                      attId,

                      OpenMode.ForRead

                    );

                  if (ent is AttributeDefinition)

                  {

                    AttributeDefinition ad =

                      (AttributeDefinition)ent;

                    AttributeReference ar =

                      new AttributeReference();

                    ar.SetAttributeFromBlock(

                      ad,

                      br.BlockTransform

                    );

                    br.AttributeCollection.AppendAttribute(ar);

                    tr.AddNewlyCreatedDBObject(ar, true);

                  }

                }

                // End attribute support code

                // Call a function to make the graphics display

                // (otherwise it will only do so when we Commit)

                doc.TransactionManager.QueueForGraphicsFlush();

              }

            }

          }

          tr.Commit();

        }

      }

    }

  }

}

Update 2:

This more recent post shows how to jig blocks with attributes.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d83452464869e200d8357b74e569e2

Listed below are links to weblogs that reference Using a jig from .NET to multiply insert AutoCAD blocks - Part 2:

blog comments powered by Disqus

Feed/Share

10 Random Posts