public void InitializeHoles(ConstrainedPointSet cps) { Contour.InitializeHoles(mHoles, this, cps); foreach (Contour c in mHoles) { c.InitializeHoles(cps); } }
public static void Triangulate(ConstrainedPointSet cps) { Triangulate(_defaultAlgorithm, cps); }
//////// public static PointSet LoadDatPointSet(string filename, bool xflip, bool yflip, bool displayFlipX, bool displayFlipY, float rotateAngleInDegrees) { var points = new List<TriangulationPoint>(); List<List<TriangulationPoint>> constrainedPoints = new List<List<TriangulationPoint>>(); List<string> constrainedPointSetNames = new List<string>(); List<TriangulationPoint> bounds = new List<TriangulationPoint>(); List<TriangulationPoint> currentList = points; double precision = TriangulationPoint.kVertexCodeDefaultPrecision; int lineNum = 0; bool skipLine = false; foreach (var line_ in File.ReadAllLines(filename)) { ++lineNum; string line = line_.Trim(); if (string.IsNullOrEmpty(line) || line.StartsWith("//") || line.StartsWith("#") || line.StartsWith(";")) { continue; } if (!skipLine && line.StartsWith("/*")) { skipLine = true; continue; } else if (skipLine) { if( line.StartsWith("*/")) { skipLine = false; } continue; } if (line.StartsWith("Precision", StringComparison.InvariantCultureIgnoreCase)) { if (line.Length > 9) { string precisionStr = line.Substring(9).Trim(); if (!double.TryParse(precisionStr, NumberStyles.Float, CultureInfo.InvariantCulture, out precision)) { Console.WriteLine("Invalid Precision '" + precisionStr + "' in file " + filename + ", line " + lineNum.ToString() + ". Setting to " + TriangulationPoint.kVertexCodeDefaultPrecision.ToString()); precision = TriangulationPoint.kVertexCodeDefaultPrecision; } } } else if (line.StartsWith("Set", StringComparison.InvariantCultureIgnoreCase)) { if (line.StartsWith("SetBegin")) { string[] setParts = line.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (setParts.Length < 2) { continue; } //if (setParts[1].Equals("Constrained", StringComparison.InvariantCultureIgnoreCase)) if (setParts[1].Equals("Constrained", StringComparison.InvariantCultureIgnoreCase) || setParts[1].Equals("Unconstrained", StringComparison.InvariantCultureIgnoreCase)) { currentList = new List<TriangulationPoint>(); constrainedPoints.Add(currentList); if( setParts.Length>2) { constrainedPointSetNames.Add(setParts[2]); } else { constrainedPointSetNames.Add(""); } } else if (bounds.Count == 0 && setParts[1].Equals("Bounds", StringComparison.InvariantCultureIgnoreCase)) { currentList = bounds; } else { currentList = points; } } else { currentList = points; } } else { var xy = line.Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); double x, y; if (xy != null && xy.Length >= 2 && double.TryParse(xy[0], NumberStyles.Float, CultureInfo.InvariantCulture, out x) && double.TryParse(xy[1], NumberStyles.Float, CultureInfo.InvariantCulture, out y)) { currentList.Add(new PolygonPoint((xflip ? -1.0 : 1.0) * x, (yflip ? -1.0 : 1.0) * y)); } else { Console.WriteLine("Invalid Input '" + line + "' in file " + filename + ", line " + lineNum.ToString()); } } } PointSet ps = null; if (constrainedPoints.Count > 0) { ConstrainedPointSet cps = null; if (bounds.Count < 3) { points.AddRange(bounds); cps = new ConstrainedPointSet(points); } else { cps = new ConstrainedPointSet(bounds); cps.AddRange(points); } int numConstrainedPointSets = constrainedPoints.Count; for( int i = 0; i < numConstrainedPointSets; ++i) { List<TriangulationPoint> hole = constrainedPoints[i]; if (hole.Count < 3) { cps.AddRange(hole); } else { cps.AddHole(hole, constrainedPointSetNames[i]); } } ps = cps; } else { if (bounds.Count < 3) { points.AddRange(bounds); ps = new PointSet(points); } else { ps = new PointSet(bounds); ps.AddRange(points); } } ps.FileName = filename; ps.DisplayFlipX = displayFlipX; ps.DisplayFlipY = displayFlipY; ps.DisplayRotate = rotateAngleInDegrees; ps.Precision = precision; return ps; }
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; } }
//////// public static PointSet LoadDatPointSet(string filename, bool xflip, bool yflip, bool displayFlipX, bool displayFlipY, float rotateAngleInDegrees) { var points = new List <TriangulationPoint>(); List <List <TriangulationPoint> > constrainedPoints = new List <List <TriangulationPoint> >(); List <string> constrainedPointSetNames = new List <string>(); List <TriangulationPoint> bounds = new List <TriangulationPoint>(); List <TriangulationPoint> currentList = points; double precision = TriangulationPoint.kVertexCodeDefaultPrecision; int lineNum = 0; bool skipLine = false; foreach (var line_ in File.ReadAllLines(filename)) { ++lineNum; string line = line_.Trim(); if (string.IsNullOrEmpty(line) || line.StartsWith("//") || line.StartsWith("#") || line.StartsWith(";")) { continue; } if (!skipLine && line.StartsWith("/*")) { skipLine = true; continue; } else if (skipLine) { if (line.StartsWith("*/")) { skipLine = false; } continue; } if (line.StartsWith("Precision", StringComparison.InvariantCultureIgnoreCase)) { if (line.Length > 9) { string precisionStr = line.Substring(9).Trim(); if (!double.TryParse(precisionStr, NumberStyles.Float, CultureInfo.InvariantCulture, out precision)) { Console.WriteLine("Invalid Precision '" + precisionStr + "' in file " + filename + ", line " + lineNum.ToString() + ". Setting to " + TriangulationPoint.kVertexCodeDefaultPrecision.ToString()); precision = TriangulationPoint.kVertexCodeDefaultPrecision; } } } else if (line.StartsWith("Set", StringComparison.InvariantCultureIgnoreCase)) { if (line.StartsWith("SetBegin")) { string[] setParts = line.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (setParts.Length < 2) { continue; } //if (setParts[1].Equals("Constrained", StringComparison.InvariantCultureIgnoreCase)) if (setParts[1].Equals("Constrained", StringComparison.InvariantCultureIgnoreCase) || setParts[1].Equals("Unconstrained", StringComparison.InvariantCultureIgnoreCase)) { currentList = new List <TriangulationPoint>(); constrainedPoints.Add(currentList); if (setParts.Length > 2) { constrainedPointSetNames.Add(setParts[2]); } else { constrainedPointSetNames.Add(""); } } else if (bounds.Count == 0 && setParts[1].Equals("Bounds", StringComparison.InvariantCultureIgnoreCase)) { currentList = bounds; } else { currentList = points; } } else { currentList = points; } } else { var xy = line.Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); double x, y; if (xy != null && xy.Length >= 2 && double.TryParse(xy[0], NumberStyles.Float, CultureInfo.InvariantCulture, out x) && double.TryParse(xy[1], NumberStyles.Float, CultureInfo.InvariantCulture, out y)) { currentList.Add(new PolygonPoint((xflip ? -1.0 : 1.0) * x, (yflip ? -1.0 : 1.0) * y)); } else { Console.WriteLine("Invalid Input '" + line + "' in file " + filename + ", line " + lineNum.ToString()); } } } PointSet ps = null; if (constrainedPoints.Count > 0) { ConstrainedPointSet cps = null; if (bounds.Count < 3) { points.AddRange(bounds); cps = new ConstrainedPointSet(points); } else { cps = new ConstrainedPointSet(bounds); cps.AddRange(points); } int numConstrainedPointSets = constrainedPoints.Count; for (int i = 0; i < numConstrainedPointSets; ++i) { List <TriangulationPoint> hole = constrainedPoints[i]; if (hole.Count < 3) { cps.AddRange(hole); } else { cps.AddHole(hole, constrainedPointSetNames[i]); } } ps = cps; } else { if (bounds.Count < 3) { points.AddRange(bounds); ps = new PointSet(points); } else { ps = new PointSet(bounds); ps.AddRange(points); } } ps.FileName = filename; ps.DisplayFlipX = displayFlipX; ps.DisplayFlipY = displayFlipY; ps.DisplayRotate = rotateAngleInDegrees; ps.Precision = precision; return(ps); }