// 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, string name) { 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 = Point2DList.WindingOrderType.Default; bool bListOK = true; Point2DList.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); List <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(this.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; continue; } // 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 = null; if (!mConstraintMap.TryGetValue(constraintCode, out tc)) { tc = new TriangulationConstraint(pts [listIdx] [0], pts [listIdx] [1]); AddConstraint(tc); } } else { Contour ph = new Contour(this, pts [listIdx], Point2DList.WindingOrderType.Unknown); ph.WindingOrder = Point2DList.WindingOrderType.Default; ph.Name = name + ":" + listIdx.ToString(); mHoles.Add(ph); } ++listIdx; } return(bOK); }
public bool AddHole(List <TriangulationPoint> points, string name) { if (points == null) { return(false); } List <Contour> pts = new List <Contour>(); int listIdx = 0; { Contour c = new Contour(this, points, WindingOrderType.Unknown); pts.Add(c); if (mPoints.Count > 1) { int numPoints = pts[listIdx].Count; for (int i = 0; i < numPoints; ++i) { ConstrainPointToBounds(pts[listIdx][i]); } } } while (listIdx < pts.Count) { pts[listIdx].RemoveDuplicateNeighborPoints(); pts[listIdx].WindingOrder = Point2DList.WindingOrderType.Default; bool bListOK = true; Point2DList.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) { List <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(this.Epsilon); err = pts[listIdx].CheckPolygon(); continue; } if ((err & PolygonError.AreaTooSmall) == PolygonError.AreaTooSmall || (err & PolygonError.SidesTooCloseToParallel) == PolygonError.SidesTooCloseToParallel || (err & PolygonError.TooThin) == PolygonError.TooThin || (err & PolygonError.Unknown) == PolygonError.Unknown) { bListOK = false; continue; } } 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) { ++listIdx; bOK = false; continue; } else if (numPoints == 2) { uint constraintCode = TriangulationConstraint.CalculateContraintCode(pts[listIdx][0], pts[listIdx][1]); TriangulationConstraint tc = null; if (!mConstraintMap.TryGetValue(constraintCode, out tc)) { tc = new TriangulationConstraint(pts[listIdx][0], pts[listIdx][1]); AddConstraint(tc); } } else { Contour ph = new Contour(this, pts[listIdx], Point2DList.WindingOrderType.Unknown); ph.WindingOrder = Point2DList.WindingOrderType.Default; ph.Name = name + ":" + listIdx.ToString(); mHoles.Add(ph); } ++listIdx; } return(bOK); }