using System;
using System.Collections;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
#pragma warning disable 0618
[assembly: CommandClass(typeof(Rivilis.Contour))]
namespace Rivilis
{
public class Contour
{
[CommandMethod("MakePline")]
public void MakePline()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
// Отбираем только отрезки и дуги
SelectionFilter sf =
new SelectionFilter(new TypedValue[] { new TypedValue((int)DxfCode.Start,"LINE,ARC") });
PromptSelectionResult rs = ed.GetSelection(sf);
if (rs.Status != PromptStatus.OK) return;
ObjectIdCollection ids = new ObjectIdCollection(rs.Value.GetObjectIds());
while (ids.Count > 0) {
using (Polyline p = MakeJoinedPoly(ref ids)) {
if (p != null) {
using (BlockTableRecord btr = db.CurrentSpaceId.Open(OpenMode.ForWrite) as BlockTableRecord) {
btr.AppendEntity(p);
}
}
else {
ed.WriteMessage("\nОшибка во входных данных!");
return;
}
}
}
}
public static Polyline MakeJoinedPoly(ref ObjectIdCollection ids)
{
if (ids.Count == 0) return null;
// Создаём полилинию
Polyline p = new Polyline();
p.SetDatabaseDefaults();
ObjectId idOwn = ObjectId.Null;
ObjectId idFirst = ids[0];
Point3d nextPt = Point3d.Origin;
Point3d prevPt = Point3d.Origin;
// Добавляем первые две вершины из первого выбранного примитива
using (Curve c = idFirst.Open(OpenMode.ForRead) as Curve) {
p.AddVertexAt(0, ToPoint2d(c.StartPoint), BulgeFromArc(c, false), 0, 0);
p.AddVertexAt(1, ToPoint2d(c.EndPoint), 0, 0, 0);
nextPt = c.EndPoint;
prevPt = c.StartPoint;
idOwn = c.OwnerId;
}
ids.Remove(idFirst);
int prevCnt = ids.Count + 1;
while (ids.Count > 0 && ids.Count < prevCnt)
{
prevCnt = ids.Count;
foreach (ObjectId id in ids) {
using (Curve cv = id.Open(OpenMode.ForRead) as Curve) {
if (cv.StartPoint == nextPt || cv.EndPoint == nextPt) {
double bulge = BulgeFromArc(cv, cv.EndPoint == nextPt);
p.SetBulgeAt(p.NumberOfVertices - 1, bulge);
if (cv.StartPoint == nextPt)
nextPt = cv.EndPoint;
else
nextPt = cv.StartPoint;
p.AddVertexAt(p.NumberOfVertices, ToPoint2d(nextPt), 0, 0, 0);
ids.Remove(id);
break;
} else if (cv.StartPoint == prevPt || cv.EndPoint == prevPt) {
double bulge = BulgeFromArc(cv, cv.StartPoint == prevPt);
if (cv.StartPoint == prevPt)
prevPt = cv.EndPoint;
else
prevPt = cv.StartPoint;
p.AddVertexAt(0, ToPoint2d(prevPt), bulge, 0, 0);
ids.Remove(id);
break;
}
}
}
}
if (p.NumberOfVertices == 0)
return null;
else
return p;
}
// Функция возвращает кривизну дуги (bulge) или 0.0
static double BulgeFromArc(Curve c, bool clockwise)
{
double bulge = 0.0;
Arc a = c as Arc;
if (a == null) return bulge;
double newStart = (a.StartAngle > a.EndAngle) ?
(a.StartAngle - 8 * Math.Atan(1)) : (a.StartAngle);
bulge = Math.Tan((a.EndAngle - newStart) / 4);
if (clockwise) bulge = -bulge;
return bulge;
}
// Функция преобразует Point3d в Point2d (отбрасывает Z)
static Point2d ToPoint2d(Point3d p) {
return new Point2d(p.X, p.Y);
}
}
}