// this method adds constraints singly and does not assume that they form a contour
        // If you are trying to add a "series" or edges (or "contour"), use AddHole instead.
        public bool AddConstraints(List <TriangulationConstraint> constraints)
        {
            if (constraints == null || constraints.Count < 1)
            {
                return(false);
            }

            bool bOK = true;

            foreach (TriangulationConstraint tc in constraints)
            {
                if (ConstrainPointToBounds(tc.P) || ConstrainPointToBounds(tc.Q))
                {
                    tc.CalculateContraintCode();
                }

                TriangulationConstraint tcTmp = null;
                if (!mConstraintMap.TryGetValue(tc.ConstraintCode, out tcTmp))
                {
                    tcTmp = tc;
                    bOK   = AddConstraint(tcTmp) && bOK;
                }
            }

            return(bOK);
        }
예제 #2
0
파일: DTSweep.cs 프로젝트: miyu/Poly2Tri
 private static void FillEdgeEvent(DTSweepContext tcx, TriangulationConstraint edge, AdvancingFrontNode node)
 {
     if (tcx.EdgeEvent.Right)
     {
         FillRightAboveEdgeEvent(tcx, edge, node);
     }
     else
     {
         FillLeftAboveEdgeEvent(tcx, edge, node);
     }
 }
예제 #3
0
        public ConstrainedPointSet(IList <TriangulationPoint> bounds, ICollection <int> indices)
            : base(bounds)
        {
            AddBoundaryConstraints();
            List <TriangulationConstraint> l = new List <TriangulationConstraint>();

            for (int i = 0; i < indices.Count; i += 2)
            {
                TriangulationConstraint tc = new TriangulationConstraint(bounds[i], bounds[i + 1]);
                l.Add(tc);
            }
            AddConstraints(l);
        }
예제 #4
0
        public override void Prepare(TriangulationContext tcx)
        {
            if (!Initialize())
            {
                return;
            }

            base.Prepare(tcx);

            Dictionary <uint, TriangulationConstraint> .Enumerator it = _constraintMap.GetEnumerator();
            while (it.MoveNext())
            {
                TriangulationConstraint tc = it.Current.Value;
                tcx.NewConstraint(tc.P, tc.Q);
            }
        }
        public bool AddConstraint(TriangulationConstraint tc)
        {
            if (tc == null || tc.P == null || tc.Q == null)
            {
                return(false);
            }

            // If we already have this constraint, then there's nothing to do.  Since we already have
            // a valid constraint in the map with the same ConstraintCode, then we're guaranteed that
            // the points are also valid (and have the same coordinates as the ones being passed in with
            // this constrain).  Return true to indicate that we successfully "added" the constraint
            if (mConstraintMap.ContainsKey(tc.ConstraintCode))
            {
                return(true);
            }

            // Make sure the constraint is not using points that are duplicates of ones already stored
            // If it is, replace the Constraint Points with the points already stored.
            TriangulationPoint p;

            if (TryGetPoint(tc.P.X, tc.P.Y, out p))
            {
                tc.P = p;
            }
            else
            {
                Add(tc.P);
            }

            if (TryGetPoint(tc.Q.X, tc.Q.Y, out p))
            {
                tc.Q = p;
            }
            else
            {
                Add(tc.Q);
            }

            mConstraintMap.Add(tc.ConstraintCode, tc);

            return(true);
        }
예제 #6
0
파일: DTSweep.cs 프로젝트: miyu/Poly2Tri
 private static void FillLeftAboveEdgeEvent(DTSweepContext tcx, TriangulationConstraint edge, AdvancingFrontNode node)
 {
     while (node.Prev.Point.X > edge.P.X)
     {
         if (tcx.IsDebugEnabled)
         {
             tcx.DebugContext.ActiveNode = node;
         }
         // Check if next node is below the edge
         Orientation o1 = TriangulationUtil.Orient2d(edge.Q, node.Prev.Point, edge.P);
         if (o1 == Orientation.Clockwise)
         {
             FillLeftBelowEdgeEvent(tcx, edge, node);
         }
         else
         {
             node = node.Prev;
         }
     }
 }
예제 #7
0
파일: DTSweep.cs 프로젝트: miyu/Poly2Tri
 private static void FillLeftConcaveEdgeEvent(DTSweepContext tcx, TriangulationConstraint edge, AdvancingFrontNode node)
 {
     Fill(tcx, node.Prev);
     if (node.Prev.Point.Equals(edge.P))
     {
         // Next above or below edge?
         if (TriangulationUtil.Orient2d(edge.Q, node.Prev.Point, edge.P) == Orientation.Clockwise)
         {
             // Below
             if (TriangulationUtil.Orient2d(node.Point, node.Prev.Point, node.Prev.Prev.Point) == Orientation.Clockwise)
             {
                 // Next is concave
                 FillLeftConcaveEdgeEvent(tcx, edge, node);
             }
             else
             {
                 // Next is convex
             }
         }
     }
 }
