public static List <List <Vector2> > SimplifyPolygon(List <Vector2> polygon, PolyFillType polyFillType = PolyFillType.pftNonZero) { if (polygon == null || polygon.Count == 0) { return(null); } List <IntPoint> polygonInt = ConvertFloatToInt(polygon); List <List <IntPoint> > polygonsInt = Clipper.SimplifyPolygon(polygonInt, polyFillType); int polygonsIntCount = polygonsInt.Count, i; //, j, polygonCount; List <List <Vector2> > polygons = new List <List <Vector2> >(polygonsIntCount); for (i = 0; i < polygonsIntCount; i++) { //polygonCount = polygonsInt [i].Count; polygons.Add(ConvertIntToFloat(polygonsInt [i])); } if (polygons == null || polygons.Count == 0) { return(null); } return(polygons); }
public override bool Read(GH_IO.Serialization.GH_IReader reader) { Operation = (ClipType)reader.GetInt32("Operation"); FillType = (PolyFillType)reader.GetInt32("FillType"); return(base.Read(reader)); }
public static List<List<Vector2>> SimplifyPolygons(List<List<Vector2>> polygon, PolyFillType polyFillType = PolyFillType.pftNonZero) { if (polygon == null || polygon.Count == 0) return null; List<List<IntPoint>> polygonsInt = new List<List<IntPoint>>(); int i;//, j, polygonCount; for(i = 0; i < polygon.Count; i++) { polygonsInt.Add(ConvertFloatToInt(polygon[i])); } polygonsInt = Clipper.SimplifyPolygons(polygonsInt, polyFillType); int polygonsIntCount = polygonsInt.Count; List<List<Vector2>> polygons = new List<List<Vector2>>(polygonsIntCount); for (i = 0; i < polygonsIntCount; i++) { polygons.Add(ConvertIntToFloat(polygonsInt [i])); } if (polygons == null || polygons.Count == 0) return null; return polygons; }
/** * Note: this method will close all unclosed subpaths of the passed path. * * @param fillingRule If the subpath is contour, pass any value. */ protected internal Path FilterFillPath(Path path, Matrix ctm, int fillingRule) { path.CloseAllSubpaths(); Clipper clipper = new Clipper(); AddPath(clipper, path); foreach (Rectangle rectangle in rectangles) { Point2D[] transfRectVertices = TransformPoints(ctm, true, GetVertices(rectangle)); AddRect(clipper, transfRectVertices, PolyType.ptClip); } PolyFillType fillType = PolyFillType.pftNonZero; if (fillingRule == PathPaintingRenderInfo.EVEN_ODD_RULE) { fillType = PolyFillType.pftEvenOdd; } PolyTree resultTree = new PolyTree(); clipper.Execute(ClipType.ctDifference, resultTree, fillType, PolyFillType.pftNonZero); return(ConvertToPath(resultTree)); }
protected override void AppendAdditionalComponentMenuItems(System.Windows.Forms.ToolStripDropDown menu) { Menu_AppendItem(menu, "Even-Odd", (s, e) => { FillType = PolyFillType.pftEvenOdd; ExpireSolution(true); }, true, FillType == PolyFillType.pftEvenOdd); Menu_AppendItem(menu, "Non-Zero", (s, e) => { FillType = PolyFillType.pftNonZero; ExpireSolution(true); }, true, FillType == PolyFillType.pftNonZero); Menu_AppendItem(menu, "Positive", (s, e) => { FillType = PolyFillType.pftPositive; ExpireSolution(true); }, true, FillType == PolyFillType.pftPositive); Menu_AppendItem(menu, "Negative", (s, e) => { FillType = PolyFillType.pftNegative; ExpireSolution(true); }, true, FillType == PolyFillType.pftNegative); }
private void Init(IEnumerable <LineStrip> lines, Plane plane, PolyFillType pft = PolyFillType.pftEvenOdd) { transform = plane.CreateMatrix(); transform = Matrix4.Mult(transform, Matrix4.CreateScale(scale)); inverseTransform = Matrix4.Invert(transform); this.plane = plane; polyTree = GetPolyTree(lines, pft); }
/// <summary> /// Performs the clipping operation. /// Can be called multiple times without reassigning subject and clip polygons /// (ie when different clipping operations are required on the same polygon sets). /// </summary> /// <param name="clipType"> Type of the clipping operation. </param> /// <param name="output"> The List that will receive the result of the clipping operation. </param> /// <param name="subjectFillType"> Fill rule that will be applied to the subject paths. </param> /// <param name="clipFillType"> Fill rule that will be applied to the clip paths. </param> /// <returns> True if the operation was successful, false otherwise. </returns> public bool Clip(ClipType clipType, ref List <List <Vector2> > output, PolyFillType subjectFillType, PolyFillType clipFillType) { var intOutput = new List <List <IntPoint> >(); bool succeeded = clipper.Execute(clipType, intOutput, subjectFillType, clipFillType); ClipperUtility.ToVector2Paths(intOutput, ref output); return(succeeded); }
public void SimplifyPolygon(IEnumerable <Point2d> poly, List <Point2d> solution, PolyFillType fillType = PolyFillType.pftEvenOdd) { List <IntPoint> _poly = poly.Select(p => this.converter.ToIntPoint(p)).ToList(); Clipper.SimplifyPolygon(_poly, fillType); solution.AddRange(_poly.Select(p => this.converter.FromIntPoint(p))); }
public StyleInfo() { pft = PolyFillType.pftNonZero; brushClr = Color.AntiqueWhite; dashArray = null; penClr = Color.Black; penWidth = 0.8; showCoords = false; }
public void SimplifyPolygons <TPoly>(IEnumerable <TPoly> polys, List <List <Point2d> > solution, PolyFillType fillType = PolyFillType.pftEvenOdd) where TPoly : IEnumerable <Point2d> { List <List <IntPoint> > _polys = polys.Select(poly => poly.Select(p => this.converter.ToIntPoint(p)).ToList()).ToList(); Clipper.SimplifyPolygons(_polys, fillType); solution.AddRange(_polys.Select(poly => poly.Select(p => this.converter.FromIntPoint(p)).ToList())); }
/// <summary> /// Converts iText filling rule constant into the corresponding constant /// of the Clipper library. /// </summary> /// <param name="fillingRule"> /// Either /// <see cref="iText.Kernel.Pdf.Canvas.PdfCanvasConstants.FillingRule.NONZERO_WINDING"/> /// or /// <see cref="iText.Kernel.Pdf.Canvas.PdfCanvasConstants.FillingRule.EVEN_ODD"/>. /// </param> /// <returns>Clipper fill type constant.</returns> public static PolyFillType GetFillType(int fillingRule) { PolyFillType fillType = PolyFillType.NON_ZERO; if (fillingRule == PdfCanvasConstants.FillingRule.EVEN_ODD) { fillType = PolyFillType.EVEN_ODD; } return(fillType); }
public static List <List <Vector2> > Simplify(List <Vector2> polygon, FillMode fillMode, out PolyTree tree) { Clipper.Clear(); Clipper.AddPath(polygon, PolyType.ptSubject, true); Clipper.AddPath(polygon, PolyType.ptClip, true); tree = new PolyTree(); PolyFillType fillType = fillMode.ToPolyFillType(); Clipper.Execute(ClipType.ctUnion, tree, fillType, fillType); return(Clipper.ClosedPathsFromPolyTree(tree)); }
public bool Execute(ClipType clipType, List <List <Point2d> > solution, PolyFillType subjFillType, PolyFillType clipFillType) { List <List <IntPoint> > _solution = new List <List <IntPoint> >(); bool ret = this.clipper.Execute(clipType, _solution, subjFillType, clipFillType); if (!ret) { Debug.WriteLine("Error in clipper.Execute"); } solution.AddRange(_solution.Select(poly => poly.Select(p => this.converter.FromIntPoint(p)).ToList())); return(ret); }
/// <summary> /// Joins all the polygones. /// ClipType: http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/ClipType.htm /// PolyFillType: http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/PolyFillType.htm /// </summary> /// <param name="sList">The s list.</param> /// <param name="cType">Type of the c.</param> /// <param name="pType">Type of the p.</param> /// <param name="pFType1">The p f type1.</param> /// <param name="pFType2">The p f type2.</param> /// <returns></returns> public static List <Polygon> JoinPolygons( this List <Polygon> sList, ClipType cType, PolyType pType = PolyType.ptClip, PolyFillType pFType1 = PolyFillType.pftNonZero, PolyFillType pFType2 = PolyFillType.pftNonZero) { var p = ClipPolygons(sList); var tList = new List <List <IntPoint> >(); var c = new Clipper(); c.AddPaths(p, pType, true); c.Execute(cType, tList, pFType1, pFType2); return(ToPolygons(tList)); }
//--------------------------------------------------------------------- private void bSave_Click(object sender, EventArgs e) { //save to SVG ... if (saveFileDialog1.ShowDialog() == DialogResult.OK) { PolyFillType pft = GetPolyFillType(); SVGBuilder svg = new SVGBuilder(); svg.style.brushClr = Color.FromArgb(0x10, 0, 0, 0x9c); svg.style.penClr = Color.FromArgb(0xd3, 0xd3, 0xda); svg.AddPolygons(subjects); svg.style.brushClr = Color.FromArgb(0x10, 0x9c, 0, 0); svg.style.penClr = Color.FromArgb(0xff, 0xa0, 0x7a); svg.AddPolygons(clips); svg.style.brushClr = Color.FromArgb(0xAA, 0x80, 0xff, 0x9c); svg.style.penClr = Color.FromArgb(0, 0x33, 0); svg.AddPolygons(solution); svg.SaveToFile(saveFileDialog1.FileName, 1.0 / scale); } }
private PolyTree GetPolyTree(IEnumerable <LineStrip> lines, PolyFillType pft) { Paths polygons = new Paths(); Clipper c = new Clipper(); c.Clear(); foreach (var line in lines) { polygons.Add(LineStripToPolygon(line)); } polygons = Clipper.SimplifyPolygons(polygons, pft); c.AddPaths(polygons, PolyType.ptSubject, true); PolyTree tree = new PolyTree(); c.Execute(ClipType.ctUnion, tree); return(tree); }
public static List <Polyline> Boolean(ClipType clipType, IEnumerable <Polyline> polyA, IEnumerable <Polyline> polyB, Plane pln, double tolerance, bool evenOddFilling) { Clipper clipper = new Clipper(0); PolyFillType polyfilltype = PolyFillType.pftEvenOdd; if (!evenOddFilling) { polyfilltype = PolyFillType.pftNonZero; } List <List <IntPoint> > PathsA = new List <List <IntPoint> >(); List <List <IntPoint> > PathsB = new List <List <IntPoint> >(); foreach (Polyline plA in polyA) { clipper.AddPath(plA.ToPath2D(pln, tolerance), PolyType.ptSubject, plA.IsClosed); } foreach (Polyline plB in polyB) { clipper.AddPath(plB.ToPath2D(pln, tolerance), PolyType.ptClip, true); } PolyTree OutputTree = new PolyTree(); clipper.Execute(clipType, OutputTree, polyfilltype, polyfilltype); List <Polyline> Output = new List <Polyline> (); foreach (PolyNode pn in OutputTree.Iterate()) { if (pn.Contour.Count > 1) { Output.Add(pn.Contour.ToPolyline(pln, tolerance, !pn.IsOpen)); } } return(Output); }
/// <summary>Note: this method will close all unclosed subpaths of the passed path.</summary> /// <param name="fillingRule">If the subpath is contour, pass any value.</param> protected internal virtual Path FilterFillPath(Path path, Matrix ctm, int fillingRule) { path.CloseAllSubpaths(); Clipper clipper = new Clipper(); ClipperBridge.AddPath(clipper, path, PolyType.SUBJECT); foreach (Rectangle rectangle in regions) { Point[] transfRectVertices = TransformPoints(ctm, true, GetRectangleVertices(rectangle)); ClipperBridge.AddRectToClipper(clipper, transfRectVertices, PolyType.CLIP); } PolyFillType fillType = PolyFillType.NON_ZERO; if (fillingRule == PdfCanvasConstants.FillingRule.EVEN_ODD) { fillType = PolyFillType.EVEN_ODD; } PolyTree resultTree = new PolyTree(); clipper.Execute(ClipType.DIFFERENCE, resultTree, fillType, PolyFillType.NON_ZERO); return(ClipperBridge.ConvertToPath(resultTree)); }
public static List <Polyline> Boolean(ClipType clipType, IEnumerable <Polyline> polyA, IEnumerable <Polyline> polyB, Plane pln, double tolerance, bool evenOddFilling) { NGonsCore.Clipper642.Clipper clipper = new NGonsCore.Clipper642.Clipper(); PolyFillType polyfilltype = PolyFillType.pftEvenOdd; if (!evenOddFilling) { polyfilltype = PolyFillType.pftNonZero; } foreach (Polyline plA in polyA) { clipper.AddPath(plA.ToPath2D(pln, tolerance), PolyType.ptSubject, plA.IsClosed); } foreach (Polyline plB in polyB) { clipper.AddPath(plB.ToPath2D(pln, tolerance), PolyType.ptClip, true); } PolyTree polytree = new PolyTree(); clipper.Execute(clipType, polytree, polyfilltype, polyfilltype); List <Polyline> output = new List <Polyline>(); // ReSharper disable once LoopCanBeConvertedToQuery foreach (PolyNode pn in polytree.Iterate()) { if (pn.Contour.Count > 1) { output.Add(pn.Contour.ToPolyline(pln, tolerance, !pn.IsOpen)); } } return(output); }
public static Mesh CreatePolygon(List <List <Vector2> > inputShapes, SVGPaintable paintable, SVGMatrix matrix, out Mesh antialiasingMesh) { antialiasingMesh = null; if (inputShapes == null || inputShapes.Count == 0) { return(null); } List <List <Vector2> > simplifiedShapes = new List <List <Vector2> >(); PolyFillType fillType = PolyFillType.pftNonZero; if (paintable.fillRule == SVGFillRule.EvenOdd) { fillType = PolyFillType.pftEvenOdd; } simplifiedShapes = SVGGeom.SimplifyPolygons(inputShapes, fillType); if (simplifiedShapes == null || simplifiedShapes.Count == 0) { return(null); } AddInputShape(simplifiedShapes); Rect bounds = GetRect(simplifiedShapes); switch (paintable.GetPaintType()) { case SVGPaintMethod.SolidGradientFill: { Color color = Color.black; SVGColorType colorType = paintable.fillColor.Value.colorType; if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None) { color.a *= paintable.fillOpacity; paintable.svgFill = new SVGFill(color); } else { color = paintable.fillColor.Value.color; color.a *= paintable.fillOpacity; paintable.svgFill = new SVGFill(color); } paintable.svgFill.fillType = FILL_TYPE.SOLID; if (color.a == 1) { paintable.svgFill.blend = FILL_BLEND.OPAQUE; } else { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } } break; case SVGPaintMethod.LinearGradientFill: { SVGLinearGradientBrush linearGradBrush = paintable.GetLinearGradientBrush(bounds, matrix); paintable.svgFill = linearGradBrush.fill; } break; case SVGPaintMethod.RadialGradientFill: { SVGRadialGradientBrush radialGradBrush = paintable.GetRadialGradientBrush(bounds, matrix); paintable.svgFill = radialGradBrush.fill; } break; case SVGPaintMethod.ConicalGradientFill: { SVGConicalGradientBrush conicalGradBrush = paintable.GetConicalGradientBrush(bounds, matrix); paintable.svgFill = conicalGradBrush.fill; } break; case SVGPaintMethod.PathDraw: { Color color = Color.black; SVGColorType colorType = paintable.fillColor.Value.colorType; if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None) { color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color); } else { color = paintable.fillColor.Value.color; color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color); } paintable.svgFill.fillType = FILL_TYPE.SOLID; if (color.a == 1) { paintable.svgFill.blend = FILL_BLEND.OPAQUE; } else { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } } break; default: break; } LibTessDotNet.Tess tesselation = new LibTessDotNet.Tess(); LibTessDotNet.ContourVertex[] path; int pathLength; for (int i = 0; i < simplifiedShapes.Count; i++) { if (simplifiedShapes[i] == null) { continue; } pathLength = simplifiedShapes[i].Count; path = new LibTessDotNet.ContourVertex[pathLength]; Vector2 position; for (int j = 0; j < pathLength; j++) { position = simplifiedShapes[i][j]; path[j].Position = new LibTessDotNet.Vec3 { X = position.x, Y = position.y, Z = 0f }; } tesselation.AddContour(path); } tesselation.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3); Mesh mesh = new Mesh(); int meshVertexCount = tesselation.Vertices.Length; Vector3[] vertices = new Vector3[meshVertexCount]; Vector2[] uv = null; Vector2[] uv2 = null; for (int i = 0; i < meshVertexCount; i++) { vertices[i] = new Vector3(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y, 0f); } int numTriangles = tesselation.ElementCount; int[] triangles = new int[numTriangles * 3]; for (int i = 0; i < numTriangles; i++) { triangles[i * 3] = tesselation.Elements[i * 3]; triangles[i * 3 + 1] = tesselation.Elements[i * 3 + 1]; triangles[i * 3 + 2] = tesselation.Elements[i * 3 + 2]; } SVGFill svgFill = paintable.svgFill; Color32 fillColor = Color.white; if (svgFill.fillType != FILL_TYPE.GRADIENT && svgFill.gradientColors == null) { fillColor = svgFill.color; } antialiasingMesh = CreateAntialiasing(simplifiedShapes, fillColor, -SVGAssetImport.antialiasingWidth, false, SVGImporter.Utils.ClosePathRule.ALWAYS); Color32[] colors32 = new Color32[meshVertexCount]; for (int i = 0; i < meshVertexCount; i++) { colors32 [i].r = fillColor.r; colors32 [i].g = fillColor.g; colors32 [i].b = fillColor.b; colors32 [i].a = fillColor.a; } if (antialiasingMesh != null) { Vector3[] antialiasingVertices = antialiasingMesh.vertices; Vector2[] antialiasingUV = antialiasingMesh.uv; Vector2[] antialiasingUV2 = antialiasingMesh.uv2; WriteUVGradientCoordinates(ref antialiasingUV, antialiasingVertices, paintable, bounds); WriteUVGradientIndexType(ref antialiasingUV2, antialiasingVertices.Length, paintable); antialiasingMesh.uv = antialiasingUV; antialiasingMesh.uv2 = antialiasingUV2; } WriteUVGradientCoordinates(ref uv, vertices, paintable, bounds); WriteUVGradientIndexType(ref uv2, meshVertexCount, paintable); mesh.vertices = vertices; mesh.triangles = triangles; if (colors32 != null) { mesh.colors32 = colors32; } if (uv != null) { mesh.uv = uv; } if (uv2 != null) { mesh.uv2 = uv2; } return(mesh); }
private void Init(IEnumerable<LineStrip> lines, Plane plane, PolyFillType pft = PolyFillType.pftEvenOdd) { transform = plane.CreateMatrix(); transform = Matrix4.Mult(transform, Matrix4.CreateScale(scale)); inverseTransform = Matrix4.Invert(transform); this.plane = plane; polyTree = GetPolyTree(lines, pft); }
public static IEnumerable <Rhino.Geometry.Curve> Boolean(ClipType operation, PolyFillType fillType, IEnumerable <Rhino.Geometry.Curve> curvesA, IEnumerable <Rhino.Geometry.Curve> curvesB, Plane?plane) { var closedA = curvesA.Where(o => o.IsClosed); var closedB = curvesB.Where(o => o.IsClosed); if (!plane.HasValue) { foreach (var curve in closedA) { var curvePlane = default(Plane); if (!curve.TryGetPlane(out curvePlane)) { continue; } plane = curvePlane; } } if (!plane.HasValue) { plane = Plane.WorldXY; } var polylinesA = new List <List <Point2d> >(); var polylinesB = new List <List <Point2d> >(); foreach (var curve in closedA) { var polyline = default(Polyline); if (!curve.TryGetPolyline(out polyline)) { continue; } polylinesA.Add(polyline.Select(o => o.Map2D(plane.Value)).ToList()); } foreach (var curve in closedB) { var polyline = default(Polyline); if (!curve.TryGetPolyline(out polyline)) { continue; } polylinesB.Add(polyline.Select(o => o.Map2D(plane.Value)).ToList()); } var minX = polylinesA.Union(polylinesB).SelectMany(o => o).Min(o => o.X); var minY = polylinesA.Union(polylinesB).SelectMany(o => o).Min(o => o.Y); var maxX = polylinesA.Union(polylinesB).SelectMany(o => o).Max(o => o.X); var maxY = polylinesA.Union(polylinesB).SelectMany(o => o).Max(o => o.Y); var unit = Math.Max(maxX - minX, maxY - minY) / (2 * 4.6e+18); var midX = (minX + maxX) / 2.0; var midY = (minY + maxY) / 2.0; var polygonsA = polylinesA.Select(o => o.Select(p => new IntPoint((p.X - midX) / unit, (p.Y - midY) / unit)).ToList()) .ToList(); var polygonsB = polylinesB.Select(o => o.Select(p => new IntPoint((p.X - midX) / unit, (p.Y - midY) / unit)).ToList()) .ToList(); var clipper = new Clipper(); clipper.AddPaths(polygonsA, PolyType.ptSubject, true); clipper.AddPaths(polygonsB, PolyType.ptClip, true); var solution = new List <List <IntPoint> >(); clipper.Execute(operation, solution, fillType, fillType); return(solution.Select(o => { var points = o.Select(p => plane.Value.Origin + (p.X * unit + midX) * plane.Value.XAxis + (p.Y * unit + midY) * plane.Value.YAxis) .ToList(); if (points.Count > 0 && points.First() != points.Last()) { points.Add(points[0]); } return new PolylineCurve(points); })); }
//------------------------------------------------------------------------------ public static Paths SimplifyPolygons(Paths polys, PolyFillType fillType = PolyFillType.pftEvenOdd) { Paths result = new Paths(); Clipper c = new Clipper(); c.StrictlySimple = true; c.AddPaths(polys, PolyType.ptSubject, true); c.Execute(ClipType.ctUnion, result, fillType, fillType); return result; }
private PolyTree GetPolyTree(IEnumerable<LineStrip> lines, PolyFillType pft) { Paths polygons = new Paths(); Clipper c = new Clipper(); c.Clear(); foreach (var line in lines) { polygons.Add(LineStripToPolygon(line)); } polygons = Clipper.SimplifyPolygons(polygons, pft); c.AddPaths(polygons, PolyType.ptSubject, true); PolyTree tree = new PolyTree(); c.Execute(ClipType.ctUnion, tree); return tree; }
private static Polygons CombinePolygons(this Polygons aPolys, Polygons bPolys, ClipType clipType, PolyFillType fillType = PolyFillType.pftEvenOdd) { var clipper = new Clipper(); clipper.AddPaths(aPolys, PolyType.ptSubject, true); clipper.AddPaths(bPolys, PolyType.ptClip, true); var outputPolys = new Polygons(); clipper.Execute(clipType, outputPolys, fillType); return(outputPolys); }
private void AppendFillTypeMenuItem(System.Windows.Forms.ToolStripDropDown menu, string text, PolyFillType fillType) { Menu_AppendItem(menu, text, (s, e) => { RecordUndoEvent("FillType"); FillType = fillType; ExpireSolution(true); }, true, FillType == fillType); }
/// <summary> /// Performs the Boolean Operations from the Clipper Library /// </summary> /// <param name="clipType"></param> /// <param name="subject"></param> /// <param name="clip"></param> /// <param name="simplifyPriorToBooleanOperation"></param> /// <param name="scale"></param> /// <param name="fillMethod"></param> /// <returns></returns> /// <exception cref="Exception"></exception> private static List <Polygon> BooleanViaClipper(PolyFillType fillMethod, ClipType clipType, IEnumerable <Polygon> subject, IEnumerable <Polygon> clip = null, bool subjectIsClosed = true, bool clipIsClosed = true) { //Remove any polygons that are only a line. //subject = subject.Where(p => p.Count > 2); //clip = clip?.Where(p => p.Count > 2); var simplifyPriorToBooleanOperation = true; if (simplifyPriorToBooleanOperation) { //subject = subject.Select(p=>SimplifyFuzzy(p)); subject = subject.Select(p => Simplify(p, 0.0000003)); } if (simplifyPriorToBooleanOperation) { //If not null //clip = clip?.Select(p => SimplifyFuzzy(p)); clip = clip?.Select(p => Simplify(p, 0.0000003)); } if (!subject.Any()) { if (clip == null || !clip.Any()) { return(new List <Polygon>()); } //Use the clip as the subject if this is a union operation and the clip is not null. if (clipType == ClipType.ctUnion) { subject = clip; clip = null; } } var subjectAll = subject.SelectMany(p => p.AllPolygons).ToList(); var clipperSolution = new List <List <IntPoint> >(); //Convert Points (TVGL) to IntPoints (Clipper) var clipperSubject = subjectAll.Select(loop => loop.Vertices.Select(point => new IntPoint(point.X * scale, point.Y * scale)).ToList()).ToList(); //Setup Clipper var clipper = new ClipperLib.Clipper() { StrictlySimple = true }; clipper.AddPaths(clipperSubject, PolyType.ptSubject, subjectIsClosed); if (clip != null) { var clipAll = clip.SelectMany(p => p.AllPolygons).ToList(); var clipperClip = clipAll.Select(loop => loop.Vertices.Select(point => new IntPoint(point.X * scale, point.Y * scale)).ToList()).ToList(); clipper.AddPaths(clipperClip, PolyType.ptClip, clipIsClosed); } //Begin an evaluation var result = clipper.Execute(clipType, clipperSolution, fillMethod, fillMethod); if (!result) { throw new Exception("Clipper Union Failed"); } //Convert back to points and return solution var solution = clipperSolution.Select(clipperPath => new Polygon(clipperPath.Select(point => new Vector2(point.X / scale, point.Y / scale)))); return(solution.CreateShallowPolygonTrees(true)); }
//------------------------------------------------------------------------------ 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(); }
public static void TesselateStroke(List <List <Vector2> > inputShapes, Color32 color, out List <List <Vector2> > simplifiedShapes, out Vector3[] vertices, out int[] triangles, out Color32[] colors32) { simplifiedShapes = null; vertices = null; triangles = null; colors32 = null; if (inputShapes == null || inputShapes.Count == 0) { return; } int i, j; simplifiedShapes = new List <List <Vector2> >(); PolyFillType fillType = PolyFillType.pftNonZero; for (i = 0; i < inputShapes.Count; i++) { if (inputShapes[i] == null || inputShapes.Count == 0) { continue; } List <List <Vector2> > output = SVGGeom.SimplifyPolygon(inputShapes[i], fillType); if (output == null || output.Count == 0) { simplifiedShapes.Add(inputShapes[i]); } else { simplifiedShapes.AddRange(output); } } LibTessDotNet.Tess tesselation = new LibTessDotNet.Tess(); LibTessDotNet.ContourVertex[] path; for (i = 0; i < simplifiedShapes.Count; i++) { if (simplifiedShapes[i] == null || simplifiedShapes[i].Count < 2) { continue; } path = new LibTessDotNet.ContourVertex[simplifiedShapes[i].Count]; for (j = 0; j < simplifiedShapes[i].Count; j++) { path[j].Position = new LibTessDotNet.Vec3 { X = simplifiedShapes[i][j].x, Y = simplifiedShapes[i][j].y, Z = 0f }; } tesselation.AddContour(path); } tesselation.Tessellate(LibTessDotNet.WindingRule.Positive, LibTessDotNet.ElementType.Polygons, 3); if (tesselation.Vertices == null || tesselation.Vertices.Length == 0) { return; } int numVertices = tesselation.Vertices.Length; int numTriangles = tesselation.ElementCount * 3; triangles = new int[numTriangles]; vertices = new Vector3[numVertices]; colors32 = new Color32[numVertices]; for (i = 0; i < numVertices; i++) { vertices[i] = new Vector3(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y, 0f); colors32[i] = color; } for (i = 0; i < numTriangles; i += 3) { triangles[i] = tesselation.Elements[i]; triangles[i + 1] = tesselation.Elements[i + 1]; triangles[i + 2] = tesselation.Elements[i + 2]; } }
public static bool CreatePolygon(List <List <Vector2> > inputShapes, SVGPaintable paintable, SVGMatrix matrix, out SVGLayer layer, bool isStroke = false) { layer = new SVGLayer(); if (inputShapes == null || inputShapes.Count == 0) { return(false); } List <List <Vector2> > simplifiedShapes = new List <List <Vector2> >(); PolyFillType fillType = PolyFillType.pftNonZero; if (paintable.fillRule == SVGFillRule.EvenOdd) { fillType = PolyFillType.pftEvenOdd; } simplifiedShapes = SVGGeom.SimplifyPolygons(inputShapes, fillType); if (simplifiedShapes == null || simplifiedShapes.Count == 0) { return(false); } AddInputShape(simplifiedShapes); Rect bounds = GetRect(simplifiedShapes); Rect viewport = paintable.viewport; if (!isStroke) { switch (paintable.GetPaintType()) { case SVGPaintMethod.SolidFill: { Color color = Color.black; SVGColorType colorType = paintable.fillColor.Value.colorType; if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None) { color.a *= paintable.fillOpacity; paintable.svgFill = new SVGFill(color); } else { color = paintable.fillColor.Value.color; color.a *= paintable.fillOpacity; paintable.svgFill = new SVGFill(color); } paintable.svgFill.fillType = FILL_TYPE.SOLID; if (color.a == 1) { paintable.svgFill.blend = FILL_BLEND.OPAQUE; } else { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } } break; case SVGPaintMethod.LinearGradientFill: { SVGLinearGradientBrush linearGradBrush = paintable.GetLinearGradientBrush(bounds, matrix, viewport); paintable.svgFill = linearGradBrush.fill; } break; case SVGPaintMethod.RadialGradientFill: { SVGRadialGradientBrush radialGradBrush = paintable.GetRadialGradientBrush(bounds, matrix, viewport); paintable.svgFill = radialGradBrush.fill; } break; case SVGPaintMethod.ConicalGradientFill: { SVGConicalGradientBrush conicalGradBrush = paintable.GetConicalGradientBrush(bounds, matrix, viewport); paintable.svgFill = conicalGradBrush.fill; } break; case SVGPaintMethod.PathDraw: { Color color = Color.black; SVGColorType colorType = paintable.fillColor.Value.colorType; if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None) { color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color); } else { color = paintable.fillColor.Value.color; color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color); } paintable.svgFill.fillType = FILL_TYPE.SOLID; if (color.a == 1) { paintable.svgFill.blend = FILL_BLEND.OPAQUE; } else { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } } break; default: break; } } else { Color color = paintable.strokeColor.Value.color; color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color, FILL_BLEND.OPAQUE, FILL_TYPE.SOLID); if (color.a != 1f) { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } paintable.svgFill.color = color; } LibTessDotNet.Tess tesselation = new LibTessDotNet.Tess(); LibTessDotNet.ContourVertex[] path; int pathLength; for (int i = 0; i < simplifiedShapes.Count; i++) { if (simplifiedShapes[i] == null) { continue; } pathLength = simplifiedShapes[i].Count; path = new LibTessDotNet.ContourVertex[pathLength]; Vector2 position; for (int j = 0; j < pathLength; j++) { position = simplifiedShapes[i][j]; path[j].Position = new LibTessDotNet.Vec3 { X = position.x, Y = position.y, Z = 0f }; } tesselation.AddContour(path, SVGImporter.LibTessDotNet.ContourOrientation.Clockwise); } tesselation.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3); int meshVertexCount = tesselation.Vertices.Length; layer.vertices = new Vector2[meshVertexCount]; for (int i = 0; i < meshVertexCount; i++) { layer.vertices[i] = new Vector2(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y) * SVGAssetImport.meshScale; } int numTriangles = tesselation.ElementCount; layer.triangles = new int[numTriangles * 3]; for (int i = 0; i < numTriangles; i++) { layer.triangles[i * 3] = tesselation.Elements[i * 3]; layer.triangles[i * 3 + 1] = tesselation.Elements[i * 3 + 1]; layer.triangles[i * 3 + 2] = tesselation.Elements[i * 3 + 2]; } layer.fill = paintable.svgFill; layer.fill.opacity = paintable.opacity; if (layer.fill.opacity < 1f && layer.fill.blend == FILL_BLEND.OPAQUE) { layer.fill.blend = FILL_BLEND.ALPHA_BLENDED; } if (layer.fill.fillType == FILL_TYPE.GRADIENT && layer.fill.gradientColors != null) { layer.fill.color = Color.white; } else if (layer.fill.fillType == FILL_TYPE.TEXTURE) { layer.fill.color = Color.white; } viewport.x *= SVGAssetImport.meshScale; viewport.y *= SVGAssetImport.meshScale; viewport.size *= SVGAssetImport.meshScale; layer.fill.viewport = viewport; if (layer.fill.transform != null) { SVGMatrix scaleMatrix = SVGMatrix.Identity().Scale(SVGAssetImport.meshScale); layer.fill.transform = scaleMatrix.Multiply(layer.fill.transform); layer.fill.transform = layer.fill.transform.Multiply(scaleMatrix.Inverse()); } Vector2 boundsMin = bounds.min * SVGAssetImport.meshScale; Vector2 boundsMax = bounds.max * SVGAssetImport.meshScale; layer.bounds = new Rect(boundsMin.x, boundsMin.y, boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y); return(true); }
//------------------------------------------------------------------------------ public bool Execute(ClipType clipType, PolyTree polytree, PolyFillType subjFillType, PolyFillType clipFillType) { if (m_ExecuteLocked) return false; m_ExecuteLocked = true; m_SubjFillType = subjFillType; m_ClipFillType = clipFillType; m_ClipType = clipType; m_UsingPolyTree = true; bool succeeded = ExecuteInternal(); //build the return polygons ... if (succeeded) BuildResult2(polytree); m_ExecuteLocked = false; return succeeded; }
//------------------------------------------------------------------------------ public static List<List<IntPoint>> SimplifyPolygons(List<List<IntPoint>> polys, PolyFillType fillType = PolyFillType.pftEvenOdd) { List<List<IntPoint>> result = new List<List<IntPoint>>(); Clipper c = new Clipper(); c.StrictlySimple = true; c.AddPaths(polys, PolyType.ptSubject, true); c.Execute(ClipType.ctUnion, result, fillType, fillType); return result; }
public static bool CreatePolygon(List <List <Vector2> > inputShapes, SVGPaintable paintable, SVGMatrix matrix, out SVGShape layer, out SVGShape antialiasingLayer, bool isStroke = false, bool antialiasing = false) { layer = new SVGShape(); antialiasingLayer = new SVGShape(); if (inputShapes == null || inputShapes.Count == 0) { return(false); } List <List <Vector2> > simplifiedShapes = new List <List <Vector2> >(); PolyFillType fillType = PolyFillType.pftNonZero; if (paintable.fillRule == SVGFillRule.EvenOdd) { fillType = PolyFillType.pftEvenOdd; } simplifiedShapes = SVGGeom.SimplifyPolygons(inputShapes, fillType); if (simplifiedShapes == null || simplifiedShapes.Count == 0) { return(false); } AddInputShape(simplifiedShapes); Rect bounds = GetRect(simplifiedShapes); Rect viewport = paintable.viewport; if (!isStroke) { switch (paintable.GetPaintType()) { case SVGPaintMethod.SolidFill: { layer.type = SVGShapeType.FILL; Color color = Color.black; SVGColorType colorType = paintable.fillColor.Value.colorType; if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None) { color.a *= paintable.fillOpacity; paintable.svgFill = new SVGFill(color); } else { color = paintable.fillColor.Value.color; color.a *= paintable.fillOpacity; paintable.svgFill = new SVGFill(color); } paintable.svgFill.fillType = FILL_TYPE.SOLID; if (color.a == 1) { paintable.svgFill.blend = FILL_BLEND.OPAQUE; } else { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } } break; case SVGPaintMethod.LinearGradientFill: { layer.type = SVGShapeType.FILL; SVGLinearGradientBrush linearGradBrush = paintable.GetLinearGradientBrush(bounds, matrix, viewport); paintable.svgFill = linearGradBrush.fill; } break; case SVGPaintMethod.RadialGradientFill: { layer.type = SVGShapeType.FILL; SVGRadialGradientBrush radialGradBrush = paintable.GetRadialGradientBrush(bounds, matrix, viewport); paintable.svgFill = radialGradBrush.fill; } break; case SVGPaintMethod.ConicalGradientFill: { layer.type = SVGShapeType.FILL; SVGConicalGradientBrush conicalGradBrush = paintable.GetConicalGradientBrush(bounds, matrix, viewport); paintable.svgFill = conicalGradBrush.fill; } break; case SVGPaintMethod.PathDraw: { layer.type = SVGShapeType.STROKE; Color color = Color.black; SVGColorType colorType = paintable.fillColor.Value.colorType; if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None) { color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color); } else { color = paintable.fillColor.Value.color; color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color); } paintable.svgFill.fillType = FILL_TYPE.SOLID; if (color.a == 1) { paintable.svgFill.blend = FILL_BLEND.OPAQUE; } else { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } } break; default: break; } } else { layer.type = SVGShapeType.STROKE; Color color = paintable.strokeColor.Value.color; color.a *= paintable.strokeOpacity; paintable.svgFill = new SVGFill(color, FILL_BLEND.OPAQUE, FILL_TYPE.SOLID); if (color.a != 1f) { paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED; } paintable.svgFill.color = color; } // Use LibTessDotNet if (true) { LibTessDotNet.Tess tesselation = new LibTessDotNet.Tess(); LibTessDotNet.ContourVertex[] path; int pathLength; for (int i = 0; i < simplifiedShapes.Count; i++) { if (simplifiedShapes[i] == null) { continue; } pathLength = simplifiedShapes[i].Count; path = new LibTessDotNet.ContourVertex[pathLength]; Vector2 position; for (int j = 0; j < pathLength; j++) { position = simplifiedShapes[i][j]; path[j].Position = new LibTessDotNet.Vec3 { X = position.x, Y = position.y, Z = 0f }; } tesselation.AddContour(path, SVGImporter.LibTessDotNet.ContourOrientation.Clockwise); } tesselation.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3); int meshVertexCount = tesselation.Vertices.Length; if (meshVertexCount == 0) { return(false); } int numTriangles = tesselation.ElementCount; layer.triangles = new int[numTriangles * 3]; layer.vertices = new Vector2[meshVertexCount]; for (int i = 0; i < numTriangles; i++) { layer.triangles[i * 3] = tesselation.Elements[i * 3]; layer.triangles[i * 3 + 1] = tesselation.Elements[i * 3 + 1]; layer.triangles[i * 3 + 2] = tesselation.Elements[i * 3 + 2]; } for (int i = 0; i < meshVertexCount; i++) { layer.vertices[i] = new Vector2(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y) * SVGAssetImport.meshScale; } } /* * else { * // Use Triangle.net library * SVGImporter.TriangleNet.Mesh triangleMesh = new SVGImporter.TriangleNet.Mesh(); * SVGImporter.TriangleNet.Geometry.InputGeometry triangleInput = new SVGImporter.TriangleNet.Geometry.InputGeometry(); * * int pathLength, m = 0; * for(int i = 0; i < simplifiedShapes.Count; i++) * { * if(simplifiedShapes[i] == null) * continue; * * pathLength = simplifiedShapes[i].Count; * Vector2 position; * for(int j = 0; j < pathLength; j++) * { * triangleInput.AddPoint(simplifiedShapes[i][j].x, simplifiedShapes[i][j].y); * } * } * * triangleMesh.Triangulate(triangleInput); * * int totalVertices = triangleMesh.vertices.Count; * layer.vertices = new Vector2[totalVertices]; * for(int i = 0; i < totalVertices; i++) * { * layer.vertices[i].x = (float)triangleMesh.vertices[i].x * SVGAssetImport.meshScale; * layer.vertices[i].y = (float)triangleMesh.vertices[i].y * SVGAssetImport.meshScale; * } * * int totalTriangles = triangleMesh.triangles.Count; * layer.triangles = new int[totalTriangles * 3]; * int ti = 0; * for(int i = 0; i < totalTriangles; i++) * { * ti = i * 3; * layer.triangles[ti] = triangleMesh.triangles[i].P0; * layer.triangles[ti + 1] = triangleMesh.triangles[i].P1; * layer.triangles[ti + 2] = triangleMesh.triangles[i].P2; * } * } */ layer.fill = paintable.svgFill; layer.fill.opacity = paintable.opacity; if (layer.fill.opacity < 1f && layer.fill.blend == FILL_BLEND.OPAQUE) { layer.fill.blend = FILL_BLEND.ALPHA_BLENDED; } if (layer.fill.fillType == FILL_TYPE.GRADIENT && layer.fill.gradientColors != null) { layer.fill.color = Color.white; } else if (layer.fill.fillType == FILL_TYPE.TEXTURE) { layer.fill.color = Color.white; } viewport.x *= SVGAssetImport.meshScale; viewport.y *= SVGAssetImport.meshScale; viewport.size *= SVGAssetImport.meshScale; layer.fill.viewport = viewport; SVGMatrix scaleMatrix = SVGMatrix.identity.Scale(SVGAssetImport.meshScale); layer.fill.transform = scaleMatrix.Multiply(layer.fill.transform); layer.fill.transform = layer.fill.transform.Multiply(scaleMatrix.Inverse()); Vector2 boundsMin = bounds.min * SVGAssetImport.meshScale; Vector2 boundsMax = bounds.max * SVGAssetImport.meshScale; layer.bounds = new Rect(boundsMin.x, boundsMin.y, boundsMax.x - boundsMin.x, boundsMax.y - boundsMin.y); if (antialiasing) { if (CreateAntialiasing(simplifiedShapes, out antialiasingLayer, Color.white, -1f, ClosePathRule.ALWAYS)) { int verticesLength = antialiasingLayer.vertices.Length; for (int i = 0; i < verticesLength; i++) { antialiasingLayer.vertices[i] *= SVGAssetImport.meshScale; } antialiasingLayer.type = SVGShapeType.ANTIALIASING; antialiasingLayer.RecalculateBounds(); antialiasingLayer.fill = layer.fill.Clone(); antialiasingLayer.fill.blend = FILL_BLEND.ALPHA_BLENDED; } } return(true); }
public static Polygons Union(this Polygons polygons, Polygons other, PolyFillType fillType = PolyFillType.pftEvenOdd) { return(polygons.CombinePolygons(other, ClipType.ctUnion, fillType)); }
//------------------------------------------------------------------------------ public bool Execute(ClipType clipType, PolyTree polytree, PolyFillType FillType = PolyFillType.pftEvenOdd) { return Execute(clipType, polytree, FillType, FillType); }
public bool Execute(ClipType clipType, List <List <Point2d> > solution, PolyFillType fillType = PolyFillType.pftEvenOdd) { return(this.Execute(clipType, solution, fillType, fillType)); }
//------------------------------------------------------------------------------ public bool Execute(ClipType clipType, Paths solution, PolyFillType subjFillType, PolyFillType clipFillType) { if (m_ExecuteLocked) return false; if (m_HasOpenPaths) throw new ClipperException("Error: PolyTree struct is need for open path clipping."); m_ExecuteLocked = true; solution.Clear(); m_SubjFillType = subjFillType; m_ClipFillType = clipFillType; m_ClipType = clipType; m_UsingPolyTree = false; bool succeeded = ExecuteInternal(); //build the return polygons ... if (succeeded) BuildResult(solution); m_ExecuteLocked = false; return succeeded; }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // SimplifyPolygon functions ... // Convert self-intersecting polygons into simple polygons //------------------------------------------------------------------------------ public static PolygonsClp SimplifyPolygon(PolygonClp poly, PolyFillType fillType = PolyFillType.pftEvenOdd) { PolygonsClp result = new PolygonsClp(); Clipper c = new Clipper(); c.ForceSimple = true; c.AddPolygon(poly, PolyType.ptSubject); c.Execute(ClipType.ctUnion, result, fillType, fillType); return result; }
//////////////////////////////////////////////// static void Main(string[] args) { ////quick test with random polygons ... //Polygons ss = new Polygons(1), cc = new Polygons(1), sss = new Polygons(); //Random r = new Random((int)DateTime.Now.Ticks); //int scale = 1000000000; //tests 128bit math //ss.Add(MakeRandomPolygon(r, 400, 350, 9, scale)); //cc.Add(MakeRandomPolygon(r, 400, 350, 9, scale)); //Clipper cpr = new Clipper(); //cpr.AddPolygons(ss, PolyType.ptSubject); //cpr.AddPolygons(cc, PolyType.ptClip); //cpr.Execute(ClipType.ctUnion, sss, PolyFillType.pftNonZero, PolyFillType.pftNonZero); //sss = Clipper.OffsetPolygons(sss, -5.0*scale, JoinType.jtMiter, 4); //SVGBuilder svg1 = new SVGBuilder(); //svg1.style.brushClr = Color.FromArgb(0x20, 0, 0, 0x9c); //svg1.style.penClr = Color.FromArgb(0xd3, 0xd3, 0xda); //svg1.AddPolygons(ss); //svg1.style.brushClr = Color.FromArgb(0x20, 0x9c, 0, 0); //svg1.style.penClr = Color.FromArgb(0xff, 0xa0, 0x7a); //svg1.AddPolygons(cc); //svg1.style.brushClr = Color.FromArgb(0xAA, 0x80, 0xff, 0x9c); //svg1.style.penClr = Color.FromArgb(0, 0x33, 0); //svg1.AddPolygons(sss); //svg1.SaveToFile("solution.svg", 1.0/scale); //return; if (args.Length < 5) { string appname = System.Environment.GetCommandLineArgs()[0]; appname = Path.GetFileName(appname); Console.WriteLine(""); Console.WriteLine("Usage:"); Console.WriteLine(" {0} CLIPTYPE s_file c_file INPUT_DEC_PLACES SVG_SCALE [S_FILL, C_FILL]", appname); Console.WriteLine(" where ..."); Console.WriteLine(" CLIPTYPE = INTERSECTION|UNION|DIFFERENCE|XOR"); Console.WriteLine(" FILLMODE = NONZERO|EVENODD"); Console.WriteLine(" INPUT_DEC_PLACES = signific. decimal places for subject & clip coords."); Console.WriteLine(" SVG_SCALE = scale of SVG image as power of 10. (Fractions are accepted.)"); Console.WriteLine(" both S_FILL and C_FILL are optional. The default is EVENODD."); Console.WriteLine("Example:"); Console.WriteLine(" Intersect polygons, rnd to 4 dec places, SVG is 1/100 normal size ..."); Console.WriteLine(" {0} INTERSECTION subj.txt clip.txt 0 0 NONZERO NONZERO", appname); return; } ClipType ct; switch (args[0].ToUpper()) { case "INTERSECTION": ct = ClipType.ctIntersection; break; case "UNION": ct = ClipType.ctUnion; break; case "DIFFERENCE": ct = ClipType.ctDifference; break; case "XOR": ct = ClipType.ctXor; break; default: Console.WriteLine("Error: invalid operation - {0}", args[0]); return; } string subjFilename = args[1]; string clipFilename = args[2]; if (!File.Exists(subjFilename)) { Console.WriteLine("Error: file - {0} - does not exist.", subjFilename); return; } if (!File.Exists(clipFilename)) { Console.WriteLine("Error: file - {0} - does not exist.", clipFilename); return; } int decimal_places = 0; if (!Int32.TryParse(args[3], out decimal_places)) { Console.WriteLine("Error: invalid number of decimal places - {0}", args[3]); return; } if (decimal_places > 8) { decimal_places = 8; } else if (decimal_places < 0) { decimal_places = 0; } double svg_scale = 0; if (!double.TryParse(args[4], out svg_scale)) { Console.WriteLine("Error: invalid value for SVG_SCALE - {0}", args[4]); return; } if (svg_scale < -18) { svg_scale = -18; } else if (svg_scale > 18) { svg_scale = 18; } svg_scale = Math.Pow(10, svg_scale - decimal_places);//nb: also compensate for decimal places PolyFillType pftSubj = PolyFillType.pftEvenOdd; PolyFillType pftClip = PolyFillType.pftEvenOdd; if (args.Length > 6) { switch (args[5].ToUpper()) { case "EVENODD": pftSubj = PolyFillType.pftEvenOdd; break; case "NONZERO": pftSubj = PolyFillType.pftNonZero; break; default: Console.WriteLine("Error: invalid cliptype - {0}", args[5]); return; } switch (args[6].ToUpper()) { case "EVENODD": pftClip = PolyFillType.pftEvenOdd; break; case "NONZERO": pftClip = PolyFillType.pftNonZero; break; default: Console.WriteLine("Error: invalid cliptype - {0}", args[6]); return; } } Polygons subjs = new Polygons(); Polygons clips = new Polygons(); if (!LoadFromFile(subjFilename, subjs, decimal_places)) { Console.WriteLine("Error processing subject polygons file - {0} ", subjFilename); OutputFileFormat(); return; } if (!LoadFromFile(clipFilename, clips, decimal_places)) { Console.WriteLine("Error processing clip polygons file - {0} ", clipFilename); OutputFileFormat(); return; } Console.WriteLine("wait ..."); Clipper cp = new Clipper(); cp.AddPolygons(subjs, PolyType.ptSubject); cp.AddPolygons(clips, PolyType.ptClip); Polygons solution = new Polygons(); //Polygons solution = new Polygons(); if (cp.Execute(ct, solution, pftSubj, pftClip)) { SaveToFile("solution.txt", solution, decimal_places); //solution = Clipper.OffsetPolygons(solution, -4, JoinType.jtRound); SVGBuilder svg = new SVGBuilder(); svg.style.brushClr = Color.FromArgb(0x20, 0, 0, 0x9c); svg.style.penClr = Color.FromArgb(0xd3, 0xd3, 0xda); svg.AddPolygons(subjs); svg.style.brushClr = Color.FromArgb(0x20, 0x9c, 0, 0); svg.style.penClr = Color.FromArgb(0xff, 0xa0, 0x7a); svg.AddPolygons(clips); svg.style.brushClr = Color.FromArgb(0xAA, 0x80, 0xff, 0x9c); svg.style.penClr = Color.FromArgb(0, 0x33, 0); svg.AddPolygons(solution); svg.SaveToFile("solution.svg", svg_scale); Console.WriteLine("finished!"); } else { Console.WriteLine("failed!"); } }
//------------------------------------------------------------------------------ public bool Execute(ClipType clipType, Polygons solution, PolyFillType subjFillType, PolyFillType clipFillType) { if( m_ExecuteLocked ) return false; bool succeeded; try { m_ExecuteLocked = true; solution.Clear(); if ( !Reset() ) { m_ExecuteLocked = false; return false; } m_SubjFillType = subjFillType; m_ClipFillType = clipFillType; m_ClipType = clipType; int botY = PopScanbeam(); do { InsertLocalMinimaIntoAEL(botY); m_HorizJoins.Clear(); ProcessHorizontals(); int topY = PopScanbeam(); succeeded = ProcessIntersections(topY); if (succeeded) ProcessEdgesAtTopOfScanbeam(topY); botY = topY; } while( succeeded && m_Scanbeam != null ); //build the return polygons ... if (succeeded) BuildResult(solution); } catch { m_Joins.Clear(); m_HorizJoins.Clear(); solution.Clear(); succeeded = false; } m_Joins.Clear(); m_HorizJoins.Clear(); DisposeAllPolyPts(); m_ExecuteLocked = false; return succeeded; }
//------------------------------------------------------------------------------ public bool Execute(ClipType clipType, List<List<IntPoint>> solution, PolyFillType FillType = PolyFillType.pftEvenOdd) { return Execute(clipType, solution, FillType, FillType); }
//------------------------------------------------------------------------------ public static Polygons SimplifyPolygons(Polygons polys, PolyFillType fillType = PolyFillType.pftEvenOdd) { Polygons result = new Polygons(); Clipper c = new Clipper(); c.AddPolygons(polys, PolyType.ptSubject); c.Execute(ClipType.ctUnion, result, fillType, fillType); return result; }
public bool Execute(ClipType clipType, PolyTree polytree, PolyFillType subjFillType = PolyFillType.EvenOdd, PolyFillType clipFillType = PolyFillType.EvenOdd) { if (_executeLocked) return false; _executeLocked = true; _subjFillType = subjFillType; _clipFillType = clipFillType; _clipType = clipType; _usingPolyTree = true; var succeeded = ExecuteInternal(); //build the return polygons ... if (succeeded) BuildResultPolytree(polytree); _executeLocked = false; return succeeded; }
public override bool Read(GH_IO.Serialization.GH_IReader reader) { Operation = (ClipType)reader.GetInt32("Operation"); FillType = (PolyFillType)reader.GetInt32("FillType"); return base.Read(reader); }
// RAIL public void genrateRail() { // generate a rail for all three: difference, intersection, union if (inputs.Count == 0) { return; } PolyFillType subjPolyFillType = PolyFillType.pftNonZero; //if (hasHoles) //subjPolyFillType = PolyFillType.pftPositive; //* organize by solids, holes (from SOLID designation) and clippers (from VOID designation) Paths subjPaths = new Paths(); Paths clipPaths = new Paths(); AXParameter inp = null; AXParameter src = null; Paths segments = new Paths(); Path tmp = null; for (int i = 0; i < inputs.Count; i++) { inp = inputs [i]; src = inp.DependsOn; if (src == null) { continue; } Paths srcPaths = src.getPaths(); if (srcPaths == null) { continue; } if (inp.polyType == PolyType.ptSubject) { subjPaths.AddRange(srcPaths); foreach (Path sp in srcPaths) { // When clipping open shapes, don't add a closingsegment: int ender = (inp.shapeState == ShapeState.Open) ? sp.Count - 1 : sp.Count; for (int j = 0; j < ender; j++) { int next_j = (j == sp.Count - 1) ? 0 : j + 1; tmp = new Path(); tmp.Add(sp[j]); tmp.Add(sp[next_j]); segments.Add(tmp); } } //subjPaths.AddRange (src.getTransformedHolePaths()); } else if (inp.polyType == PolyType.ptClip) { clipPaths.AddRange(srcPaths); //clipPaths.AddRange (src.getTransformedHolePaths()); } else { continue; } } // turn subjs and holes into segments to be clipped // foreach(Path sp in subjPaths) // { // // each path // //int ender = // for(int i=0; i<sp.Count-1; i++) // { // int next_i = (i == sp.Count-1) ? 0 : i+1; // tmp = new Path(); // tmp.Add (sp[i]); // tmp.Add (sp[next_i]); // segments.Add(tmp); // } // } //Debug.Log ("segments"); //Archimatix.printPaths(segments); Clipper railc = new Clipper(Clipper.ioPreserveCollinear); if (segments != null) { railc.AddPaths(segments, PolyType.ptSubject, false); } if (clipPaths != null) { railc.AddPaths(clipPaths, PolyType.ptClip, true); } AXClipperLib.PolyTree solutionRail = new AXClipperLib.PolyTree(); // DIFFERENCE_RAIL if ((differenceRail.Dependents != null && differenceRail.Dependents.Count > 0) || combineType == CombineType.DifferenceRail) { railc.Execute(ClipType.ctDifference, solutionRail, subjPolyFillType, PolyFillType.pftNonZero); differenceRail.polyTree = null; differenceRail.paths = assembleRailPathsFromClippedSegments(solutionRail); if (differenceRail.paths.Count == 0) { differenceRail.paths = subjPaths; } alignPathsDirestionsWithSource(ref differenceRail.paths, ref segments); thickenAndOffset(ref differenceRail, differenceRail); } // INTERSECTION RAIL if ((intersectionRail.Dependents != null && intersectionRail.Dependents.Count > 0) || combineType == CombineType.IntersectionRail) { //railc.Execute(ClipType.ctIntersection, solutionRail, subjPolyFillType, PolyFillType.pftNonZero); railc.Execute(ClipType.ctIntersection, solutionRail, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); intersectionRail.polyTree = null; intersectionRail.paths = assembleRailPathsFromClippedSegments(solutionRail); if (intersectionRail.paths.Count == 0) { AXGeometryTools.Utilities.reversePaths(ref intersectionRail.paths); } alignPathsDirestionsWithSource(ref intersectionRail.paths, ref segments); thickenAndOffset(ref intersectionRail, intersectionRail); } }
/// <summary> /// Joins all the polygones. /// ClipType: http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/ClipType.htm /// PolyFillType: http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/PolyFillType.htm /// </summary> /// <param name="sList">The s list.</param> /// <param name="cType">Type of the c.</param> /// <param name="pType">Type of the p.</param> /// <param name="pFType1">The p f type1.</param> /// <param name="pFType2">The p f type2.</param> /// <returns></returns> public static List<Polygon> ELJoinPolygons(this List<Polygon> sList, ClipType cType, PolyType pType = PolyType.ptClip, PolyFillType pFType1 = PolyFillType.pftNonZero, PolyFillType pFType2 = PolyFillType.pftNonZero) { var p = ELClipPolygons(sList); var tList = new List<List<IntPoint>>(); var c = new Clipper(); c.AddPaths(p, pType, true); c.Execute(cType, tList, pFType1, pFType2); return ToPolygons(tList); }
/// <summary> /// Convert self intersecting polygons into simple polygons /// </summary> /// <param name="polys"></param> /// <param name="fillType"></param> /// <returns></returns> public static List<List<IntPoint>> SimplifyPolygons(IEnumerable<List<IntPoint>> polys, PolyFillType fillType = PolyFillType.EvenOdd) { Contract.Requires(polys != null); Contract.Requires(Contract.ForAll(polys, a => a != null)); Contract.Ensures(Contract.Result<List<List<IntPoint>>>() != null); var result = new List<List<IntPoint>>(); var c = new Clipper { ForceSimple = true }; c.AddPolygons(polys, PolyType.Subject); c.Execute(ClipType.Union, result, fillType, fillType); return result; }
//------------------------------------------------------------------------------ public bool Execute(ClipType clipType, ExPolygons solution, PolyFillType subjFillType, PolyFillType clipFillType) { if (m_ExecuteLocked) return false; m_ExecuteLocked = true; solution.Clear(); m_SubjFillType = subjFillType; m_ClipFillType = clipFillType; m_ClipType = clipType; bool succeeded = ExecuteInternal(true); //build the return polygons ... if (succeeded) BuildResultEx(solution); m_ExecuteLocked = false; return succeeded; }
public bool Execute(ClipType clipType, List<List<IntPoint>> solution, PolyFillType subjFillType = PolyFillType.EvenOdd, PolyFillType clipFillType = PolyFillType.EvenOdd) { Contract.Requires(solution != null); if (_executeLocked) return false; _executeLocked = true; solution.Clear(); _subjFillType = subjFillType; _clipFillType = clipFillType; _clipType = clipType; _usingPolyTree = false; var succeeded = ExecuteInternal(); //build the return polygons ... if (succeeded) BuildResultPointList(solution); _executeLocked = false; return succeeded; }