public List<DelaunayTriangle> TriangulateComplex( PolyTree polyTree, bool ignoreFills = false, bool ignoreHoles = true) { PolyNode rootNode; if (polyTree.Total == 0) { Console.WriteLine(0); rootNode = new PolyNode(); } else { rootNode = polyTree.GetFirst().Parent; } // Equivalent to rootNode.Contour = bounds; var contourField = rootNode.GetType().GetField("m_polygon", BindingFlags.Instance | BindingFlags.NonPublic); if (contourField == null) { throw new Exception("Could not find field contour backing field."); } contourField.SetValue(rootNode, kTriangulatorBounds); var result = new List<DelaunayTriangle>(); int i = 0; for (var currentNode = rootNode; currentNode != null; currentNode = currentNode.GetNext()) { if ((ignoreHoles && currentNode.IsHole) || (ignoreFills && !currentNode.IsHole)) continue; var polyline = DownscalePolygon(currentNode.Contour); var finalPolygon = new Polygon(polyline); foreach (var child in currentNode.Childs) { var shrunkContour = EdgeShrink(child.Contour); var holePoints = DownscalePolygon(shrunkContour); var holePoly = new Polygon(holePoints); finalPolygon.AddHole(holePoly); } P2T.Triangulate(finalPolygon); result.AddRange(finalPolygon.Triangles); } return result; }
//------------------------------------------------------------------------------ private void BmpUpdateNeeded() { const int textOffset = 20; if (bmpGraphics == null) return; FillMode fm = (mEvenOdd.Checked ? FillMode.Alternate : FillMode.Winding); bmpGraphics.Clear(Color.White); //draw the subject and clip paths ... Paths openPaths = new Paths(); Paths closedPaths = new Paths(); Paths clipPaths = new Paths(); //sort the paths into open and closed subjects and (closed) clips ... foreach (MultiPath mp2 in allPaths) if (mp2.RefID == CLIP) clipPaths.Add(mp2.Flatten()); else if (mp2.IsClosed) closedPaths.Add(mp2.Flatten()); else openPaths.Add(mp2.Flatten()); DrawPath(bmpGraphics, openPaths, false, 0x0, 0xFFAAAAAA, fm, 1.0); DrawPath(bmpGraphics, closedPaths, true, 0x0, 0xFFAAAAAA, fm, 1.0); DrawPath(bmpGraphics, clipPaths, true, 0x10FF6600, 0x99FF6600, fm, 1.0); if (cbShowCoords.Checked) { Font fnt = new Font("Arial", 8); SolidBrush brush = new SolidBrush(Color.Navy); foreach (MultiPath mp2 in allPaths) { foreach (MultiPathSegment mps in mp2) foreach (IntPoint ip in mps) { IntPoint ip2 = new IntPoint(ip.X / scale, ip.Y / scale); string coords = ip2.X.ToString() + "," + ip2.Y.ToString(); bmpGraphics.DrawString(coords, fnt, brush, ip2.X - textOffset, ip2.Y - textOffset, null); } } fnt.Dispose(); brush.Dispose(); } //for the active path, draw control buttons and control lines too ... MultiPath activePath = GetActivePath(); if (activePath != null && activePath.Count > 0) { foreach (MultiPathSegment mps in activePath) { CurveType pt = mps.curvetype; if (pt == CurveType.CubicBezier) DrawBezierCtrlLines(bmpGraphics, mps, 0xFFEEEEEE); else if (pt == CurveType.QuadBezier) DrawBezierCtrlLines(bmpGraphics, mps, 0xFFEEEEEE); } DrawButtons(bmpGraphics, activePath); //display the coords of a moving button ... if (MovingButtonIdx >= 0) { Font f = new Font("Arial", 8); SolidBrush b = new SolidBrush(Color.Navy); IntPoint ip = MovingButtonSeg[MovingButtonIdx]; ip.X = (int)(ip.X / scale); ip.Y = (int)(ip.Y / scale); string coords = ip.X.ToString() + "," + ip.Y.ToString(); bmpGraphics.DrawString(coords, f, b, ip.X - textOffset, ip.Y - textOffset, null); f.Dispose(); b.Dispose(); } } //if there's any clipping to be done, do it here ... if (!mNone.Checked && GetCurrentSubjMultiPath() != null && GetCurrentClipMultiPath() != null) { PolyFillType pft = (mEvenOdd.Checked ? PolyFillType.pftEvenOdd : PolyFillType.pftNonZero); ClipType ct; if (mUnion.Checked) ct = ClipType.ctUnion; else if (mDifference.Checked) ct = ClipType.ctDifference; else if (mXor.Checked) ct = ClipType.ctXor; else ct = ClipType.ctIntersection; //CLIPPING DONE HERE ... Clipper c = new Clipper(); c.ZFillFunction = MultiPaths.ClipCallback; //set the callback function (called at intersections) if (openPaths.Count > 0) c.AddPaths(openPaths, PolyType.ptSubject, false); if (closedPaths.Count > 0) c.AddPaths(closedPaths, PolyType.ptSubject, true); c.AddPaths(clipPaths, PolyType.ptClip, true); PolyTree polytree = new PolyTree(); Paths solution; c.Execute(ct, polytree, pft, pft); //EXECUTE CLIP !!!!!!!!!!!!!!!!!!!!!! solution = Clipper.ClosedPathsFromPolyTree(polytree); if (!cbReconstCurve.Checked) DrawPath(bmpGraphics, solution, true, 0x2033AA00, 0xFF33AA00, fm, 2.0); solution = Clipper.OpenPathsFromPolyTree(polytree); if (!cbReconstCurve.Checked) DrawPath(bmpGraphics, solution, false, 0x0, 0xFF33AA00, fm, 2.0); //now to demonstrate reconstructing beziers & arcs ... if (cbReconstCurve.Checked) { PolyNode pn = polytree.GetFirst(); while (pn != null) { if (pn.IsHole || pn.Contour.Count < 2) { pn = pn.GetNext(); continue; } if (pn.ChildCount > 0) throw new Exception("Sorry, this demo doesn't currently handle holes"); //and reconstruct each curve ... MultiPath reconstructedMultiPath = allPaths.Reconstruct(pn.Contour); if (cbShowCtrls.Enabled && cbShowCtrls.Checked) { //show (small) buttons on the red reconstructed path too ... DrawButtons(bmpGraphics, reconstructedMultiPath, true); } //now to show how accurate these reconstructed (control) paths are, //we flatten them (drawing them red) so we can compare them with //the original flattened paths (light gray) ... Paths paths = new Paths(); paths.Add(reconstructedMultiPath.Flatten()); DrawPath(bmpGraphics, paths, !pn.IsOpen, 0x18FF0000, 0xFFFF0000, fm, 2.0); pn = pn.GetNext(); } } //else //shows just how many vertices there are in flattened paths ... //{ // solution = Clipper.PolyTreeToPaths(polytree); // MultiPath flatMultiPath = new MultiPath(null, 0, false); // foreach (Path p in solution) // flatMultiPath.NewMultiPathSegment(PathType.Line, p); // DrawButtons(bmpGraphics, flatMultiPath, true); //} } string s = " "; if (mIntersection.Checked) s += "INTERSECTION"; else if (mUnion.Checked) s += "UNION"; else if (mDifference.Checked) s += "DIFFERENCE"; else if (mXor.Checked) s += "XOR"; else s += "NO CLIPPING"; s += " with "; if (mEvenOdd.Checked) s += "EVENODD fill."; else s += "NONZERO fill."; toolStripStatusLabel2.Text = s; displayPanel.Invalidate(); }
private Paths PolyTreeToPolygons(PolyTree tree) { Paths p = new Paths(); PolyNode n = tree.GetFirst(); while (null != n) { p.Add(n.Contour); n = n.GetNext(); } return p; }
private PolyTree Punch(PolyTree input, PolyTree hole) { var subtractClipper = new Clipper(Clipper.ioStrictlySimple); for (var it = input.GetFirst(); it != null; it = it.GetNext()) { subtractClipper.AddPath(it.Contour, PolyType.ptSubject, true); } for (var it = hole.GetFirst(); it != null; it = it.GetNext()) { subtractClipper.AddPath(it.Contour, PolyType.ptClip, true); } var result = new PolyTree(); subtractClipper.Execute(ClipType.ctDifference, result, PolyFillType.pftNonZero, PolyFillType.pftNonZero); return result; }
private PolyTree Offset(PolyTree input, double delta) { var clipperOffset = new ClipperOffset(); for (var currentNode = input.GetFirst(); currentNode != null; currentNode = currentNode.GetNext()) { clipperOffset.AddPath(currentNode.Contour, JoinType.jtMiter, EndType.etClosedPolygon); } var result = new PolyTree(); clipperOffset.Execute(ref result, delta); return result; }
private static void DrawPolyTree(PolyTree inputUnionTree) { var bitmap = new Bitmap(200, 200); using (var g = Graphics.FromImage(bitmap)) { const double kScale = kInverseClipperScaleFactor * 10; g.SmoothingMode = SmoothingMode.AntiAlias; for (var current = inputUnionTree.GetFirst(); current != null; current = current.GetNext()) { Console.WriteLine("Current Is Hole: " + current.IsHole); Console.WriteLine("Current Contour Count: " + current.Contour.Count); Console.WriteLine("Current Child Count: " + current.Childs.Count); for (var i = 0; i < current.Contour.Count; i++) { foreach (var child in current.Childs) { for (var j = 0; j < child.Contour.Count - 1; j++) { for (var k = j + 1; k < child.Contour.Count; k++) { var a = child.Contour[j]; var b = child.Contour[k]; g.DrawLine(Pens.Red, (float)(a.X * kScale), (float)(a.Y * kScale), (float)(b.X * kScale), (float)(b.Y * kScale)); } } } { var a = current.Contour[i]; var b = current.Contour[(i + 1) % current.Contour.Count]; g.DrawLine(Pens.Cyan, (float)(a.X * kScale), (float)(a.Y * kScale), (float)(b.X * kScale), (float)(b.Y * kScale)); } } } } NaviUtil.ShowBitmap(bitmap); }