public static Ngons MinkowskiSumSegment(Ngon pattern, IntPoint p1, IntPoint p2, bool flip_pattern) { Clipper clipper = new Clipper(); Ngon p1_c = pattern.Clone(p1.X, p1.Y, flip_pattern); if (p1 == p2) { return new Ngons() { p1_c } } ; Ngon p2_c = pattern.Clone(p2.X, p2.Y, flip_pattern); Ngons full = new Ngons(); clipper.AddPath(p1_c, PolyType.ptSubject, true); clipper.AddPath(p2_c, PolyType.ptSubject, true); clipper.AddPaths(Clipper.MinkowskiSum(pattern.Clone(0, 0, flip_pattern), new Ngon() { p1, p2 }, false), PolyType.ptSubject, true); clipper.Execute(ClipType.ctUnion, full, PolyFillType.pftNonZero); return(full); }
private static Ngons MSumConcave(Ngon pattern, Ngons subject, bool flip_pattern, double rigidness = 1.0) { Ngon subj = subject[0]; Ngon patt = pattern.Clone(0, 0, flip_pattern); if (rigidness < 1.0) { subj = ConvexHull(subj, rigidness); patt = ConvexHull(patt, rigidness); } Ngons sres = MinkowskiSumBoundary(patt, subj, false); return(sres.Count == 0 ? sres : new Ngons() { sres[0] }); }
private void cmd_optimal_rotation(int handle) { Ngon hull = polygon_lib[handle].GetTransformedPoly()[0]; int n = hull.Count; double best_t = 0; int best = 0; long best_area = long.MaxValue; bool flip_best = false; for (int i = 0; i < n; i++) { double t = GeomUtility.AlignToEdgeRotation(hull, i); Mat3x3 rot = Mat3x3.RotateCounterClockwise(t); Ngon clone = hull.Clone(rot); IntRect bounds = GeomUtility.GetBounds(clone); long area = bounds.Area(); double aspect = bounds.Aspect(); if (area < best_area) { best_area = area; best = i; best_t = t; flip_best = aspect > 1.0; } } double flip = flip_best ? Math.PI * 0.5 : 0; IntPoint around = hull[best]; cmd_translate(handle, (double)-around.X, (double)-around.Y); cmd_rotate(handle, best_t + flip); cmd_translate(handle, (double)around.X, (double)around.Y); }
private static Ngons MSumConvex(Ngon pattern, Ngons subject, bool flip_pattern) { Ngon h_p = ConvexHull(pattern.Clone(0, 0, flip_pattern)); Ngon h_s = ConvexHull(subject[0].Clone()); int n_p = h_p.Count; int n_s = h_s.Count; int sp = 0; for (int k = 0; k < n_p; k++) { if (h_p[k].Y < h_p[sp].Y) { sp = k; } } int ss = 0; for (int k = 0; k < n_s; k++) { if (h_s[k].Y < h_s[ss].Y) { ss = k; } } Ngon poly = new Ngon(n_p + n_s); int i = 0; int j = 0; while (i < n_p || j < n_s) { int ip = (sp + i + 1) % n_p; int jp = (ss + j + 1) % n_s; int ii = (sp + i) % n_p; int jj = (ss + j) % n_s; IntPoint sum = new IntPoint(h_p[ii].X + h_s[jj].X, h_p[ii].Y + h_s[jj].Y); IntPoint v = new IntPoint(h_p[ip].X - h_p[ii].X, h_p[ip].Y - h_p[ii].Y); IntPoint w = new IntPoint(h_s[jp].X - h_s[jj].X, h_s[jp].Y - h_s[jj].Y); poly.Add(sum); if (i == n_p) { j++; continue; } if (j == n_s) { i++; continue; } long cross = v.Y * w.X - v.X * w.Y; if (cross < 0) { i++; } else if (cross > 0) { j++; } else { long dot = v.X * w.X + v.Y * w.Y; if (dot > 0) { i++; j++; } else { throw new Exception(); } } } return(Clipper.SimplifyPolygon(poly)); }
public static Ngon ConvexHull(Ngon subject, double rigidness = 0) { if (subject.Count == 0) { return(new Ngon()); } if (rigidness >= 1) { return(subject.Clone()); } subject = subject.Clone(); if (Clipper.Area(subject) < 0) { Clipper.ReversePaths(new Ngons() { subject }); } Ngon last_hull = new Ngon(); Ngon hull = subject; double subj_area = Clipper.Area(hull); int last_vert = 0; for (int i = 1; i < subject.Count; i++) { if (hull[last_vert].Y > hull[i].Y) { last_vert = i; } } while (last_hull.Count != hull.Count) { last_hull = hull; hull = new Ngon(); hull.Add(last_hull[last_vert]); int steps_since_insert = 0; int max_steps = rigidness <= 0 ? int.MaxValue : (int)Math.Round(10 - (10 * rigidness)); int n = last_hull.Count; int start = last_vert; for (int i = 1; i < n; i++) { IntPoint a = last_hull[last_vert]; IntPoint b = last_hull[(start + i) % n]; IntPoint c = last_hull[(start + i + 1) % n]; IntPoint ab = new IntPoint(b.X - a.X, b.Y - a.Y); IntPoint ac = new IntPoint(c.X - a.X, c.Y - a.Y); if (ab.Y * ac.X < ab.X * ac.Y || steps_since_insert >= max_steps) { hull.Add(b); last_vert = (start + i) % n; steps_since_insert = -1; } steps_since_insert++; } last_vert = 0; double hull_area = Clipper.Area(hull); if (subj_area / hull_area < Math.Sqrt(rigidness)) { hull = Clipper.SimplifyPolygon(hull, PolyFillType.pftNonZero)[0]; break; } } return(hull); }