000

Index Labels

Mimicking AutoCAD's "AREA" Command With .NET Code

.
In response to the question asked to me on how to do something similar to AutoCAD's "AREA" command, I spent most my lunch break time and got this simple code that mimicking the AREA" command. Well, just a simple version of "AREA" command.

First, a class does the work - MyAreaCmd:

using System.Collections.Generic;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;

namespace AreaCommand
{
public class MyAreaCmd
{
private Document _dwg;
private Editor _editor;

private double _area = 0.0;
private double _perimeter = 0.0;

private Autodesk.AutoCAD.DatabaseServices.Polyline _pline = null;
private List _points;
private bool _pickDone;

public MyAreaCmd(Document dwg)
{
_dwg = dwg;
_editor = _dwg.Editor;
}

public double Area
{
get { return _area; }
}

public double Perimeter
{
get { return _perimeter; }
}

public bool GetArea()
{
_pline=null;

//Pick first point
Point3d pt1;
if (!GetFirstPoint(out pt1)) return false;

//Pick second point
Point3d pt2;
if (!GetSecondPoint(pt1, out pt2)) return false;

_pickDone = false;

_points = new List();
_points.Add(new Point2d(pt1.X,pt1.Y));
_points.Add(new Point2d(pt2.X, pt2.Y));

try
{
//Handling mouse cursor moving during picking
_editor.PointMonitor +=
new PointMonitorEventHandler(_editor_PointMonitor);

while (true)
{
if (!PickNextPoint()) break;
}

if (_pline != null && _pickDone)
{
_area = _pline.Area;
_perimeter = _pline.Length;
}
}
catch
{
throw;
}
finally
{
ClearTransientGraphics();

//Remove PointMonitor handler
_editor.PointMonitor -=
new PointMonitorEventHandler(_editor_PointMonitor);
}

return _pickDone;
}

#region private methods

private bool GetFirstPoint(out Point3d pt)
{
pt = new Point3d();

PromptPointOptions opt =
new PromptPointOptions("\nPick first corner: ");
PromptPointResult res = _editor.GetPoint(opt);

if (res.Status == PromptStatus.OK)
{
pt = res.Value;
return true;
}
else
{
return false;
}
}

private bool GetSecondPoint(Point3d basePt, out Point3d pt)
{
pt = new Point3d();

PromptPointOptions opt =
new PromptPointOptions("\nPick next corner: ");
opt.UseBasePoint = true;
opt.BasePoint = basePt;
PromptPointResult res = _editor.GetPoint(opt);

if (res.Status == PromptStatus.OK)
{
pt = res.Value;
return true;
}
else
{
return false;
}
}

private bool PickNextPoint()
{
PromptPointOptions opt =
new PromptPointOptions("\nPick next corner: ");
if (_points.Count > 2)
{
opt.Keywords.Add("Undo");
opt.Keywords.Add("Total");
opt.AppendKeywordsToMessage = true;
}

PromptPointResult res = _editor.GetPoint(opt);

if (res.Status == PromptStatus.OK)
{
_points.Add(new Point2d(res.Value.X,res.Value.Y));
return true;
}
else if (res.Status == PromptStatus.Keyword)
{
if (res.StringResult == "Undo")
{
if (_points.Count > 2)
{
_points.RemoveAt(_points.Count - 1);
}
return true;
}
else
{
_pickDone = true;
return false;
}
}
else
{
_pickDone = false;
return false;
}
}

private void ClearTransientGraphics()
{
if (_pline != null)
{
TransientManager.CurrentTransientManager.EraseTransients(
TransientDrawingMode.DirectTopmost,
128, new IntegerCollection());

_pline.Dispose();
_pline = null;
}
}

private void _editor_PointMonitor(object sender, PointMonitorEventArgs e)
{
ClearTransientGraphics();

//Draw polyline
Point2d pt = new Point2d(e.Context.RawPoint.X, e.Context.RawPoint.Y);

_pline = new Autodesk.AutoCAD.DatabaseServices.Polyline(_points.Count + 1);

for (int i = 0; i < _points.Count; i++)
{
_pline.AddVertexAt(i, _points[i], 0.0, 0.0, 0.0);
}

_pline.AddVertexAt(_points.Count, pt, 0.0, 0.0, 0.0);
_pline.Closed = true;

TransientManager.CurrentTransientManager.AddTransient(
_pline, TransientDrawingMode.DirectTopmost,
128, new IntegerCollection());
}

#endregion
}
}
Then, I use MyAreaCmd class in a command method:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;

