Thursday, February 23, 2023

Prompting Area by Moving Mouse Cursor To Trace Boundary

AutoCAD users who work in civil engineering/land development/surveying very often want a easy way to know the area value of a enclosed area, be it by a single closed polyline, or by a boundary formed by multiple entities. AutoCAD provides "AREA" command for user to pick points to get the area value of the boundary formed by the picked points. If the area is formed by a closed polyline, or a circle, user can also use "LIST" command to see the area value.

Readers who come to my blogs often probably know that I am a fan of using Transient graphics to help AutoCAD user with visual hints. Here is another example of using Transient graphics in conjunction with Editor.PointMonitor event handle to allow user to move mouse cursor freely to get visual feedback of an enclosed area.

The code is quite simple and straightforward, so, no need for the extra explanation.

This is the class that handles Editor.PointMinitor event and trace the boundary of possible area:

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using CadDb = Autodesk.AutoCAD.DatabaseServices;
using System;
 
namespace AreaPrompting
{
    public class AreaDetector : IDisposable
    {
        private readonly Document _dwg;
        private readonly Editor _ed;
        private readonly TransientManager _tsManager = 
            TransientManager.CurrentTransientManager;
        private MPolygon _mPoly = null;
 
        public AreaDetector()
        {
            _dwg = Application.DocumentManager.MdiActiveDocument;
            _ed = _dwg.Editor;
        }
 
        public void Dispose()
        {
            ClearTransient();
        }
 
        public void PromptArea()
        {
            try
            {
                _ed.PointMonitor += Editor_PointMonitor;
                _ed.GetPoint("\nMove mouse cursor into an enclosed area:");
            }
            finally
            {
                _ed.PointMonitor-= Editor_PointMonitor;
                ClearTransient();
            }
        }
 
        #region private methods
 
        private void Editor_PointMonitor(object sender, PointMonitorEventArgs e)
        {
            ClearTransient();
            var polygon = DetectArea(e.Context.RawPoint);
            if (polygon!=null)
            {
                _mPoly = polygon;
                _tsManager.AddTransient(
                    _mPoly, TransientDrawingMode.Highlight, 128, new IntegerCollection());
 
                e.AppendToolTipText($"AREA={_mPoly.Area}");
            }
        }
 
        private void ClearTransient()
        {
            if (_mPoly!=null)
            {
                _tsManager.EraseTransient(
                    _mPoly, new Autodesk.AutoCAD.Geometry.IntegerCollection());
                _mPoly.Dispose();
            }
        }
 
        private MPolygon DetectArea(Point3d point)
        {
            MPolygon polygon = null;
            var boundaryEnts = _ed.TraceBoundary(point, false);
            if(boundaryEnts!=null && boundaryEnts.Count>0)
            {
                var pline = boundaryEnts[0] as CadDb.Polyline;
                if (pline!=null)
                {
                    polygon = new MPolygon();
                    polygon.ColorIndex = 9;
                    polygon.SetPattern(HatchPatternType.PreDefined, "SOLID");
                    polygon.AppendLoopFromBoundary(
                        pline, false, Tolerance.Global.EqualVector);
                }
            }
 
            return polygon;
        }
 
        #endregion
    }
}


This is the CommandMethod to execute the above code:

using Autodesk.AutoCAD.Runtime;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;
 
[assembly: CommandClass(typeof(AreaPrompting.MyCommands))]
 
namespace AreaPrompting
{
    public class MyCommands
    {
        [CommandMethod("GetArea")]
        public static void RunCommand()
        {
            var dwg = CadApp.DocumentManager.MdiActiveDocument;
            var ed = dwg.Editor;
 
            using (var detector = new AreaDetector())
            {
                detector.PromptArea();
            }
 
        }
 
    }
}

See the video clip showing the code effect:


One may notice one annoying thing: when Editor.TraceBoundary() method is called (many times while mouse moves), AutoCAD shows useless/meaningless messages at command line. I guess the message was used when Autodesk's engineers implemented and tested the TraceBoundary() method, and they forgot to clean them out after they had their job done!

Followers

About Me

My photo
After graduating from university, I worked as civil engineer for more than 10 years. It was AutoCAD use that led me to the path of computer programming. Although I now do more generic business software development, such as enterprise system, timesheet, billing, web services..., AutoCAD related programming is always interesting me and I still get AutoCAD programming tasks assigned to me from time to time. So, AutoCAD goes, I go.