Esempio n. 1
0
        /// <summary>
        /// Get the optimal quality for tradeoff between speed and precision of NFP
        /// </summary>
        /// <param name="subj_handle"></param>
        /// <param name="pattern_handle"></param>
        /// <returns></returns>
        private NFPQUALITY GetNFPQuality(int subj_handle, int pattern_handle, double max_area_bounds)
        {
            Ngon S = polygon_lib[subj_handle].GetTransformedPoly()[0];
            Ngon P = polygon_lib[pattern_handle].GetTransformedPoly()[0];

            if (GeomUtility.AlmostRectangle(S) && GeomUtility.AlmostRectangle(P))
            {
                return(NFPQUALITY.Simple);
            }

            double s_A = GeomUtility.GetBounds(S).Area();
            double p_A = GeomUtility.GetBounds(P).Area();

            if (p_A / s_A > 1000)
            {
                return(NFPQUALITY.Simple);
            }

            if (s_A / max_area_bounds < 0.05)
            {
                return(NFPQUALITY.Simple);
            }

            if (p_A / s_A > 100)
            {
                return(NFPQUALITY.Convex);
            }

            if (p_A / s_A > 50)
            {
                return(NFPQUALITY.ConcaveLight);
            }

            if (p_A / s_A > 10)
            {
                return(NFPQUALITY.ConcaveMedium);
            }

            if (p_A / s_A > 2)
            {
                return(NFPQUALITY.ConcaveHigh);
            }

            if (p_A / s_A > 0.25)
            {
                return(NFPQUALITY.ConcaveFull);
            }

            return(NFPQUALITY.Full);
        }
Esempio n. 2
0
        public int AddCanvasFitPolygon(IntRect canvas, int pattern_handle)
        {
            Ngon B = polygon_lib[pattern_handle].GetTransformedPoly()[0];

            Ngon C = GeomUtility.CanFitInsidePolygon(canvas, B);

            polygon_lib.Add(new PolyRef()
            {
                poly = new Ngons()
                {
                    C
                }, trans = Mat3x3.Eye()
            });
            return(polygon_lib.Count - 1);
        }
Esempio n. 3
0
        public int[] AddCanvasFitPolygon(IEnumerable <int> handles)
        {
            HashSet <int> unique = PreprocessHandles(handles);

            long w = 0;
            long h = 0;

            foreach (int i in unique)
            {
                IntRect bds = GeomUtility.GetBounds(polygon_lib[i].GetTransformedPoly()[0]);
                w += bds.Width();
                h += bds.Height();
            }

            w += 1000;
            h += 1000;

            IntRect canvas = new IntRect(0, h, w, 0);

            return(handles.Select(p => AddCanvasFitPolygon(canvas, p)).ToArray());
        }
Esempio n. 4
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);
        }
Esempio n. 5
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);
        }
Esempio n. 6
0
        private void cmd_refit(params object[] param)
        {
            Rect64        target  = (Rect64)param[0];
            bool          stretch = (bool)param[1];
            HashSet <int> unique  = PreprocessHandles(param[2] as IEnumerable <int>);

            HashSet <Vector64> points = new HashSet <Vector64>();

            foreach (int i in unique)
            {
                points.UnionWith(polygon_lib[i].poly[0].Select(p => polygon_lib[i].trans * new Vector64(p.X, p.Y)));
            }

            Vector64 scale, trans;

            GeomUtility.GetRefitTransform(points, target, stretch, out scale, out trans);

            foreach (int i in unique)
            {
                cmd_scale(i, scale.X, scale.Y);
                cmd_translate(i, trans.X, trans.Y);
            }
        }
Esempio n. 7
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);
        }