Using a jig from .NET to multiply insert AutoCAD blocks

A big thanks to Holger Seidel from CADsys for proposing this topic and providing the bulk of the code. My main contribution - aside from some minor edits - was to implement the logic in the "BJIG" command to allow selection of the block and then loop to multiply insert it. The jig definition is almost entirely Holger's.

The below C# code essentially implements a streamlined "multiple insert" command, without the options to scale or rotate the block (this would be very simple to add, of course).

The code was written for AutoCAD 2007-2008. The only change you should need for AutoCAD 2006 is to change JigPromptPointOptions to JigPromptOptions (which was changed to an abstract class in AutoCAD 2007, so you now need to use one of the derived concrete classes).

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Geometry;

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 blockId = 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, blockId);

              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 btr =

                  (BlockTableRecord)tr.GetObject(

                    bt[BlockTableRecord.ModelSpace],

                    OpenMode.ForWrite

                  );

                btr.AppendEntity(

                  entJig.GetEntity()

                );

                tr.AddNewlyCreatedDBObject(

                  entJig.GetEntity(),

                  true

                );

                // Call a function to make the graphics display

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

                doc.TransactionManager.QueueForGraphicsFlush();

              }

            }

          }

          tr.Commit();

        }

      }

    }

  }

}

A follow-up to this post, showing how to support attributes and annotation scaling, is available here.

