Kean Walmsley


  • About the Author
    Kean on Google+

July 2014

Sun Mon Tue Wed Thu Fri Sat
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    








« A learning path for newbie programmers | Main | A new project wizard for AutoCAD .NET development »

June 15, 2009

Highlighting named blocks using AutoCAD 2010’s overrule API from .NET

This is a nice sample provided by Stephen Preston, who manages DevTech’s Americas team. Stephen has put this together in anticipation of his upcoming AU class on the overrule API introduced in AutoCAD 2010. [I know the final class list has not yet been announced, but Stephen is co-owner of the Customization & Programming track at this year’s AU and presumably has the inside skinny on the selected classes. Which means he has a head-start on preparing his material, lucky fellow. :-)]

The sample allows the user to enter a text string that it uses to highlight any block containing that string in its name. This is quite handy for identifying the instances of a particular block in a drawing, but it might also be modified to highlight other objects (you might want to highlight mis-spelt words or standards violations, for instance).

Here’s the C# code, reformatted for this blog:

using System;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.GraphicsInterface;

 

namespace MyCustomFilterOverrule

{

  // This is our custom DrawableOverrule class. We're just

  // overruling WorldDraw and IsApplicable.

  // This class is implemented as a singleton class, and

  // includes subroutines that are called by the CommandMethods

  // in another class

 

  public class MyDrawOverrule : DrawableOverrule

  {

    // Where properties have been defined, use the property rather

    // than the raw variable.

    // I'm using properties where I need some additional logic to

    // run as I get/set the variable.

 

    // The text we'll search for in our block name.

 

    private string mTxt;

 

    // Color Index of block highlight

 

    private short mColor = 3;

 

    // Used to track whether this Overrule has been registered

    // (so we don't try to register it more than once).

 

    private bool mRegistered = false;

 

    // Used to store one and only instance of our singleton class

 

    private static MyDrawOverrule mSingleton;

 

    // Used to reset Overruling value to the value it had before

    // we switched them on. (There may be other overrules in place)

 

    private static bool mOldOverruleValue;

 

    // The color we highlight blocks with

    private short HighlightColor

    {

      get { return mColor; }

      set { if (value >= 0 && value <= 127) mColor = value; }

    }

 

    // The text we'll search for in the block name

 

    private string SearchText

    {

      get { return mTxt; }

      set { mTxt = value; }

    }

 

    // Private constructor because its a singleton

 

    private MyDrawOverrule()

    {

      // Do nothing

    }

 

    // Shared propery to return our singleton instance

    // (and instantiate new instance on first call)

 

    public static MyDrawOverrule GetInstance

    {

      get

      {

        if (mSingleton == null)

        {

          mSingleton = new MyDrawOverrule();

        }

        return mSingleton;

      }

    }

 

    private void InitOverrule()

    {

      if (!mRegistered)

      {

        Overrule.AddOverrule(

          RXObject.GetClass(typeof(BlockReference)), this, false

        );

        SetCustomFilter();

        mOldOverruleValue = Overrule.Overruling;

        mRegistered = true;

      }

      Overrule.Overruling = true;

    }

 

    // Prompts user to select the color index they want to

    // highlight blocks with

 

    public void SetColor()

    {

      Editor ed =

        Application.DocumentManager.MdiActiveDocument.Editor;

 

      PromptIntegerOptions opts =

        new PromptIntegerOptions(

          "\nEnter block finder color index: "

        );

      opts.DefaultValue = HighlightColor;

      opts.LowerLimit = 0;

      opts.UpperLimit = 127;

      opts.UseDefaultValue = true;

      PromptIntegerResult res = ed.GetInteger(opts);

 

      // If requested highlight color is a new color,

      // then we want to change it

 

      if (res.Status == PromptStatus.OK &&

          HighlightColor != res.Value)

      {

        HighlightColor = (short)res.Value;

 

        // Regen is required to update changes on screen

 

        ed.Regen();

      }

    }

 

    public void FindText()

    {

      Editor ed =

        Application.DocumentManager.MdiActiveDocument.Editor;

 

      ed.WriteMessage(

        "\nCurrent block search text is \"{0}\".", SearchText

      );

      PromptStringOptions opts =

        new PromptStringOptions(

          "\nEnter new block search text: "

        );

      PromptResult res = ed.GetString(opts);

 

      // If the user cancelled then we exit the command

 

      if (res.Status != PromptStatus.OK)

        return;

 

      // If the user didn't type any text then we remove

      // the overrule and exit

 

      if (res.StringResult == "")

      {

        SearchText = "";

        ResetBlocks();

      }

      else

      {

        // Set search text for Overrule to that entered by user

 

        SearchText = res.StringResult.ToUpper();

        InitOverrule();

 

        // Turn Overruling on

 

        Overrule.Overruling = true;

 

        // Regen is required to update changes on screen.

 

        ed.Regen();

      }

    }

 

