private Slice GetPairs(bool outside) { Slice s = new Slice(this); PolyNode n = polyTree.GetFirst(); Paths polygons = new Paths(); while (null != n) { int depth = 0; PolyNode parent = n.Parent; while (parent != null) { depth++; parent = parent.Parent; } int test = (depth - 1) % 4; if ((outside && test < 2) || (!outside && test >= 2)) { polygons.Add(n.Contour); } n = n.GetNext(); } s.polyTree = PolygonsToPolyTree(polygons); return(s); }
private List <DelaunayTriangle> GenerateTriangles() { List <DelaunayTriangle> triangles = new List <DelaunayTriangle>(); Dictionary <PolyNode, Polygon> dict = new Dictionary <PolyNode, Polygon>(); PolyNode curt = m_polyTree.GetFirst(); while (curt != null) { var polygon = Convert(curt.Contour); dict.Add(curt, polygon); if (curt.IsHole && curt.Parent != null) { dict[curt.Parent].AddHole(polygon); } curt = curt.GetNext(); } foreach (var pair in dict) { var node = pair.Key; var poly = pair.Value; if (node.IsHole == false) { P2T.Triangulate(poly); triangles.AddRange(poly.Triangles); } } return(triangles); }
public IEnumerable <Slice> IndividualPolygons() { PolyNode n = polyTree.GetFirst(); Paths polygons = new Paths(); while (null != n) { if (!n.IsHole && polygons.Count > 0) { Slice s = new Slice(this); s.polyTree = PolygonsToPolyTree(polygons); yield return(s); polygons = new Paths(); } polygons.Add(n.Contour); n = n.GetNext(); } if (polygons.Count > 0) { Slice s = new Slice(this); s.polyTree = PolygonsToPolyTree(polygons); yield return(s); } }
public void RemoveHoles(float maxPerimiter) { Paths keep = new Paths(); PolyNode node = polyTree.GetFirst(); while (node != null) { if (node.IsHole && node.ChildCount == 0) { var line = LineStripFromPolygon(node.Contour); float length = line.Length(LineStrip.Type.Closed); if (length < maxPerimiter) { // Remove it } else { keep.Add(node.Contour); } } else { keep.Add(node.Contour); } node = node.GetNext(); } Clipper c = new Clipper(); c.Clear(); c.AddPaths(keep, PolyType.ptSubject, true); polyTree = new PolyTree(); c.Execute(ClipType.ctUnion, polyTree); }
public virtual void GetNextPolyNodeNotEmptyTest() { PolyNode node = new PolyNode(); node.AddChild(new PolyNode()); node.AddChild(new PolyNode()); NUnit.Framework.Assert.AreSame(node.Childs[0], node.GetNext()); }
public virtual void GetNextPolyNodeWithSiblingTest() { PolyNode node = new PolyNode(); PolyNode child1 = new PolyNode(); PolyNode child2 = new PolyNode(); node.AddChild(child1); node.AddChild(child2); NUnit.Framework.Assert.AreSame(child2, child1.GetNext()); }
/// <summary> /// Converts Clipper library /// <see cref="PolyTree"/> /// abstraction into iText /// <see cref="iText.Kernel.Geom.Path"/> /// object. /// </summary> public static Path ConvertToPath(PolyTree result) { Path path = new Path(); PolyNode node = result.GetFirst(); while (node != null) { AddContour(path, node.Contour, !node.IsOpen); node = node.GetNext(); } return(path); }
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); }
public IEnumerable <LineStrip> GetLines(LineType type) { PolyNode n = polyTree.GetFirst(); while (null != n) { bool hole = n.IsHole; if (type == LineType.All || (hole && type == LineType.Hole) || (!hole && type == LineType.Outside)) { yield return(LineStripFromPolygon(n.Contour)); } n = n.GetNext(); } }
public Slice PolygonsWithoutHoles() { Slice s = new Slice(this); PolyNode n = polyTree.GetFirst(); Paths polygons = new Paths(); while (null != n) { if (!n.IsHole && n.ChildCount == 0) { polygons.Add(n.Contour); } n = n.GetNext(); } s.polyTree = PolygonsToPolyTree(polygons); return(s); }
/// <summary> /// Get all the polygons which contain holes /// </summary> /// <returns></returns> public Slice PolygonsWithHoles() { Slice s = new Slice(this); PolyNode n = polyTree.GetFirst(); Paths polygons = new Paths(); while (null != n) { if (n.IsHole) { if (!polygons.Contains(n.Parent.Contour)) { polygons.Add(n.Parent.Contour); } polygons.Add(n.Contour); } n = n.GetNext(); } s.polyTree = PolygonsToPolyTree(polygons); return(s); }
public virtual void GetNextNoChildsTest() { PolyNode node = new PolyNode(); NUnit.Framework.Assert.IsNull(node.GetNext()); }
public List <PointF[]> Triangulate(PolyTree solution) { List <PointF[]> list = new List <PointF[]>(); Tess tess = new Tess(); tess.NoEmptyPolygons = true; Func <IntPoint, ContourVertex> selector = delegate(IntPoint p) { ContourVertex result = default(ContourVertex); result.Position = new Vec3 { X = (float)p.X, Y = (float)p.Y, Z = 0f }; return(result); }; for (PolyNode polyNode = solution.GetFirst(); polyNode != null; polyNode = polyNode.GetNext()) { if (!polyNode.IsOpen) { ContourVertex[] vertices = polyNode.Contour.Select(selector).ToArray(); tess.AddContour(vertices); } } tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); int elementCount = tess.ElementCount; for (int i = 0; i < elementCount; i++) { Vec3 position = tess.Vertices[tess.Elements[i * 3 + 0]].Position; Vec3 position2 = tess.Vertices[tess.Elements[i * 3 + 1]].Position; Vec3 position3 = tess.Vertices[tess.Elements[i * 3 + 2]].Position; List <PointF> list2 = new List <PointF> { new PointF(position.X, position.Y), new PointF(position2.X, position2.Y), new PointF(position3.X, position3.Y) }; if (Math.Cross(list2[0], list2[1], list2[2]) > 0f) { list2.Reverse(); } list.Add(list2.ToArray()); } return(list); }
//------------------------------------------------------------------------------ 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(); }
/// <summary> /// Get a list of triangles which will fill the area described by the slice /// </summary> public IEnumerable <Triangle> Triangles() { TriangleNet.Behavior behavior = new TriangleNet.Behavior(); behavior.ConformingDelaunay = true; foreach (var poly in IndividualPolygons()) { PolyNode node = polyTree.GetFirst(); InputGeometry geometry = new InputGeometry(); while (node != null) { var offset = geometry.Points.Count(); var index = 0; foreach (IntPoint point in node.Contour) { geometry.AddPoint(point.X, point.Y); if (index > 0) { geometry.AddSegment(index - 1 + offset, index + offset); } index++; } geometry.AddSegment(index - 1 + offset, offset); if (node.IsHole) { // To describe a hole, AddHole must be called with a location inside the hole. IntPoint last = new IntPoint(0, 0); bool lastKnown = false; double longest = 0; IntPoint longestAlong = new IntPoint(0, 0); IntPoint from = new IntPoint(0, 0); foreach (IntPoint point in node.Contour) { if (lastKnown) { IntPoint along = new IntPoint(point.X - last.X, point.Y - last.Y); double length = Math.Sqrt(along.X * along.X + along.Y * along.Y); if (length > longest) { longest = length; longestAlong = along; from = last; } } last = point; lastKnown = true; } if (longest > 0) { double perpendicularX = ((double)longestAlong.Y * (double)scale * 0.001d) / longest; double perpendicularY = -((double)longestAlong.X * (double)scale * 0.001d) / longest; geometry.AddHole(perpendicularX + from.X + longestAlong.X / 2.0d, perpendicularY + from.Y + longestAlong.Y / 2.0d); } else { } } node = node.GetNext(); } if (geometry.Points.Count() > 0) { var mesh = new TriangleNet.Mesh(behavior); mesh.Triangulate(geometry); mesh.Renumber(); foreach (Triangle t in this.GetMeshTriangles(mesh)) { yield return(t); } } } }