I suspect that many of you who have worked with point clouds will have come across this issue: the standard CIRCLE command in AutoCAD will create the circle on the plane of the active User Coordinate System (UCS), even when the circle is defined by three points on its circumference. This behaviour is probably fine for the majority of 2D drafting activities, but if you want to create circles from a point cloud – by selecting points from its perimeter using the Node object snap – then it’s less than ideal.
The code in today’s post implements a very simple jig that creates the circle in 3D, irrespective of the current UCS. It works especially well when picking points from point clouds, which is something I’ll be showing in a future post.
Here’s the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
namespace EntityJigging
{
public class ThreePtCircleJig : EntityJig
{
Point3d _first, _second, _third;
public ThreePtCircleJig(
Point3d first, Point3d second
)
: base(new Circle())
{
_first = first;
_second = second;
}
protected override SamplerStatus Sampler(
JigPrompts jp
)
{
// We acquire a single 3D point
JigPromptPointOptions jo =
new JigPromptPointOptions(
"\nSelect third point"
);
jo.UserInputControls =
UserInputControls.Accept3dCoordinates;
PromptPointResult ppr = jp.AcquirePoint(jo);
if (ppr.Status == PromptStatus.OK)
{
// Check whether it's basically unchanged
if (
_third.DistanceTo(ppr.Value) <
Tolerance.Global.EqualPoint
)
{
return SamplerStatus.NoChange;
}
// Otherwise just set the jig's state
_third = ppr.Value;
return SamplerStatus.OK;
}
return SamplerStatus.Cancel;
}
protected override bool Update()
{
// Create a temporary CircularArc3d by three points
// and use it to create our Circle
CircularArc3d ca =
new CircularArc3d(_first, _second, _third);
Circle cir = Entity as Circle;
cir.Center = ca.Center;
cir.Normal = ca.Normal;
cir.Radius = ca.Radius;
return true;
}
public Entity GetEntity()
{
return Entity;
}
}
public class Commands
{
[CommandMethod("ADNPLUGINS", "3PCIR", CommandFlags.Modal)]
public void CreateCircle()
{
Document doc =
Autodesk.AutoCAD.ApplicationServices.
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
// Ask the user to select the first two points
// outside the jig
PromptPointOptions ppo =
new PromptPointOptions(
"\nSelect first point"
);
ppo.AllowNone = false;
PromptPointResult ppr = ed.GetPoint(ppo);
if (ppr.Status != PromptStatus.OK)
return;
Point3d first = ppr.Value;
ppo.Message = "\nSelect second point";
ppr = ed.GetPoint(ppo);
if (ppr.Status != PromptStatus.OK)
return;
Point3d second = ppr.Value;
// Pass the points into the jig
ThreePtCircleJig cj =
new ThreePtCircleJig(first, second);
// Then execute it
PromptResult pr = ed.Drag(cj);
if (pr.Status != PromptStatus.OK)
return;
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
// Add our circle to the current space
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
doc.Database.CurrentSpaceId,
OpenMode.ForWrite
);
Entity ent = cj.GetEntity();
btr.AppendEntity(ent);
tr.AddNewlyCreatedDBObject(ent, true);
tr.Commit();
}
}
}
}
The 3PCIR command isn’t especially exciting, in action. If you’re interested, you can see it in my next YouTube video about integrating AutoCAD with Kinect (which I’ll post a link to before long).