[assembly: CommandClass(typeof(AreaCommand.MyCommands))]

namespace AreaCommand
{
public class MyCommands
{
[CommandMethod("MyArea")]
public static void GetArea()
{
Document dwg = Autodesk.AutoCAD.ApplicationServices.
Application.DocumentManager.MdiActiveDocument;
Editor ed = dwg.Editor;

MyAreaCmd cmd = new MyAreaCmd(dwg);

if (cmd.GetArea())
{
ed.WriteMessage("\nArea = {0}", cmd.Area);
ed.WriteMessage("\nPerimeter = {0}", cmd.Perimeter);
}
else
{
ed.WriteMessage("\n*Cancelled*");
}
}
}
}

See this video clip for the action.

Pretty simple, eh? Here are notes:

1. I did not try to give extra options during the picking as the real "Area" command does, such as [Arc/Length...]. if someone is interested in to expend the functionality, fell free to try.

2. The real "Area" command fills the picked polygon with color so that the area enclosed in the polygon is visually stand-out. I did not successfully mimic that. By "did not successfully", I mean I tried to create a hatch as Transient Graphics in the PointMonitor event handler. However, to my surprise, the code to append hatch's loop would fail unless the newly instantiated Hatch object and the loop object (closed Polyline) were appended into the drawing database in a transaction (hope someone would confirm this or confirm that I was wrong on this). Since the polygon has to be cleared and redraw (as Transient Graphics) repeatedly in the PointMonitor event handler, I felt repeatedly adding/erasing the Hatch in/from database within a transaction would be horrible thing to do. So I gave it up (for now).

Blog Archive

Labels

3D Modeling 3D Sketch Inventor AI Design AI in Manufacturing AI Tools Architecture Artificial Intelligence AutoCAD AutoCAD advice AutoCAD Basics AutoCAD Beginners AutoCAD Civil3D AutoCAD commands AutoCAD efficiency AutoCAD features AutoCAD File Management AutoCAD Layer AutoCAD learning AutoCAD print settings AutoCAD productivity AutoCAD Teaching AutoCAD Techniques AutoCAD tips AutoCAD training. AutoCAD tricks AutoCAD Tutorial AutoCAD workflow AutoCAD Xref Autodesk Autodesk 2025 Autodesk AI Tools Autodesk AutoCAD Autodesk Fusion 360 Autodesk Inventor Autodesk Inventor Frame Generator Autodesk Inventor iLogic Autodesk Recap Autodesk Revit Autodesk Software Autodesk Video Automation Automation Tutorial Basic Commands Basics Beginner Beginner Tips BIM BIM Implementation Block Editor ByLayer CAD comparison CAD Design CAD File Size Reduction CAD line thickness CAD Optimization CAD Productivity CAD software clean CAD file cleaning command Cloud Collaboration command abbreviations Construction Technology Contraints Create resizable blocks CTB STB Data Reference Data Shortcut design software Design Workflow Digital Design Digital Twin Drafting Standards Drawing Automation Dref Dynamic Block Dynamic Block AutoCAD Dynamic Blocks Dynamic doors Dynamic windows eco design editing commands energy efficiency Engineering Engineering Design Engineering Innovation Engineering Technology engineering tools Excel Express Tools External Reference Fast Structural Design Fusion 360 Generative Design green building Grips heavy CAD file Heavy CAD Files iLogic Industry 4.0 Insight Inventor API Inventor Drawing Template Inventor Frame Generator Inventor Graphics Issues Inventor IDW Inventor Tips Keyboard Shortcuts Learn AutoCAD Machine Learning in CAD maintenance command Management Manufacturing Innovation Metal Structure ObjectARX .NET API Organization OVERKILL OVERKILL AutoCAD Palette PDF Plot Style AutoCAD Practice Drawing Printing Quality professional printing Professional Tips PTC Creo PURGE PURGE AutoCAD ReCap reduce CAD file size Resizable Block Revit Revit Best Practices Revit Workflow Ribbon screen shortcut keys Shortcuts Siemens NX Sketch Small Firms Smart Block Smart Factory SolidWorks Steel Structure Design sustainability Sustainable Manufacturing toolbar Tutorial User Interface (UI) Workbook Workspace XLS Xref