public void DeleteAndSearchTest() { var tree = new RBush <Point>(maxEntries: 4); tree.BulkLoad(points); var len = points.Length; // Delete an existent point. bool resultExistent = tree.Delete(points[0]); var shouldFindPointsExistent = points .Skip(1) .OrderBy(x => x) .ToList(); var foundPointsExistent = tree.Search() .OrderBy(x => x) .ToList(); // Try to delete a non-existent point. bool resultNonExistent = tree.Delete(new Point(1245, 1233, 1245, 1233)); var shouldFindPointsNonExistent = shouldFindPointsExistent; var foundPointsNonExistent = tree.Search() .OrderBy(x => x) .ToList(); Assert.True(resultExistent); Assert.Equal(shouldFindPointsExistent, foundPointsExistent); Assert.False(resultNonExistent); Assert.Equal(shouldFindPointsNonExistent, foundPointsNonExistent); }
public void RunTestGroup(int maxEntries, int numberOfItems) { RBush <Item> rBush = new RBush <Item>(maxEntries); double spaceScale = 50; IEnumerable <Item> items = ItemListGenerator.GenerateItems(numberOfItems, spaceScale); Console.WriteLine("maxEntries = " + maxEntries); // Tests: RunTest("BulkLoad", numberOfItems, () => { rBush.BulkLoad(items); }); RunTest("Search OLD", numberOfItems, () => { rBush.Search_Old(); }); RunTest("Search NEW", numberOfItems, () => { rBush.Search(); }); RunTest("Search envelope (Inf. bounds) OLD", numberOfItems, () => { rBush.Search_Old(Envelope.InfiniteBounds); }); RunTest("Search envelope (Inf. bounds) NEW", numberOfItems, () => { rBush.Search(Envelope.InfiniteBounds); }); RunTest("Iterate through IEnumerable [for comparison]", numberOfItems, () => { foreach (Item i in items) { } }); Console.ReadLine(); }
public void TestSearch_AfterBulkLoadWithSplitRoot() { int maxEntries = 4; var tree = new RBush <Point>(maxEntries); int numFirstSet = maxEntries * maxEntries + 2; // Split-root will occur twice. var firstSet = points.Take(numFirstSet); Envelope firstSetEnvelope = new Envelope( firstSet.Min(p => p.Envelope.MinX), firstSet.Min(p => p.Envelope.MinY), firstSet.Max(p => p.Envelope.MaxX), firstSet.Max(p => p.Envelope.MaxY)); tree.BulkLoad(firstSet); int numExtraPoints = 5; var extraPointsSet = points.TakeLast(numExtraPoints); Envelope extraPointsSetEnvelope = new Envelope( extraPointsSet.Min(p => p.Envelope.MinX), extraPointsSet.Min(p => p.Envelope.MinY), extraPointsSet.Max(p => p.Envelope.MaxX), extraPointsSet.Max(p => p.Envelope.MaxY)); foreach (var p in extraPointsSet) { tree.Insert(p); } Assert.Equal(extraPointsSet.OrderBy(x => x), tree.Search(extraPointsSetEnvelope).OrderBy(x => x)); }
public void BasicRemoveTest() { var tree = new RBush <Point>(maxEntries: 4); tree.BulkLoad(points); var len = points.Length; tree.Delete(points[0]); tree.Delete(points[1]); tree.Delete(points[2]); tree.Delete(points[len - 1]); tree.Delete(points[len - 2]); tree.Delete(points[len - 3]); var shouldFindPoints = points .Skip(3).Take(len - 6) .OrderBy(x => x) .ToList(); var foundPoints = tree.Search() .OrderBy(x => x) .ToList(); Assert.Equal(shouldFindPoints, foundPoints); Assert.Equal(shouldFindPoints.Count, tree.Count); Assert.Equal( shouldFindPoints.Aggregate(Envelope.EmptyBounds, (e, p) => e.Extend(p.Envelope)), tree.Envelope); }
public static IEnumerable <IPoint> Execute(IGeometry line1, IGeometry line2) { IDictionary <string, IPoint> unique = new Dictionary <string, IPoint>(); IList <IPoint> intersections = new List <IPoint>(); RBush <Extensions.SpatialDataWrapper <Segment> > tree = new RBush <Extensions.SpatialDataWrapper <Segment> >(); tree.BulkLoad(LineSegment.Execute(line2).Select(a => a.AsSpatialData <Segment>())); foreach (Segment segment in LineSegment.Execute(line1)) { foreach (Extensions.SpatialDataWrapper <Segment> match in tree.Search(segment.BBox.AsEnvelope())) { IPoint intersect = Intersects(segment.LineString, match.GetOriginalData <Segment>().LineString); if (intersect != null) { var key = string.Join(",", intersect.X, intersect.Y); if (!unique.ContainsKey(key)) { unique.Add(key, intersect); intersections.Add(intersect); } } } } return(intersections); }
public void TestSearchAfterInsertWithSplitRoot() { var maxEntries = 4; var tree = new RBush <Point>(maxEntries); var numFirstSet = maxEntries * maxEntries + 2; // Split-root will occur twice. var firstSet = points.Take(numFirstSet); foreach (var p in firstSet) { tree.Insert(p); } var numExtraPoints = 5; var extraPointsSet = points.Skip(points.Length - numExtraPoints); var extraPointsSetEnvelope = extraPointsSet.Aggregate(Envelope.EmptyBounds, (e, p) => e.Extend(p.Envelope)); foreach (var p in extraPointsSet) { tree.Insert(p); } // first 10 entries and last 5 entries are completely mutually exclusive // so searching the bounds of the new set should only return the new set exactly Assert.Equal(extraPointsSet.OrderBy(x => x), tree.Search(extraPointsSetEnvelope).OrderBy(x => x)); }
public void BasicRemoveTest() { var tree = new RBush <Point>(maxEntries: 4); tree.BulkLoad(points); var len = points.Length; tree.Delete(points[0]); tree.Delete(points[1]); tree.Delete(points[2]); tree.Delete(points[len - 1]); tree.Delete(points[len - 2]); tree.Delete(points[len - 3]); var shouldFindPoints = points .Skip(3).Take(len - 6) .OrderBy(x => x) .ToList(); var foundPoints = tree.Search() .OrderBy(x => x) .ToList(); Assert.Equal(shouldFindPoints, foundPoints); }
public void TestBulk() { var tree = new RBush <Point>(); tree.BulkLoad(missingEnvelopeTestData); var envelope = new Envelope( minX: 34.73274678, minY: 31.87729923, maxX: 34.73274678, maxY: 31.87729923); Assert.Equal( expected: tree.Search().Where(p => p.Envelope.Intersects(envelope)).Count(), actual: tree.Search(envelope).Count); }
public void SearchReturnsEmptyResultIfNothingFound() { var tree = new RBush <Point>(maxEntries: 4); tree.BulkLoad(points); Assert.Equal(new Point[] { }, tree.Search(new Envelope(200, 200, 210, 210))); }
public void BulkLoadTestData() { var tree = new RBush <Point>(); tree.BulkLoad(points); Assert.Equal(points.Length, tree.Count); Assert.Equal(points.OrderBy(x => x).ToList(), tree.Search().OrderBy(x => x).ToList()); }
public void BulkLoadAfterDeleteTest2() { var pts = GetPoints(20); var ptsDelete = pts.Take(4); var tree = new RBush <Point>(maxEntries: 4); tree.BulkLoad(pts); foreach (var item in ptsDelete) { tree.Delete(item); } tree.BulkLoad(ptsDelete); Assert.Equal(pts.Count, tree.Search().Count); Assert.Equal(pts.OrderBy(x => x).ToList(), tree.Search().OrderBy(x => x).ToList()); }
public void MissingEnvelopeTestInsertIndividually() { var tree = new RBush <Point>(); foreach (var p in missingEnvelopeTestData) { tree.Insert(p); } var envelope = new Envelope( minX: 34.73274678, minY: 31.87729923, maxX: 34.73274678, maxY: 31.87729923); Assert.Equal( expected: tree.Search().Where(p => p.Envelope.Intersects(envelope)).Count(), actual: tree.Search(envelope).Count); }
public void InsertTestData() { var tree = new RBush <Point>(); foreach (var p in points) { tree.Insert(p); } Assert.Equal(points.Length, tree.Count); Assert.Equal(points.OrderBy(x => x), tree.Search().OrderBy(x => x)); }
public void InsertAfterDeleteTest1() { var pts = GetPoints(20); var ptsDelete = pts.Take(18); var tree = new RBush <Point>(maxEntries: 4); foreach (var item in pts) { tree.Insert(item); } foreach (var item in ptsDelete) { tree.Delete(item); } foreach (var item in ptsDelete) { tree.Insert(item); } Assert.Equal(pts.Count, tree.Search().Count); Assert.Equal(pts.OrderBy(x => x).ToList(), tree.Search().OrderBy(x => x).ToList()); }
public IEnumerable <Body> BodiesNear(Vector2 point, int maximumDistance = 0, bool offsetSize = false) { if (maximumDistance == 0) { return(this.Bodies); } else { return(RTree.Search(new Envelope( point.X - maximumDistance / 2, point.Y - maximumDistance / 2, point.X + maximumDistance / 2, point.Y + maximumDistance / 2 ))); } }
public void TestSearchAfterInsert() { var maxEntries = 9; var tree = new RBush <Point>(maxEntries); var firstSet = points.Take(maxEntries); var firstSetEnvelope = firstSet.Aggregate(Envelope.EmptyBounds, (e, p) => e.Extend(p.Envelope)); foreach (var p in firstSet) { tree.Insert(p); } Assert.Equal(firstSet.OrderBy(x => x), tree.Search(firstSetEnvelope).OrderBy(x => x)); }
public void InsertTestData() { var tree = new RBush <Point>(); foreach (var p in points) { tree.Insert(p); } Assert.Equal(points.Length, tree.Count); Assert.Equal(points.OrderBy(x => x), tree.Search().OrderBy(x => x)); Assert.Equal( points.Aggregate(Envelope.EmptyBounds, (e, p) => e.Extend(p.Envelope)), tree.Envelope); }
public void SearchReturnsMatchingResults() { var tree = new RBush <Point>(maxEntries: 4); tree.BulkLoad(points); var searchEnvelope = new Envelope(40, 20, 80, 70); var shouldFindPoints = points .Where(p => p.Envelope.Intersects(searchEnvelope)) .OrderBy(x => x) .ToList(); var foundPoints = tree.Search(searchEnvelope) .OrderBy(x => x) .ToList(); Assert.Equal(shouldFindPoints, foundPoints); }
public void AdditionalRemoveTest() { var tree = new RBush <Point>(); var numDelete = 18; foreach (var p in points) { tree.Insert(p); } foreach (var p in points.Take(numDelete)) { tree.Delete(p); } Assert.Equal(points.Length - numDelete, tree.Count); Assert.Equal(points.Skip(numDelete).OrderBy(x => x), tree.Search().OrderBy(x => x)); }
public void BinarySerializeBasicTest() { RBush <Point> treeOriginal = new RBush <Point>(maxEntries: 4); treeOriginal.BulkLoad(points); Envelope searchEnvelope = new Envelope(20, 15, 60, 31); byte[] byteArr = treeOriginal.BinarySerialize(); RBush <Point> treeDeserialized = byteArr.BinaryDeserialize() as RBush <Point>; Assert.True(treeOriginal.Count == treeDeserialized.Count); Assert.True(treeOriginal.Envelope == treeDeserialized.Envelope); IReadOnlyList <Point> treeOriginalSearchResult = treeOriginal.Search(searchEnvelope); IReadOnlyList <Point> treeDeserializedSearchResult = treeDeserialized.Search(searchEnvelope); Assert.True(treeOriginalSearchResult.Count == treeDeserializedSearchResult.Count); Assert.True(treeOriginalSearchResult[0].Envelope == treeDeserializedSearchResult[0].Envelope); }
public void TestSearchAfterInsert() { int maxEntries = 9; var tree = new RBush <Point>(maxEntries); var firstSet = points.Take(maxEntries); Envelope firstSetEnvelope = new Envelope( firstSet.Min(p => p.Envelope.MinX), firstSet.Min(p => p.Envelope.MinY), firstSet.Max(p => p.Envelope.MaxX), firstSet.Max(p => p.Envelope.MaxY)); foreach (var p in firstSet) { tree.Insert(p); } Assert.Equal(firstSet.OrderBy(x => x), tree.Search(firstSetEnvelope).OrderBy(x => x)); }
public void BulkLoadMergesTreesProperly() { var smaller = GetPoints(10); var tree1 = new RBush <Point>(maxEntries: 4); tree1.BulkLoad(smaller); tree1.BulkLoad(points); var tree2 = new RBush <Point>(maxEntries: 4); tree2.BulkLoad(points); tree2.BulkLoad(smaller); Assert.True(tree1.Count == tree2.Count); Assert.True(tree1.Root.Height == tree2.Root.Height); var allPoints = points.Concat(smaller).OrderBy(x => x).ToList(); Assert.Equal(allPoints, tree1.Search().OrderBy(x => x).ToList()); Assert.Equal(allPoints, tree2.Search().OrderBy(x => x).ToList()); }
public IEnumerable <Body> BodiesNear(Envelope searchArea) { return(RTreeDynamic.Search(searchArea) .Union(RTreeStatic.Search(searchArea))); }
public void SurfaceMeshByBoundary() { Document adoc = Application.DocumentManager.MdiActiveDocument; if (adoc == null) { return; } Database db = adoc.Database; DB = db; Editor ed = adoc.Editor; ED = ed; CivilDocument cdok = CivilDocument.GetCivilDocument(adoc.Database); try { Color currColor = db.Cecolor; if (!currColor.IsByLayer)//Если текущий слой не по слою, то расчитать более темный цвет для границ участков { Color dimmerColor = Utils.GetDimmerColor(currColor, BORDER_DIM_MULTIPLIER); ColorForBorder = dimmerColor; } else { ColorForBorder = Color.FromColorIndex(ColorMethod.ByAci, 256); } if (!TinSurfIdIsValid()) { //Выбрать поверхность if (!PickTinSurf(ed)) { return;//Если выбор не успешен, прервать выполнение } } //Подсветить поверхность HighlightTinSurf(true); //Запрос ключевых слов while (true) { const string kw1 = "ПОВерхность"; const string kw2 = "ВОЗвышение"; const string kw3 = "ОТКлонкниеОтДуг"; const string kw4 = "СОЗдаватьГраницы"; PromptKeywordOptions pko = new PromptKeywordOptions("\nЗадайте параметры или пустой ввод для продолжения"); pko.Keywords.Add(kw1); pko.Keywords.Add(kw2); pko.Keywords.Add(kw3); pko.Keywords.Add(kw4); pko.AllowNone = true; PromptResult pr = ed.GetKeywords(pko); if (pr.Status == PromptStatus.Cancel) { return; } if (String.IsNullOrEmpty(pr.StringResult)) { break; } switch (pr.StringResult) { case kw1: if (!PickTinSurf(ed)) { return; } break; case kw2: if (!GetMeshElevation(ed)) { return; } break; case kw3: if (!GetApproxParam(ed)) { return; } break; case kw4: if (!GetCreateBorders(ed)) { return; } break; } } //Проверка текущего набора выбора acSSet = null; PromptSelectionResult acSSPrompt; acSSPrompt = ed.SelectImplied(); if (acSSPrompt.Status == PromptStatus.OK) { acSSet = acSSPrompt.Value; } else { //Множественный выбор блоков TypedValue[] tv = new TypedValue[] { new TypedValue(0, "INSERT") }; SelectionFilter flt = new SelectionFilter(tv); PromptSelectionOptions pso = new PromptSelectionOptions(); pso.MessageForAdding = "\nВыберите блоки участков"; acSSPrompt = adoc.Editor.GetSelection(pso, flt); if (acSSPrompt.Status == PromptStatus.OK) { acSSet = acSSPrompt.Value; } } if (acSSet != null) { Common.Timer timerMain = new Common.Timer(); timerMain.Start(); foreach (SelectedObject acSSObj in acSSet) { string blockName = null; Common.Timer timer = new Common.Timer(); timer.Start(); try { if (acSSObj != null) { //полилинии внутри блока List <ObjectId> polylines = new List <ObjectId>(); BlockReference blockReference = null; ObjectId btrId = ObjectId.Null; using (Transaction tr = db.TransactionManager.StartTransaction()) { //блок внутри набора выбора blockReference = tr.GetObject(acSSObj.ObjectId, OpenMode.ForRead) as BlockReference; tr.Commit(); } Matrix3d transform = Matrix3d.Identity; if (blockReference != null) { //трансформация из системы координат блока в мировую систему координат transform = blockReference.BlockTransform; //Перебор всех объектов внутри блока //Найти все правильные полилинии в блоке using (Transaction tr = db.TransactionManager.StartTransaction()) { btrId = blockReference.BlockTableRecord; BlockTableRecord blockTableRecord = tr.GetObject(btrId, OpenMode.ForRead) as BlockTableRecord; if (blockTableRecord.XrefStatus == XrefStatus.NotAnXref) { blockName = blockTableRecord.Name; foreach (ObjectId id in blockTableRecord) { using (Polyline poly = tr.GetObject(id, OpenMode.ForRead) as Polyline) { if (poly != null && (poly.Closed || poly.GetPoint2dAt(0).Equals(poly.GetPoint2dAt(poly.NumberOfVertices - 1))) &&//Полилиния замкнута !Utils.PolylineIsSelfIntersecting(poly) &&//Не имеет самопересечений poly.Visible == true &&//Учет многовидовых блоков poly.Bounds != null ) { polylines.Add(id); } } AcadDb.Entity ent = tr.GetObject(id, OpenMode.ForRead) as AcadDb.Entity; if (ent is Polyline) { Polyline poly = ent as Polyline; } } if (polylines.Count > 0) { //Проверить все линии на пересечение друг с другом. Удалить из списка те, которые имеют пересечения HashSet <ObjectId> polylinesWithNoIntersections = new HashSet <ObjectId>(polylines); //Сделать RBush для всех полилиний RBush <SpatialEntity> polylinesTree = new RBush <SpatialEntity>(); List <SpatialEntity> spatialEntities = new List <SpatialEntity>(); foreach (ObjectId polyId in polylines) { spatialEntities.Add(new SpatialEntity(polyId)); } polylinesTree.BulkLoad(spatialEntities); foreach (SpatialEntity se in spatialEntities) { //Нахождение всех объектов, расположенных в пределах BoundingBox для этой полилинии IReadOnlyList <SpatialEntity> nearestNeighbors = polylinesTree.Search(se.Envelope); if (nearestNeighbors.Count > 1) { Polyline thisPoly = tr.GetObject(se.ObjectId, OpenMode.ForRead) as Polyline; foreach (SpatialEntity n in nearestNeighbors) { if (!n.Equals(se))//Всегда будет находиться та же самая полилиния { Polyline otherPoly = tr.GetObject(n.ObjectId, OpenMode.ForRead) as Polyline; Point3dCollection pts = new Point3dCollection(); thisPoly.IntersectWith(otherPoly, Intersect.OnBothOperands, pts, IntPtr.Zero, IntPtr.Zero); if (pts.Count > 0) { polylinesWithNoIntersections.Remove(thisPoly.Id); polylinesWithNoIntersections.Remove(otherPoly.Id); break; } } } } } //Аппроксимация всех полилиний, которые имеют кривизну List <Polyline> polylinesToProcess = new List <Polyline>(); foreach (ObjectId polyId in polylinesWithNoIntersections) { using (Polyline poly = tr.GetObject(polyId, OpenMode.ForRead) as Polyline) { polylinesToProcess.Add(ApproximatePolyBulges(poly, approxParam));//Какой допуск оптимален? } } //Удалить все повторяющиеся подряд точки полилинии foreach (Polyline poly in polylinesToProcess) { for (int i = 0; i < poly.NumberOfVertices;) { Point2d curr = poly.GetPoint2dAt(i); int nextIndex = (i + 1) % poly.NumberOfVertices; Point2d next = poly.GetPoint2dAt(nextIndex); if (next.IsEqualTo(curr, new Tolerance(0.001, 0.001)))//Прореживать точки, расположенные слишком близко//TODO: Учесть масштабирование блока { poly.RemoveVertexAt(nextIndex); } else { i++; } } } //Построение дерева вложенности полилиний using (TinSurface tinSurf = tr.GetObject(tinSurfId, OpenMode.ForRead) as TinSurface) { using (PolylineNesting polylineNesting = new PolylineNesting(tinSurf)) { foreach (Polyline poly in polylinesToProcess) { poly.TransformBy(transform); polylineNesting.Insert(poly); } //Расчет полигонов polylineNesting.CalculatePoligons(); //Построение сети using (SubDMesh sdm = polylineNesting.CreateSubDMesh()) { List <Line> lines = new List <Line>(); if (createBorders) { //Создание 3d линий по границе lines = polylineNesting.CreateBorderLines(); } //Объекты постоены в координатах пространства модели if (sdm != null) { BlockTableRecord btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForWrite); if (btr.GetBlockReferenceIds(true, false).Count > 1) { //Если у блока несколько вхождений, то создавать объекты в пространстве модели BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable; BlockTableRecord ms = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite); ms.AppendEntity(sdm); tr.AddNewlyCreatedDBObject(sdm, true); foreach (Line line in lines) { ms.AppendEntity(line); tr.AddNewlyCreatedDBObject(line, true); } } else { //Если у блока только одно вхождение, то создавать сеть внутри блока sdm.TransformBy(transform.Inverse()); btr.AppendEntity(sdm); tr.AddNewlyCreatedDBObject(sdm, true); foreach (Line line in lines) { line.TransformBy(transform.Inverse()); btr.AppendEntity(line); tr.AddNewlyCreatedDBObject(line, true); } } } foreach (Line line in lines) { line.Dispose(); } } } } } } tr.Commit(); } } } } catch (System.Exception ex) { string message = "Возникла ошибка при обработке одного из выбранных объектов"; if (!String.IsNullOrEmpty(blockName)) { message = "Возникла ошибка при обработке вхождения блока " + blockName; } Utils.ErrorToCommandLine(ed, message, ex); } timer.TimeOutput(blockName); } ed.WriteMessage("\n" + timerMain.TimeOutput("Затрачено времени (параметр аппроксимации - " + approxParam + ")") ); ed.Regen(); } } catch (System.Exception ex) { CommonException(ex, "Ошибка при создании сетей по участкам поверхности"); } finally { HighlightTinSurf(false); } }
private void Create3dProfile(object arg) { try { if (doc != null) { List <ObjectId> toHighlight = new List <ObjectId>(); using (doc.LockDocument()) { Editor ed = doc.Editor; Database db = doc.Database; using (Transaction tr = db.TransactionManager.StartTransaction()) { //найти координату X начала профиля (крайнюю левую) double minx = double.PositiveInfinity; List <ObjectId> allSelected = new List <ObjectId>(soilHatchIds); foreach (ObjectId id in allSelected) { Entity ent = null; try { ent = (Entity)tr.GetObject(id, OpenMode.ForRead); } catch (Autodesk.AutoCAD.Runtime.Exception) { continue; } Extents3d?ext = ent.Bounds; if (ext != null) { Point3d minPt = ext.Value.MinPoint; if (minx > minPt.X) { minx = minPt.X; } } } //Штриховки должны быть заранее раскиданы по слоям в соответствии с ИГЭ! //пересчет всех точек штриховок в координаты: //X - положение отностиельно начала профиля с учетом горизонтального масштаба профиля, //Y - отметка расчитанная согласно базовой отметке с учетом вертикального масштаба профиля Matrix2d transform = new Matrix2d(new double[] { HorScaling, 0, 0, 0, VertScaling, 0, 0, 0, 1 }) * Matrix2d.Displacement(new Vector2d(-minx, -ElevBasePoint.Value.Y + ElevationInput / VertScaling)); C5.IntervalHeap <HatchEvent> eventQueue = new C5.IntervalHeap <HatchEvent>(); List <HatchData> allHatchData = new List <HatchData>(); List <Point2dCollection> selfintersectingLoops = new List <Point2dCollection>(); foreach (ObjectId id in soilHatchIds) { //получить все точки штриховок с учетом возможных дуг, сплайнов и проч //Для каждой штриховки создается набор композитных кривых, состоящих из линейных сегментов Hatch hatch = null; try { hatch = (Hatch)tr.GetObject(id, OpenMode.ForRead); } catch (Autodesk.AutoCAD.Runtime.Exception) { continue; } List <CompositeCurve2d> boundaries = new List <CompositeCurve2d>(); List <Extents2d> extends = new List <Extents2d>(); List <Point2dCollection> ptsCollList = new List <Point2dCollection>(); List <List <double> > ptParamsList = new List <List <double> >(); for (int i = 0; i < hatch.NumberOfLoops; i++) { HatchLoop hl = hatch.GetLoopAt(i); if (!hl.LoopType.HasFlag(HatchLoopTypes.SelfIntersecting) && !hl.LoopType.HasFlag(HatchLoopTypes.Textbox) && !hl.LoopType.HasFlag(HatchLoopTypes.TextIsland) && !hl.LoopType.HasFlag(HatchLoopTypes.NotClosed)) { List <Curve2d> curves = Utils.GetHatchLoopCurves(hl); List <Curve2d> compositeCurveElems = new List <Curve2d>(); double _minx = double.PositiveInfinity; double _miny = double.PositiveInfinity; double _maxx = double.NegativeInfinity; double _maxy = double.NegativeInfinity; Action <Point2d> updateExtends = new Action <Point2d>(p => { _minx = p.X < _minx ? p.X : _minx; _miny = p.Y < _miny ? p.Y : _miny; _maxx = p.X > _maxx ? p.X : _maxx; _maxy = p.Y > _maxy ? p.Y : _maxy; }); Point2dCollection ptsColl = new Point2dCollection(); List <double> ptParams = new List <double>(); double currParam = 0; foreach (Curve2d c in curves) { if (!(c is LineSegment2d)) { Interval interval = c.GetInterval(); PointOnCurve2d[] samplePts = c.GetSamplePoints(interval.LowerBound, interval.UpperBound, 0.02); Point2d[] pts = samplePts.Select(p => transform * p.Point).ToArray(); for (int n = 0; n < pts.Length - 1; n++) { LineSegment2d lineSeg = new LineSegment2d(pts[n], pts[n + 1]); compositeCurveElems.Add(lineSeg); ptsColl.Add(pts[n]); ptParams.Add(currParam); updateExtends(pts[n]); currParam += lineSeg.Length; } } else { LineSegment2d lineSeg = (LineSegment2d)c; lineSeg.TransformBy(transform); compositeCurveElems.Add(lineSeg); ptsColl.Add(lineSeg.StartPoint); ptParams.Add(currParam); updateExtends(lineSeg.StartPoint); currParam += lineSeg.Length; } } CompositeCurve2d boundary = new CompositeCurve2d(compositeCurveElems.ToArray()); Extents2d ext = new Extents2d(_minx, _miny, _maxx, _maxy); boundaries.Add(boundary); ptsCollList.Add(ptsColl); ptParamsList.Add(ptParams); extends.Add(ext); } } //контуры штриховок не могут иметь самопересечений! #region Проверка на пересечения //проверка на самопересечения //bool badBoundaries = false; HashSet <int> badBoundaries = new HashSet <int>(); HashSet <int> splitBoundaries = new HashSet <int>();//Если 2 контура в одной штриховке пересекаются, то разносить их по разным штриховкам //List<HatchData> decomposeHatchData = new List<HatchData>();//TODO: самопересекающиеся полигоны нужно разбить на отдельные по количеству самопересечний. for (int i = 0; i < boundaries.Count; i++) { CompositeCurve2d b = boundaries[i]; CurveCurveIntersector2d intersector = new CurveCurveIntersector2d(b, b); if (intersector.NumberOfIntersectionPoints > 0) { //если происходит только наложение??? badBoundaries.Add(i); selfintersectingLoops.Add(ptsCollList[i]); } } if (boundaries.Count > 1) { //проверка на взаимные пересечения. //Исп RBush для того чтобы избежать проверки на пересечение каждого с каждым и квадратичной сложности //(работает только если контуры разнесены) //Не брать в расчет пересечения по касательной RBush <Spatial> boundariesRBush = new RBush <Spatial>(); List <Spatial> spatialData = new List <Spatial>(); for (int i = 0; i < extends.Count; i++) { spatialData.Add(new Spatial(extends[i], i)); } boundariesRBush.BulkLoad(spatialData); foreach (Spatial s in spatialData) { IReadOnlyList <Spatial> nearestNeighbors = boundariesRBush.Search(s.Envelope); if (nearestNeighbors.Count > 1) { CompositeCurve2d thisCurve = boundaries[(int)s.Obj]; foreach (Spatial n in nearestNeighbors) { if (!s.Equals(n)) { CompositeCurve2d otherCurve = boundaries[(int)n.Obj]; CurveCurveIntersector2d intersector = new CurveCurveIntersector2d(thisCurve, otherCurve); if (intersector.NumberOfIntersectionPoints > 0 || intersector.OverlapCount > 0) { bool matches = false; //Проверить, что кривые не накладываются друг на друга по всей длине (то есть полностью совпадают) if (intersector.OverlapCount > 0) { //сумма длин всех интервалов перекрытия равна общей длине кривой double thisCurveOverlapLength = 0; double otherCurveOverlapLength = 0; for (int i = 0; i < intersector.OverlapCount; i++) { Interval[] intervals = intersector.GetOverlapRanges(i); Interval thisOverlapInterval = intervals[0]; thisCurveOverlapLength += thisOverlapInterval.Length; Interval otherOverlapInterval = intervals[1]; otherCurveOverlapLength += otherOverlapInterval.Length; } Interval thisCurveInterval = thisCurve.GetInterval(); Interval otherCurveInterval = otherCurve.GetInterval(); if (Utils.LengthIsEquals(thisCurveOverlapLength, thisCurveInterval.Length) && Utils.LengthIsEquals(otherCurveOverlapLength, otherCurveInterval.Length)) { matches = true; } } if (!matches) { splitBoundaries.Add((int)s.Obj); splitBoundaries.Add((int)n.Obj); } else { badBoundaries.Add((int)s.Obj); badBoundaries.Add((int)n.Obj); } } } } } } } splitBoundaries.ExceptWith(badBoundaries); List <HatchData> splitHatchData = new List <HatchData>(); if (badBoundaries.Count > 0 || splitBoundaries.Count > 0) { List <CompositeCurve2d> boundariesClear = new List <CompositeCurve2d>(); List <Extents2d> extendsClear = new List <Extents2d>(); List <Point2dCollection> ptsCollListClear = new List <Point2dCollection>(); List <List <double> > ptParamsListClear = new List <List <double> >(); for (int i = 0; i < boundaries.Count; i++) { if (!badBoundaries.Contains(i) && !splitBoundaries.Contains(i)) { boundariesClear.Add(boundaries[i]); extendsClear.Add(extends[i]); ptsCollListClear.Add(ptsCollList[i]); ptParamsListClear.Add(ptParamsList[i]); } } foreach (int index in splitBoundaries) { splitHatchData.Add(new HatchData( new HatchNestingNode( boundaries[index], extends[index], ptsCollList[index], ptParamsList[index], hatch))); } boundaries = boundariesClear; extends = extendsClear; ptsCollList = ptsCollListClear; ptParamsList = ptParamsListClear; } #endregion //определяется вложенность контуров штриховки //ЕСЛИ ШТРИХОВКА СОСТОИТ ИЗ 2 И БОЛЕЕ КОНТУРОВ, КОТОРЫЕ НЕ ВЛОЖЕНЫ ДРУГ В ДРУГА, //ТО ЭТИ КОНТУРЫ ДОЛЖНЫ РАССМАТРИВАТЬСЯ КАК ОТДЕЛЬНЫЕ ШТРИХОВКИ!!! HatchNestingTree hatchNestingTree = new HatchNestingTree(boundaries, extends, ptsCollList, ptParamsList, hatch); List <HatchData> currHatchData = hatchNestingTree.GetHatchData(); currHatchData.AddRange(splitHatchData);//добавить контуры, полученные из взаимно пересекающихся контуров //currHatchData.AddRange(decomposeHatchData); allHatchData.AddRange(currHatchData); //Каждая штриховка имеет диапазон по X от начала до конца по оси. //В общую очередь событий сохраняются события начала и конца штриховки foreach (HatchData hd in currHatchData) { hd.AddEventsToQueue(eventQueue); } } //Трассу разбить на отрезки, на которых будут вставлены прямолинейные сегменты штриховок Polyline alignmentPoly = null; try { alignmentPoly = (Polyline)tr.GetObject(AlignmentPolyId, OpenMode.ForRead); } catch (Autodesk.AutoCAD.Runtime.Exception) { return; } int segments = alignmentPoly.NumberOfVertices - 1; List <AlignmentSegment> alignmentSegments = new List <AlignmentSegment>(); Action <Point2d, Point2d> addAlignmentSegment = new Action <Point2d, Point2d>((p0, p1) => { double start = alignmentPoly.GetDistAtPoint(new Point3d(p0.X, p0.Y, 0)); double end = alignmentPoly.GetDistAtPoint(new Point3d(p1.X, p1.Y, 0)); if (Math.Abs(start - end) > Tolerance.Global.EqualPoint)//TODO: Это спорный момент - ведь может быть большое множество очень коротких участков подряд! { Vector2d startDir = p1 - p0; alignmentSegments.Add(new AlignmentSegment(start, end, p0, startDir)); } }); for (int i = 0; i < segments; i++) { SegmentType segmentType = alignmentPoly.GetSegmentType(i); Point2d startLoc = alignmentPoly.GetPoint2dAt(i); Point2d endLoc = alignmentPoly.GetPoint2dAt(i + 1); switch (segmentType) { case SegmentType.Line: addAlignmentSegment(startLoc, endLoc); break; case SegmentType.Arc: CircularArc2d arc = new CircularArc2d(startLoc, endLoc, alignmentPoly.GetBulgeAt(i), false); Interval interval = arc.GetInterval(); PointOnCurve2d[] samplePts = arc.GetSamplePoints(interval.LowerBound, interval.UpperBound, 0.1); for (int n = 0; n < samplePts.Length - 1; n++) { addAlignmentSegment(samplePts[n].Point, samplePts[n + 1].Point); } break; } } //проход по каждому отрезку трассы (диапазон отрезка - диапазон длины полилинии) HashSet <HatchData> currentHatchData = new HashSet <HatchData>(); foreach (AlignmentSegment alignmentSegment in alignmentSegments) { if (eventQueue.Count == 0) { break; //штриховки закончились } //Получить те штриховки, диапазон по X которых пересекается с диапазоном текущего отрезка //(СКАНИРУЮЩАЯ ЛИНИЯ: события - начало, конец штриховки) HashSet <HatchData> intervalHatchData = new HashSet <HatchData>(currentHatchData);//штриховки пришедшие из предыдущего участка остаются все //Собрать все события до конца сегмента //Если при проходе от начала до конца сегмента какая-то штриховка проходится полностью от начала до конца, то //все ее контуры без изменений должны быть переданы для создания М-полигона!!! (для них обход графа не нужен!) HashSet <HatchData> startedInsideInterval = new HashSet <HatchData>(); List <HatchData> hatchesCompletelyInsideInterval = new List <HatchData>(); while (eventQueue.Count > 0) { HatchEvent nextEvent = eventQueue.FindMin(); if (nextEvent.Position > alignmentSegment.End) { break; } else if (nextEvent.Start) { //добавить штриховку в текущий набор HatchData hd = eventQueue.DeleteMin().HatchData; currentHatchData.Add(hd); //добавлять в набор текущего интервла только в том случае, //если сканирующая линия еще не дошла до конца интервала if (nextEvent.Position < alignmentSegment.End && !Utils.LengthIsEquals(nextEvent.Position, alignmentSegment.End)) //Допуск нужен { startedInsideInterval.Add(hd); intervalHatchData.Add(hd); } } else { //убрать штриховку из текущего набора HatchData hd = eventQueue.DeleteMin().HatchData; currentHatchData.Remove(hd); if (startedInsideInterval.Contains(hd)) { hatchesCompletelyInsideInterval.Add(hd); } } } foreach (HatchData hd in hatchesCompletelyInsideInterval) { HatchSegmentData hsd = new HatchSegmentData(hd); alignmentSegment.HatchSegmentData.Add(hsd); hsd.Polygons = hd.GetAllBoundaries(); } intervalHatchData.ExceptWith(hatchesCompletelyInsideInterval); foreach (HatchData hd in intervalHatchData) { HatchSegmentData hsd = new HatchSegmentData(hd); alignmentSegment.HatchSegmentData.Add(hsd); //для каждой штриховки выполнить построение и обход графа сегмента штриховки HatchSegmentGraph graph = new HatchSegmentGraph(alignmentSegment.Start, alignmentSegment.End, hd, doc.Editor); //сохранить наборы полигонов для текущего диапазона hsd.Polygons = graph.Result; } } //для каждого диапазона создать полученные полигоны в 3d BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable; BlockTableRecord ms = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite); BlockTableRecord btr = new BlockTableRecord();//Каждый профиль в отдельный блок btr.Name = Guid.NewGuid().ToString(); ObjectId btrId = bt.Add(btr); tr.AddNewlyCreatedDBObject(btr, true); foreach (AlignmentSegment alignmentSegment in alignmentSegments) { List <Entity> flatObjs = new List <Entity>(); foreach (HatchSegmentData hsd in alignmentSegment.HatchSegmentData) { //PlaneSurface hsd.GetNesting(); Dictionary <Point2dCollection, List <Point2dCollection> > bwhs = hsd.GetBoundariesWithHoles(); foreach (KeyValuePair <Point2dCollection, List <Point2dCollection> > bwh in bwhs) { //создать Region Region region = null; using (Polyline poly = new Polyline()) { for (int i = 0; i < bwh.Key.Count; i++) { poly.AddVertexAt(i, bwh.Key[i], 0, 0, 0); } poly.Closed = true; DBObjectCollection coll = new DBObjectCollection(); coll.Add(poly); try { DBObjectCollection regionColl = Region.CreateFromCurves(coll); foreach (DBObject dbo in regionColl) { region = (Region)dbo; break; } } catch { } } //из Region создать PlaneSurface if (region != null) { using (PlaneSurface planeSurface = new PlaneSurface()) { planeSurface.CreateFromRegion(region); planeSurface.LayerId = hsd.Hatch.LayerId; planeSurface.ColorIndex = 256; ObjectId planeSurfaceId = ms.AppendEntity(planeSurface); tr.AddNewlyCreatedDBObject(planeSurface, true); //вырезать отверстия в PlaneSurface foreach (Point2dCollection holePts2d in bwh.Value) { if (holePts2d.Count < 3) { continue; } using (Polyline poly = new Polyline()) { for (int i = 0; i < holePts2d.Count; i++) { poly.AddVertexAt(i, holePts2d[i], 0, 0, 0); } poly.Closed = true; ObjectIdCollection trimPolyColl = new ObjectIdCollection(); trimPolyColl.Add(ms.AppendEntity(poly)); tr.AddNewlyCreatedDBObject(poly, true); List <Point2d> ptsList = new List <Point2d>(holePts2d.ToArray()); Point2d pickPt2d = Utils.GetAnyPointInsidePoligon(ptsList, Utils.DirectionIsClockwise(ptsList)); try { AcadDB.Surface.TrimSurface(planeSurfaceId, new ObjectIdCollection(), trimPolyColl, new Vector3dCollection() { Vector3d.ZAxis }, new Point3d(pickPt2d.X, pickPt2d.Y, 0), -Vector3d.ZAxis, false, false); } catch /*(Exception ex)*/ { //Вывод в командную строку Utils.ErrorToCommandLine(doc.Editor, "Ошибка при попытке вырезания отверстия в поверхности" /*, ex*/); } //Удалить все объекты, добавленные в чертеж! poly.Erase(); } } flatObjs.Add((Entity)planeSurface.Clone()); //Удалить все объекты, добавленные в чертеж! planeSurface.Erase(); } region.Dispose(); } } } foreach (Entity ent in flatObjs) { ent.TransformBy(alignmentSegment.Transform); /*ms*/ btr.AppendEntity(ent); tr.AddNewlyCreatedDBObject(ent, true); ent.Dispose(); } } BlockReference br = new BlockReference(Point3d.Origin, btrId); ms.AppendEntity(br); tr.AddNewlyCreatedDBObject(br, true); if (selfintersectingLoops.Count > 0) { Utils.ErrorToCommandLine(doc.Editor, "Отбраковано самопересекающихся контуров штриховок - " + selfintersectingLoops.Count + " (отмечены на профиле)"); ObjectId layerId = Utils.CreateLayerIfNotExists("САМОПЕРЕСЕКАЮЩИЙСЯ КОНТУР ШТРИХОВКИ", db, tr, color: Color.FromColorIndex(ColorMethod.ByAci, 1), lineWeight: LineWeight.LineWeight200); Matrix2d returnTransform = transform.Inverse(); foreach (Point2dCollection pts in selfintersectingLoops) { using (Polyline selfIntersectingPoly = new Polyline()) { selfIntersectingPoly.LayerId = layerId; selfIntersectingPoly.ColorIndex = 256; for (int i = 0; i < pts.Count; i++) { Point2d pt = pts[i].TransformBy(returnTransform); selfIntersectingPoly.AddVertexAt(i, pt, 0, 0, 0); } toHighlight.Add(ms.AppendEntity(selfIntersectingPoly)); tr.AddNewlyCreatedDBObject(selfIntersectingPoly, true); //selfIntersectingPoly.Highlight(); } } } tr.Commit(); } } ps.Visible = false; if (toHighlight.Count > 0) { using (Transaction tr = doc.Database.TransactionManager.StartTransaction()) { foreach (ObjectId id in toHighlight) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForRead); ent.Highlight(); } tr.Commit(); } } } } catch (System.Exception ex) { GeologyConvertationCommand.ClosePalette(null, null); CommonException(ex, "Ошибка при создании 3d профиля геологии"); } }