예제 #8
0
        private void AddBoundaryConstraints()
        {
            TriangulationPoint ptLL;
            TriangulationPoint ptLR;
            TriangulationPoint ptUR;
            TriangulationPoint ptUL;

            if (!TryGetPoint(MinX, MinY, out ptLL))
            {
                ptLL = new TriangulationPoint(MinX, MinY);
                Add(ptLL);
            }
            if (!TryGetPoint(MaxX, MinY, out ptLR))
            {
                ptLR = new TriangulationPoint(MaxX, MinY);
                Add(ptLR);
            }
            if (!TryGetPoint(MaxX, MaxY, out ptUR))
            {
                ptUR = new TriangulationPoint(MaxX, MaxY);
                Add(ptUR);
            }
            if (!TryGetPoint(MinX, MaxY, out ptUL))
            {
                ptUL = new TriangulationPoint(MinX, MaxY);
                Add(ptUL);
            }
            TriangulationConstraint tcLLtoLR = new TriangulationConstraint(ptLL, ptLR);

            AddConstraint(tcLLtoLR);
            TriangulationConstraint tcLRtoUR = new TriangulationConstraint(ptLR, ptUR);

            AddConstraint(tcLRtoUR);
            TriangulationConstraint tcURtoUL = new TriangulationConstraint(ptUR, ptUL);

            AddConstraint(tcURtoUL);
            TriangulationConstraint tcULtoLL = new TriangulationConstraint(ptUL, ptLL);

            AddConstraint(tcULtoLL);
        }
예제 #9
0
파일: DTSweep.cs 프로젝트: miyu/Poly2Tri
        private static void FillLeftBelowEdgeEvent(DTSweepContext tcx, TriangulationConstraint edge, AdvancingFrontNode node)
        {
            if (tcx.IsDebugEnabled)
            {
                tcx.DebugContext.ActiveNode = node;
            }

            if (node.Point.X > edge.P.X)
            {
                if (TriangulationUtil.Orient2d(node.Point, node.Prev.Point, node.Prev.Prev.Point) == Orientation.Clockwise)
                {
                    // Concave
                    FillLeftConcaveEdgeEvent(tcx, edge, node);
                }
                else
                {
                    // Convex
                    FillLeftConvexEdgeEvent(tcx, edge, node);
                    // Retry this one
                    FillLeftBelowEdgeEvent(tcx, edge, node);
                }
            }
        }
예제 #10
0
파일: DTSweep.cs 프로젝트: miyu/Poly2Tri
 private static void FillRightConvexEdgeEvent(DTSweepContext tcx, TriangulationConstraint edge, AdvancingFrontNode node)
 {
     // Next concave or convex?
     if (TriangulationUtil.Orient2d(node.Next.Point, node.Next.Next.Point, node.Next.Next.Next.Point) == Orientation.AntiClockwise)
     {
         // Concave
         FillRightConcaveEdgeEvent(tcx, edge, node.Next);
     }
     else
     {
         // Convex
         // Next above or below edge?
         if (TriangulationUtil.Orient2d(edge.Q, node.Next.Next.Point, edge.P) == Orientation.AntiClockwise)
         {
             // Below
             FillRightConvexEdgeEvent(tcx, edge, node.Next);
         }
         else
         {
             // Above
         }
     }
 }
예제 #11
0
 public bool TryGetConstraint(uint constraintCode, out TriangulationConstraint tc)
 {
     return(_constraintMap.TryGetValue(constraintCode, out tc));
 }
