/// <summary>
/// возвращает список точек пересечения кривых на плане по вектору
/// Использовались части кода от Александра Ривилиса
/// </summary>
/// <param name="bCurId">ObjectId секущей кривой</param>
/// <param name="iCurId">ObjectId пересекаемой кривой </param>
/// <param name="bCur">секущая кривая</param>
/// <param name="iCur">пересекаемая кривая</param>
/// <param name="iBlock">Блок если пересекаемая кривая находится в блоке</param>
/// <param name="plane">план на котором ищутся пересечения</param>
/// <param name="vector">направление проецирования на план</param>
/// <param name="firstLast">возвращать точки пересечения на концах пересекаемой линии?</param>
/// <returns>список точек пересечения на пересекаемой кривой</returns>
private List<Point3d> IntersectPoints(ObjectId bCurId, ObjectId iCurId, Curve bCur, Curve iCur, Plane plane, Vector3d vector, bool firstLast)
{
List<Point3d> result = new List<Point3d>();
//если кривых нет то останавливаем
if ((bCurId == ObjectId.Null & bCur == null) | (iCurId == ObjectId.Null & iCur == null)) return result;
//если кривые заданы через ObjectId то получаем
if (bCur == null | iCur == null)
{
using (Transaction tr = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction())
{
if (bCur == null)
{
bCur = tr.GetObject(bCurId, OpenMode.ForRead, false, true) as Curve;
}
if (iCur == null)
{
iCur = tr.GetObject(iCurId, OpenMode.ForRead, false, true) as Curve;
}
tr.Commit();
}
}
//если вдруг что-то пошло не так и кривые мы все таки не получили то прекращаем
if (bCur == null | iCur == null) return result;
//получаем проекции кривых на плоскость
using (Curve bCurPr = bCur.GetProjectedCurve(plane, vector))
using (Curve iCurPr = iCur.GetProjectedCurve(plane, vector))
{
//проверяем что проекции имеют длину
if ((bCurPr.GetDistanceAtParameter(bCurPr.StartParam) + bCurPr.GetDistanceAtParameter(bCurPr.EndParam)) == 0) return result;
if ((iCurPr.GetDistanceAtParameter(iCurPr.StartParam) + iCurPr.GetDistanceAtParameter(iCurPr.EndParam)) == 0) return result;
//получаем Curve3d
using (Curve3d bCurPr3d = bCurPr.GetGeCurve())
using (Curve3d iCurPr3d = iCurPr.GetGeCurve())
{
//получаем точки пересечения кривых
using (CurveCurveIntersector3d cInt = new CurveCurveIntersector3d(bCurPr3d, iCurPr3d, vector))
{
//если пересечения есть
if (cInt.NumberOfIntersectionPoints > 0)
{
//получаем непроецированную кривую как Curve3d
using (Curve3d iCur3d = iCur.GetGeCurve())
{
//проходим по пересечениям
for (int i = 0; i < cInt.NumberOfIntersectionPoints; i++)
{
//если касание пропускаем
if (cInt.IsTangential(i)) continue;
//получаем точку пересечения
Point3d point = cInt.GetIntersectionPoint(i);
//если это точка начала или конца и она не нужна то пропускаем
if (!firstLast)
{
if ((i == 0 | i == (cInt.NumberOfIntersectionPoints - 1)) & (point.Equals(iCurPr3d.StartPoint) | point.Equals(iCurPr3d.EndPoint))) continue;
}
//строим линию из этой точки и ищем реальную точку на непроецированной кривой
using (Line3d line = new Line3d(point, vector))
{
//получаем точки пересечения линии и непроецированной кривой
using (CurveCurveIntersector3d cits = new CurveCurveIntersector3d(iCur3d, line, vector))
{
if (cits.NumberOfIntersectionPoints > 0)
{
for (int j = 0; j < cits.NumberOfIntersectionPoints; j++)
{
//если этой точки нет в списке то добавляем в список
if (!result.Contains(cits.GetIntersectionPoint(j))) result.Add(cits.GetIntersectionPoint(j));
}
}
}
}
}
}
}
}
}
}
//возвращаем отсортированные точки
return SortPoint(result, iCur);
}
/// <summary>
/// Возвращает ObjectId кривых в лупе отрисованных в текущем пространстве
/// (немного доработанная функция от Александра Ривилиса)
/// </summary>
/// <param name="loop"></param>
/// <param name="plane"></param>
/// <param name="iBlock"></param>
/// <returns></returns>
private List<ObjectId> GetCurveFromLoop(HatchLoop loop, Plane plane, Hatch hatch)
{
List<ObjectId> result = new List<ObjectId>();
using (Transaction tr = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction())
{
using (BlockTableRecord ms = tr.GetObject(HostApplicationServices.WorkingDatabase.CurrentSpaceId, OpenMode.ForWrite, false, true) as BlockTableRecord)
{
if (loop.IsPolyline)
{
using (Polyline poly = new Polyline())
{
int iVertex = 0;
foreach (BulgeVertex bv in loop.Polyline)
{
poly.AddVertexAt(iVertex++, bv.Vertex, bv.Bulge, 0.0, 0.0);
}
poly.Normal = hatch.Normal;
poly.Elevation = hatch.Elevation;
result.Add(ms.AppendEntity(poly));
tr.AddNewlyCreatedDBObject(poly, true);
}
}
else
{
foreach (Curve2d cv in loop.Curves)
{
LineSegment2d line2d = cv as LineSegment2d;
CircularArc2d arc2d = cv as CircularArc2d;
EllipticalArc2d ellipse2d = cv as EllipticalArc2d;
NurbCurve2d spline2d = cv as NurbCurve2d;
if (line2d != null)
{
using (Line ent = new Line())
{
ent.StartPoint = new Point3d(plane, line2d.StartPoint);
ent.EndPoint = new Point3d(plane, line2d.EndPoint);
result.Add(ms.AppendEntity(ent));
tr.AddNewlyCreatedDBObject(ent, true);
}
}
else if (arc2d != null)
{
if (arc2d.IsClosed() || Math.Abs(arc2d.EndAngle - arc2d.StartAngle) < 1e-5)
{
using (Circle ent = new Circle(new Point3d(plane, arc2d.Center), plane.Normal, arc2d.Radius))
{
result.Add(ms.AppendEntity(ent));
tr.AddNewlyCreatedDBObject(ent, true);
}
}
else
{
if (arc2d.IsClockWise)
{
arc2d = arc2d.GetReverseParameterCurve() as CircularArc2d;
}
double angle = new Vector3d(plane, arc2d.ReferenceVector).AngleOnPlane(plane);
double startAngle = arc2d.StartAngle + angle;
double endAngle = arc2d.EndAngle + angle;
using (Arc ent = new Arc(new Point3d(plane, arc2d.Center), plane.Normal, arc2d.Radius, startAngle, endAngle))
{
result.Add(ms.AppendEntity(ent));
tr.AddNewlyCreatedDBObject(ent, true);
}
}
}
else if (ellipse2d != null)
{
//-------------------------------------------------------------------------------------------
// Bug: Can not assign StartParam and EndParam of Ellipse:
// Ellipse ent = new Ellipse(new Point3d(plane, e2d.Center), plane.Normal,
// new Vector3d(plane,e2d.MajorAxis) * e2d.MajorRadius,
// e2d.MinorRadius / e2d.MajorRadius, e2d.StartAngle, e2d.EndAngle);
// ent.StartParam = e2d.StartAngle;
// ent.EndParam = e2d.EndAngle;
// error CS0200: Property or indexer 'Autodesk.AutoCAD.DatabaseServices.Curve.StartParam' cannot be assigned to -- it is read only
// error CS0200: Property or indexer 'Autodesk.AutoCAD.DatabaseServices.Curve.EndParam' cannot be assigned to -- it is read only
//---------------------------------------------------------------------------------------------
// Workaround is using Reflection
//
using (Ellipse ent = new Ellipse(new Point3d(plane, ellipse2d.Center), plane.Normal,
new Vector3d(plane, ellipse2d.MajorAxis) * ellipse2d.MajorRadius,
ellipse2d.MinorRadius / ellipse2d.MajorRadius, ellipse2d.StartAngle, ellipse2d.EndAngle))
{
ent.GetType().InvokeMember("StartParam", BindingFlags.SetProperty, null,
ent, new object[] { ellipse2d.StartAngle });
ent.GetType().InvokeMember("EndParam", BindingFlags.SetProperty, null,
ent, new object[] { ellipse2d.EndAngle });
result.Add(ms.AppendEntity(ent));
tr.AddNewlyCreatedDBObject(ent, true);
}
}
else if (spline2d != null)
{
if (spline2d.HasFitData)
{
NurbCurve2dFitData n2fd = spline2d.FitData;
using (Point3dCollection p3ds = new Point3dCollection())
{
foreach (Point2d p in n2fd.FitPoints) p3ds.Add(new Point3d(plane, p));
using (Spline ent = new Spline(p3ds, new Vector3d(plane, n2fd.StartTangent), new Vector3d(plane, n2fd.EndTangent),
/* n2fd.KnotParam, */ n2fd.Degree, n2fd.FitTolerance.EqualPoint))
{
result.Add(ms.AppendEntity(ent));
tr.AddNewlyCreatedDBObject(ent, true);
}
}
}
else
{
NurbCurve2dData n2fd = spline2d.DefinitionData;
using (Point3dCollection p3ds = new Point3dCollection())
{
DoubleCollection knots = new DoubleCollection(n2fd.Knots.Count);
foreach (Point2d p in n2fd.ControlPoints) p3ds.Add(new Point3d(plane, p));
foreach (double k in n2fd.Knots) knots.Add(k);
double period = 0;
using (Spline ent = new Spline(n2fd.Degree, n2fd.Rational,
spline2d.IsClosed(), spline2d.IsPeriodic(out period),
p3ds, knots, n2fd.Weights, n2fd.Knots.Tolerance, n2fd.Knots.Tolerance))
{
result.Add(ms.AppendEntity(ent));
tr.AddNewlyCreatedDBObject(ent, true);
}
}
}
}
}
}
}
tr.Commit();
}
return result;
}
/// <summary>
/// выбор объекта на чертеже и возврат его ObjectId
/// </summary>
/// <param name="objTypes">список с типами допущенных для выбора объектов, пустой лист любого объекта</param>
/// <param name="soob">Выводимое сообщение при выборе</param>
/// <returns></returns>
private ObjectId GetObjectId(List<string> objTypes, string soob)
{
//повторяем пока не выбран нужный объект
while (true)
{
//Выбираем объект на чертеже
PromptEntityResult entRes = Application.DocumentManager.MdiActiveDocument.Editor.GetEntity("\n" + soob);
//Если объект не выбран то прекращаем программу
if (entRes.Status == PromptStatus.Cancel)
{
return ObjectId.Null;
}
//проверка на тип объекта если выбранный объект корректен то выходим из цикла выбора
if (objTypes.Count == 0) return entRes.ObjectId;
foreach (string objType in objTypes)
if (entRes.ObjectId.ObjectClass.Name.ToLower().Equals(objType.ToLower()))
return entRes.ObjectId;
}
}
/// <summary>
/// используется что бы определить положение объекта относительно других кривых
/// даст точный результат если объекты из списка образуют замкнутый контур
/// </summary>
/// <param name="cur">элемент который проверяется (кривая или точка)</param>
/// <param name="curvesId">список ObjectId кривых</param>
/// <param name="plane"></param>
/// <param name="vector"></param>
/// <param name="kontur">кривая если нужно передать уже открытую</param>
/// <returns>
/// 0 - ошибка исходных данных
/// 1 - внутри кривых
/// 2 - снаружи кривых
/// </returns>
private int CurveInCurves(Object cur, List<ObjectId> curvesId, Plane plane, Vector3d vector, Curve kontur)
{
if ((curvesId.Count == 0 & kontur == null) | cur == null ) return 0;
//счетчик общего числа пересечений
//создаем список точек что бы не задваивать пересечения
//если вдруг точка пересечения попадет в стык между двумя кривыми
//встречается часто если сечется прямоугольником так как вектор параллелен оси
List<Point3d> points = new List<Point3d>();
using (Transaction tr = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction())
{
//строим луч из центра кривой в плане штриховки
using (Ray ray = new Ray())
{
//создаем луч из центра кривой
if (cur is Curve) ray.BasePoint = GetCentr(cur as Curve);
if (cur is Point3d) ray.BasePoint = (Point3d)cur;
ray.UnitDir = plane.Normal.GetPerpendicularVector();
//проходим по всем кривым и ищем пересечения
using (Curve3d ray3d = ray.GetGeCurve())
{
List<Curve> curves = new List<Curve>();
foreach (ObjectId id in curvesId) curves.Add(tr.GetObject(id, OpenMode.ForRead, false, true) as Curve);
if (kontur != null) curves.Add(kontur);
foreach (Curve curve in curves)
{
using (Curve3d loopCur3d = curve.GetGeCurve())
using (CurveCurveIntersector3d cuin = new CurveCurveIntersector3d(ray3d, loopCur3d, vector))
{
if (cuin.NumberOfIntersectionPoints > 0)
{
//ищем число пересечений не считая касательных
for (int i = 0; i < cuin.NumberOfIntersectionPoints; i++)
if (cuin.IsTransversal(i))
{
if (!points.Contains(cuin.GetIntersectionPoint(i)))
{
points.Add(cuin.GetIntersectionPoint(i));
}
}
}
}
}
}
}
tr.Commit();
}
//если число пересечений нечетное то точка изнутри, если четное или ноль то снаружи
if (points.Count % 2 != 0) return 1;
else return 2;
}
/// <summary>
/// удаляет объекты из списка по id
/// </summary>
/// <param name="ids"></param>
private void DeleteObj(List<ObjectId> ids)
{
using (Transaction tr = HostApplicationServices.WorkingDatabase.TransactionManager.StartTransaction())
{
foreach (ObjectId id in ids)
{
using (Entity c = tr.GetObject(id, OpenMode.ForWrite, false, true) as Entity)
{
c.Erase();
}
}
tr.Commit();
}
}
/// <summary>
/// проверяет положение кривой part относительно кривой kontur
/// </summary>
/// <param name="kontur"></param>
/// <param name="part"></param>
/// <param name="iBlock"></param>
/// <returns>
/// 0 - ошибка исходных данных
/// 1 - внутри
/// 2 - снаружи
/// 3 - на границе
/// 4 - внутри и касается контура
/// 5 - снаружи и касается контура
/// 6 - пересекает контур
/// </returns>
private int PartIn(Curve kontur, Curve part, Plane plane, Vector3d vector)
{
if (kontur == null | part == null) return 0;
//внутри контура
bool into = false;
//снаружи контура
bool outer = false;
//на границе контура
bool g = false;
//создаем список из трех точек
List<Point3d> points = new List<Point3d>
{
part.StartPoint,
part.EndPoint,
GetCentr(part)
};
//проверяем на пересечение
List<Point3d> per = IntersectPoints(ObjectId.Null, ObjectId.Null, kontur.Clone() as Curve, part.Clone() as Curve, plane, vector, false);
if (per.Count > 0) return 6;
foreach (Point3d point in points)
{
//проверяем на нахождение на контуре
//если проекция точки на контур совпадает с точкой то она на контуре
if (kontur.GetClosestPointTo(point, false).Equals(point))
{
g = true;
continue;
}
//если не на границе то пользуемся определением положения через луч
int res = CurveInCurves(point, new List<ObjectId>(), plane, vector, kontur);
if (res == 1) into = true;
if (res == 2) outer = true;
}
//точки только внутри
if (into & !outer & !g)
{
return 1;
}
//точки только снаружи
if (!into & outer & !g)
{
return 2;
}
//точки только на границe
if (!into & !outer & g)
{
return 3;
}
//точки внутри и на границе
if (into & !outer & g)
{
return 4;
}
//точки снаружи и на границе
if (!into & outer & g)
{
return 5;
}
return 6;
}
}
}