Creating an AutoCAD multileader spraying out from central text using .NET
Some more fun with multileaders... this post shows some code that adds multiple leader lines to a multileader/MLeader, each of them "spraying" out from the central text. We ask the user for the central point and the location of the first leader along with the number of leader lines to "spray". These lines then get created at evenly spaced angles around from this initial location.
I can't think of anything immediately useful about this technique, other than it was fun to write the code and it shows how to add multiple leader lines. It also generates some fun results. :-)
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;
namespace DimensionLibrary
{
public class DimensionCommands
{
[CommandMethod("spray")]
static public void SprayMultiLeader()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
// Get the start point of the leader
PromptPointResult ppr =
ed.GetPoint(
"\nSpecify position of text: "
);
if (ppr.Status != PromptStatus.OK)
return;
Point3d startPt = ppr.Value;
// Get the end point of the leader
PromptPointOptions ppo =
new PromptPointOptions(
"\nSpecify first arrowhead location: "
);
ppo.BasePoint = startPt;
ppo.UseBasePoint = true;
ppr = ed.GetPoint(ppo);
if (ppr.Status != PromptStatus.OK)
return;
Point3d endPt = ppr.Value;
// Get the number of leader lines
// to "spray" out from the center
PromptIntegerOptions pio =
new PromptIntegerOptions(
"\nNumber of leader lines <1>: "
);
pio.AllowNone = true;
pio.AllowZero = false;
PromptIntegerResult pir =
ed.GetInteger(pio);
int numLines;
if (pir.Status == PromptStatus.None)
numLines = 1;
else
{
if (pir.Status != PromptStatus.OK)
return;
else
numLines = pir.Value;
}
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
);
// Create the MLeader
MLeader mld = new MLeader();
for(int i=0; i < numLines; i++)
{
// Each leader line sprays out
// at a different angle
Vector3d vec = endPt - startPt;
vec =
vec.RotateBy(
i * 2 * System.Math.PI / numLines,
mld.Normal
);
Point3d landPt = startPt + vec;
int ldNum = mld.AddLeader();
int lnNum = mld.AddLeaderLine(ldNum);
mld.AddFirstVertex(lnNum, landPt);
mld.AddLastVertex(lnNum, startPt);
}
mld.LeaderLineType =
LeaderType.SplineLeader;
// Create the MText
MText mt = new MText();
mt.Contents =
"Multileader with " +
numLines.ToString() +
" \nradial splines";
mld.ContentType =
ContentType.MTextContent;
mld.MText = mt;
mld.TextLocation = startPt;
// Add the MLeader
btr.AppendEntity(mld);
tr.AddNewlyCreatedDBObject(mld, true);
tr.Commit();
}
catch (Exception ex)
{
ed.WriteMessage("\nException: " + ex.Message);
// Would also happen automatically
// if we didn't commit
tr.Abort();
}
}
}
}
}
Here's a 7-line multileader created by the SPRAY command:


Subscribe via RSS
Is there any chance of making the MLeader associated with the entity using ObjectARX .NET 2008? Thanks!
-Gagan
Posted by: Gagan Gajabaharia | May 29, 2008 at 05:43 PM
Gagan,
I haven't looked into whether MLeaders can be associative to geometry. If it's not available as core functionality, you could certain implement your own associativity using events in .NET (probably a comibination of Database.ObjectModified and DocumentManager.DocumentLockModeWillChange).
I'd suggest posting your question to the discussion groups or asking the ADN team (if you're a member).
Regards,
Kean
Posted by: Kean | May 29, 2008 at 08:54 PM
Whenever I attempt to run your code in Civil-3D 2009, all of the leaders come out of the left side of the MLeader.
If I select and drag the MLeader slightly, it will "recalculate" itself, and display as shown in your screen shot, with leaders coming out both sides of the text. But if I simply run the code, all leaders emanate from the left side of the text only.
If I run your code in Civil-3D 2008, I get the same results as you, with leaders coming out both sides of the text. However, with C3D 2009, they only come out the left side.
Any idea why, or how to get around this issue? I'd like to create an MLeader to the left of a point, and have the leader come out the right side of the text, but I can't seem to manage it in 2009.
I have tried using the default acad.dwt template, and also "Starting from Scratch", just to try to eliminate any possible issues with the template, and I get the same result.
Posted by: Sinc | July 08, 2008 at 04:20 AM
This appears to be something different in base AutoCAD 2009 (and therefore the products built upon it).
Adding this line of code forces a recalculation of the MLeader (I put it just before the line that commits the transaction):
mld.MoveMLeader(new Vector3d(), MoveType.MoveAllPoints);
It essentially moves all the points of the MLeader through a zero-length vector. So it does nothing, but the geometry gets corrected.
I hope this helps you,
Kean
Posted by: Kean | July 08, 2008 at 09:52 AM
Thanks! That worked.
Posted by: Sinc | July 08, 2008 at 02:17 PM