Esempio n. 1
0
        /// <summary>
        /// Добавить точку полилинии, которая попала в этот треугольник
        /// </summary>
        /// <param name="pt"></param>
        public void AddPolylinePoint(PolylinePt pt)
        {
            SortedSet <PolylinePt> polylinePts = null;

            pts.TryGetValue(pt.Node, out polylinePts);
            if (polylinePts == null)
            {
                polylinePts = new SortedSet <PolylinePt>();
                pts.Add(pt.Node, polylinePts);
            }
            polylinePts.Add(pt);
        }
Esempio n. 2
0
        /// <summary>
        /// Расчитать полигоны для построения сети
        /// </summary>
        public void CalculatePoligons()
        {
            //Определить внутренние вершины в этом треугольнике
            foreach (LinkedListNode <GraphNode> lln in vertexNodes)
            {
                VertexGraphNode vgn = (VertexGraphNode)lln.Value;
                vgn.IsInnerVertex = polylineNesting.InnerVerts.Contains(verts[vgn.VertNum]);
            }


            List <List <Point3d> > holes = new List <List <Point3d> >();

            //Добавление оставшихся узлов и ребер в граф
            foreach (PolylinePart pp in PolylineParts)
            {
                PolylinePt check = pp.PolylinePts.First();
                if (check.TinSurfaceEdge != null || check.TinSurfaceVertex != null) //Эта полилиния пересекает треугольник?
                {
                    PolylinePt[] nodePts = new PolylinePt[]                         //Точки присоединения полилинии к границам треугольника
                    {
                        pp.PolylinePts.First(),
                                 pp.PolylinePts.Last()
                    };
                    for (short i = 0; i < 2; i++)
                    {
                        PolylinePt pt        = nodePts[i];
                        GraphNode  graphNode = null;
                        if (pt.TinSurfaceVertex != null)
                        {
                            //Определить номер этой вершины в этом треугольнике и получить ссылку на узел графа
                            short vertNum = GetVertNum(pt.TinSurfaceVertex);
                            if (vertNum == -1)
                            {
                                throw new Exception();
                            }
                            graphNode = vertexNodes[vertNum].Value;
                        }
                        else
                        {
                            //Определить номер этого ребра, добавить узел этого ребра
                            short edgeNum = GetEdgeNum(pt.TinSurfaceEdge);
                            if (edgeNum == -1)
                            {
                                throw new Exception();
                            }
                            graphNode = new EdgeGraphNode(this, edgeNum, pt.Point2D);
                        }

                        //дополнить свойства graphNode указателями на участок полилинии
                        graphNode.PolylinePart = pp;
                        graphNode.PolylinePartConnectedByStart = i == 0;
                        if (i == 0)
                        {
                            pp.StartNode = graphNode;
                        }
                        else
                        {
                            pp.EndNode = graphNode;
                        }
                    }
                    //Соединения для созданных узлов
                    pp.StartNode.ConnectedLinkedListNode = pp.EndNode.LinkedListNode;
                    pp.EndNode.ConnectedLinkedListNode   = pp.StartNode.LinkedListNode;
                }
                else
                {
                    //Эта полилиния полностью находится внутри треугоьника
                    //Если эта полилиния - внешняя граница, то добавить полигон по всем точкам полилинии
                    if (pp.PolylineNestingNode.IsOuterBoundary)
                    {
                        List <Point3d> poligon = new List <Point3d>();
                        Polygons.Add(poligon);
                        foreach (PolylinePt pt in pp.PolylinePts)
                        {
                            poligon.Add(new Point3d(pt.Point2D.X, pt.Point2D.Y, pt.Z));
                        }
                    }
                    else
                    {
                        //Если эта полилиния ограничивает островок, то отложить этот полигон для дальнейшей обработки
                        List <Point3d> hole = new List <Point3d>();
                        holes.Add(hole);
                        foreach (PolylinePt pt in pp.PolylinePts)
                        {
                            hole.Add(new Point3d(pt.Point2D.X, pt.Point2D.Y, pt.Z));
                        }
                    }
                }
            }



            //Составление маршрутов обхода графа
            //Правила
            //- Начинать обход с любого еще не обойденнго узла, из которого исходит участок полилинии. Запомнить ссылку на PolylineNesting.Node
            //- Если из текущего узла исходит участок полилинии, который еще не обойден, то обойти его
            //- Из текущего узла не исходит такого участка полилинии (например, мы только что обошли участок полилинии и пришли в узел на ребре) =>
            //  - Есть 2 варианта куда идти дальше: либо вперед до следующего узла, либо назад
            //  Проверяются оба варианта. При этом:
            //      - Обходить до тех пор пока не будет дотигнут стартовый узел
            //      - Нельзя заходить в те узлы которые уже посещены (только замыкание со стартовым узлом)
            //      - Нельзя заходить в узлы вершин, которые не являются внутренними
            //  Если в итоге получаются 2 варината обхода, взять точку изнутри каждого из обойденных полигонов и с помощью алгоритма WindingNumber проверить,
            //  попадают ли они внутрь PolylineNesting.Node. Если PolylineNesting.Node.IsOuterBoundary = true,
            //  то принять обход, точка которого попала внутрь PolylineNesting.Node, иначе принять обход, точка которого не попала внутрь PolylineNesting.Node


            //DisplayUtils.Polyline(vert2dLocs, true, 1, SurfaceMeshByBoundaryCommand.DB, null, SurfaceMeshByBoundaryCommand.ED);
            for (LinkedListNode <GraphNode> lln = graphNodes.First; lln != null; lln = lln.Next)
            {
                GraphNode startNode = lln.Value;
                if (!startNode.Visited && startNode.PolylinePart != null)
                {
                    startNode.Visited = true;
                    PolylinePart startPolyPart = startNode.PolylinePart;
                    GraphNode    nextNode      = startNode.ConnectedLinkedListNode.Value;
                    if (nextNode.Visited || startPolyPart.Visited)
                    {
                        //Такой ситуации не должно быть. Отметить проблемный треугольник
                        DisplayUtils.Polyline(vert2dLocs, true, 1, SurfaceMeshByBoundaryCommand.DB);
                        continue;
                    }

                    PolylineNesting.Node pNNode = startPolyPart.PolylineNestingNode;

                    //Начать составление маршрутов 2 вариантов замкнутого пути. Начинается всегда с прохода по участку полилинии
                    List <PathElement> path1 = new List <PathElement>()
                    {
                        startNode, startPolyPart, nextNode
                    };
                    List <PathElement> path2 = new List <PathElement>()
                    {
                        startNode, startPolyPart, nextNode
                    };

                    startPolyPart.Visited = true;//необходимо для правильной работы PathPreparing
                    bool path1Prepared = PathPreparing(nextNode, startNode, true, path1);
                    bool path2Prepared = PathPreparing(nextNode, startNode, false, path2);


                    List <Point3d> poligon1 = null;
                    List <Point3d> poligon2 = null;
                    if (path1Prepared)
                    {
                        //Заполнить полигон 1
                        poligon1 = GetPoligonFromPath(path1);
                        //DisplayUtils.Polyline(Utils.Poligon3DTo2D(poligon1), true, 1, SurfaceMeshByBoundaryCommand.DB);
                    }
                    if (path2Prepared)
                    {
                        //Заполнить полигон 2
                        poligon2 = GetPoligonFromPath(path2);
                        //DisplayUtils.Polyline(Utils.Poligon3DTo2D(poligon2), true, 1, SurfaceMeshByBoundaryCommand.DB);
                    }

                    List <PathElement> actualPath    = null;
                    List <Point3d>     actualPoligon = null;
                    if (path1Prepared && path2Prepared)//Если составлено 2 возможных путя
                    {
                        //Для 1-го варианта обхода найти внутреннюю точку (не на границе)
                        IList <Point2d> poligon1_2d = Utils.Poligon3DTo2D(poligon1);
                        //IList<Point2d> poligon2_2d = Utils.Poligon3DTo2D(poligon2);
                        Point2d?p1 = null;
                        try
                        {
                            p1 = Utils.GetAnyPointInsidePoligon(poligon1_2d, Utils.DirectionIsClockwise(poligon1_2d));
                        }
                        catch (Exception)
                        {
                            //Такой ситуации не должно быть. Отметить проблемный треугольник
                            DisplayUtils.Polyline(vert2dLocs, true, 1, SurfaceMeshByBoundaryCommand.DB);
                            continue;
                        }
                        //Point2d p2 = Utils.GetAnyPointInsidePoligon(poligon2_2d, Utils.DirectionIsClockwise(poligon2_2d));

                        if (p1 != null)
                        {
                            //Определить находится ли эта точка внутри полилинии
                            bool p1InsidePolyline = Utils.PointIsInsidePolylineWindingNumber(p1.Value, pNNode.Point2DCollection);

                            //Проверить, подходит ли 1-й вариант с учетом свойства IsOuterBoundary
                            if ((pNNode.IsOuterBoundary && p1InsidePolyline) || (!pNNode.IsOuterBoundary && !p1InsidePolyline))
                            {
                                //Первый вариант правильный
                                actualPoligon = poligon1;
                                actualPath    = path1;
                            }
                            else
                            {
                                //Второй вариант правильный
                                actualPoligon = poligon2;
                                actualPath    = path2;
                            }
                        }
                    }
                    else if (path1Prepared)
                    {
                        actualPoligon = poligon1;
                        actualPath    = path1;
                    }
                    else if (path2Prepared)
                    {
                        actualPoligon = poligon2;
                        actualPath    = path2;
                    }

                    if (actualPoligon != null)
                    {
                        //Для принятого пути обхода:
                        // - Добавить полигон в набор
                        // - Присвоить свойству Visited значение true
                        Polygons.Add(actualPoligon);
                        foreach (PathElement pe in actualPath)
                        {
                            pe.Visited = true;
                        }
                    }
                }
            }



            //~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~
            //ОБРАБОТКА ОТВЕРСТИЙ ВНУТРИ ПОЛИГОНОВ
            if (holes.Count > 0)
            {
                //Каждое отверстие находится внутри одного из рассчитанных полигонов. Определить полигон, в который вложено отверстие
                //Эти полигоны будут дополнены участками, включающими в себя отверстия
                //в соответствии с https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf п 3 - 5
                List <PolygonWithNested> poligonsWithHoles = PolygonWithHoles.ResolveHoles(Polygons, holes);


                foreach (PolygonWithNested p in poligonsWithHoles)
                {
                    if (p.Polygon == null)
                    {
                        //Если отверстия есть в корневом узле, значит нужно рассматривать полигон равный текущему треугольнику с отверстиями
                        p.Polygon = new List <Point3d>()
                        {
                            tinSurfaceTriangle.Vertex1.Location,
                            tinSurfaceTriangle.Vertex2.Location,
                            tinSurfaceTriangle.Vertex3.Location
                        };
                    }
                    else
                    {
                        //Если оказывается, что полигон включает в себя отверстие, то он должен быть удален из Polygons
                        //Такие полигоны будут разбиваться на треугольники
                        Polygons.Remove(p.Polygon);
                    }


                    p.MakeSimple();
                    //Polygons.Add(p.Polygon);
                    //Нельзя просто добавить простой полигон к общему списку полигонов (SubDMesh создается неправильно).
                    //Необходимо сделать триангуляцию
                    //TEST
                    #region Отрисовка простого полигона
                    //using (Transaction tr
                    //    = SurfaceMeshByBoundaryCommand.DB.TransactionManager.StartTransaction())
                    //using (Polyline pline = new Polyline())
                    //{
                    //    BlockTable bt = tr.GetObject(SurfaceMeshByBoundaryCommand.DB.BlockTableId, OpenMode.ForWrite) as BlockTable;
                    //    BlockTableRecord ms = (BlockTableRecord)tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

                    //    pline.Color = Color.FromColorIndex(ColorMethod.ByAci, 5);
                    //    foreach (Point3d pt in p.Polygon)
                    //    {
                    //        pline.AddVertexAt(0, new Point2d(pt.X, pt.Y), 0, 0, 0);
                    //    }
                    //    pline.Closed = true;

                    //    ms.AppendEntity(pline);
                    //    tr.AddNewlyCreatedDBObject(pline, true);

                    //    tr.Commit();
                    //}
                    #endregion
                    //TEST


                    EarClippingTriangulator triangulator = new EarClippingTriangulator(p.Polygon);
                    foreach (List <Point3d> tr in triangulator.Triangles)
                    {
                        Polygons.Add(tr);
                    }
                }
            }



            //~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~//~
        }
