public List<Polygon> Clip(Polygon p1, Polygon p2, OpType operation) { List<IntPoint> pol1 = new List<IntPoint>(); List<IntPoint> pol2 = new List<IntPoint>(); List<List<IntPoint>> res = new List<List<IntPoint>>(); foreach (Point point in p1.Points) { pol1.Add(new IntPoint(point.X, point.Y)); } foreach (Point point in p2.Points) { pol2.Add(new IntPoint(point.X, point.Y)); } Clipper clipper = new Clipper(); clipper.AddPolygon(pol1, PolyType.ptSubject); clipper.AddPolygon(pol2, PolyType.ptClip); switch (operation) { case OpType.Difference: clipper.Execute(ClipType.ctDifference, res); break; case OpType.Intersection: clipper.Execute(ClipType.ctIntersection, res); break; case OpType.Union: clipper.Execute(ClipType.ctUnion, res); break; case OpType.Xor: clipper.Execute(ClipType.ctXor, res); break; } List<Polygon> ret = new List<Polygon>(); foreach (var poly in res) { Polygon pol = new Polygon() { Points = new List<Point>() }; foreach (var poi in poly) { pol.Points.Add(new Point() { X = poi.X, Y = poi.Y }); } ret.Add(pol); } return ret; }
public PolyOffsetBuilder(Polygons pts, Polygons solution, double delta, JoinType jointype, double MiterLimit = 2) { //precondtion: solution != pts if (delta == 0) { solution = pts; return; } this.pts = pts; this.delta = delta; if (MiterLimit <= 1) MiterLimit = 1; double RMin = 2/(MiterLimit*MiterLimit); normals = new List<DoublePoint>(); double deltaSq = delta*delta; solution.Clear(); solution.Capacity = pts.Count; for (m_i = 0; m_i < pts.Count; m_i++) { int len = pts[m_i].Count; if (len > 1 && pts[m_i][0].X == pts[m_i][len - 1].X && pts[m_i][0].Y == pts[m_i][len - 1].Y) len--; if (len == 0 || (len < 3 && delta <= 0)) continue; else if (len == 1) { Polygon arc; arc = BuildArc(pts[m_i][len - 1], 0, 2 * Math.PI, delta); solution.Add(arc); continue; } //build normals ... normals.Clear(); normals.Capacity = len; for (int j = 0; j < len -1; ++j) normals.Add(GetUnitNormal(pts[m_i][j], pts[m_i][j+1])); normals.Add(GetUnitNormal(pts[m_i][len - 1], pts[m_i][0])); currentPoly = new Polygon(); m_k = len - 1; for (m_j = 0; m_j < len; ++m_j) { switch (jointype) { case JoinType.jtMiter: { m_R = 1 + (normals[m_j].X*normals[m_k].X + normals[m_j].Y*normals[m_k].Y); if (m_R >= RMin) DoMiter(); else DoSquare(MiterLimit); break; } case JoinType.jtRound: DoRound(); break; case JoinType.jtSquare: DoSquare(1); break; } m_k = m_j; } solution.Add(currentPoly); } //finally, clean up untidy corners ... Clipper clpr = new Clipper(); clpr.AddPolygons(solution, PolyType.ptSubject); if (delta > 0) { clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftPositive); } else { IntRect r = clpr.GetBounds(); Polygon outer = new Polygon(4); outer.Add(new IntPoint(r.left - 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.top - 10)); outer.Add(new IntPoint(r.left - 10, r.top - 10)); clpr.AddPolygon(outer, PolyType.ptSubject); clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative); if (solution.Count > 0) { solution.RemoveAt(0); for (int i = 0; i < solution.Count; i++) solution[i].Reverse(); } } }
static public PolyTree FindDistictObjectBounds(ImageBuffer image) { MarchingSquaresByte marchingSquaresData = new MarchingSquaresByte(image, 5, 0); marchingSquaresData.CreateLineSegments(); Polygons lineLoops = marchingSquaresData.CreateLineLoops(1); if (lineLoops.Count == 1) { return null; } // create a bounding polygon to clip against IntPoint min = new IntPoint(long.MaxValue, long.MaxValue); IntPoint max = new IntPoint(long.MinValue, long.MinValue); foreach (Polygon polygon in lineLoops) { foreach (IntPoint point in polygon) { min.X = Math.Min(point.X - 10, min.X); min.Y = Math.Min(point.Y - 10, min.Y); max.X = Math.Max(point.X + 10, max.X); max.Y = Math.Max(point.Y + 10, max.Y); } } Polygon boundingPoly = new Polygon(); boundingPoly.Add(min); boundingPoly.Add(new IntPoint(min.X, max.Y)); boundingPoly.Add(max); boundingPoly.Add(new IntPoint(max.X, min.Y)); // now clip the polygons to get the inside and outside polys Clipper clipper = new Clipper(); clipper.AddPolygons(lineLoops, PolyType.ptSubject); clipper.AddPolygon(boundingPoly, PolyType.ptClip); PolyTree polyTreeForPlate = new PolyTree(); clipper.Execute(ClipType.ctIntersection, polyTreeForPlate); return polyTreeForPlate; }
//------------------------------------------------------------------------------ // SimplifyPolygon functions ... // Convert self-intersecting polygons into simple polygons //------------------------------------------------------------------------------ public static Polygons SimplifyPolygon(Polygon poly) { Polygons result = new Polygons(); Clipper c = new Clipper(); c.AddPolygon(poly, PolyType.ptSubject); c.Execute(ClipType.ctUnion, result); return result; }
//------------------------------------------------------------------------------ // SimplifyPolygon functions ... // Convert self-intersecting polygons into simple polygons //------------------------------------------------------------------------------ public static Polygons SimplifyPolygon(Polygon poly, PolyFillType fillType = PolyFillType.pftEvenOdd) { Polygons result = new Polygons(); Clipper c = new Clipper(); c.AddPolygon(poly, PolyType.ptSubject); c.Execute(ClipType.ctUnion, result, fillType, fillType); return result; }
public PolyOffsetBuilder(Polygons pts, Polygons solution, double delta, JoinType jointype, double MiterLimit = 2, bool AutoFix = true) { //precondtion: solution != pts if (delta == 0) { solution = pts; return; } this.pts = pts; this.delta = delta; //AutoFix - fixes polygon orientation if necessary and removes //duplicate vertices. Can be set false when you're sure that polygon //orientation is correct and that there are no duplicate vertices. if (AutoFix) { int Len = pts.Count, botI = 0; while (botI < Len && pts[botI].Count == 0) botI++; if (botI == Len) return; //botPt: used to find the lowermost (in inverted Y-axis) & leftmost point //This point (on pts[botI]) must be on an outer polygon ring and if //its orientation is false (counterclockwise) then assume all polygons //need reversing ... IntPoint botPt = pts[botI][0]; for (int i = botI; i < Len; ++i) { if (pts[i].Count == 0) continue; if (UpdateBotPt(pts[i][0], ref botPt)) botI = i; for (int j = pts[i].Count -1; j > 0; j--) { if (PointsEqual(pts[i][j], pts[i][j -1])) pts[i].RemoveAt(j); else if (UpdateBotPt(pts[i][j], ref botPt)) botI = i; } } if (!Orientation(pts[botI])) ReversePolygons(pts); } if (MiterLimit <= 1) MiterLimit = 1; double RMin = 2.0 / (MiterLimit*MiterLimit); normals = new List<DoublePoint>(); double deltaSq = delta*delta; solution.Clear(); solution.Capacity = pts.Count; for (m_i = 0; m_i < pts.Count; m_i++) { int len = pts[m_i].Count; if (len > 1 && pts[m_i][0].X == pts[m_i][len - 1].X && pts[m_i][0].Y == pts[m_i][len - 1].Y) len--; if (len == 0 || (len < 3 && delta <= 0)) continue; else if (len == 1) { Polygon arc; arc = BuildArc(pts[m_i][len - 1], 0, 2 * Math.PI, delta); solution.Add(arc); continue; } //build normals ... normals.Clear(); normals.Capacity = len; for (int j = 0; j < len -1; ++j) normals.Add(GetUnitNormal(pts[m_i][j], pts[m_i][j+1])); normals.Add(GetUnitNormal(pts[m_i][len - 1], pts[m_i][0])); currentPoly = new Polygon(); m_k = len - 1; for (m_j = 0; m_j < len; ++m_j) { switch (jointype) { case JoinType.jtMiter: { m_R = 1 + (normals[m_j].X*normals[m_k].X + normals[m_j].Y*normals[m_k].Y); if (m_R >= RMin) DoMiter(); else DoSquare(MiterLimit); break; } case JoinType.jtRound: DoRound(); break; case JoinType.jtSquare: DoSquare(1); break; } m_k = m_j; } solution.Add(currentPoly); } //finally, clean up untidy corners ... Clipper clpr = new Clipper(); clpr.AddPolygons(solution, PolyType.ptSubject); if (delta > 0) { clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftPositive); } else { IntRect r = clpr.GetBounds(); Polygon outer = new Polygon(4); outer.Add(new IntPoint(r.left - 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.top - 10)); outer.Add(new IntPoint(r.left - 10, r.top - 10)); clpr.AddPolygon(outer, PolyType.ptSubject); clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative); if (solution.Count > 0) { solution.RemoveAt(0); for (int i = 0; i < solution.Count; i++) solution[i].Reverse(); } } }
//------------------------------------------------------------------------------ public PolyOffsetBuilder(Polygons pts, Polygons solution, bool isPolygon, double delta, JoinType jointype, EndType endtype, double limit = 0) { //precondition: solution != pts if (delta == 0) { solution = pts; return; } m_p = pts; m_delta = delta; m_rmin = 0.5; if (jointype == JoinType.jtMiter) { if (limit > 2) m_rmin = 2.0 / (limit * limit); limit = 0.25; //just in case endtype == etRound } else { if (limit <= 0) limit = 0.25; else if (limit > Math.Abs(delta)) limit = Math.Abs(delta); } double deltaSq = delta * delta; solution.Clear(); solution.Capacity = pts.Count; for (m_i = 0; m_i < pts.Count; m_i++) { int len = pts[m_i].Count; if (len == 0 || (len < 3 && delta <= 0)) continue; else if (len == 1) { currentPoly = new Polygon(); currentPoly = BuildArc(pts[m_i][0], 0, 2 * Math.PI, delta, limit); solution.Add(currentPoly); continue; } bool forceClose = PointsEqual(pts[m_i][0], pts[m_i][len - 1]); if (forceClose) len--; //build normals ... normals.Clear(); normals.Capacity = len; for (int j = 0; j < len - 1; ++j) normals.Add(GetUnitNormal(pts[m_i][j], pts[m_i][j + 1])); if (isPolygon || forceClose) normals.Add(GetUnitNormal(pts[m_i][len - 1], pts[m_i][0])); else normals.Add(new DoublePoint(normals[len - 2])); currentPoly = new Polygon(); if (isPolygon || forceClose) { m_k = len - 1; for (m_j = 0; m_j < len; ++m_j) OffsetPoint(jointype, limit); solution.Add(currentPoly); if (!isPolygon) { currentPoly = new Polygon(); m_delta = -m_delta; m_k = len - 1; for (m_j = 0; m_j < len; ++m_j) OffsetPoint(jointype, limit); m_delta = -m_delta; currentPoly.Reverse(); solution.Add(currentPoly); } } else { m_k = 0; for (m_j = 1; m_j < len - 1; ++m_j) OffsetPoint(jointype, limit); IntPoint pt1; if (endtype == EndType.etButt) { m_j = len - 1; pt1 = new IntPoint((Int64)Round(pts[m_i][m_j].X + normals[m_j].X * delta), (Int64)Round(pts[m_i][m_j].Y + normals[m_j].Y * delta)); AddPoint(pt1); pt1 = new IntPoint((Int64)Round(pts[m_i][m_j].X - normals[m_j].X * delta), (Int64)Round(pts[m_i][m_j].Y - normals[m_j].Y * delta)); AddPoint(pt1); } else { m_j = len - 1; m_k = len - 2; normals[m_j].X = -normals[m_j].X; normals[m_j].Y = -normals[m_j].Y; if (endtype == EndType.etSquare) DoSquare(); else DoRound(limit); } //re-build Normals ... for (int j = len - 1; j > 0; j--) { normals[j].X = -normals[j - 1].X; normals[j].Y = -normals[j - 1].Y; } normals[0].X = -normals[1].X; normals[0].Y = -normals[1].Y; m_k = len - 1; for (m_j = m_k - 1; m_j > 0; --m_j) OffsetPoint(jointype, limit); if (endtype == EndType.etButt) { pt1 = new IntPoint((Int64)Round(pts[m_i][0].X - normals[0].X * delta), (Int64)Round(pts[m_i][0].Y - normals[0].Y * delta)); AddPoint(pt1); pt1 = new IntPoint((Int64)Round(pts[m_i][0].X + normals[0].X * delta), (Int64)Round(pts[m_i][0].Y + normals[0].Y * delta)); AddPoint(pt1); } else { m_k = 1; if (endtype == EndType.etSquare) DoSquare(); else DoRound(limit); } solution.Add(currentPoly); } } //finally, clean up untidy corners ... Clipper clpr = new Clipper(); clpr.AddPolygons(solution, PolyType.ptSubject); if (delta > 0) { clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftPositive); } else { IntRect r = clpr.GetBounds(); Polygon outer = new Polygon(4); outer.Add(new IntPoint(r.left - 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.bottom + 10)); outer.Add(new IntPoint(r.right + 10, r.top - 10)); outer.Add(new IntPoint(r.left - 10, r.top - 10)); clpr.AddPolygon(outer, PolyType.ptSubject); clpr.ReverseSolution = true; clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative); if (solution.Count > 0) solution.RemoveAt(0); } }
public string TranslateGerber( string path ) { String output = ""; PointF pstart = new PointF(0, 0); PointF pend = new PointF(0, 0); Double x, y; int d; Regex reXYLine = new Regex(@"^X(\d+)Y(\d+)D(\d\d)\*$"); Regex reFSLA = new Regex(@"%FSLAX(\d)(\d)Y(\d)(\d)\*%"); Regex reApDef = new Regex(@"%ADD(\d+)R,([\d\.]+)X([\d\.]+)\*%"); Regex reApGroup = new Regex(@"^D(\d+)\*$"); List<string> fileLines = new List<string>(); StreamReader srt; List<LineF> lines = new List<LineF>(); // read the border file if (null != path) { srt = new StreamReader(path); while (true) { string line = srt.ReadLine(); if (null == line) break; fileLines.Add(line); } srt.Close(); } int decimal_x = 4, decimal_y = 4; double mul_x = Math.Pow(10, decimal_x); double mul_y = Math.Pow(10, decimal_y); foreach (string line in fileLines) { // format is 2.4 (CHECK?) //string line = srt.ReadLine(); //if (null == line) break; Match m = reFSLA.Match(line); if (m.Success) { Group group = m.Groups[2]; CaptureCollection cc = group.Captures; decimal_x = Int32.Parse(cc[0].Value); group = m.Groups[4]; cc = group.Captures; decimal_y = Int32.Parse(cc[0].Value); mul_x = Math.Pow(10, decimal_x); mul_y = Math.Pow(10, decimal_y); } m = reXYLine.Match(line); if (m.Success) { Group group = m.Groups[1]; CaptureCollection cc = group.Captures; //x = Double.Parse(cc[0].Value) / 10000 * INMM; // *dscale; x = Double.Parse(cc[0].Value) / mul_x * INMM; // *dscale; group = m.Groups[2]; cc = group.Captures; //y = Double.Parse(cc[0].Value) / 10000 * INMM; // *dscale; y = Double.Parse(cc[0].Value) / mul_y * INMM; // *dscale; group = m.Groups[3]; cc = group.Captures; d = Int32.Parse(cc[0].Value); // D02 is move, D01 is line... if (d == 2 || d == 1) { if (x > maxx) maxx = x; if (y > maxy) maxy = y; if (x < minx) minx = x; if (y < miny) miny = y; } } } xrange = maxx - minx; yrange = maxy - miny; List<Aperture> apertures = new List<Aperture>(); string ee = Path.GetExtension(path).ToUpper(); if (Path.GetExtension(path).ToUpper().Equals(".DRD")) { readDrills(fileLines, out apertures, ref maxx, ref maxy, ref minx, ref miny); output += ("// Excellon (drill) file: " + Path.GetFileName(path) + "\r\n\r\n"); foreach (Aperture ap in apertures) { output += string.Format("\tcircle {0:00.00}, {1:00.00}, {2:00.00}\r\n", ap.border.Left + ap.border.Width / 2, ap.border.Top + ap.border.Height / 2, ap.CircleDiameter ); // ap.border.Width ); } return output ; } else readApertures(fileLines, out apertures, out lines, ref maxx, ref maxy, ref minx, ref miny); // now create a set of polygons that we can clip... Polygons polys = new Polygons(); foreach (LineF line in lines) { // Console.WriteLine("Line: width is " + line.width); // circle at start, end polys.Add(ListToPoly(CircleToPoints(line.start, line.width))); polys.Add(ListToPoly(CircleToPoints(line.end, line.width))); // tangent lines? here, a rectangle Polygon rect = new Polygon(); LineF lf1 = line.shift(90, line.width / 2); LineF lf2 = line.shift(-90, line.width / 2); rect.Add(new IntPoint((long)(lf1.start.X * SCALE), (long)(lf1.start.Y * SCALE))); rect.Add(new IntPoint((long)(lf1.end.X * SCALE), (long)(lf1.end.Y * SCALE))); rect.Add(new IntPoint((long)(lf2.end.X * SCALE), (long)(lf2.end.Y * SCALE))); rect.Add(new IntPoint((long)(lf2.start.X * SCALE), (long)(lf2.start.Y * SCALE))); polys.Add(rect); } foreach (Aperture ap in apertures) { if (ap.CircleDiameter > 0) { polys.Add(ListToPoly(CircleToPoints(ap))); } else { Polygon rect = new Polygon(); rect.Add(new IntPoint((long)(ap.border.Left * SCALE), (long)(ap.border.Top * SCALE))); rect.Add(new IntPoint((long)(ap.border.Right * SCALE), (long)(ap.border.Top * SCALE))); rect.Add(new IntPoint((long)(ap.border.Right * SCALE), (long)(ap.border.Bottom * SCALE))); rect.Add(new IntPoint((long)(ap.border.Left * SCALE), (long)(ap.border.Bottom * SCALE))); polys.Add(rect); } } Polygons solution = new Polygons (); Clipper clip = new Clipper(); //foreach (Polygon poly in polys) for( int i = 0; i< polys.Count; i++ ) { Polygon poly = polys[i]; if (!Clipper.Orientation(poly)) poly.Reverse(); clip.AddPolygon(poly, PolyType.ptSubject); } //clip.AddPolygons(polys, PolyType.ptSubject); clip.Execute(ClipType.ctUnion, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero); polys = solution; // let's look at this ... output += ("// Gerber file: " + Path.GetFileName( path ) + "\r\n\r\n"); { //DXF.DxfDocument doc = new DXF.DxfDocument(); foreach (Polygon poly in polys) { for (int i = 1; i < poly.Count; i++) { /* doc.AddEntity(new DXF.Entities.Line( new DXF.Vector2(poly[i - 1].X / (double)SCALE, poly[i - 1].Y / (double)SCALE), new DXF.Vector2(poly[i ].X / (double)SCALE, poly[i ].Y / (double)SCALE) )); */ output += string.Format("\tline {0:00.00}, {1:00.00}, {2:00.00}, {3:00.00}\r\n", poly[i - 1].X / (double)SCALE, poly[i - 1].Y / (double)SCALE, poly[i].X / (double)SCALE, poly[i].Y / (double)SCALE); } /* doc.AddEntity(new DXF.Entities.Line( new DXF.Vector2(poly[poly.Count - 1].X / (double)SCALE, poly[poly.Count - 1].Y / (double)SCALE), new DXF.Vector2(poly[0].X / (double)SCALE, poly[0].Y / (double)SCALE) )); */ output += string.Format("\tline {0:00.00}, {1:00.00}, {2:00.00}, {3:00.00}\r\n", poly[poly.Count - 1].X / (double)SCALE, poly[poly.Count - 1].Y / (double)SCALE, poly[0].X / (double)SCALE, poly[0].Y / (double)SCALE); } return output; /** // add a bounding box... doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2(minx, miny), new DXF.Vector2(maxx, miny))); doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2(maxx, miny), new DXF.Vector2(maxx, maxy))); doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2(maxx, maxy), new DXF.Vector2(minx, maxy))); doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2(minx, maxy), new DXF.Vector2(minx, miny))); **/ // add a reference at (0,0) //doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2( -5, 5 ), new DXF.Vector2( 5, -5 ))); //doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2( 5, 5 ), new DXF.Vector2( -5, -5 ))); //doc.Save(outputPath, DXF.Header.DxfVersion.AutoCad2000); } /* // readDrills(drillFileLines, out drillApertures, ref maxx, ref maxy, ref minx, ref miny); DXF.DxfDocument doc = new DXF.DxfDocument(); foreach (LineF line in lines) { Console.WriteLine("Line: width is " + line.width); // circle at start, end doc.AddEntity(new DXF.Entities.Circle(new DXF.Vector2(line.start.X, line.start.Y), line.width / 2)); doc.AddEntity(new DXF.Entities.Circle(new DXF.Vector2(line.end.X, line.end.Y), line.width / 2)); // tangent lines? LineF lf1 = line.shift(90, line.width / 2); doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2(lf1.start.X, lf1.start.Y), new DXF.Vector2(lf1.end.X, lf1.end.Y))); LineF lf2 = line.shift(-90, line.width / 2); doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2(lf2.start.X, lf2.start.Y), new DXF.Vector2(lf2.end.X, lf2.end.Y))); // doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2(line.start.X, line.start.Y), new DXF.Vector2(line.end.X, line.end.Y))); } foreach (Aperture ap in apertures) { if (ap.CircleDiameter > 0) { double half = ap.border.Width/2; doc.AddEntity( new DXF.Entities.Circle( new DXF.Vector2( ap.border.Left + half, ap.border.Top + half ), ap.border.Width/2 )); Console.WriteLine("ap circle"); } else { // rectangle in 4 lines... doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2(ap.border.Left, ap.border.Top), new DXF.Vector2(ap.border.Right, ap.border.Top))); doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2(ap.border.Left, ap.border.Bottom), new DXF.Vector2(ap.border.Right, ap.border.Bottom))); doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2(ap.border.Left, ap.border.Top), new DXF.Vector2(ap.border.Left, ap.border.Bottom))); doc.AddEntity(new DXF.Entities.Line(new DXF.Vector2(ap.border.Right, ap.border.Top), new DXF.Vector2(ap.border.Right, ap.border.Bottom))); Console.WriteLine("ap rectangle"); } } doc.Save(outputPath, DXF.Header.DxfVersion.AutoCad2000 ); */ }
private void Slice(Plane p) { float epsilon = 0.01f; // TODO: compute proper epsilon value List<PolyLine> linePile = new List<PolyLine>(); // Pile of disconnected lines on the slice plane List<Vector3> all_points = new List<Vector3>(); foreach (Face f in this.faces) { PolyLine newLine = TrianglePlaneIntersect(f, p); // Only add lines with exactly 2 points - others are a no match or error if (newLine.points.Count() == 2 && (newLine.points[0] - newLine.points[1]).Length> epsilon) { linePile.Add(newLine); // Add the vertices to the all_points list - only need to add the first one, the tail will be the head of another point bool matched = false; foreach (Vector3 point in all_points) { if ((point - newLine.points[0]).Length < epsilon) { matched = true; break; } } if (!matched) { all_points.Add(newLine.points[0]); } } } // linePile is a unordered list of line segments. // If a line segment is oriented with point[0] on (0, 0, 0) and point[1] // somewhere on the positive Y axis, the solid object is in the direction of the positive x axis. // // p[1]xxxxxxxxxxxxxxxxxxxxxxxx // xx xx // xx <object over here> xx // xx xx // p[0]xxxxxxxxxxxxxxxxxxxxxxxx // List<PolyLine> newPolyLines = new List<PolyLine>(); for (int i = 0; i < linePile.Count(); i++) { int points = linePile[i].points.Count(); Vector3 v1 = linePile[i].points[0]; Vector3 v2 = linePile[i].points[1]; //DrawCone1(v1, v2); List<Vector3> points_on_line = new List<Vector3>(); foreach (Vector3 v in all_points) { if ((v1 - v).Length >= epsilon && (v2 - v).Length >= epsilon && DistanceToCylinder(v1, v2, v) < epsilon) { points_on_line.Add(v); } } points_on_line.Insert(0, v1); points_on_line.Add(v2); // Order from v1 to v2 var sorted = points_on_line.OrderBy(order_vec => (order_vec - v1).Length); PolyLine newPolyLine = new PolyLine(); foreach (Vector3 v in sorted) { if (newPolyLine.points.Count() == 0 || (newPolyLine.points[newPolyLine.points.Count() - 1] - v).Length > epsilon) { newPolyLine.points.Add(v); } } if (newPolyLine.points.Count() >= 2) { newPolyLines.Add(newPolyLine); } if (newPolyLine.points.Count() >= 3) { // Shouldn't get here! } } List<LinePointIndices> lpis = new List<LinePointIndices>(); List<Vector3> vertices = new List<Vector3>(); List<List<int>> v_lookup = new List<List<int>>(); foreach (PolyLine l in newPolyLines) { int lastIndex = -1; foreach (Vector3 pointVec in l.points) { int currentIndex = -1; for (int i = 0; i < vertices.Count(); i++) { float length = (vertices[i] - pointVec).Length; if (length < epsilon) { currentIndex = i; continue; } } if (currentIndex == -1) { vertices.Add(pointVec); v_lookup.Add(new List<int>()); currentIndex = vertices.Count() - 1; } if (lastIndex != -1 && lastIndex != currentIndex) { LinePointIndices line = new LinePointIndices(); bool already_matched = false; foreach (int line_index in v_lookup[lastIndex]) { LinePointIndices l2 = lpis[line_index]; if (l2.indices[1] == currentIndex) { already_matched = true; } } if (!already_matched) { line.indices.Add(lastIndex); line.indices.Add(currentIndex); lpis.Add(line); v_lookup[lastIndex].Add(lpis.Count() - 1); v_lookup[currentIndex].Add(lpis.Count() - 1); } } lastIndex = currentIndex; } } //List<Vector3> scaled = new List<Vector3>(); List<int> vector_indices_to_see = new List<int>(); foreach (Vector3 v in vertices) { //scaled.Add(v / 125); vector_indices_to_see.Add(vector_indices_to_see.Count()); } List<LinePointIndices> slices = new List<LinePointIndices>(); GL.PushMatrix(); GL.PointSize(10); List<int> seenVertices = new List<int>(); while(vector_indices_to_see.Count() > 0) { List<int> line_indices = v_lookup [vector_indices_to_see[0]]; vector_indices_to_see.RemoveAt(0); if (line_indices.Count() == 0) { continue; } LinePointIndices line = lpis[line_indices[0]]; // Only need to look at one line with this vertex LinePointIndices start_line = new LinePointIndices(); start_line.indices.Add(line.indices[0]); start_line.indices.Add(line.indices[1]); GL.Color3(Color.Green); DrawCone1(vertices[start_line.indices[0]], vertices[start_line.indices[1]]); LinePointIndices loop = FindLoop(seenVertices, p.normal, vertices, v_lookup, lpis, start_line); if (loop != null) { slices.Add(loop); GL.Color3(Color.LightBlue); GL.Begin(BeginMode.LineLoop); Vector3 add = new Vector3(0, 0, 0); foreach (int i in loop.indices) { vector_indices_to_see.RemoveAll(value => value == i); GL.Vertex3(vertices[i] + add); seenVertices.Add(i); //add += new Vector3(0, 0, 25); } GL.End(); //GL.Translate(new Vector3(0, 0, +100)); } //break; } GL.PointSize(1); GL.PopMatrix(); Vector3 normal = new Vector3(0, 0, 1); float toolRadius = 100; GL.LineWidth(1); List<IntPoint> boundingBox = new List<IntPoint>(); boundingBox.Add(new IntPoint(-1000, -1000)); boundingBox.Add(new IntPoint(3000, -1000)); boundingBox.Add(new IntPoint(3000, 3000)); boundingBox.Add(new IntPoint(-1000, 3000)); List<LineLoop> loops = new List<LineLoop>(); foreach (LinePointIndices l in slices) { LineStrip line = new LineStrip(); for (int i = 0; i < l.indices.Count (); i++) { line.Append(vertices[l.indices[i]]); } line.Append(vertices[l.indices[0]]); loops.Add(new LineLoop (line)); } if (loops.Count() > 0) { Vector3 up = new Vector3(0, 0, 1); if (Math.Abs (normal.Z) > 0.8) { up = new Vector3(1, 0, 0); } float distance = Vector3.Dot(loops[0].GetVertex(0), normal); Matrix4 transform = Matrix4.LookAt(normal * distance, normal * (distance - 1), up); Matrix4 inverseTransform = Matrix4.Invert(transform); Clipper c = new Clipper(); c.Clear(); try { // These loops go clockwise foreach (LineLoop loop in loops) { List<IntPoint> polygon = new List<IntPoint>(); foreach (Vector3 vertex in loop.Vertices) { Vector3 result = Vector3.Transform(vertex, transform); polygon.Add(new IntPoint((long)result.X, (long)result.Y)); } polygon.RemoveAt(0); c.AddPolygon(polygon, PolyType.ptClip); GL.PushMatrix(); GL.Translate(new Vector3(0, 0, 100)); //loop.Draw(); GL.PopMatrix(); } List<List<IntPoint>> union = new List<List<IntPoint>>(); bool r = c.Execute(ClipType.ctUnion, union, PolyFillType.pftNonZero, PolyFillType.pftNonZero); List<List<IntPoint>> with_offset = Clipper.OffsetPolygons(union, toolRadius, JoinType.jtSquare); List<List<IntPoint>> whatsLeft = Clipper.OffsetPolygons(with_offset, -toolRadius, JoinType.jtRound); List<LineStrip> strips = new List<LineStrip>(); foreach (List<IntPoint> polygon in with_offset) { LineStrip strip = new LineStrip(); foreach (IntPoint point in polygon) { strip.Append(Vector3.Transform(new Vector3(point.X, point.Y, 0.0f), inverseTransform)); } strip.Append(Vector3.Transform(new Vector3(polygon[0].X, polygon[0].Y, 0.0f), inverseTransform)); strips.Add(strip); //new LineLoop(strip).Draw(); } List<List<IntPoint>> removeArea = new List<List<IntPoint>>(); c.Clear(); c.AddPolygons(with_offset, PolyType.ptClip); c.AddPolygon(boundingBox, PolyType.ptSubject); List<List<IntPoint>> resultingPolygon = new List<List<IntPoint>>(); c.Execute(ClipType.ctDifference, removeArea, PolyFillType.pftNonZero, PolyFillType.pftNonZero); removeArea = Clipper.CleanPolygons(removeArea, toolRadius / 100); c.Clear(); c.AddPolygons(removeArea, PolyType.ptClip); PolyTree test = new PolyTree(); c.Execute(ClipType.ctUnion, test, PolyFillType.pftNonZero, PolyFillType.pftNonZero); //PolyNode pn = test.GetFirst(); //while (pn != null) //{ // if (pn.IsHole) // { // LineLoop l = new LineLoop(pn.Contour, inverseTransform); // l.Draw(); // } // pn = pn.GetNext(); //} List<Polygons> polys = FlattenPolyTree(test); //GL.PushMatrix(); foreach (Polygons polygons in polys) { //GL.Translate(new Vector3 (0, 0, 100)); //foreach (Polygon polygon in polygons) //{ // LineLoop l = new LineLoop(polygon, inverseTransform); // l.Draw(); //} List<Polygons> paths = ReducePolygon(polygons, toolRadius, inverseTransform); //IOrderedEnumerable<List<IntPoint>> ordered = paths.OrderBy(poly => Clipper.Area(poly)); GL.PushMatrix(); List<Polygons> paths2 = new List<Polygons>(); List<Polygons> paths3 = new List<Polygons>(); foreach (Polygons polygons2 in paths) { var newPolys = new Polygons(); foreach (Polygon poly in polygons2) { if (Clipper.Area(poly) > 0) { newPolys.Add(poly); } } paths2.Add(newPolys); //GL.Translate(new Vector3(0, 0, 100)); var newInnerPolys = new Polygons(); foreach (Polygon poly in polygons2) { if (paths3.Count() == 0) { //newInnerPoly } if (Clipper.Area(poly) < 0) { LineLoop l = new LineLoop(poly, inverseTransform); l.Draw(); } } } foreach (Polygons polygons2 in paths2) { GL.Translate(new Vector3(0, 0, 100)); foreach (Polygon poly in polygons2) { LineLoop l = new LineLoop(poly, inverseTransform); l.Draw(); } } GL.PopMatrix(); } //GL.PopMatrix(); double boundingBoxArea = Clipper.Area(boundingBox); // Outer Polygon // Inner Polygons //ReducePolygon(boundingBox, with_offset, toolRadius, inverseTransform); //strips = new List<LineStrip>(); //double area = 1; //int loopTimes = 0; //List<List<IntPoint>> cutPolygons = new List<List<IntPoint>>(); //List<Vector3> parentPoints = new List<Vector3>(); //GL.PushMatrix(); //while (removeArea.Count() > 0) //{ // List<Vector3> points = new List<Vector3>(); // foreach (List<IntPoint> polygon in removeArea) // { // double area = Clipper.Area(polygon); // // if (area > 0) // Bigger to Smaller // { // } // IntPoint[] newP = new IntPoint[polygon.Count()]; // polygon.CopyTo(newP); // cutPolygons.Add(new List<IntPoint>(newP)); // // // LineLoop l = new LineLoop(polygon, inverseTransform); // //l.Draw(); // points.AddRange(l.Vertices); // // //ReducePolygon(null, polygon, toolRadius, inverseTransform); // //area += Clipper.Area(polygon); // //LineStrip strip = new LineStrip(); // //foreach (IntPoint point in polygon) // //{ // // strip.Append(Vector3.Transform(new Vector3(point.X, point.Y, 0.0f), inverseTransform)); // //} // //strip.Append(Vector3.Transform(new Vector3(polygon[0].X, polygon[0].Y, 0.0f), inverseTransform)); // // //strips.Add(strip); // //new LineLoop(strip).Draw(); // } // // //GL.Color3(Color.Black); // //GL.Begin(BeginMode.Lines); // //foreach (Vector3 v in points) // //{ // // foreach (Vector3 v2 in parentPoints) // // { // // if ((v - v2).Length < toolRadius * 2) // // { // // GL.Vertex3(v); // // GL.Vertex3(v2); // // } // // } // //} // //GL.End(); // // parentPoints = points; // removeArea = Clipper.OffsetPolygons(removeArea, -toolRadius, JoinType.jtRound); // removeArea = Clipper.CleanPolygons(removeArea, toolRadius / 100); //} //GL.PopMatrix(); //IOrderedEnumerable<List<IntPoint>> ordered = cutPolygons.OrderBy(poly => Clipper.Area(poly)); // //GL.PushMatrix(); //foreach (List<IntPoint> poly in ordered) //{ // GL.Translate(new Vector3(0, 0, 100)); // LineLoop l = new LineLoop(poly, inverseTransform); // l.Draw(); //} //GL.PopMatrix(); ////strips = new List<LineStrip>(); //GL.Color3(Color.Red); //GL.LineWidth(2); //foreach (List<IntPoint> polygon in whatsLeft) //{ // LineStrip strip = new LineStrip(); // foreach (IntPoint point in polygon) // { // strip.Append(Vector3.Transform(new Vector3(point.X, point.Y, 0.0f), inverseTransform)); // } // strip.Append(Vector3.Transform(new Vector3(polygon[0].X, polygon[0].Y, 0.0f), inverseTransform)); // // strips.Add(strip); // new LineLoop(strip).Draw(); //} //GL.LineWidth(1); } catch (Exception e) { } } }