20 responses to “Using a jig from .NET to multiply insert AutoCAD blocks”

  1. How would you go about adding Attribute References to the jig prior to appending them to from the block table record?

  2. Kean Walmsley Avatar

    A good question... adding the attributes works fine once the block reference is in the database, but there appears to be a problem if the attributes are being added to the block reference before it gets appended. I'm checking in with our Engineering team on this.

    Kean

  3. Kean Walmsley Avatar

    OK - this currently isn't possible. Sorry for the bad news. I've posted some code to show how to append attributes after the jig process has completed in my next post.

    Kean

  4. Tony Tanzillo Avatar

    Thanks for a good basic example of a 2D jig.

    If you ever get around to doing an example that supports 3D, keep in mind that with the Dynamic UCS feature, you have to read the current value of the Editor's CurrentUserCoordainateSystem property in each jig update, and transform your block using that. If you do, then the jig will support DUCS like any good 3D jig should

  5. Tony Tanzillo Avatar

    Regarding support for dragging attributes and blocks, it can be done by creating the attributes and transforming each of them along with the block reference, without having to add them to the blockref.

  6. Newbie Question: What is a jig? Can you point me to a simple example (on this blog or elsewhere) using c# to insert one dynamic block ona drawing, then inserting a different type of dynamic block on the same drawing at a particular point on the first block. An example would be:
    1) insert a dynamic block that is a square. Set side length to 3000mm.
    2) at each corner of the square, insert a dynamic block that is a differnt sized circle. the center of each circle is located at each corner of the square. circle radius 1 = 500mm, 2 is 550 mm, 3 is 600mm, 4 is 650mm.
    The dynamic blocks that I am using are quite complex however so any help in describing how to work with inertion points is greatly appreciated.
    Thanks for a GREAT blog...even though most of it is going over my head at this point.

    --mspan

  7. Hi mspan,

    Here's the description of the AcEdJig class (the underlying ObjectARX class for a jig) from the ObjectARX Reference, part of the SDK:

    >>>
    The AcEdJig class is used to perform drag sequences, usually to acquire, create, edit, and add a new entity to the database. If you are deriving a new entity class, you will usually want to implement your own version of AcEdJig. This class enables the AutoCAD user to define certain aspects of an entity using a pointing device, and it gives the programmer access to the AutoCAD drag mechanism. (The class takes its name from โ€œjig,โ€ a device used to hold a machine part that is being bent or molded in place.)
    <<<

    I don't know of a pre-existing sample to do what you want - the requirement you've got is quite unusual, but not particularly difficult to solve. You have the control to do this from your app, for sure. Perhaps someone on the AutoCAD .NET Discussion Group will be able to help.

    Regards,

    Kean

  8. Hi Kean,

    You said that performing a rotation jig on an entity is quite simple. For a newbie like me, it's not so simple. Could you post an example or indicate me an example?

    Any help is greatly appreciated.

    Thanks,
    Danny

    P.S. Great blog!! You're my main source of knowledge...

  9. Hi Danny,

    As you asked so nicely... ๐Ÿ™‚

    Using a jig to rotate an AutoCAD entity via .NET

    Cheers,

    Kean

  10. Frank Nauwelaerts Avatar
    Frank Nauwelaerts

    Hi Kean,

    Is it possible to just drag all the attributes of a blockreference, without the blockref itself, in one motion? We have to insert a lot of blocks (with atts) each with a different orientation but we'd like to have all info (the atts) nicely aligned and horizontal (in WCS and UCS). Prompts like this:
    - insertionpoint block?
    - rotation block?
    - position of your attributes?

    Thought i got it using AcEdDragGen but it won't accept a sset with only subentities. AcEdJig doesn't seem to offer a solution either since it's single entities. I can move the atts in one motion with a rubberband but dragging would be nicer right?

    No can do?

    Regards,

    Frank Nauwelaerts

  11. Kean Walmsley Avatar

    Hi Frank,

    I can't see a way of doing this, without creating an intermediate block reference and replicating the attribute information but no geometry. You'd still have to get around the attribute jigging issue, of course.

    Cheers,

    Kean

  12. great blogs! your blog is my only dependable source. thanks a ton.

  13. Frank Nauwelaerts Avatar
    Frank Nauwelaerts

    Hi Kean,

    I "aceddraggen" temporary, plain textentities with the same appearance, instead of the attributes. Works like a charm, if i might say so myself.

    Thanks,

    Frank

  14. Kean Walmsley Avatar

    Thanks for sharing the tip, Frank!

    Kean

  15. Hi Kean,

    I want to placed block reference at some location without any interference. While placing a block I want to indicate to user whether it intersects with any other blocks or not. If it intersects then I want to change the color of block to 'RED' or otherwise 'BLUE'. Such that there is a need to find intersecting blocks and change the color while user drags a block.

    For that I have used EntityJig. I am using 'Sampler function' to change color of dragging
    block.

    I have used AcadSelectionSets and SelectByPolygon method in 'Sampler function' for getting intersecting blocks of Jig Entity. But I am getting selection count as 0 everytime even I have specified entire area to select all entities coming inside it.

    Is there any way to get intersecting selection set of EntityJig?

    Thanks in advance.
    VIKS

  16. Hi Viks,

    You work for an ADN member, so I suggest posting your question via the ADN site so one of my team can help you.

    During some selection commands I've been able to call Editor.SelectCrossingWindow() to find out the entities under the cursor, but I doubt it will work from a jig selection.

    ADN should be able to help more.

    Kean

  17. Hi All,

    Just a word of caution if you're running multiple jigs in a row. If a reactor, PointMonitor, custom property manager etc is listening to the mouse cursor and opens a transaction as part of it's usual business then jigs past the first one will not work properly. To work around that, you can only do the transaction stuff if Editor.IsDragging is false.

    (Took me a whole day of debugging to work this out so thought others might want to know ๐Ÿ™‚ )

    Cheers,
    Chris

  18. Can a jig optionally be controlled from a form? For example, use the mouse or values in text boxes to set block position, rotation, scale etc? So far I can't keep the jig visible when the form is displayed.

  19. You might be able to show a modeless dialog (maybe even the property palette - I recall it was possible to use the property palette during a command, at some point, to collect user input, although I don't recall whether the mechanism was jig-capable), but it's true that a modal dialog will not work.

    I haven't tried this myself, though.

    Kean

  20. Thanks. I use this code as template for my function!

Leave a Reply to dannyw Cancel reply

Your email address will not be published. Required fields are marked *