Esempio n. 3
0
        /// <summary>
        /// Определить участки полилиний, попавшие в треугольник
        /// </summary>
        public void ResolvePolylineParts()
        {
            foreach (KeyValuePair <PolylineNesting.Node, SortedSet <PolylinePt> > kvp in pts)
            {
                //TEST
                #region MyRegion
                //using (Transaction tr = PolylineNesting.db.TransactionManager.StartTransaction())
                //using (Polyline pline = new Polyline())
                //{
                //    PolylineNesting.ms = tr.GetObject(PolylineNesting.ms.Id, OpenMode.ForWrite) as BlockTableRecord;

                //    Point3d vert13d = TinSurfaceTriangle.Vertex1.Location;
                //    Point3d vert23d = TinSurfaceTriangle.Vertex2.Location;
                //    Point3d vert33d = TinSurfaceTriangle.Vertex3.Location;

                //    pline.Color = Color.FromColorIndex(ColorMethod.ByAci, 5);
                //    pline.AddVertexAt(0, new Point2d(vert13d.X, vert13d.Y), 0, 0, 0);
                //    pline.AddVertexAt(1, new Point2d(vert23d.X, vert23d.Y), 0, 0, 0);
                //    pline.AddVertexAt(2, new Point2d(vert33d.X, vert33d.Y), 0, 0, 0);
                //    pline.Closed = true;

                //    PolylineNesting.ms.AppendEntity(pline);
                //    tr.AddNewlyCreatedDBObject(pline, true);

                //    tr.Commit();
                //    pline.Draw();
                //    PolylineNesting.ed.Regen();
                //    PolylineNesting.ed.UpdateScreen();
                //}
                #endregion
                //TEST
                //Участок полилинии состоит из точек, параметры которых не перескакивают через целые значения
                //При этом если участок содержит параметр 0,
                //то необходимо состыковать его с замыкающими точками (1 или более)
                //Замыкающие точки - участок без перехода через целые значения с наибольшими параметрами
                //После стыковки участка с параметром 0, удалить все участки, содержащие менее 2 точек
                //Участок полилинии должен начинаться и заканчиваться точкой лежащей на ребре или совпавшей с вершиной,
                //кроме тех случаев, когда вся полилиния находится внутри одного треугольника
                //Не нужны участки, у которых все сегменты лежат на ребрах треугольника

                PolylineNesting.Node   node             = kvp.Key;
                PolylinePt             ptWithStartParam = null;
                SortedSet <PolylinePt> polylinePts      = kvp.Value;
                //Последовательности без перехода через  целые значения
                List <LinkedList <PolylinePt> > sequences = new List <LinkedList <PolylinePt> >();
                double?prevParamFloor = null;
                foreach (PolylinePt pt in polylinePts)
                {
                    double parameter = pt.Parameter;
                    if (parameter == node.Polyline.StartParam) //стартовый параметр - всегда 0?
                    {
                        ptWithStartParam = pt;
                    }

                    if (prevParamFloor != null && sequences.Count > 0 && parameter - prevParamFloor <= 1)
                    {
                        //Продолжить последовательность
                        sequences.Last().AddLast(pt);
                    }
                    else
                    {
                        //Начать новую последовательность
                        LinkedList <PolylinePt> seq = new LinkedList <PolylinePt>();
                        seq.AddLast(pt);
                        sequences.Add(seq);
                    }

                    prevParamFloor = Math.Floor(parameter);
                }

                //Если обнаружен стартовый параметр, то объединить первую и последнюю последовательности
                if (ptWithStartParam != null && sequences.Count > 1)
                {
                    LinkedList <PolylinePt> seq1 = sequences.First();
                    LinkedList <PolylinePt> seq2 = sequences.Last();


                    if (
                        //seq1.First().TinSurfaceEdge==null
                        seq2.Last().Parameter >= node.Polyline.EndParam - 1//Нужно проверить параметр последней точки последей последовательности (что он находится в пределах 1.00 от конечного параметра полилинии)
                        )
                    {
                        for (LinkedListNode <PolylinePt> lln = seq2.Last; lln != null; lln = lln.Previous)
                        {
                            seq1.AddFirst(lln.Value);
                        }
                        sequences.RemoveAt(sequences.Count - 1);
                    }
                }

                //Проверить все участки полилинии и удалить неправильные
                //Tolerance tolerance = Tolerance.Global;
                Point2d  vert1       = new Point2d(tinSurfaceTriangle.Vertex1.Location.X, tinSurfaceTriangle.Vertex1.Location.Y);
                Point2d  vert2       = new Point2d(tinSurfaceTriangle.Vertex2.Location.X, tinSurfaceTriangle.Vertex2.Location.Y);
                Point2d  vert3       = new Point2d(tinSurfaceTriangle.Vertex3.Location.X, tinSurfaceTriangle.Vertex3.Location.Y);
                Vector2d edge1Vector = vert2 - vert1;
                Vector2d edge2Vector = vert3 - vert2;
                Vector2d edge3Vector = vert1 - vert3;


                sequences.RemoveAll(seq =>
                {
                    bool removeThis = seq.Count < 2;//Количество точек не менее двух

                    if (!removeThis)
                    {
                        //Не может быть с одной стороны ребро или вершина а с другой нет
                        bool firstPtOnEdge = seq.First().TinSurfaceEdge != null || seq.First().TinSurfaceVertex != null;
                        bool lastPtOnEdge  = seq.Last().TinSurfaceEdge != null || seq.Last().TinSurfaceVertex != null;
                        removeThis         = firstPtOnEdge != lastPtOnEdge;//Несоответствие привязки участка к ребрам
                        if (!removeThis)
                        {
                            removeThis = true;
                            //Проверить все ребра на совпадение с ребрами треугольника
                            for (LinkedListNode <PolylinePt> lln = seq.First; lln.Next != null; lln = lln.Next)
                            {
                                Point2d segPt1 = lln.Value.Point2D;
                                Point2d segPt2 = lln.Next.Value.Point2D;
                                if (!(Utils.LinesAreOverlapping(segPt1, segPt2, vert1, vert2) ||
                                      Utils.LinesAreOverlapping(segPt1, segPt2, vert2, vert3) ||
                                      Utils.LinesAreOverlapping(segPt1, segPt2, vert3, vert1)))
                                {
                                    //Если сегмент не накладывается ни на одно ребро треугольника, то закончить проверку
                                    removeThis = false;
                                    break;
                                }
                            }
                        }
                    }


                    return(removeThis);
                });

                foreach (LinkedList <PolylinePt> seq in sequences)
                {
                    PolylineParts.Add(new PolylinePart(seq));
                }
            }
        }