December 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      










« Waiting for my Raspberry Pi | Main | A handy jig for creating AutoCAD text using .NET – Part 2 »

August 10, 2012

A handy jig for creating AutoCAD text using .NET – Part 1

Back in March, I received an email from Thomas Fitou suggesting an interesting blog topic:

I was thinking about a cool feature in jigs:

  • You invoke a command to enter an Mtext or text
  • The editor is asking for some text
  • You enter the text
  • Then a jig is dragged asking for position
  • But in the editor appear some options:[R]egular [B]old [I]talic [R]otate 90
  • If the user hits "B" the text becomes bold
  • If the user hits "R" the text is rotated 90 degrees
  • If the user hits "R" again, another 90 degrees and so on...

It struck me as an interesting idea, but wasn’t something I managed to get to until now. It turned out to be a pretty interesting mini-project, too – so much so that I decided to split it across 3 separate posts:

  1. A basic jig to position, rotate and size a DBText object
  2. An extended version that supports font-level formatting (bold, italic, etc.)
  3. For extra points: interactive alignment adjustment (left, middle, right)

In today’s post, then, we’re going to see a basic jig implementation that allows the user to position, rotate and adjust the size of the created text.

A few notes on design decisions related to this code:

  • I decided to stick with DBText rather than including MText
  • A few previous implementations on this blog have made sure geometry is database-resident before jigging it
    • While not needed for this initial post, it is needed later on, so I’ve adopted that same approach, here
  • The proposed implementation suggested the use of single keystrokes to enable different modes (at least that’s how I read it)
    • The code uses the standard keyword mechanism, which means Enter is needed to submit the mode change
  • I’ve placed the UI paths (i.e. the keywords) in the code for the latter parts – for now they don’t do anything, though
    • I dropped the “Regular” keyword, with the idea that “Bold” and “Italic” should really be toggles (and “R” is already fairly busy between “ROtate90” and “RIght”, for that matter)

Here’s the C# code for this initial version:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.Runtime;

using System;

 

public class Commands

{

  [CommandMethod("QT")]

  static public void QuickText()

  {

    Document doc =

      Application.DocumentManager.MdiActiveDocument;

    Database db = doc.Database;

    Editor ed = doc.Editor;

 

    PromptStringOptions pso =

      new PromptStringOptions("\nEnter text string");

    pso.AllowSpaces = true;

    PromptResult pr = ed.GetString(pso);

 

    if (pr.Status != PromptStatus.OK)

      return;

 

    Transaction tr =

      doc.TransactionManager.StartTransaction();

    using (tr)

    {

      BlockTableRecord btr =

        (BlockTableRecord)tr.GetObject(

          db.CurrentSpaceId, OpenMode.ForWrite

        );

 

      // Create the text object, set its normal and contents

 

      DBText txt = new DBText();

      txt.Normal =

        ed.CurrentUserCoordinateSystem.

          CoordinateSystem3d.Zaxis;

      txt.TextString = pr.StringResult;

 

      // We'll add the text to the database before jigging

      // it - this allows alignment adjustments to be

      // reflected

 

      btr.AppendEntity(txt);

      tr.AddNewlyCreatedDBObject(txt, true);

 

      // Create our jig

 

      TextPlacementJig pj = new TextPlacementJig(tr, db, txt);

 

      // Loop as we run our jig, as we may have keywords

 

      PromptStatus stat = PromptStatus.Keyword;

      while (stat == PromptStatus.Keyword)

      {

        PromptResult res = ed.Drag(pj);

        stat = res.Status;

        if (

          stat != PromptStatus.OK &&

          stat != PromptStatus.Keyword

        )

          return;

      }

 

      tr.Commit();

    }

  }

 

  class TextPlacementJig : EntityJig

  {

    // Declare some internal state

 

    Database _db;

    Transaction _tr;

    Point3d _position;

    double _angle, _txtSize;

 

    // Constructor

 

    public TextPlacementJig(

      Transaction tr, Database db, Entity ent

    ) : base(ent)

    {

      _db = db;

      _tr = tr;

      _angle = 0;

      _txtSize = 1;

    }

 

    protected override SamplerStatus Sampler(

      JigPrompts jp

    )

    {

      // We acquire a point but with keywords

 

      JigPromptPointOptions po =

        new JigPromptPointOptions(

          "\nPosition of text"

        );

 

      po.UserInputControls =

        (UserInputControls.Accept3dCoordinates |

          UserInputControls.NullResponseAccepted |

          UserInputControls.NoNegativeResponseAccepted |

          UserInputControls.GovernedByOrthoMode);

 

      po.SetMessageAndKeywords(

        "\nSpecify position of text or " +

        "[Bold/Italic/LArger/Smaller/" +

         "ROtate90/LEft/Middle/RIght]: ",

        "Bold Italic LArger Smaller " +

        "ROtate90 LEft Middle RIght"

      );

 

      PromptPointResult ppr = jp.AcquirePoint(po);

 

      if (ppr.Status == PromptStatus.Keyword)

      {

        switch (ppr.StringResult)

        {

          case "Bold":

            {

              // TODO

 

              break;

            }

          case "Italic":

            {

              // TODO

 

              break;

            }

          case "LArger":

            {

              // Multiple the text size by two

 

              _txtSize *= 2;

              break;

            }

          case "Smaller":

            {

              // Divide the text size by two

 

              _txtSize /= 2;

              break;

            }

          case "ROtate90":

            {

              // To rotate clockwise we subtract 90 degrees and

              // then normalise the angle between 0 and 360

 

              _angle -= Math.PI / 2;

              while (_angle < Math.PI * 2)

              {

                _angle += Math.PI * 2;

              }

              break;

            }

          case "LEft":

            {

              // TODO

 

              break;

            }

          case "RIght":

            {

              // TODO

 

              break;

            }

          case "Middle":

            {

              // TODO

 

              break;

            }

        }

 

        return SamplerStatus.OK;

      }

      else if (ppr.Status == PromptStatus.OK)

      {

        // Check if it has changed or not (reduces flicker)

 

        if (

          _position.DistanceTo(ppr.Value) <

            Tolerance.Global.EqualPoint

        )

          return SamplerStatus.NoChange;

 

        _position = ppr.Value;

        return SamplerStatus.OK;

      }

 

      return SamplerStatus.Cancel;

    }

 

    protected override bool Update()

    {

      // Set properties on our text object

 

      DBText txt = (DBText)Entity;

 

      txt.Position = _position;

      txt.Height = _txtSize;

      txt.Rotation = _angle;

 

      return true;

    }

  }

}

When we run our QT (which stands for QuickText) command, we can use it to quickly enter, preview and place a text object:

Command: QT

Enter text string: Some text

Jigging some text

Specify position of text or

[Bold/Italic/LArger/Smaller/ROtate90/LEft/Middle/RIght]: LA

Increasing its size

Specify position of text or

[Bold/Italic/LArger/Smaller/ROtate90/LEft/Middle/RIght]: RO

Rotating it

Specify position of text or

[Bold/Italic/LArger/Smaller/ROtate90/LEft/Middle/RIght]:

And it gets placed

In the next post, we’ll implement the font-formatting options for bold, italic and bold-italic text (which, as it requires modification to the associated text style, is harder than it sounds).

blog comments powered by Disqus

Feed/Share

10 Random Posts