using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
namespace Gaps
{
public static class Extention
{
public static bool Parallel(this Vector3d a, Vector3d b, double delta)
{
double c = Math.Abs(a.GetAngleTo(b));
return c < delta || c > Math.PI - delta;
}
public static Line Extrapolate(this IEnumerable<Line> lines)
{
List
<Point3d
> points
= new List
<Point3d
>(); Line line = lines.First();
foreach (var item in lines)
{
points.Add(item.StartPoint);
points.Add(item.EndPoint);
}
points = points.OrderBy(a => line.Delta.DotProduct(a.GetAsVector())).ToList();
return new Line
(points
.First(),points
.Last()); }
}
public class Gaps
{
double _gap = 6;
[CommandMethod("Heal")]
public void healGaps()
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptSelectionOptions pso
= new PromptSelectionOptions
(); pso.MessageForAdding = "\nSelect lines to heal";
TypedValue
[] tv
= new TypedValue
[1] { new TypedValue
((int)DxfCode
.Start,
"LINE") }; PromptSelectionResult psr
= ed
.GetSelection(pso,
new SelectionFilter
(tv
)); if (psr.Status != PromptStatus.OK) return;
using (Transaction tr = doc.TransactionManager.StartTransaction())
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
List<Line> lines = psr.Value.GetObjectIds().Select(a => (Line)tr.GetObject(a, OpenMode.ForRead)).ToList();
IEnumerator<Line> Iline = lines.GetEnumerator();
Iline.MoveNext();
do
{
Line line = Iline.Current;
Point3d a = line.EndPoint, b = line.StartPoint;
IEnumerable<Line> healers = lines.Where(c => c.Delta.Parallel(line.Delta, .1) && (
(c.GetClosestPointTo(a, false).GetVectorTo(a).Parallel(c.Delta, 0.1))
|| (c.GetClosestPointTo(b, false).GetVectorTo(b).Parallel(c.Delta, 0.1))
));
if (healers.Count() > 1)
{
Line healed = healers.Extrapolate();
ed.WriteMessage("\n{0}..{1}", healed.StartPoint, healed.EndPoint);
healed.SetPropertiesFrom(healers.First());
foreach (var item in healers.ToArray())
{
lines.Remove(item);
item.UpgradeOpen();
item.Erase();
}
btr.AppendEntity(healed);
tr.AddNewlyCreatedDBObject(healed, true);
lines.Add(healed);
Iline = lines.GetEnumerator();
}
} while (Iline.MoveNext());
tr.Commit();
}
}
public void HealPolyLines()
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptSelectionOptions pso
= new PromptSelectionOptions
(); pso.MessageForAdding = "\nSelect lines to heal";
TypedValue
[] tv
= new TypedValue
[4]; //new TypedValue[4]; tv
.SetValue(new TypedValue
((int)DxfCode
.Operator,
"<or"),
0); tv
.SetValue(new TypedValue
((int)DxfCode
.Start,
"LWPOLYLINE"),
1); tv
.SetValue(new TypedValue
((int)DxfCode
.Start,
"LINE"),
2); tv
.SetValue(new TypedValue
((int)DxfCode
.Operator,
"or>"),
3); PromptSelectionResult psr
= ed
.GetSelection(pso,
new SelectionFilter
(tv
)); if (psr.Status != PromptStatus.OK) return;
using (Transaction tr = doc.TransactionManager.StartTransaction())
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
List<Curve> lines = psr.Value.GetObjectIds().Select(a => (Curve)tr.GetObject(a, OpenMode.ForRead)).ToList();
}
Polyline p
= new Polyline
(); SegmentType t = p.GetSegmentType(p.NumberOfVertices);
List
<LineSegment3d
> segments
= new List
<LineSegment3d
>(); switch (t)
{
case SegmentType.Arc:
break;
case SegmentType.Coincident:
break;
case SegmentType.Empty:
break;
case SegmentType.Line:
segments.Add(p.GetLineSegmentAt(p.NumberOfVertices));
break;
case SegmentType.Point:
break;
default:
break;
}
}
[CommandMethod("GF")]
public void gapFast()
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptEntityOptions peo
= new PromptEntityOptions
("\nSelect the line to break around: "); peo.SetRejectMessage("Only a line!");
peo
.AddAllowedClass(typeof(Line
),
false); peo
.AddAllowedClass(typeof(Polyline
),
false); peo
.AddAllowedClass(typeof(Polyline2d
),
false); peo
.AddAllowedClass(typeof(Polyline3d
),
false); //peo.AddAllowedClass(typeof(Line2d), false);
//peo.AddAllowedClass(typeof(Line3d), false);
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK) return;
ObjectId keepId = per.ObjectId;
peo.Message = "\nSelect the line to break: ";
per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK) return;
ObjectId breakId = per.ObjectId;
try
{
using (Transaction tr = doc.TransactionManager.StartTransaction())
{
_btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
_OriginalCurves
= new Dictionary
<ObjectId, Curve
>(); Curve breakCurve = (Curve)tr.GetObject(breakId, OpenMode.ForRead);
Curve keepCurve = (Curve)tr.GetObject(keepId, OpenMode.ForRead);
breakLines
(new Curve
[1] { breakCurve
},
new Curve
[1] { keepCurve
}, ed, db, doc
); tr.Commit();
}
}
catch (System.Exception e)
{
ed.WriteMessage("\nError: {0}\n{1}", e.GetBaseException(), e.Message);
}
finally
{
_btr = null;
_OriginalCurves = null;
}
}
[CommandMethod("gap")]
public void TestBreaks()
{
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptSelectionOptions pso
= new PromptSelectionOptions
(); pso.MessageForAdding = "\nSelect lines to break around";
TypedValue
[] tv
= new TypedValue
[4]; tv
.SetValue(new TypedValue
((int)DxfCode
.Operator,
"<or"),
0); tv
.SetValue(new TypedValue
((int)DxfCode
.Start,
"LWPOLYLINE"),
1); tv
.SetValue(new TypedValue
((int)DxfCode
.Start,
"LINE"),
2); tv
.SetValue(new TypedValue
((int)DxfCode
.Operator,
"or>"),
3); TypedValue
[] fil
= new TypedValue
[1] { new TypedValue
((int)DxfCode
.Start,
"LWPOLYLINE") }; SelectionFilter sf
= new SelectionFilter
(tv
); PromptSelectionResult psr = ed.GetSelection(pso, sf);
if (psr.Status != PromptStatus.OK) return;
SelectionSet keepers = psr.Value;
pso.MessageForAdding = "\nSelect lines to break";
psr = ed.GetSelection(pso, sf);
if (psr.Status != PromptStatus.OK) return;
SelectionSet breakers = psr.Value;
PromptDoubleOptions pdo
= new PromptDoubleOptions
("\nEnter spacing"); pdo.DefaultValue = _gap;
pdo.AllowNone = true;
pdo.AllowNegative = false;
pdo.AllowZero = false;
PromptDoubleResult pdr = ed.GetDouble(pdo);
if (pdr.Status != (PromptStatus.OK | PromptStatus.None))
{
ed.WriteMessage("\nInvalid input");
return;
}
_gap = pdr.Value;
ObjectIdCollection keepIds
= new ObjectIdCollection
(keepers
.GetObjectIds()); ObjectIdCollection breakIds
= new ObjectIdCollection
(breakers
.GetObjectIds()); try
{
using (Transaction tr = doc.TransactionManager.StartTransaction())
{
_btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
_OriginalCurves
= new Dictionary
<ObjectId, Curve
>(); List
<Curve
> keepCurves
= new List
<Curve
>(); foreach (ObjectId id in keepIds)
{
keepCurves.Add((Curve)tr.GetObject(id, OpenMode.ForRead));
}
List
<Curve
> breakCurves
= new List
<Curve
>(); foreach (ObjectId id in breakIds)
{
breakCurves.Add((Curve)tr.GetObject(id, OpenMode.ForRead));
}
breakLines(breakCurves.ToArray(), keepCurves.ToArray(), ed, db, doc);
tr.Commit();
}
}
catch (System.Exception e)
{
ed.WriteMessage("\nError: {0}\n{1}", e.GetBaseException(), e.Message);
}
finally
{
_btr = null;
_OriginalCurves = null;
}
}
private BlockTableRecord _btr;
private Dictionary<ObjectId, Curve> _OriginalCurves;
public void breakLines(Curve[] breakCurves, Curve[] keepCurves, Editor ed, Database db, Document doc)
{
Transaction tr = doc.TransactionManager.TopTransaction;
try
{
Dictionary
<Curve, Point3dCollection
> intersections
= new Dictionary
<Curve, Point3dCollection
>(); for (int i = breakCurves.Length - 1; i >= 0; i--)
{
Point3dCollection intersectionPoints
= new Point3dCollection
(); for (int j = keepCurves.Length - 1; j >= 0; j--)
{
Point3dCollection tempIntersectionPoints
= new Point3dCollection
(); breakCurves[i].IntersectWith(keepCurves[j], Intersect.OnBothOperands, tempIntersectionPoints, (IntPtr)0, (IntPtr)0);
foreach (Point3d point in tempIntersectionPoints)
{
try
{
double dist = breakCurves[i].GetDistAtPoint(point);
double length = breakCurves[i].GetDistAtPoint(breakCurves[i].EndPoint);
if (dist > _gap / 2 & length - dist > _gap / 2)
{
intersectionPoints.Add(point);
}
}
catch { }
}
}
List
<Point3d
> sortPoints
= new List
<Point3d
>(); foreach (Point3d point in intersectionPoints)
sortPoints.Add(point);
intersectionPoints.Clear();
foreach (Point3d point in sortPoints.OrderBy(pt => breakCurves[i].GetParameterAtPoint(pt)))
intersectionPoints.Add(point);
intersections.Add(breakCurves[i], intersectionPoints);
}
foreach (Curve breakCurve in breakCurves)
{
if (intersections[breakCurve].Count == 0) continue;
DBObjectCollection brokenCurves = breakCurve.GetSplitCurves(intersections[breakCurve]);
if (brokenCurves.Count == 0) continue;
List
<DBObject
> curves
= new List
<DBObject
>(); foreach (DBObject o in brokenCurves)
curves.Add(o);
curves.OrderBy(o => breakCurve.GetParameterAtPoint((o as Curve).StartPoint));
DBObjectCollection newcurves
= new DBObjectCollection
(); for (int i = 0; i < curves.Count; i++)
{
Curve curve = curves[i] as Curve;
if (curve.GetDistAtPoint(curve.EndPoint) > _gap)
{
curve.SetPropertiesFrom(breakCurve);
_btr.AppendEntity(curve);
tr.AddNewlyCreatedDBObject(curve, true);
newcurves.Add(curve);
}
}
Curve brokenCurve = null;
Polyline poly = null;
for (int n = 0; n < newcurves.Count; n++)
{
brokenCurve = (Curve)newcurves[n];
double startParam = brokenCurve.StartParam;
double endParam = brokenCurve.EndParam;
Point3d newStartPoint = brokenCurve.GetPointAtDist(_gap / 2);
Point3d newEndPoint = brokenCurve.GetPointAtDist(brokenCurve.GetDistanceAtParameter(brokenCurve.EndParam) - brokenCurve.GetDistanceAtParameter(brokenCurve.StartParam) - _gap / 2);
Point3d startPoint
= new Point3d
(); Point3d endPoint
= new Point3d
(); try
{
bool isPoly = (brokenCurve.GetRXClass().DxfName == "LWPOLYLINE");
if (isPoly)
poly = (Polyline)brokenCurve;
if (n == 0) //first curve in list
{
endPoint = brokenCurve.GetClosestPointTo(newEndPoint, false);
if (isPoly)
poly
.SetPointAt(poly
.NumberOfVertices - 1,
new Point2d
(endPoint
.X, endPoint
.Y)); else
brokenCurve.EndPoint = endPoint;
}
else if (n == newcurves.Count - 1)//last curve in list
{
startPoint = brokenCurve.GetClosestPointTo(newStartPoint, false);
if (isPoly)
poly
.SetPointAt(0,
new Point2d
(startPoint
.X, startPoint
.Y)); else
brokenCurve.StartPoint = startPoint;
}
else
{
startPoint = brokenCurve.GetClosestPointTo(newStartPoint, false);
endPoint = brokenCurve.GetClosestPointTo(newEndPoint, false);
if (isPoly)
{
poly
.SetPointAt(0,
new Point2d
(startPoint
.X, startPoint
.Y)); poly
.SetPointAt(poly
.NumberOfVertices - 1,
new Point2d
(endPoint
.X, endPoint
.Y)); }
else
{
brokenCurve.StartPoint = startPoint;
brokenCurve.EndPoint = endPoint;
}
}
}
catch (System.Exception e)
{
ed.WriteMessage("\nError processing {2}: {0}\n{1}", e.Message, e.StackTrace, brokenCurve.GetType());
}
}
breakCurve.UpgradeOpen();
breakCurve.Erase();
}
}
catch (System.Exception e)
{
Autodesk.AutoCAD.Runtime.Exception ex = e as Autodesk.AutoCAD.Runtime.Exception;
if (ex != null)
{
if (ex.ErrorStatus == Autodesk.AutoCAD.Runtime.ErrorStatus.InvalidInput)
{
}
}
ed.WriteMessage("\nError: {0}\n{1}", e.Message, e.StackTrace);
throw;
}
}
}
}