I've often seen the question, over the years, of how to draw text in the plane of the screen, even when the current view is not planar to the current UCS. This ability to "screen fix" text has been there, but has required a number of sometimes tricky transformations to get the right behaviour. Well, during a recent internal discussion I became aware of a really handy facility inside AutoCAD which allows you to dependably draw screen-fixed text without jumping through hoops.
In this simple example, we're implementing a DrawJig - a jig that doesn't host an entity but allows us to implement a WorldDraw() callback for something to be drawn - which draws text at a fixed screen location, with a fixed size and orientation. Our code takes the simple task of asking the user to select a point, and shows the current cursor location during the drag at an offset of 30, 30 from the bottom left corner of the drawing window.
Here's the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
namespace JigTextPlanarToScreen
{
public class TextJig : DrawJig
{
private Point3d _position;
public Point3d Position
{
get { return _position; }
}
// We'll keep our style alive rather than recreating it
private TextStyle _style;
public TextJig()
{
_style = new TextStyle();
_style.Font =
new FontDescriptor("Calibri", false, true, 0, 0);
_style.TextSize = 10;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
JigPromptPointOptions opts = new JigPromptPointOptions();
opts.UserInputControls =
UserInputControls.Accept3dCoordinates;
opts.Message = "\nSelect point: ";
PromptPointResult res = prompts.AcquirePoint(opts);
if (res.Status == PromptStatus.OK)
{
if (_position == res.Value)
{
return SamplerStatus.NoChange;
}
else
{
_position = res.Value;
return SamplerStatus.OK;
}
}
return SamplerStatus.Cancel;
}
protected override bool WorldDraw(WorldDraw draw)
{
// We make use of another interface to push our transforms
WorldGeometry2 wg2 = draw.Geometry as WorldGeometry2;
if (wg2 != null)
{
// Push our transforms onto the stack
wg2.PushOrientationTransform(
OrientationBehavior.Screen
);
wg2.PushPositionTransform(
PositionBehavior.Screen,
new Point2d(30, 30)
);
// Draw our screen-fixed text
wg2.Text(
new Point3d(0, 0, 0), // Position
new Vector3d(0, 0, 1), // Normal
new Vector3d(1, 0, 0), // Direction
_position.ToString(), // Text
true, // Rawness
_style // TextStyle
);
// Remember to pop our transforms off the stack
wg2.PopModelTransform();
wg2.PopModelTransform();
}
return true;
}
[CommandMethod("SELPT")]
static public void SelectPointWithJig()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
TextJig jig = new TextJig();
PromptResult res = ed.Drag(jig);
if (res.Status == PromptStatus.OK)
{
ed.WriteMessage(
"\nPoint selected: {0}",
jig.Position
);
}
}
}
}
Now let's see our SELPT command in action.
First in a fairly standard view:
And now in an arbitrary 3D view:
OK, that's it for today. Right now I'm at our Developer Day event in Paris, and after this I'm taking a four-week break over the holiday season. Which means my blog output is likely to slow down (to a trickle, perhaps even stop completely) over the coming weeks. So - just in case - I'd like to wish all the readers of "Through the Interface" all the very best for the holiday season. Thank you for your continued support and readership over the last year, here's looking forward to a fun and productive 2009! :-)