예제 #1
0
        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);
            }
        }
예제 #2
0
        private static Ngons MSumSimple(Ngon pattern, Ngons subject, bool flip_pattern)
        {
            IntRect pB = GetBounds(pattern);
            IntRect sB = GetBounds(subject[0]);

            if (flip_pattern)
            {
                pB = new IntRect(-pB.right, -pB.bottom, -pB.left, -pB.top);
            }

            long l = pB.left + sB.left;
            long r = pB.right + sB.right;
            long t = pB.top + sB.top;
            long b = pB.bottom + sB.bottom;

            Ngon p = new Ngon()
            {
                new IntPoint(l, b), new IntPoint(r, b), new IntPoint(r, t), new IntPoint(l, t)
            };

            return(new Ngons()
            {
                p
            });
        }
예제 #3
0
        private static Ngons MSumFull(Ngon pattern, Ngons subject, bool flip_pattern)
        {
            Clipper clipper = new Clipper();

            Ngons full = new Ngons();

            long scale = flip_pattern ? -1 : 1;

            for (int i = 0; i < pattern.Count; i++)
            {
                clipper.AddPaths(subject.Clone(scale * pattern[i].X, scale * pattern[i].Y), PolyType.ptSubject, true);
            }

            clipper.Execute(ClipType.ctUnion, full, PolyFillType.pftNonZero);
            clipper.Clear();

            clipper.AddPaths(full, PolyType.ptSubject, true);
            clipper.AddPaths(MinkowskiSumBoundary(pattern, subject, flip_pattern), PolyType.ptSubject, true);

            Ngons res = new Ngons();

            clipper.Execute(ClipType.ctUnion, res, PolyFillType.pftNonZero);

            return(res);
        }
예제 #4
0
        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);
        }
예제 #5
0
        public static Ngons Clone(this Ngons polys, Mat3x3 T)
        {
            Ngons clone = new Ngons(polys.Count);

            for (int i = 0; i < polys.Count; i++)
            {
                clone.Add(polys[i].Clone(T));
            }
            return(clone);
        }
예제 #6
0
        public static Ngons Clone(this Ngons polys, long shift_x, long shift_y, bool flip_first = false)
        {
            Ngons clone = new Ngons(polys.Count);

            for (int i = 0; i < polys.Count; i++)
            {
                clone.Add(polys[i].Clone(shift_x, shift_y, flip_first));
            }
            return(clone);
        }
예제 #7
0
            public Ngons GetTransformedPoly()
            {
                Ngons n = new Ngons(poly.Count);

                for (int i = 0; i < poly.Count; i++)
                {
                    Ngon nn = new Ngon(poly[i].Count);
                    for (int j = 0; j < poly[i].Count; j++)
                    {
                        nn.Add(GetTransformedPoint(i, j));
                    }
                    n.Add(nn);
                }
                return(n);
            }
예제 #8
0
        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]
            });
        }
예제 #9
0
        public static Ngons MinkowskiSumBoundary(Ngon pattern, Ngons path, bool flip_pattern)
        {
            Clipper clipper = new Clipper();

            Ngons full = new Ngons();

            for (int i = 0; i < path.Count; i++)
            {
                Ngons seg = MinkowskiSumBoundary(pattern, path[i], flip_pattern);
                clipper.AddPaths(full, PolyType.ptSubject, true);
                clipper.AddPaths(seg, PolyType.ptSubject, true);

                Ngons res = new Ngons();
                clipper.Execute(ClipType.ctUnion, res, PolyFillType.pftNonZero);
                full = res;
                clipper.Clear();
            }

            return(full);
        }
예제 #10
0
        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);
        }
예제 #11
0
        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));
        }
예제 #12
0
        /// <summary>
        /// Append a set triangulated polygons to the nester and get handles for each point to the correp. polygon island
        /// </summary>
        /// <param name="points"></param>
        /// <param name="tris"></param>
        /// <returns></returns>
        public int[] AddPolygons(IntPoint[] points, int[] tris, double miter_distance = 0.0)
        {
            // from points to clusters of tris
            int[] poly_map = new int[points.Length];
            for (int i = 0; i < poly_map.Length; i++)
            {
                poly_map[i] = -1;
            }

            HashSet <int>[] graph = new HashSet <int> [points.Length];
            for (int i = 0; i < graph.Length; i++)
            {
                graph[i] = new HashSet <int>();
            }
            for (int i = 0; i < tris.Length; i += 3)
            {
                int t1 = tris[i];
                int t2 = tris[i + 1];
                int t3 = tris[i + 2];

                graph[t1].Add(t2);
                graph[t1].Add(t3);
                graph[t2].Add(t1);
                graph[t2].Add(t3);
                graph[t3].Add(t1);
                graph[t3].Add(t2);
            }

            if (graph.Any(p => p.Count == 0))
            {
                throw new Exception("No singular vertices should exist on mesh");
            }

            int[] clust_ids = new int[points.Length];

            HashSet <int> unmarked  = new HashSet <int>(Enumerable.Range(0, points.Length));
            int           clust_cnt = 0;

            while (unmarked.Count > 0)
            {
                Queue <int> open  = new Queue <int>();
                int         first = unmarked.First();
                unmarked.Remove(first);
                open.Enqueue(first);
                while (open.Count > 0)
                {
                    int c = open.Dequeue();
                    clust_ids[c] = clust_cnt;
                    foreach (int n in graph[c])
                    {
                        if (unmarked.Contains(n))
                        {
                            unmarked.Remove(n);
                            open.Enqueue(n);
                        }
                    }
                }

                clust_cnt++;
            }

            Ngons[] clusters = new Ngons[clust_cnt];
            for (int i = 0; i < tris.Length; i += 3)
            {
                int clust = clust_ids[tris[i]];
                if (clusters[clust] == null)
                {
                    clusters[clust] = new Ngons();
                }

                IntPoint p1 = points[tris[i]];
                IntPoint p2 = points[tris[i + 1]];
                IntPoint p3 = points[tris[i + 2]];

                clusters[clust].Add(new Ngon()
                {
                    p1, p2, p3
                });
            }

            List <Ngons> fulls = new List <Ngons>();

            for (int i = 0; i < clust_cnt; i++)
            {
                Ngons cl = clusters[i];

                Clipper c = new Clipper();
                foreach (Ngon n in cl)
                {
                    c.AddPath(n, PolyType.ptSubject, true);
                }

                Ngons full = new Ngons();
                c.Execute(ClipType.ctUnion, full, PolyFillType.pftNonZero);
                full = Clipper.SimplifyPolygons(full, PolyFillType.pftNonZero);

                if (miter_distance > 0.00001)
                {
                    Ngons         full_miter = new Ngons();
                    ClipperOffset co         = new ClipperOffset();
                    co.AddPaths(full, JoinType.jtMiter, EndType.etClosedPolygon);
                    co.Execute(ref full_miter, miter_distance);
                    full_miter = Clipper.SimplifyPolygons(full_miter, PolyFillType.pftNonZero);
                    fulls.Add(full_miter);
                }
                else
                {
                    fulls.Add(full);
                }
            }

            for (int i = 0; i < clust_ids.Length; i++)
            {
                clust_ids[i] += polygon_lib.Count;
            }

            for (int i = 0; i < fulls.Count; i++)
            {
                polygon_lib.Add(new PolyRef()
                {
                    poly = fulls[i], trans = Mat3x3.Eye()
                });
            }

            return(clust_ids);
        }
예제 #13
0
        /// <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);
        }