예제 #12
0
        // Assumes that points being passed in the list are connected and form a polygon.
        // Note that some error checking is done for robustness, but for the most part,
        // we have to rely on the user to feed us "correct" data
        public bool AddHole(List <TriangulationPoint> points)
        {
            if (points == null)
            {
                return(false);
            }

            //// split our self-intersection sections into their own lists
            List <Contour> pts     = new List <Contour>();
            int            listIdx = 0;

            {
                Contour c = new Contour(this, points, WindingOrderType.Unknown);
                pts.Add(c);

                // only constrain the points if we actually HAVE a bounding rect
                if (MPoints.Count > 1)
                {
                    // constrain the points to bounding rect
                    int numPoints = pts[listIdx].Count;
                    for (int i = 0; i < numPoints; ++i)
                    {
                        ConstrainPointToBounds(pts[listIdx][i]);
                    }
                }
            }

            while (listIdx < pts.Count)
            {
                // simple sanity checking - remove duplicate coincident points before
                // we check the polygon: fast, simple algorithm that eliminate lots of problems
                // that only more expensive checks will find
                pts[listIdx].RemoveDuplicateNeighborPoints();
                pts[listIdx].WindingOrder = WindingOrderType.Default;

                bool         bListOk = true;
                PolygonError err     = pts[listIdx].CheckPolygon();
                while (bListOk && err != PolygonError.None)
                {
                    if ((err & PolygonError.NotEnoughVertices) == PolygonError.NotEnoughVertices)
                    {
                        bListOk = false;
                        continue;
                    }
                    if ((err & PolygonError.NotSimple) == PolygonError.NotSimple)
                    {
                        // split the polygons, remove the current list and add the resulting list to the end
                        //List<Point2DList> l = TriangulationUtil.SplitSelfIntersectingPolygon(pts[listIdx], pts[listIdx].Epsilon);
                        IEnumerable <Point2DList> l = PolygonUtil.SplitComplexPolygon(pts[listIdx], pts[listIdx].Epsilon);
                        pts.RemoveAt(listIdx);
                        foreach (Point2DList newList in l)
                        {
                            Contour c = new Contour(this);
                            c.AddRange(newList);
                            pts.Add(c);
                        }
                        err = pts[listIdx].CheckPolygon();
                        continue;
                    }
                    if ((err & PolygonError.Degenerate) == PolygonError.Degenerate)
                    {
                        pts[listIdx].Simplify(Epsilon);
                        err = pts[listIdx].CheckPolygon();
                        continue;
                        //err &= ~(PolygonError.Degenerate);
                        //if (pts[listIdx].Count < 3)
                        //{
                        //    err |= PolygonError.NotEnoughVertices;
                        //    bListOK = false;
                        //    continue;
                        //}
                    }
                    if ((err & PolygonError.AreaTooSmall) == PolygonError.AreaTooSmall ||
                        (err & PolygonError.SidesTooCloseToParallel) == PolygonError.SidesTooCloseToParallel ||
                        (err & PolygonError.TooThin) == PolygonError.TooThin ||
                        (err & PolygonError.Unknown) == PolygonError.Unknown)
                    {
                        bListOk = false;
                    }
                    // non-convex polygons are ok
                    //if ((err & PolygonError.NotConvex) == PolygonError.NotConvex)
                    //{
                    //}
                }
                if (!bListOk && pts[listIdx].Count != 2)
                {
                    pts.RemoveAt(listIdx);
                }
                else
                {
                    ++listIdx;
                }
            }

            bool bOk = true;

            listIdx = 0;
            while (listIdx < pts.Count)
            {
                int numPoints = pts[listIdx].Count;
                if (numPoints < 2)
                {
                    // should not be possible by this point...
                    ++listIdx;
                    bOk = false;
                    continue;
                }
                else if (numPoints == 2)
                {
                    uint constraintCode = TriangulationConstraint.CalculateContraintCode(pts[listIdx][0], pts[listIdx][1]);
                    TriangulationConstraint tc;
                    if (!_constraintMap.TryGetValue(constraintCode, out tc))
                    {
                        tc = new TriangulationConstraint(pts[listIdx][0], pts[listIdx][1]);
                        AddConstraint(tc);
                    }
                }
                else
                {
                    Contour ph = new Contour(this, pts[listIdx], WindingOrderType.Unknown)
                    {
                        WindingOrder = WindingOrderType.Default,
                    };
                    _holes.Add(ph);
                }
                ++listIdx;
            }

            return(bOk);
        }
