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 a Spline some time ago using the AutoCAD .NET class EntityJig.
AutoCAD .NET: Create a Spline Jig From EntityJig
http://spiderinnet1.typepad.com/blog/2012/09/autocad-net-create-a-spline-jig-from-entityjig.html
However, the Spline Jigger there did not look so cool due to some limitation of the AutoCAD Spline class. Its default parameter-less constructor will create a Spline with some weird fit points that people do not have any ideas of; if a point array is provided to its the other constructor, at least three points have to be in the array and they cannot be identical; its RemoveFitPointAt() call has to make sure that at least three fit points exist in the Spline to succeed; etc.
In order to work around these issues, we had to pick three points before the Spline was really being jigged. That made the first version of the Spline Jig look a bit clumsy. In addition, the first version would not cancel out the last temporary input either when the Enter Key were pressed, not like what the AutoCAD native Spline command behaves in this regard.
In this article, let us get rid of these and create a better Spline jig using the same EntityJig in the AutoCAD .NET API. Here is the second SplineJig version 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 SplineJig2 : EntityJig
{
#region Fields
private static Vector3d TinyOffset = new Vector3d(1e-10,1e-10,0);
private int mCurrentJigIndex = 3;
private Autodesk.AutoCAD.Geometry.Point3d mLastVertex;
#endregion
#region Constructors
public SplineJig2(Spline ent)
: base(ent)
{
Entity.SetDatabaseDefaults();
Entity.TransformBy(UCS);
mLastVertex = ent.GetFitPointAt(2);
}
#endregion
#region Properties
private static Editor Editor
{
get
{
return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
}
}
private Matrix3d UCS
{
get
{
return Editor.CurrentUserCoordinateSystem;
}
}
#endregion
#region Overrides
public new Spline Entity // Overload the Entity property for convenience.
{
get
{
return base.Entity as Spline;
}
}
bool mNewPoint = true;
protected override bool Update()
{
try
{
if (mNewPoint)
{
Entity.InsertFitPointAt(mCurrentJigIndex++, mLastVertex);
mNewPoint = false;
}
else
{
Entity.InsertFitPointAt(mCurrentJigIndex, mLastVertex);
if( Entity.NumFitPoints > mCurrentJigIndex )
Entity.RemoveFitPointAt(mCurrentJigIndex - 1);
}
return true;
}
catch (SystemException ex)
{
Editor.WriteMessage(ex.ToString());
return false;
}
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
JigPromptPointOptions prOptions1 = new JigPromptPointOptions("\nFit point (Enter to finish):");
prOptions1.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.GovernedByUCSDetect | UserInputControls.NullResponseAccepted;
PromptPointResult prResult1 = prompts.AcquirePoint(prOptions1);
if (prResult1.Status == PromptStatus.Cancel && prResult1.Status == PromptStatus.Error)
return SamplerStatus.Cancel;
if (prResult1.Value.DistanceTo(mLastVertex) < 1)
{
return SamplerStatus.NoChange;
}
else
{
mLastVertex = prResult1.Value;
return SamplerStatus.OK;
}
}
#endregion
#region Methods to Call
public static bool Jig(Spline ent)
{
SplineJig2 jigger = null;
try
{
jigger = new SplineJig2(ent);
PromptResult pr;
int dummyIndex = 0;
do
{
pr = Editor.Drag(jigger);
if (pr.Status == PromptStatus.Keyword)
{
// Keyword handling code
}
if (dummyIndex++ < 2)
{
jigger.Entity.RemoveFitPointAt(0);
jigger.mCurrentJigIndex--;
}
jigger.mNewPoint = true;
} while (pr.Status != PromptStatus.Cancel && pr.Status != PromptStatus.Error && pr.Status != PromptStatus.None);
if (pr.Status == PromptStatus.Cancel || pr.Status == PromptStatus.Error)
{
return false;
}
else
{
jigger.Entity.RemoveFitPointAt(jigger.mCurrentJigIndex - 1);
return true;
}
}
catch
{
return false;
}
}
#endregion
#region Test Commands
[CommandMethod("TestSplineJig2")]
public static void TestSplineJig2_Method()
{
try
{
PromptPointOptions prOpt = new PromptPointOptions("\nFit point (Enter to finish):");
PromptPointResult ppr = Editor.GetPoint(prOpt);
if (ppr.Status != PromptStatus.OK)
return;
Point3d pt1 = ppr.Value.Subtract(TinyOffset);
Point3d pt0 = pt1.Subtract(TinyOffset);
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
using (Spline ent = new Spline(new Point3dCollection(new Point3d[] { pt0, pt1, ppr.Value }), 2, 0))
{
ent.SetDatabaseDefaults();
btr.AppendEntity(ent);
tr.AddNewlyCreatedDBObject(ent, true);
if (SplineJig2.Jig(ent))
tr.Commit();
}
}
}
catch (System.Exception ex)
{
Editor.WriteMessage(ex.ToString());
}
}
#endregion
}
}
Here is what the the sceen looked like when a Spline was being jigged by the above code and command.
Though the screenshot and the command line inputs look almost the same as in the first version, the dynamic behavior of the second SplineJig has been improved a lot.
From the first fit point input on, the spline begins to jig right away.
The other two needed temporary points for the Spline constructor are created automatically based on some simple but functional algorithm.
The two dummy points will be removed at the earliest good chances to make the SplineJig look natural and the underlying data accurate.
After the Enter Key is pressed, the temporary last fit point captured from the cursor at that moment will be removed from the SplineJig to make it behave more like the AutoCAD Spline command.
The logic of the first version SplineJig has been improved. The resultant Spline entity will have exactly the same fit points in both count and values as entered by left mouse button clicks or keyboard inputs.
The code is more concise but the SplineJig2 behaves much better.
A few highlights about the code may be helpful:
• The Spline entity type is specified in the constructor of the EntityJig derivative.
• The Sampler() override is to acquire input for the fit points of the Spline.
• Some UserInputControls flags are used here, e.g. GovernedByUCSDetect and Accept3dCoordinates to collect a point from UCS but interpreted in WCS.
• If the input is close (less than 1 unit distance) to the last fit point in the spline, the SamplerStatus.NoChange is returned in the Sampler() override to avoid unnecessary flashing. The tolerance can be adjusted for sure to meet different needs.
• Please do not forget to handle the cancel/escape circumstance as demonstrated.
• The Update() override is to update the Spline with a new fit point being added temporarily.
• The Editor.Drag() is the power to fire the jig and is called repeatedly in a loop to collect more fit points. That can avoid the unnecessary complexities of the Spline Jig itself such as in the Sampler() and Update() calls.
• 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 Spline entity be really added to the database.
• A handy index flag is to tell the Spline Jig which fit point input it is so as to determine whether to update or add it to the Spline and how.
• The above test was performed in a UCS instead of the default WCS, indicating the second version of the SplineJig still perfectly honored the current UCS as in the first version and as in any jig samples we demonstrated before.
The leading edge AutoCAD .NET Addin Wizard (AcadNetAddinWizard) provides a coder, Entity Jigger, to help us create entity jig code automatically, quickly and reliably.
Posted by: |