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:

Createleader

35 responses to “Creating an AutoCAD leader with a different arrowhead using .NET”

  1. Carlos Maggiotti Avatar

    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

  2. Hi Carlos,

    The acdbmgd.dll assembly (which is only part of what you want, I expect), is available as part of RealDWG (autodesk.com/rea...).

    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

  3. 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!

  4. Kean Walmsley Avatar

    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

  5. How can you tell what arrow head a leader has?

  6. 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

  7. 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?

  8. 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?

  9. 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

  10. Kullaireddy Tadipatri Avatar
    Kullaireddy Tadipatri

    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

  11. 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

  12. HΔ± kean
    I wonder
    How to do for example I define new dimstyle and than overrides lots of property of setvariable for new dimstyles (Dimexo,Dimasz bla bla) but my new dimstyle property doesnt change in my new document, just that change if I define dimensioning from coding before .
    Always do we have to define a method to reset Aplication set variables from coding (like your application hear) to change current DimStyle settings
    Thank yu
    Our

  13. Hi alyoşa,

    I'm afraid I don't fully understand your question, or what the problem is.

    Perhaps you can post your code (and a more complete description of what you're trying to do) to the AutoCAD .NET Discussion Group?

    Regards,

    Kean

  14. Hi Kean.

    How can the code be extended to allow the user a multiple selection of line-points for the leader (more than startPt and endPt).

    Kind regards,
    Michael

  15. Hi Michael,

    Try searching this blog for MLEADER.

    Cheers,

    Kean

  16. Thank you. Thats exactly what i am looking for.

    Michael

  17. Hey Kean!

    Please tell me how can I set the arrow object to closed-filled?

    I would like to have closed-filled arrow with my MLeader, but when I send stringname = "" or "." I'm getting error about no found key.

    Have you got some clue for me? I googled and I found nothing πŸ™‚

  18. Hi Greg,

    The default arrowhead doesn't use a block definition, by all accounts, so that's why looking for it in the block table is failing.

    If you want the default (i.e. closed, filled) arrowhead, you may have to set DIMBLK to "" before creating and adding the MLeader to the database (resetting DIMBLK afterwards). At least that's what I'd expect to work.

    Cheers.

    Kean

  19. Thanks - it works well. But ...

    There is one little problem - I'm passing "" or "." (both works) to DIMBLK. And this is OK for new drawing.

    But if I open some older file, where I have few dimensions styles, it takes the default symbol for the leader from current dimension style.

    i.e -> I have two styles (Scale 100, Scale 50).
    Scale 100 has leader = closed filled.
    Scale 50 has leader = oblique.

    If I have Scale 100 as current, the mleader function works great. If I change it to Scale 50, I'm getting mleader with oblique arrow.

    It seems, that acadApp.SetSystemVariable("DIMBLK", "."); doesn't work then.

  20. This fix my problem:
    ld.Dimldrblk = ObjectId.Null;

    πŸ™‚

  21. Excellent. πŸ™‚

    Kean

  22. This code no longer works with AutoCAD 2012. The associativity is broken between the MText and the Leader.

  23. I see the problem. I'll ask someone from ADN to look into it.

    Kean

  24. OK, there is indeed a problem with creating leaders in this way in AutoCAD 2012. We're on it.

    Kean

  25. Hi,Kean
    How to set the size of leader line arrowheads?
    And it seems that the leader object cannot build annotations with mtext.
    Any suggestion?
    Thanks.

  26. Kean Walmsley Avatar

    Sorry, I don't have time to answer this (and it's really a support question - it's not really related to the code in this post).

    Please post to ADN or the AutoCAD .NET Discussion Group.

    Kean

  27. Hello Kean!
    can we use instead MText Block refernce for Leader?
    how?

    thank you

  28. Hi Sergey,

    I'm sorry - I don't quite understand your question. But if what you want to do can be done via the AutoCAD editor, then it can probably be done via the API (and conversely, if it can't then it probably can't).

    Regards,

    Kean

  29. Hi, Kean,

    I try to use below code to check the DWG file status if user do the modification for AutoCAD 2005:

    object chkStatus = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("DBMOD")

    And I always get error message:
    "Autodesk.AutoCAD.ApplicationServices.Application' 'GetSystemVariable' definition is not included" when I build solution(.Net 2005 C#)

    It means that I can't use [GetSystemVariable] API for AutoCAD 2005?
    (Actually it works in AutoCAD 2013)

    Thanks

    BR,
    Jay
    2014.3.10

  30. Hi Jay,

    AutoCAD 2005 only had a preview version of the .NET API. There's a lot that was missing from that version.

    Best regards,

    Kean

  31. Hello Kean....

    how can i make arrowheads on both ends of the polyline.???

    Regards.

    1. Kean Walmsley Avatar

      Hi Ajit,

      That's beyond the scope of this post. Please post your question to the relevant online forum.

      Thanks,

      Kean

  32. Hi
    Thanks for the code for leader
    When you use the _DOT can the dot been show after first click like Autocad do

  33. You would need a jig for that.

    Here's an example of a jig for a multileader: keanw.com/2007/09/creating-a-mult.html

    Kean

  34. Thanks πŸ™‚

Leave a Reply to CSharpbird Cancel reply

Your email address will not be published. Required fields are marked *