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      










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

August 15, 2012

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

Earlier in this series, we implemented a jig to rotate, size and place text more easily in an AutoCAD drawing, which we then extended to allow adjustment of font-level properties. In this post, we’re going to add some additional functionality to allow the text to be justified differently around the cursor location.

It has to be said that the code introduced in this post isn’t very extensive, but nonetheless tricky to get right (and therefore deserving of its own post). It’s also worth noting that the changes would be much more complicated if we hadn’t designed the code to add the text to the database prior to passing it to the jig: that’s a pre-requisite for the code in this post to work properly.

The primary property we want to modify is DBText.HorizontalMode. We will set this to the following items in the TextHorizontalMode enumeration, depending on the keyword chosen: TextLeft, TextMid and TextRight. That’s the easy bit: the tricky part is that we also need to change the AlignmentPoint property, in the case where the HorizontalMode is other than TextLeft, and then call AdjustAlignment().

Here’s the updated C# code, with new lines marked in red (and here’s the source file for you to download):

    1 using Autodesk.AutoCAD.ApplicationServices;

    2 using Autodesk.AutoCAD.DatabaseServices;

    3 using Autodesk.AutoCAD.EditorInput;

    4 using Autodesk.AutoCAD.Geometry;

    5 using Autodesk.AutoCAD.GraphicsInterface;

    6 using Autodesk.AutoCAD.Runtime;

    7 using System;

    8 

    9 public class Commands

   10 {

   11   [CommandMethod("QT")]

   12   static public void QuickText()

   13   {

   14     Document doc =

   15       Application.DocumentManager.MdiActiveDocument;

   16     Database db = doc.Database;

   17     Editor ed = doc.Editor;

   18 

   19     PromptStringOptions pso =

   20       new PromptStringOptions("\nEnter text string");

   21     pso.AllowSpaces = true;

   22     PromptResult pr = ed.GetString(pso);

   23 

   24     if (pr.Status != PromptStatus.OK)

   25       return;

   26 

   27     Transaction tr =

   28       doc.TransactionManager.StartTransaction();

   29     using (tr)

   30     {

   31       BlockTableRecord btr =

   32         (BlockTableRecord)tr.GetObject(

   33           db.CurrentSpaceId, OpenMode.ForWrite

   34         );

   35 

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

   37 

   38       DBText txt = new DBText();

   39       txt.Normal =

   40         ed.CurrentUserCoordinateSystem.

   41           CoordinateSystem3d.Zaxis;

   42       txt.TextString = pr.StringResult;

   43 

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

   45       // it - this allows alignment adjustments to be

   46       // reflected

   47 

   48       btr.AppendEntity(txt);

   49       tr.AddNewlyCreatedDBObject(txt, true);

   50 

   51       // Create our jig

   52 

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

   54 

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

   56 

   57       PromptStatus stat = PromptStatus.Keyword;

   58       while (stat == PromptStatus.Keyword)

   59       {

   60         PromptResult res = ed.Drag(pj);

   61         stat = res.Status;

   62         if (

   63           stat != PromptStatus.OK &&

   64           stat != PromptStatus.Keyword

   65         )

   66           return;

   67       }

   68 

   69       tr.Commit();

   70     }

   71   }

   72 

   73   class TextPlacementJig : EntityJig

   74   {

   75     // Declare some internal state

   76 

   77     Database _db;

   78     Transaction _tr;

   79     Point3d _position;

   80     double _angle, _txtSize;

   81     bool _toggleBold, _toggleItalic;

   82     TextHorizontalMode _align;

   83 

   84     // Constructor

   85 

   86     public TextPlacementJig(

   87       Transaction tr, Database db, Entity ent

   88     ) : base(ent)

   89     {

   90       _db = db;

   91       _tr = tr;

   92       _angle = 0;

   93       _txtSize = 1;

   94     }

   95 

   96     protected override SamplerStatus Sampler(

   97       JigPrompts jp

   98     )

   99     {

  100       // We acquire a point but with keywords

  101 

  102       JigPromptPointOptions po =

  103         new JigPromptPointOptions(

  104           "\nPosition of text"

  105         );

  106 

  107       po.UserInputControls =

  108         (UserInputControls.Accept3dCoordinates |

  109           UserInputControls.NullResponseAccepted |

  110           UserInputControls.NoNegativeResponseAccepted |

  111           UserInputControls.GovernedByOrthoMode);

  112 

  113       po.SetMessageAndKeywords(

  114         "\nSpecify position of text or " +

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

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

  117         "Bold Italic LArger Smaller " +

  118         "ROtate90 LEft Middle RIght"

  119       );

  120 

  121       PromptPointResult ppr = jp.AcquirePoint(po);

  122 

  123       if (ppr.Status == PromptStatus.Keyword)

  124       {

  125         switch (ppr.StringResult)

  126         {

  127           case "Bold":

  128             {

  129               _toggleBold = true;

  130               break;

  131             }

  132           case "Italic":

  133             {

  134               _toggleItalic = true;

  135               break;

  136             }

  137           case "LArger":

  138             {

  139               // Multiple the text size by two

  140 

  141               _txtSize *= 2;

  142               break;

  143             }

  144           case "Smaller":

  145             {

  146               // Divide the text size by two

  147 

  148               _txtSize /= 2;

  149               break;

  150             }

  151           case "ROtate90":

  152             {

  153               // To rotate clockwise we subtract 90 degrees and

  154               // then normalise the angle between 0 and 360

  155 

  156               _angle -= Math.PI / 2;

  157               while (_angle < Math.PI * 2)

  158               {

  159                 _angle += Math.PI * 2;

  160               }

  161               break;

  162             }

  163           case "LEft":

  164             {

  165               _align = TextHorizontalMode.TextLeft;

  166               break;

  167             }

  168           case "RIght":

  169             {

  170               _align = TextHorizontalMode.TextRight;

  171               break;

  172             }

  173           case "Middle":

  174             {

  175               _align = TextHorizontalMode.TextMid;

  176               break;

  177             }

  178         }

  179 

  180         return SamplerStatus.OK;

  181       }

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

  183       {

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

  185 

  186         if (

  187           _position.DistanceTo(ppr.Value) <

  188             Tolerance.Global.EqualPoint

  189         )

  190           return SamplerStatus.NoChange;

  191 

  192         _position = ppr.Value;

  193         return SamplerStatus.OK;

  194       }

  195 

  196       return SamplerStatus.Cancel;

  197     }

  198 

  199     protected override bool Update()

  200     {

  201       // Set properties on our text object

  202 

  203       DBText txt = (DBText)Entity;

  204 

  205       txt.Position = _position;

  206       txt.Height = _txtSize;

  207       txt.Rotation = _angle;

  208       txt.HorizontalMode = _align;

  209       if (_align != TextHorizontalMode.TextLeft)

  210       {

  211         txt.AlignmentPoint = _position;

  212         txt.AdjustAlignment(_db);

  213       }

  214 

  215       // Set the bold and/or italic properties on the style

  216 

  217       if (_toggleBold || _toggleItalic)

  218       {

  219         TextStyleTable tab =

  220           (TextStyleTable)_tr.GetObject(

  221             _db.TextStyleTableId, OpenMode.ForRead

  222           );

  223 

  224         TextStyleTableRecord style =

  225           (TextStyleTableRecord)_tr.GetObject(

  226             txt.TextStyleId, OpenMode.ForRead

  227           );

  228 

  229         // A bit convoluted, but this check will tell us

  230         // whether the new style is bold/italic

  231 

  232         bool bold = !(style.Font.Bold == _toggleBold);

  233         bool italic = !(style.Font.Italic == _toggleItalic);

  234         _toggleBold = false;

  235         _toggleItalic = false;

  236 

  237         // Get the new style name based on the old name and

  238         // a suffix ("_BOLD", "_ITALIC" or "_BOLDITALIC")

  239 

  240         var oldName = style.Name.Split(new[] { '_' });

  241         string newName =

  242           oldName[0] +

  243           (bold || italic ? "_" +

  244             (bold ? "BOLD" : "") +

  245             (italic ? "ITALIC" : "")

  246             : "");

  247 

  248         // We only create a duplicate style if one doesn't

  249         // already exist

  250 

  251         if (tab.Has(newName))

  252         {

  253           txt.TextStyleId = tab[newName];

  254         }

  255         else

  256         {

  257           // We have to create a new style - clone the old one

  258 

  259           TextStyleTableRecord newStyle =

  260             (TextStyleTableRecord)style.Clone();

  261 

  262           // Set a new name to avoid duplicate keys

  263 

  264           newStyle.Name = newName;

  265 

  266           // Create a new font based on the old one, but with

  267           // our values for bold & italic

  268 

  269           FontDescriptor oldFont = style.Font;

  270           FontDescriptor newFont =

  271             new FontDescriptor(

  272               oldFont.TypeFace, bold, italic,

  273               oldFont.CharacterSet, oldFont.PitchAndFamily

  274             );

  275 

  276           // Set it on the style

  277 

  278           newStyle.Font = newFont;

  279 

  280           // Add the new style to the text style table and

  281           // the transaction

  282 

  283           tab.UpgradeOpen();

  284           ObjectId styleId = tab.Add(newStyle);

  285           _tr.AddNewlyCreatedDBObject(newStyle, true);

  286 

  287           // And finally set the new style on our text object

  288 

  289           txt.TextStyleId = styleId;

  290         }

  291       }

  292 

  293       return true;

  294     }

  295   }

  296 }

When we run the updated QT command…

Command: QT

Enter text string: Yet more text

 

Left justified to start

Specify position of text or

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

 

Then switch to middle

Specify position of text or

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

 

Finish up with right

Specify position of text or

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

Specify position of text or

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

Specify position of text or

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

Specify position of text or

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

Specify position of text or

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

 

Apply some other options

Specify position of text or

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

 

And then place it

The overall functionality seems very useful (thanks for the suggestion, Thomas! :-) and certainly streamlines the creation of simple text inside a drawing.

That’s all I currently have planned for this series of posts, but be sure to let me know if there’s functionality you would like to see added (something related to Annotation Scaling, perhaps?).

blog comments powered by Disqus

Feed/Share

10 Random Posts