예제 #13
0
        public static void InitializeHoles(List <Contour> holes, ITriangulatable parent, ConstrainedPointSet cps)
        {
            int numHoles = holes.Count;
            int holeIdx  = 0;

            // pass 1 - remove duplicates
            while (holeIdx < numHoles)
            {
                int hole2Idx = holeIdx + 1;
                while (hole2Idx < numHoles)
                {
                    bool bSamePolygon = PolygonUtil.PolygonsAreSame2D(holes[holeIdx], holes[hole2Idx]);
                    if (bSamePolygon)
                    {
                        // remove one of them
                        holes.RemoveAt(hole2Idx);
                        --numHoles;
                    }
                    else
                    {
                        ++hole2Idx;
                    }
                }
                ++holeIdx;
            }

            // pass 2: Intersections and Containment
            holeIdx = 0;
            while (holeIdx < numHoles)
            {
                bool bIncrementHoleIdx = true;
                int  hole2Idx          = holeIdx + 1;
                while (hole2Idx < numHoles)
                {
                    if (PolygonUtil.PolygonContainsPolygon(holes[holeIdx], holes[holeIdx].Bounds, holes[hole2Idx], holes[hole2Idx].Bounds, false))
                    {
                        holes[holeIdx].AddHole(holes[hole2Idx]);
                        holes.RemoveAt(hole2Idx);
                        --numHoles;
                    }
                    else if (PolygonUtil.PolygonContainsPolygon(holes[hole2Idx], holes[hole2Idx].Bounds, holes[holeIdx], holes[holeIdx].Bounds, false))
                    {
                        holes[hole2Idx].AddHole(holes[holeIdx]);
                        holes.RemoveAt(holeIdx);
                        --numHoles;
                        bIncrementHoleIdx = false;
                        break;
                    }
                    else
                    {
                        bool bIntersect = PolygonUtil.PolygonsIntersect2D(holes[holeIdx], holes[holeIdx].Bounds, holes[hole2Idx], holes[hole2Idx].Bounds);
                        if (bIntersect)
                        {
                            // this is actually an error condition
                            // fix by merging hole1 and hole2 into hole1 (including the holes inside hole2!) and delete hole2
                            // Then, because hole1 is now changed, restart it's check.
                            PolygonOperationContext ctx = new PolygonOperationContext();
                            if (!ctx.Init(PolygonUtil.PolyOperation.Union | PolygonUtil.PolyOperation.Intersect, holes[holeIdx], holes[hole2Idx]))
                            {
                                if (ctx.mError == PolygonUtil.PolyUnionError.Poly1InsidePoly2)
                                {
                                    holes[hole2Idx].AddHole(holes[holeIdx]);
                                    holes.RemoveAt(holeIdx);
                                    --numHoles;
                                    bIncrementHoleIdx = false;
                                    break;
                                }
                                else
                                {
                                    throw new Exception("PolygonOperationContext.Init had an error during initialization");
                                }
                            }
                            PolygonUtil.PolyUnionError pue = PolygonUtil.PolygonOperation(ctx);
                            if (pue == PolygonUtil.PolyUnionError.None)
                            {
                                Point2DList union        = ctx.Union;
                                Point2DList intersection = ctx.Intersect;

                                // create a new contour for the union
                                Contour c = new Contour(parent);
                                c.AddRange(union);
                                c.Name         = "(" + holes[holeIdx].Name + " UNION " + holes[hole2Idx].Name + ")";
                                c.WindingOrder = Point2DList.WindingOrderType.Default;

                                // add children from both of the merged contours
                                int numChildHoles = holes[holeIdx].GetNumHoles();
                                for (int i = 0; i < numChildHoles; ++i)
                                {
                                    c.AddHole(holes[holeIdx].GetHole(i));
                                }
                                numChildHoles = holes[hole2Idx].GetNumHoles();
                                for (int i = 0; i < numChildHoles; ++i)
                                {
                                    c.AddHole(holes[hole2Idx].GetHole(i));
                                }

                                // make sure we preserve the contours of the intersection
                                Contour cInt = new Contour(c);
                                cInt.AddRange(intersection);
                                cInt.Name         = "(" + holes[holeIdx].Name + " INTERSECT " + holes[hole2Idx].Name + ")";
                                cInt.WindingOrder = Point2DList.WindingOrderType.Default;
                                c.AddHole(cInt);

                                // replace the current contour with the merged contour
                                holes[holeIdx] = c;

                                // toss the second contour
                                holes.RemoveAt(hole2Idx);
                                --numHoles;

                                // current hole is "examined", so move to the next one
                                hole2Idx = holeIdx + 1;
                            }
                            else
                            {
                                throw new Exception("PolygonOperation had an error!");
                            }
                        }
                        else
                        {
                            ++hole2Idx;
                        }
                    }
                }
                if (bIncrementHoleIdx)
                {
                    ++holeIdx;
                }
            }

            numHoles = holes.Count;
            holeIdx  = 0;
            while (holeIdx < numHoles)
            {
                int numPoints = holes[holeIdx].Count;
                for (int i = 0; i < numPoints; ++i)
                {
                    int  j = holes[holeIdx].NextIndex(i);
                    uint constraintCode        = TriangulationConstraint.CalculateContraintCode(holes[holeIdx][i], holes[holeIdx][j]);
                    TriangulationConstraint tc = null;
                    if (!cps.TryGetConstraint(constraintCode, out tc))
                    {
                        tc = new TriangulationConstraint(holes[holeIdx][i], holes[holeIdx][j]);
                        cps.AddConstraint(tc);
                    }

                    // replace the points in the holes with valid points
                    if (holes[holeIdx][i].VertexCode == tc.P.VertexCode)
                    {
                        holes[holeIdx][i] = tc.P;
                    }
                    else if (holes[holeIdx][j].VertexCode == tc.P.VertexCode)
                    {
                        holes[holeIdx][j] = tc.P;
                    }
                    if (holes[holeIdx][i].VertexCode == tc.Q.VertexCode)
                    {
                        holes[holeIdx][i] = tc.Q;
                    }
                    else if (holes[holeIdx][j].VertexCode == tc.Q.VertexCode)
                    {
                        holes[holeIdx][j] = tc.Q;
                    }
                }
                ++holeIdx;
            }
        }