    // Removes our overrules

 

    public void ResetBlocks()

    {

      Editor ed =

        Application.DocumentManager.MdiActiveDocument.Editor;

 

      Overrule.Overruling = mOldOverruleValue;

      if (mRegistered)

      {

        Overrule.RemoveOverrule(

          RXObject.GetClass(typeof(BlockReference)), this

        );

        mRegistered = false;

        ed.Regen();

      }

    }

 

    // Overrule WorldDraw so we can draw our additional

    // graphics

 

    public override bool WorldDraw(Drawable drawable, WorldDraw wd)

    {

      // Better safe than sorry - check it really is a

      // BlockReference before continuing.

 

      BlockReference br = drawable as BlockReference;

      if (br != null)

      {

        // Now we want to draw a green box around the attributes

        // extents

 

        Extents3d ext = (Extents3d)br.Bounds;

        Point3d maxPt = ext.MaxPoint;

        Point3d minPt = ext.MinPoint;

        Point3dCollection pts = new Point3dCollection();

 

        // These are the vertices of the highlight box

 

        pts.Add(new Point3d(minPt.X, minPt.Y, minPt.Z));

        pts.Add(new Point3d(minPt.X, maxPt.Y, minPt.Z));

        pts.Add(new Point3d(maxPt.X, maxPt.Y, minPt.Z));

        pts.Add(new Point3d(maxPt.X, minPt.Y, minPt.Z));

 

        // Store current filltype and set to FillAlways

 

        FillType oldFillType = wd.SubEntityTraits.FillType;

        wd.SubEntityTraits.FillType = FillType.FillAlways;

 

        // Store old graphics color and set to the color we want

 

        short oldColor = wd.SubEntityTraits.Color;

        wd.SubEntityTraits.Color = HighlightColor;

 

        // Draw the filled polygon

 

        wd.Geometry.Polygon(pts);

 

        // Restore old settings

 

        wd.SubEntityTraits.FillType = oldFillType;

        wd.SubEntityTraits.Color = oldColor;

      }

 

      // Let the overruled Drawable draw itself.

 

      return base.WorldDraw(drawable, wd);

    }

 

    // This function is called if we call SetCustomFilter on our

    // custom overrule.

    // We add our own code to return true if the BlockReference

    // passed in is one we want to highlight.

 

    public override bool IsApplicable(RXObject overruledSubject)

    {

      // If it's a BlockReference, we check if the Block Name

      // contains our string

 

      BlockReference br = overruledSubject as BlockReference;

      if (br != null && SearchText != "")

      {

        // Returns whether the filter is applicable to this object

 

        return br.Name.Contains(SearchText);

      }

 

      // Only get to here if object isn't a BlockReference

 

      return false;

    }

  }

 

  // Our command class, which relays commands to MyDrawOverrule.

 

  public class myPlugin

  {

    [CommandMethod("SHOWBLOCKS")]

    public static void FindText()

    {

      MyDrawOverrule.GetInstance.FindText();

    }

 

    [CommandMethod("SHOWCOLOR")]

    public static void SetColor()

    {

      MyDrawOverrule.GetInstance.SetColor();

    }

  }

}

Here’s what happens when we OPEN the “Mechanical – Multileaders.dwg” sample drawing, NETLOAD our application and use SHOWBLOCKS to look for the “M045” text string:

Highlighted blocks

Here’s what we see if we broaden the search to include all blocks with the string “M0” in their name and change the highlight colour to 1 using SHOWCOLOR:

More highlighted blocks

To clear the selection, the user simply has to run SHOWBLOCKS and specify an empty string as the search term.

Stephen will be presenting both C# and VB.NET versions of this sample application during his class at this year’s AU. If you find overrules interesting, then I strongly recommend signing up for the session (I’ll let you know when registrations are open). I’m sure that during the class Stephen will be demonstrating other interesting capabilities made available to AutoCAD .NET developers by this very cool API.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d83452464869e201157114a20d970b

Listed below are links to weblogs that reference Highlighting named blocks using AutoCAD 2010’s overrule API from .NET:

blog comments powered by Disqus

10 Random Posts