AutoCAD .NET API provides two concrete Jig classes for us to jig different entities in different circumstances, EntityJig and DrawJig. EntityJig is to jig a specific entity as its name indicates and the DrawJig is to jig anything that has graphics to draw, which can be a single entity, a group of entities, or something that is not available natively in AutoCAD.
We have demonstrated jigging various AutoCAD entities such as Line, Multiple-Line, Circle, Polyline, DBText, and Block, performing various actions dynamically, using either EntityJig or DrawJig, such as Insert, Move, Rotate, Copy, Array, and Mirror, and creating various Solid types such as Box, Cube, Sphere, Cone, Cylinder, Pyramid, Prism, Wedge, Frustum, Torus, The Pentagon, and The Solar System in many early posts. In this article, let us see how to fillet a polygon composed of a closed AutoCAD 2D Polyline dynamically.
Here is the core code of dynamic fillet jig along with a test command:
#region Namespaces
using System;
using System.Text;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.Drawing;
using System.IO;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Windows;
using MgdAcApplication = Autodesk.AutoCAD.ApplicationServices.Application;
using MgdAcDocument = Autodesk.AutoCAD.ApplicationServices.Document;
using AcWindowsNS = Autodesk.AutoCAD.Windows;
#endregion
namespace AcadNetAddinWizard_Namespace
{
public class FilletJigger : EntityJig
{
#region Fields
public int mCurJigFactorIndex = 1;
private Point3d mBasePoint = new Point3d();
private Point3d mNewPoint; // Factor #1
public Point2dCollection mOriginalVertices;
#endregion
#region Constructors
public FilletJigger(Entity ent, Point3d basePoint)
: base(ent)
{
mOriginalVertices = new Point2dCollection();
for (int i = 0; i < PLine.NumberOfVertices; i++)
{
mOriginalVertices.Add(PLine.GetPoint2dAt(i));
}
mNewPoint = mBasePoint = basePoint.TransformBy(UCS);
}
#endregion
#region Properties
private Editor Editor
{
get
{
return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
}
}
private Matrix3d UCS
{
get
{
return Editor.CurrentUserCoordinateSystem;
}
}
private Polyline PLine
{
get
{
return Entity as Polyline;
}
}
#endregion
#region Overrides
protected override bool Update()
{
double dist = mBasePoint.DistanceTo(mNewPoint);
Point2dCollection ptCol = new Point2dCollection();
for (int i = 0; i < mOriginalVertices.Count; i++)
{
Point2d current = mOriginalVertices[i];
Point2d previous = i == 0 ? mOriginalVertices[mOriginalVertices.Count - 1] : mOriginalVertices[i - 1];
Point2d next = i == mOriginalVertices.Count - 1 ? mOriginalVertices[0] : mOriginalVertices[i + 1];
Point2d pt1 = current + (previous - current) / current.GetDistanceTo(previous) * dist;
Point2d pt2 = current + (next - current) / current.GetDistanceTo(next) * dist;
ptCol.Add(pt1);
ptCol.Add(pt2);
}
for (int i = 0; i < PLine.NumberOfVertices; i++)
PLine.SetPointAt(i, ptCol[i]);
for (int i = PLine.NumberOfVertices; i < ptCol.Count; i++)
PLine.AddVertexAt(i, ptCol[i], 0, 0, 0);
return true;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
switch (mCurJigFactorIndex)
{
case 1:
JigPromptPointOptions prOptions1 = new JigPromptPointOptions("\nLocation:");
prOptions1.UserInputControls = UserInputControls.Accept3dCoordinates |
UserInputControls.GovernedByOrthoMode | UserInputControls.GovernedByUCSDetect;
prOptions1.BasePoint = mBasePoint;
prOptions1.UseBasePoint = true;
PromptPointResult prResult1 = prompts.AcquirePoint(prOptions1);
if (prResult1.Status == PromptStatus.Cancel) return SamplerStatus.Cancel;
if (prResult1.Value.Equals(mNewPoint)) //Use better comparision method if wanted.
{
return SamplerStatus.NoChange;
}
else
{
mNewPoint = prResult1.Value;
return SamplerStatus.OK;
}
default:
break;
}
return SamplerStatus.OK;
}
#endregion
#region Methods to Call
public static FilletJigger jigger = null;
public static bool Jig(Entity ent, Point3d basePt)
{
try
{
jigger = new FilletJigger(ent, basePt);
PromptResult pr;
do
{
pr = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.Drag(jigger);
if (pr.Status == PromptStatus.Keyword)
{
// Add keyword handling code below
}
else
{
jigger.mCurJigFactorIndex++;
}
} while (pr.Status != PromptStatus.Cancel && pr.Status != PromptStatus.Error && jigger.mCurJigFactorIndex <= 1);
if (pr.Status == PromptStatus.Cancel || pr.Status == PromptStatus.Error)
{
if (jigger != null && jigger.Entity != null)
jigger.Entity.Dispose();
return false;
}
else
return true;
}
catch
{
if (jigger != null && jigger.Entity != null)
jigger.Entity.Dispose();
return false;
}
}
#endregion
#region Test Commands
[CommandMethod("TestFilletJigger")]
public static void TestFilletJigger_Method()
{
Editor ed = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
Database db = HostApplicationServices.WorkingDatabase;
try
{
PromptEntityResult selRes = ed.GetEntity("\nPick a polygon to fillet:");
if (selRes.Status == PromptStatus.OK)
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Entity ent = tr.GetObject(selRes.ObjectId, OpenMode.ForWrite) as Entity;
if (ent != null && ent is Polyline && ((Polyline)ent).Closed)
{
if (FilletJigger.Jig(ent, selRes.PickedPoint))
tr.Commit();
else
tr.Abort();
}
}
}
}
catch (System.Exception ex)
{
ed.WriteMessage(ex.ToString());
}
}
#endregion
}
}
Here is what the screen looks like when a rectangle has been filleted dynamically by the dynamic fillet jig:
NOTE: The isometric view is in a UCS instead of WCS, indicating our fillet Jigger honors UCS perfectly.
A few highlights about the code may be helpful:
• Our Fillet Jig is supposed to support closed 2d Polyline only for now.
• The picked point on the entity will determine where to jig the Entity from and to.
• The Sampler() override is to acquire input for the new location of the base point.
• Some UserInputControls flags are used here, GovernedByUCSDetect, UseBasePointElevation, and Accept3dCoordinates to collect a point from UCS but intepreted in WCS.
• If the input is the same as the stored variable, we’d better return SamplerStatus.NoChange to avoid unnecessary flashing; if not, return SamplerStatus.OK.
• Please do not forget to handle the cancel/escape circumstance as demonstrated.
• The Update() override is to update new location of the Entity through the TransformBy() call on a Vector calculated from the previous base point and the new input location since not every Entity type has an Location or BasePoint property.
• The old base point needs to be replaced with the new location just collected so that the next movement can still behave well in every Update() call.
• The Editor.Draw() is the power to fire the jig.
• The while loop needs to think about the PromptStatus.Keyword case of the PromptResult after each Jig Drag.
• Keyword handling code can be added as commented.
• Only after the jig succeeds should the entity be finally filleted.
The leading edge AutoCAD .NET Addin Wizard (AcadNetAddinWizard) provides two jigging related coders, Entity Jigger and Draw Jigger, to help us create jigging code automatically, quickly, reliably, and professionally.
Recent Comments