public static Ngons MinkowskiSum(Ngon pattern, Ngons subject, NFPQUALITY quality, bool flip_pattern) { switch (quality) { case NFPQUALITY.Simple: return(MSumSimple(pattern, subject, flip_pattern)); case NFPQUALITY.Convex: return(MSumConvex(pattern, subject, flip_pattern)); case NFPQUALITY.ConcaveLight: return(MSumConcave(pattern, subject, flip_pattern, 0.25)); case NFPQUALITY.ConcaveMedium: return(MSumConcave(pattern, subject, flip_pattern, 0.55)); case NFPQUALITY.ConcaveHigh: return(MSumConcave(pattern, subject, flip_pattern, 0.85)); case NFPQUALITY.ConcaveFull: return(MSumConcave(pattern, subject, flip_pattern, 1.0)); case NFPQUALITY.Full: return(MSumFull(pattern, subject, flip_pattern)); default: return(null); } }
public void CMD_Nest(IEnumerable <int> handles, NFPQUALITY max_quality = NFPQUALITY.Full) { command_buffer.Enqueue(new Command() { Call = cmd_nest, param = new object[] { handles, max_quality } }); }
/// <summary> /// Parallel kernel for generating NFP of pattern on handle, return the index in the library of this NFP /// Decides the optimal quality for this NFP /// </summary> /// <param name="subj_handle"></param> /// <param name="pattern_handle"></param> /// <param name="lib_set_at"></param> /// <returns></returns> private int NFPKernel(int subj_handle, int pattern_handle, double max_area_bounds, int lib_set_at, NFPQUALITY max_quality = NFPQUALITY.Full) { NFPQUALITY quality = GetNFPQuality(subj_handle, pattern_handle, max_area_bounds); quality = (NFPQUALITY)Math.Min((int)quality, (int)max_quality); return(AddMinkowskiSum(subj_handle, pattern_handle, quality, true, lib_set_at)); }
public int AddMinkowskiSum(int subj_handle, int pattern_handle, NFPQUALITY quality, bool flip_pattern, int set_at = -1) { Ngons A = polygon_lib[subj_handle].GetTransformedPoly(); Ngons B = polygon_lib[pattern_handle].GetTransformedPoly(); Ngons C = GeomUtility.MinkowskiSum(B[0], A, quality, flip_pattern); PolyRef pref = new PolyRef() { poly = C, trans = Mat3x3.Eye() }; if (set_at < 0) { polygon_lib.Add(pref); } else { polygon_lib[set_at] = pref; } return(set_at < 0 ? polygon_lib.Count - 1 : set_at); }
/// <summary> /// Nest the collection of handles with minimal enclosing square from origin /// </summary> /// <param name="handles"></param> private void cmd_nest(params object[] param) { HashSet <int> unique = PreprocessHandles(param[0] as IEnumerable <int>); NFPQUALITY max_quality = (NFPQUALITY)param[1]; cmd_translate_origin_to_zero(unique); int n = unique.Count; Dictionary <int, IntRect> bounds = new Dictionary <int, IntRect>(); foreach (int handle in unique) { bounds.Add(handle, GeomUtility.GetBounds(polygon_lib[handle].GetTransformedPoly()[0])); } int[] ordered_handles = unique.OrderByDescending(p => Math.Max(bounds[p].Height(), bounds[p].Width())).ToArray(); double max_bound_area = bounds[ordered_handles[0]].Area(); int start_cnt = polygon_lib.Count; int[] canvas_regions = AddCanvasFitPolygon(ordered_handles); int base_cnt = polygon_lib.Count; for (int i = 0; i < n * n - n; i++) { polygon_lib.Add(new PolyRef()); } int update_breaks = 10; int nfp_chunk_sz = n * n / update_breaks * update_breaks == n * n ? n * n / update_breaks : n * n / update_breaks + 1; // the row corresponds to pattern and col to nfp for this pattern on col subj int[,] nfps = new int[n, n]; for (int k = 0; k < update_breaks; k++) { int start = k * nfp_chunk_sz; int end = Math.Min((k + 1) * nfp_chunk_sz, n * n); if (start >= end) { break; } Parallel.For(start, end, i => nfps[i / n, i % n] = i / n == i % n ? -1 : NFPKernel(ordered_handles[i % n], ordered_handles[i / n], max_bound_area, base_cnt + i - (i % n > i / n ? 1 : 0) - i / n, max_quality)); double progress = Math.Min(((double)(k + 1)) / (update_breaks + 1) * 50.0, 50.0); background_worker.ReportProgress((int)progress); if (background_worker.CancellationPending) { break; } } int place_chunk_sz = Math.Max(n / update_breaks, 1); bool[] placed = new bool[n]; for (int i = 0; i < n; i++) { if (i % 10 == 0 && background_worker.CancellationPending) { break; } Clipper c = new Clipper(); c.AddPath(polygon_lib[canvas_regions[i]].poly[0], PolyType.ptSubject, true); for (int j = 0; j < i; j++) { if (!placed[j]) { continue; } c.AddPaths(polygon_lib[nfps[i, j]].GetTransformedPoly(), PolyType.ptClip, true); } Ngons fit_region = new Ngons(); c.Execute(ClipType.ctDifference, fit_region, PolyFillType.pftNonZero); IntPoint o = polygon_lib[ordered_handles[i]].GetTransformedPoint(0, 0); IntRect bds = bounds[ordered_handles[i]]; long ext_x = bds.right - o.X; long ext_y = bds.top - o.Y; IntPoint place = new IntPoint(0, 0); long pl_score = long.MaxValue; for (int k = 0; k < fit_region.Count; k++) { for (int l = 0; l < fit_region[k].Count; l++) { IntPoint cand = fit_region[k][l]; long cd_score = Math.Max(cand.X + ext_x, cand.Y + ext_y); if (cd_score < pl_score) { pl_score = cd_score; place = cand; placed[i] = true; } } } if (!placed[i]) { continue; } cmd_translate(ordered_handles[i], (double)(place.X - o.X), (double)(place.Y - o.Y)); for (int k = i + 1; k < n; k++) { cmd_translate(nfps[k, i], (double)(place.X - o.X), (double)(place.Y - o.Y)); } if (i % place_chunk_sz == 0) { double progress = Math.Min(60.0 + ((double)(i / place_chunk_sz)) / (update_breaks + 1) * 40.0, 100.0); background_worker.ReportProgress((int)progress); } } // remove temporary added values polygon_lib.RemoveRange(start_cnt, polygon_lib.Count - start_cnt); }