Creating an AutoCAD leader with a different arrowhead using .NET
Most of this week I've spent catching up after a nice, long break, as well as spending a few days in Prague helping interview potential recruits for our European team. Now it's finally time for me to climb back into the blogging saddle...
This first entry of 2007 is based on some code provided by Viru Aithal, a member of our team based in Bangalore. The code demonstrates how to create a leader using an arrowhead other than the current default (the one referred to by the DIMBLK system variable).
Here's the C# code:
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using System;
[assembly:
CommandClass(
typeof(
DimensionLibrary.DimensionCommands
)
)
]
namespace DimensionLibrary
{
public class DimensionCommands
{
static ObjectId GetArrowObjectId(string newArrName)
{
ObjectId arrObjId = ObjectId.Null;
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
// Get the current value of DIMBLK
string oldArrName =
Application.GetSystemVariable(
"DIMBLK"
) as string;
// Set DIMBLK to the new style
// (this action may create a new block)
Application.SetSystemVariable(
"DIMBLK",
newArrName
);
// Reset the previous value of DIMBLK
if (oldArrName.Length != 0)
Application.SetSystemVariable(
"DIMBLK",
oldArrName
);
// Now get the objectId of the block
Transaction tr =
db.TransactionManager.StartTransaction();
using(tr)
{
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
arrObjId = bt[newArrName];
tr.Commit();
}
return arrObjId;
}
// Define Command "ld"
[CommandMethod("ld")]
static public void CreateLeader()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
const string arrowName = "_DOT";
ObjectId arrId = GetArrowObjectId(arrowName);
// Get the start point of the leader
PromptPointResult result =
ed.GetPoint(
"\nSpecify leader start point: "
);
if (result.Status != PromptStatus.OK)
return;
Point3d startPt = result.Value;
// Get the end point of the leader
PromptPointOptions opts =
new PromptPointOptions(
"\nSpecify end point: "
);
opts.BasePoint = startPt;
opts.UseBasePoint = true;
result = ed.GetPoint(opts);
if (result.Status != PromptStatus.OK)
return;
Point3d endPt = result.Value;
// Now let's create the leader itself
Transaction tr =
db.TransactionManager.StartTransaction();
using (tr)
{
try
{
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForWrite
);
// Add the MText
MText mt = new MText();
mt.Contents =
"Leader with the \"" +
arrowName +
"\" arrow head";
mt.Location = endPt;
ObjectId mtId = btr.AppendEntity(mt);
tr.AddNewlyCreatedDBObject(mt, true);
// Add the Leader
Leader ld = new Leader();
ld.AppendVertex(startPt);
ld.AppendVertex(endPt);
btr.AppendEntity(ld);
tr.AddNewlyCreatedDBObject(ld, true);
ld.Annotation = mtId;
ld.Dimldrblk = arrId;
tr.Commit();
}
catch
{
tr.Abort();
}
}
}
}
}
Some comments on the technique used:
A helper function (GetArrowObjectId(arrowName)) is used to get the ObjectID of the block of our arrow head. To make sure this block exists, the function sets the value of DIMBLK to the arrowhead name, which - assuming the name is valid - will create the block in the block table. Then we simply have to get its ID and return it.
Once you've built the code, simply run the "LD" command, and select two points defining your leader (the code can easily be extended to allow selection of additional points and entry of a user-defined annotation string, of course).
Here's what you should see:


Subscribe via RSS
Hello Kean...
How get the Autodesk.AutoCAD.Runtime libraries without install Autocad?
I need use a dwg/dft(Solid Edge) Viewer in a .NET Winform.
Thanks afterhand
Posted by: Carlos Maggiotti | February 14, 2007 at 04:37 PM
Hi Carlos,
The acdbmgd.dll assembly (which is only part of what you want, I expect), is available as part of RealDWG (http://www.autodesk.com/realdwg).
To implement a DWG viewer from scratch would take a lot of work - I suggest looking at DWG TrueView (which can be embedded as an ActiveX control in a WinForm).
Regards,
Kean
Posted by: Kean | February 14, 2007 at 04:47 PM
hello kean!
i am just new to this civil3d, and find it convenient to use than in my accustomed Land Dev't, i was planning to shift but then i found out that the DaylightBench Sub-assemblies has its limited user inputs in benching, if i just can modify its user inputs and separating
Cut from Fill Benching controls....
is it possible to modify the default inputs?
or do i have to make a new one?
i have been researching about this Vb.net programming but i guess i need help regarding this one. your tip is highly much appreciated.
thnks!
Posted by: zeus | May 03, 2008 at 10:35 AM
Hello Zeus,
I suggest posting a question to one of the Civil 3D discussion groups or submitting it via ADN, if you're a member.
Regards,
Kean
Posted by: Kean | May 05, 2008 at 08:57 AM
How can you tell what arrow head a leader has?
Posted by: Ben | September 09, 2008 at 11:56 PM
The Leader object's Dimldrblk property contains the ObjectID of the block definition for the arrow-head. You should be able to open that and extract the information you need (its name, for instance).
Kean
Posted by: Kean | September 10, 2008 at 08:33 AM
Hi Kean.
I just had one of my users point out a problem, which used to work fine, but I recently migrated it to Managed code, from COM, and we have only been on 2009 for a short time, so I'm not sure which is the problem. The old com code did basically what this post does, except it assigned a block reference to the annotation property along with assigning a special arrow. Now the Managed code I have looks an awful lot like the code above, but replace the Mtext with a Block. It errors saying eNotApplicable when I try to set the Annotation to the Blockref's ID. Any Ideas?
Posted by: David Osborne | November 20, 2008 at 03:09 AM
Hi again...
I found it. Apparently it had nothing to do with the fact that I was using a block instead of text, nor the Managed code, but that my leader and block were not at Z = 0.
Since the block I'm refering to is a tag for elevation, that's kind of a requirement, but if I create the leader and block at 0 elevation and assign the blocks ID to the annotation, then move them up to the proper elevation it works.
On the discussion group thread where I found this info, the guy said he had the code working in C# but it would not work in VB, which is what I'm using... Only a problem in VB?
Posted by: David Osborne | November 20, 2008 at 07:32 PM
David -
No idea - this is the sort of question I'd typically suggest asking of the ADN team (I don't have time to research issues that are even slightly off-topic, at the moment).
You might consider joining - it seems like it would be of use to you.
Kean
Posted by: Kean | November 20, 2008 at 10:20 PM
Hi Kean,
in which version Autocad & which DLL we get this name space "using Autodesk.AutoCAD.EditorInput;"
and
"Application.SetSystemVariable"
I am unable to get the above things
currently i am Using Autocad 2005
Posted by: Kullaireddy Tadipatri | June 29, 2009 at 02:44 PM
AutoCAD 2005 really only had a "preview" version of the .NET API - a lot changed in subsequent releases (and it's only since 2006 that we've attempted to maintain compatibilty - see the comments in this post).
I strongly recommend working with a newer version of AutoCAD if you're expecting to use its managed API.
Kean
Posted by: Kean Walmsley | June 30, 2009 at 09:21 AM