In a
previous post I used events to prompt the user to draw a polyline. This approach
is very unreliable, especially when you run into exceptions and those are not
handled properly by the event subscribed to. You could end up with some very odd
behaviors!
So I had to look for an alternative and used Jigs to get the job done. Following example is
a snapable polyline jig that can be closed. On top of that I provided the
possibility to undo previous inserted vertexes.
C# Code
public sealed class SnapablePolylineJig : EntityJig, IDisposable
{
#region Variables & Properties
private readonly Point3dCollection _point3DCollection;
private readonly Plane _plane;
private readonly Matrix3d _ucs;
private Point3d _mTempPoint;
private readonly Document _document;
private readonly Editor _editor;
private readonly Database _database;
private ObjectId _snapPlineOid = ObjectId.Null;
private readonly KeywordCollection _keywordCollection;
public Polyline Polyline
{
get { return Entity as Polyline; }
}
public string Prompt { get; set; }
#endregion
public SnapablePolylineJig() : base(new Polyline())
{
_document = Application.DocumentManager.MdiActiveDocument;
_editor = _document.Editor;
_database = _document.Database;
// Create a point collection to
store our vertices
_point3DCollection = new Point3dCollection();
// Get the current UCS
_ucs =
_editor.CurrentUserCoordinateSystem;
// Create a temporary plane, to
help with calcs
var origin = new Point3d(0, 0, 0);
var normal = new Vector3d(0, 0, 1);
normal = normal.TransformBy(_ucs);
_plane = new Plane(origin, normal);
// Create polyline, set defaults,
add dummy vertex
var pline = Entity as Polyline;
if (pline != null)
{
pline.SetDatabaseDefaults();
pline.Normal = normal;
pline.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0);
}
}
public SnapablePolylineJig(string prompt)
: this()
{
Prompt = prompt;
}
public SnapablePolylineJig(string prompt, KeywordCollection keywordCollection)
: this(prompt)
{
if (keywordCollection == null)
throw new ArgumentNullException("keywordCollection");
_keywordCollection =
keywordCollection;
}
protected override bool Update()
{
// Update the dummy vertex to be
our
// 3D point projected onto our
plane
if (Polyline != null)
Polyline.SetPointAt(
Polyline.NumberOfVertices -
1,
_mTempPoint.Convert2d(_plane)
);
return true;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
var jigOpts =
new JigPromptPointOptions
{
UserInputControls = (UserInputControls.Accept3dCoordinates |
UserInputControls.NullResponseAccepted |
UserInputControls.NoNegativeResponseAccepted
)
};
if (_point3DCollection.Count == 0)
{
// For the first vertex, just ask
for the point
jigOpts.Message = "\n" + Prompt;
}
else if (_point3DCollection.Count > 0)
{
// For subsequent vertices, use a
base point
jigOpts.BasePoint =
_point3DCollection[_point3DCollection.Count - 1];
jigOpts.UseBasePoint = true;
jigOpts.Message = "\n" + Prompt;
if (_keywordCollection != null)
{
foreach (Keyword keyword in _keywordCollection)
{
jigOpts.Keywords.Add(keyword.GlobalName, keyword.LocalName,
keyword.DisplayName, keyword.Visible,
keyword.Enabled);
}
}
}
else // should never happen
return SamplerStatus.Cancel;
// Get the point itself
PromptPointResult res =
prompts.AcquirePoint(jigOpts);
// Check if it has changed or not
// (reduces flicker)
if (_mTempPoint == res.Value)
{
return SamplerStatus.NoChange;
}
if (res.Status == PromptStatus.OK)
{
_mTempPoint = res.Value;
return SamplerStatus.OK;
}
return SamplerStatus.Cancel;
}
private void RemoveLastVertex()
{
if (Polyline != null)
{
if (_point3DCollection.Count > 0)
{
Polyline.RemoveVertexAt(_point3DCollection.Count);
_point3DCollection.RemoveAt(_point3DCollection.Count);
}
}
}
private void AddLatestVertex()
{
// Add the latest selected point
to
// our internal list...
// This point will already be in
the
// most recently added pline
vertex
_point3DCollection.Add(_mTempPoint);
// Create a new dummy vertex...
// can have any initial value
if (Polyline != null)
Polyline.AddVertexAt(
Polyline.NumberOfVertices,
new Point2d(0, 0),
0, 0, 0
);
}
public void Dispose()
{
RemoveLastVertex();
Remove();
_point3DCollection.Dispose();
_plane.Dispose();
}
private void Remove()
{
//RemoveLastVertex();
if (_snapPlineOid != ObjectId.Null)
{
Transaction tr =
_database.TransactionManager.StartTransaction();
using (tr)
{
var pl = tr.GetObject(_snapPlineOid, OpenMode.ForWrite) as Polyline;
if (pl != null) pl.Erase(true);
tr.Commit();
_snapPlineOid = ObjectId.Null;
}
}
}
public void Draw()
{
AddLatestVertex();
if (_snapPlineOid != ObjectId.Null)
Remove();
if (Polyline.NumberOfVertices >
2)
{
var snapPline = new Polyline();
int i = 0;
foreach (Point3d pt in _point3DCollection)
{
snapPline.AddVertexAt(i, new Point2d(pt.X, pt.Y), 0,
(Polyline.GetStartWidthAt(i)),
Polyline.GetEndWidthAt(i));
i++;
}
using (Transaction tr =
_database.TransactionManager.StartTransaction())
{
var btr = (BlockTableRecord)
tr.GetObject(_database.CurrentSpaceId, OpenMode.ForWrite, false);
btr.AppendEntity(snapPline);
tr.AddNewlyCreatedDBObject(snapPline, true);
_snapPlineOid =
snapPline.ObjectId;
tr.Commit();
}
}
}
public void Undo()
{
RemoveLastVertex();
Remove();
}
public void Close()
{
if (_point3DCollection.Count > 2)
{
Polyline.AddVertexAt(
Polyline.NumberOfVertices,
new Point2d(_point3DCollection[0].X,
_point3DCollection[0].Y),
0, 0, 0
);
}
}
}
Jig Service Class
public class PolylineJigService
{
internal Document Document { get { return Application.DocumentManager.MdiActiveDocument;
} }
internal Editor Editor { get { return Document.Editor; } }
public Polyline Draw(bool closable , bool undoable)
{
if (closable && !undoable)
return DrawClosable();
if (!closable && undoable)
return DrawUndoable();
if (closable)
return DrawClosableUndoable();
return Draw();
}
private Polyline Draw()
{
SnapablePolylineJig jig;
using (jig = new SnapablePolylineJig())
{
// Loop to set the vertices
directly on the polyline
bool bSuccess, bComplete;
do
{
PromptResult res = Editor.Drag(jig);
bSuccess = (res.Status == PromptStatus.OK);
bComplete = (res.Status == PromptStatus.None);
if (bSuccess)
{
jig.Draw();
}
} while (bSuccess && !bComplete);
}
return jig.Polyline;
}
private Polyline DrawClosable()
{
SnapablePolylineJig jig;
var collection = new KeywordCollection {{"C", "C", "Close", true, true}};
using (jig = new SnapablePolylineJig("Select point of
polyline",
collection))
{
// Loop to set the vertices
directly on the polyline
bool bSuccess, bComplete, bKeyword,
bClosed = false;
do
{
PromptResult res = Editor.Drag(jig);
jig.Prompt = "Draw next
point of polyline";
bSuccess = (res.Status == PromptStatus.OK);
bKeyword = (res.Status == PromptStatus.Keyword);
bComplete = (res.Status == PromptStatus.None);
if (bSuccess && !bKeyword)
{
jig.Draw();
}
if (bKeyword)
{
if (res.StringResult == "C")
{
bClosed = true;
bComplete = true;
jig.Close();
jig.Close();
}
}
} while (!bSuccess && bKeyword
&& !bClosed || bSuccess && !bComplete);
}
return jig.Polyline;
}
private Polyline DrawUndoable()
{
SnapablePolylineJig jig;
var collection = new KeywordCollection {{"U", "U", "Undo", true, true}};
using (jig = new SnapablePolylineJig("Select point of
polyline",
collection))
{
// Loop to set the vertices
directly on the polyline
bool bSuccess, bComplete, bKeyword;
do
{
PromptResult res = Editor.Drag(jig);
bSuccess = (res.Status == PromptStatus.OK);
bKeyword = (res.Status == PromptStatus.Keyword);
bComplete = (res.Status == PromptStatus.None);
if (bSuccess && !bKeyword)
{
jig.Draw();
}
if (bKeyword)
{
if (res.StringResult == "U")
jig.Undo();
}
} while (!bSuccess && bKeyword||
bSuccess && !bComplete);
}
return jig.Polyline;
}
private Polyline DrawClosableUndoable()
{
SnapablePolylineJig jig;
var collection = new KeywordCollection {{"C", "C", "Close", true, true}, {"U", "U", "Undo", true, true}};
using (jig = new SnapablePolylineJig("Select point of
polyline",
collection))
{
// Loop to set the vertices
directly on the polyline
bool bSuccess, bComplete, bKeyword,
bClosed = false;
do
{
PromptResult res = Editor.Drag(jig);
bSuccess = (res.Status == PromptStatus.OK);
bKeyword = (res.Status == PromptStatus.Keyword);
bComplete = (res.Status == PromptStatus.None);
if (bSuccess && ! bKeyword)
{
jig.Draw();
}
if (bKeyword)
{
if (res.StringResult == "U")
jig.Undo();
if (res.StringResult == "C")
{
bClosed = true;
bComplete = true;
jig.Close();
jig.Close();
}
}
} while (!bSuccess && bKeyword
&& !bClosed || bSuccess && !bComplete);
}
return jig.Polyline;
}
}
Code In Action
After we
jigged the polyline we loop through the vertexes of the polyline.
[CommandMethod("SnapablePolylineJig")]
public void SnapablePolylineJig()
{
Polyline polyline;
var service = new PolylineJigService();
polyline = service.Draw(true, true);
if (polyline != null)
{
// Use a for loop to get each
vertex, one by one
var vn = polyline.NumberOfVertices;
var list = new List<Point2d>();
for (var i = 0; i < vn; i++)
{
// Could also get the 3D point
here
var pt = polyline.GetPoint2dAt(i);
list.Add(new Point2d(pt.X, pt.Y));
}
}
}
No comments:
Post a Comment