September 15, 2008

I'm still a little frazzled after transcribing the 18,000 word interview with John Walker (and largely with two fingers - at such times the fact that I've never learned to touch-type is a significant cause of frustration, as you might imagine). I'm also attending meetings all this coming week, so I've gone for the cheap option, once again, of dipping into my magic folder of code generated and provided by my team.

The technique for this one came from a response sent out by Philippe Leefsma, from DevTech EMEA, but he did mention a colleague helped him by suggesting the technique. So thanks to Philippe and our anonymous colleague for the initial idea of calling -DIMINSPECT.

The problem solved by Philippe's code is that no API is exposed via .NET to enable the "inspection" capability of dimensions inside AutoCAD. The protocol is there in ObjectARX, in the AcDbDimension class, but this has - at the time of writing - not been exposed via the managed API. One option would be to create a wrapper or mixed-mode module to call through to unmanaged C++, but the following approach simply calls through to the -DIMINSPECT command (the command-line version of DIMINSPECT) to set the inspection parameters.

I've integrated - and extended - the technique shown in this previous post to send the command as quietly as possible. One problem I realised with the previous implementation is that UNDO might leave the user in a problematic state - with the NOMUTT variable set to 1. This modified approach does a couple of things differently:

Rather than using the NOMUTT command to set the system variable, it launches another custom command, FINISH_COMMAND

This command has been registered with the NoUndoMarker command-flag, to make it invisible to the undo mechanism (well, at least in terms of automatic undo)

It sets the NOMUTT variable to 0

It should be possible to share this command across others that have the need to call commands quietly

It uses the COM API to create an undo group around the operations we want to consider one "command"

The implementation related to the "quiet command calling" technique is wrapped up in a code region to make it easy to hide

One remaining - and, so far, unavoidable - piece of noise on the command-line is due to our use of the (handent) function: it echoes entity name of the selected dimension.

Here's the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Interop;

namespace InspectDimension

{

publicclassCommands

{

[CommandMethod("INSP")]

staticpublicvoid InspectDim()

{

Document doc =

Application.DocumentManager.MdiActiveDocument;

Database db = doc.Database;

Editor ed = doc.Editor;

PromptEntityOptions peo =

newPromptEntityOptions("\nSelect a dimension: ");

peo.SetRejectMessage(

"\nEntity must be a dimension."

);

peo.AddAllowedClass(typeof(Dimension), false);

PromptEntityResult per = ed.GetEntity(peo);

if (per.Status != PromptStatus.OK)

return;

Transaction tr =

db.TransactionManager.StartTransaction();

using (tr)

{

Dimension dim =

tr.GetObject(per.ObjectId, OpenMode.ForRead)

asDimension;

if (dim != null)

{

string shape = "Round";

string label = "myLabel";

string rate = "100%";

string cmd =

"-DIMINSPECT Add (handent \"" +

dim.Handle + "\"" + ") \n" +

shape + "\n" + label + "\n" +

rate + "\n";

SendQuietCommand(doc, cmd);

};

tr.Commit();

}

}

#region QuietCommandCalling

conststring kFinishCmd = "FINISH_COMMAND";

privatestaticvoid SendQuietCommand(

Document doc,

string cmd

)

{

// Get the old value of NOMUTT

object nomutt =

Application.GetSystemVariable("NOMUTT");

// Add the string to reset NOMUTT afterwards

AcadDocument oDoc =

(AcadDocument)doc.AcadDocument;

oDoc.StartUndoMark();

cmd += "_" + kFinishCmd + " ";

// Set NOMUTT to 1, reducing cmd-line noise

Application.SetSystemVariable("NOMUTT", 1);

doc.SendStringToExecute(cmd, true, false, false);

}

[CommandMethod(kFinishCmd, CommandFlags.NoUndoMarker)]

staticpublicvoid FinishCommand()

{

Document doc =

Application.DocumentManager.MdiActiveDocument;

AcadDocument oDoc =

(AcadDocument)doc.AcadDocument;

oDoc.EndUndoMark();

Application.SetSystemVariable("NOMUTT", 0);

}

#endregion

}

}

Here are the results of running the INSP command and selecting a dimension object. First the command-line output:

Command: INSP

Select a dimension: <Entity name: -401f99f0>

Command:

And now the graphics, before and after calling INSP and selecting the dimension:

In the end the post didn't turn out to be quite as quick to write as expected, but anyway - so it goes. I'm now halfway from Zürich to Washington, D.C., and had the time to kill. I probably won't have the luxury when I'm preparing my post for the middle of the week, unless I end up suffering from jet-lag. :-)