Moving text in an AutoCAD block using .NET – Part 2

I was planning to post about Autodesk University 2013 today, but things have just been too hectic. I have a 3-hour layover in Heathrow on the journey home โ€“ which starts this evening โ€“ so I'll try to use that to post a summary of this year's AU as experienced by yours truly.

In the last post we saw some code to move an entity โ€“ any entity, with text as the primary requirement โ€“ in a block.

Here's a version of the C# code that shows the entity as it's being jigged across the screen to its new position. The interesting part of this, in many ways, is the transformations that are needed pre- and post-jig to make sure the entity is under the cursor (the same transformation matrices calculated from the nested containers in the last post).

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.Runtime;

 

namespace Textformations

{

  public class DisplacementJig : EntityJig

  {

    private Point3d _pos;

    private Point3d _loc;

 

    public DisplacementJig(Entity ent, Point3d basePt)

      : base(ent)

    {

      _loc = basePt;

    }

 

    protected override bool Update()

    {

      var disp = _pos - _loc;

      _loc = _pos;

      var mat = Matrix3d.Displacement(disp);

      Entity.TransformBy(mat);

      return true;

    }

 

    protected override SamplerStatus Sampler(JigPrompts prompts)

    {

      var opts =

        new JigPromptPointOptions("\nSelect displacement");

      opts.BasePoint = _pos;

      opts.UserInputControls =

        UserInputControls.NoZeroResponseAccepted;

 

      var ppr = prompts.AcquirePoint(opts);

      if (_pos == ppr.Value)

        r
eturn
SamplerStatus.NoChange;

 

      _pos = ppr.Value;

 

      return SamplerStatus.OK;

    }

  }

 

  public class Commands2

  {

    [CommandMethod("MTIBJIG")]

    public static void MoveTextInBlock()

    {

      var doc = Application.DocumentManager.MdiActiveDocument;

      var db = doc.Database;

      var ed = doc.Editor;

 

      // Start by getting the text (or other) object in the block

 

      var pneo =

        new PromptNestedEntityOptions("\nSelect text inside block");

      var pner = ed.GetNestedEntity(pneo);

 

      if (pner.Status != PromptStatus.OK)

        return;

 

      var selId = pner.ObjectId;

 

      // Start a transaction to access the object

 

      var oc = selId.ObjectClass;

      if (

        !oc.IsDerivedFrom(

          RXClass.GetClass(typeof(DBText))

        ) &&

        !oc.IsDerivedFrom(

          RXClass.GetClass(typeof(MText))

        )

      )

      {

        // Isn't a text object - ask whether we continue

 

        ed.WriteMessage(

          "\nObject is not text, it is a {0}.", oc.Name

        );

 

        var pko =

          new PromptKeywordOptions(

            "\nDo you want to continue? [Yes/No]", "Yes No"

          );

        pko.AppendKeywordsToMessage = true;

        pko.AllowNone = true;

        pko.Keywords.Default = "No";

 

        var pr = ed.GetKeywords(pko);

        if (

          pr.Status != PromptStatus.OK || pr.StringResult == "No"

        )

          return;

      }

 

      // Start a transaction to modify the object

 

      using (var tr = doc.TransactionManager.StartTransaction())

      {

        // Unless we get a block reference container, use the

        // identity matrix as the block transform

 

        var brMat = Matrix3d.Identity;

 

        // Get the containers around the nested entity

 

        var conts = pner.GetContainers();

        foreach (var brId in conts)

        {

          var br =

            tr.GetObject(brId, OpenMode.ForRead) as BlockReference;

          if (br != null)

          {

            brMat = brMat.PreMultiplyBy(br.BlockTransform);

          }

        }

 

        // Transform the entity

 

        var ent = (Entity)tr.GetObject(selId, OpenMode.ForWrite);

 

        // Before we run the jig, transform the object by the

        // aggregate transform of the containers

 

        ent.TransformBy(brMa
t);

 

        // Run the jig to displace the object

 

        var dj = new DisplacementJig(ent, pner.PickedPoint);

        var pr = ed.Drag(dj);

        if (pr.Status == PromptStatus.OK)

        {

          // We can transform the entity back, now (at least in

          // terms of the containers: the displacement remains)

 

          ent.TransformBy(brMat.Inverse());

 

          // Open each of the containers and set a property so that

        // they each get regenerated

 

          foreach (var id in conts)

          {

            var ent2 = tr.GetObject(id, OpenMode.ForWrite) as Entity;

            if (ent2 != null)

            {

              // We might also have called this method:

              // ent2.RecordGraphicsModified(true);

              // but setting a property works better with undo

 

              ent2.Visible = ent2.Visible;

            }

          }

 

          tr.Commit();

        }

      }

    }

  }

}

Here's the new MTIBJIG command in action:

MTIBJIG

8 responses to “Moving text in an AutoCAD block using .NET – Part 2”

  1. Love it!

  2. Hi Kean!

    Would it be possible for us to highlight only the subentities themselves (such as the DBText or MText), instead of highlighting the whole block reference when moving the mouse over it?

    Thanks!

  3. Hi Samir,

    You mean outside of a command, to control the rollover highlighting behaviour?

    I haven't tried this myself. It's just possible something can be done using a PointMonitor, but I actually suspect not. You could always just EXPLODE the blocks, of course. ๐Ÿ˜‰

    Kean

  4. Kean,

    I actually mean as a "plus" to this post of yours ๐Ÿ™‚
    When you get to the part where you need to select the text (or some other entity), I wonder if there's a way we could highlight the subentities instead of the whole block reference when you move your mouse over them. Temporarily exploding the blocks recursively could definitely do the trick, but would that work for external references as well?

  5. Also, exploding blocks might not have the desired effect if those blocks have attributes or are XCLIPing some content, because exploding the blocks might reveal a lot of "clutter".

  6. Sure - was just joking about EXPLODE.

    I now understand better what you're after. I'll give it a try, but I expect it's going to get messy... ๐Ÿ™‚

    Kean

  7. Kean, I have tried unsuccessfully to combine both this and the Part 1 with no success. What I am trying to do is also show the displacement line.
    I thought I could use the opts.basepoint in the Sampler function, but failed. What am I missing mate?

    1. You might try using AcquireDistance() rather than AcquirePoint()...

      Kean

Leave a Reply

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