Extension methods
static class Extensions
{
/// <summary>
/// Adds an arc (fillet), if able, at each polyline vertex.
/// </summary>
/// <param name="pline">The instance to which the method applies.</param>
/// <param name="radius">The arc radius.</param>
public static void FilletAll(this Polyline pline, double radius)
{
int j = pline.Closed ? 0 : 1;
for (int i = j; i < pline.NumberOfVertices - j; i++)
{
i += pline.FilletAt(i, radius);
}
}
/// <summary>
/// Adds an arc (fillet) at the specified vertex.
/// </summary>
/// <param name="pline">The instance to which the method applies.</param>
/// <param name="index">The index of the verex.</param>
/// <param name="radius">The arc radius.</param>
/// <returns>1 if the operation succeeded, 0 if it failed.</returns>
public static int FilletAt(this Polyline pline, int index, double radius)
{
int prev = index == 0 && pline.Closed ? pline.NumberOfVertices - 1 : index - 1;
if (pline.GetSegmentType(prev) != SegmentType.Line ||
pline.GetSegmentType(index) != SegmentType.Line)
{
return 0;
}
LineSegment2d seg1 = pline.GetLineSegment2dAt(prev);
LineSegment2d seg2 = pline.GetLineSegment2dAt(index);
Vector2d vec1 = seg1.StartPoint - seg1.EndPoint;
Vector2d vec2 = seg2.EndPoint - seg2.StartPoint;
double angle = vec1.GetAngleTo(vec2) / 2.0;
double dist = radius / Math.Tan(angle);
if (dist > seg1.Length || dist > seg2.Length)
{
return 0;
}
Point2d pt1 = seg1.EndPoint + vec1.GetNormal() * dist;
Point2d pt2 = seg2.StartPoint + vec2.GetNormal() * dist;
double bulge = Math.Tan((Math.PI / 2.0 - angle) / 2.0);
if (Clockwise(seg1.StartPoint, seg1.EndPoint, seg2.EndPoint))
{
bulge = -bulge;
}
pline.AddVertexAt(index, pt1, bulge, 0.0, 0.0);
pline.SetPointAt(index + 1, pt2);
return 1;
}
/// <summary>
/// Evaluates if the points are clockwise.
/// </summary>
/// <param name="p1">First point.</param>
/// <param name="p2">Second point</param>
/// <param name="p3">Third point</param>
/// <returns>True if points are clockwise, False otherwise.</returns>
private static bool Clockwise(Point2d p1, Point2d p2, Point2d p3)
{
return ((p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X)) < 1e-8;
}
}
Testing command
public class CommandMethods
{
[CommandMethod("Test", CommandFlags.Modal)]
public void Test()
{
Document doc = AcAp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptDistanceOptions pdo = new PromptDistanceOptions("\nFillet radius: ");
pdo.AllowZero = false;
pdo.AllowNegative = false;
PromptDoubleResult pdr = ed.GetDistance(pdo);
if (pdr.Status != PromptStatus.OK)
return;
double radius = pdr.Value;
PromptEntityOptions peo = new PromptEntityOptions("\nSelect a polyline: ");
peo.SetRejectMessage("Not a polyline.");
peo.AddAllowedClass(typeof(Polyline), true);
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
return;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Polyline pline = (Polyline)tr.GetObject(per.ObjectId, OpenMode.ForWrite);
pline.FilletAll(radius);
tr.Commit();
}
}
}