Beispiel #1
0
        /**
         *  将NestPath列表转换成父子关系的树
         * @param list
         * @param idstart
         * @return
         */
        public static int toTree(List <NestPath> list, int idstart)
        {
            List <NestPath> parents = new List <NestPath>();
            int             id      = idstart;

            /**
             * 找出所有的内回环
             */
            for (int i = 0; i < list.Count; i++)
            {
                NestPath p       = list[i];
                bool     isChild = false;
                for (int j = 0; j < list.Count; j++)
                {
                    if (j == i)
                    {
                        continue;
                    }

                    if (GeometryUtil.pointInPolygon(p.getSegments()[0], list[j]) == true)
                    {
                        list[j].getChildren().Add(p);
                        p.setParent(list[j]);
                        isChild = true;
                        break;
                    }
                }
                if (!isChild)
                {
                    parents.Add(p);
                }
            }

            /**
             *  将内环从list列表中去除
             */
            for (int i = 0; i < list.Count; i++)
            {
                if (parents.IndexOf(list[i]) < 0)
                {
                    list.RemoveAt(i);
                    i--;
                }
            }

            for (int i = 0; i < parents.Count; i++)
            {
                parents[i].setId(id);
                id++;
            }

            for (int i = 0; i < parents.Count; i++)
            {
                if (parents[i].getChildren().Count > 0)
                {
                    id = toTree(parents[i].getChildren(), id);
                }
            }
            return(id);
        }
        /**
         * 为一个polygon 返回一个角度
         * @param part
         * @return
         */
        private double randomAngle(NestPath part)
        {
            List <double> angleList = new List <double>();
            double        rotate    = Math.Max(1, part.getRotation());

            if (rotate == 0)
            {
                angleList.Add(0);
            }
            else
            {
                for (int i = 0; i < rotate; i++)
                {
                    angleList.Add((360 / rotate) * i);
                }
            }
            //打乱角度列表的排序
            angleList.Shuffle();
            //Collections.shuffle(angleList);
            for (int i = 0; i < angleList.Count; i++)
            {
                Bound rotatedPart = GeometryUtil.rotatePolygon(part, angleList[i]);
                if (rotatedPart.getWidth() < binBounds.getWidth() && rotatedPart.getHeight() < binBounds.getHeight())
                {
                    return(angleList[i]);
                }
            }

            /**
             * 没有找到合法的角度
             */
            return(-1);
        }
Beispiel #3
0
        /**
         * 在遗传算法中每次突变或者是交配产生出新的种群时,可能会出现板件与旋转角度不适配的结果,需要重新检查并适配。
         * @param binPolygon
         * @param tree
         * @return
         */
        private static List <int> checkIfCanBePlaced(NestPath binPolygon, List <NestPath> tree)
        {
            List <int> CanBePlacdPolygonIndex = new List <int>();
            Bound      binBound = GeometryUtil.getPolygonBounds(binPolygon);

            for (int i = 0; i < tree.Count; i++)
            {
                NestPath nestPath = tree[i];
                if (nestPath.getRotation() == 0)
                {
                    Bound bound = GeometryUtil.getPolygonBounds(nestPath);
                    if (bound.width < binBound.width && bound.height < binBound.height)
                    {
                        CanBePlacdPolygonIndex.Add(i);
                        continue;
                    }
                }
                else
                {
                    for (int j = 0; j < nestPath.getRotation(); j++)
                    {
                        Bound rotatedBound = GeometryUtil.rotatePolygon(nestPath, (360 / nestPath.getRotation()) * j);
                        if (rotatedBound.width < binBound.width && rotatedBound.height < binBound.height)
                        {
                            CanBePlacdPolygonIndex.Add(i);
                            break;
                        }
                    }
                }
            }
            return(CanBePlacdPolygonIndex);
        }
Beispiel #4
0
        static void Main(string[] args)
        {
            NestPath bin       = new NestPath();
            double   binWidth  = 75;
            double   binHeight = 41;

            bin.add(0, 0);
            bin.add(binWidth, 0);
            bin.add(binWidth, binHeight);
            bin.add(0, binHeight);
            Console.WriteLine("Bin Size : Width = " + binWidth + " Height=" + binHeight);
            //将多边形转换为坐标形式
            var nestPaths = SvgUtil.transferSvgIntoPolygons("test3.xml");

            Console.WriteLine("Reading File = test1.xml");
            Console.WriteLine("No of parts = " + nestPaths.Count);
            Config config = new Config();

            Console.WriteLine("Configuring Nest");
            Nest nest = new Nest(bin, nestPaths, config, 2);

            Console.WriteLine("Performing Nest");
            List <List <Placement> > appliedPlacement = nest.startNest();

            Console.WriteLine("Nesting Completed");
            var svgPolygons = SvgUtil.svgGenerator(nestPaths, appliedPlacement, binWidth, binHeight);

            Console.WriteLine("Converted to SVG format");
            SvgUtil.saveSvgFile(svgPolygons, "output.svg");
            Console.WriteLine("Saved svg file..Opening File");
            Process.Start("output.svg");
            Console.ReadLine();
        }
Beispiel #5
0
 /**
  *  创建一个新的Nest对象
  * @param binPath   底板多边形
  * @param parts     板件多边形列表
  * @param config    参数设置
  * @param count     迭代计算次数
  */
 public Nest(NestPath binPath, List <NestPath> parts, Config config, int count)
 {
     this.binPath   = binPath;
     this.parts     = parts;
     this.config    = config;
     this.loopCount = count;
     nfpCache       = new Dictionary <string, List <NestPath> >();
 }
 public GeneticAlgorithm(List <NestPath> adam, NestPath bin, Config config)
 {
     this.adam      = adam;
     this.bin       = bin;
     this.config    = config;
     this.binBounds = GeometryUtil.getPolygonBounds(bin);
     population     = new List <Individual>();
     init();
 }
Beispiel #7
0
        public static NestPath toNestCoordinates(Path polygon)
        {
            NestPath clone = new NestPath();

            for (int i = 0; i < polygon.Count; i++)
            {
                Segment s = new Segment((double)polygon[i].X / Config.CLIIPER_SCALE, (double)polygon[i].Y / Config.CLIIPER_SCALE);
                clone.add(s);
            }
            return(clone);
        }
Beispiel #8
0
        /**
         *  坐标转换,与clipper库交互必须坐标转换
         * @param polygon
         * @return
         */
        public static Path scaleUp2ClipperCoordinates(NestPath polygon)
        {
            Path p = new Path();

            foreach (Segment s in polygon.getSegments())
            {
                ClipperCoor cc = CommonUtil.toClipperCoor(s.x, s.y);
                p.Add(new IntPoint(cc.getX(), cc.getY()));
            }
            return(p);
        }
Beispiel #9
0
        public static NestPath clipperToNestPath(Path polygon)
        {
            NestPath normal = new NestPath();

            for (int i = 0; i < polygon.Count; i++)
            {
                NestCoor nestCoor = toNestCoor(polygon[i].X, polygon[i].Y);
                normal.add(new Segment(nestCoor.getX(), nestCoor.getY()));
            }
            return(normal);
        }
Beispiel #10
0
        public static NestPath Path2NestPath(Path path)
        {
            NestPath nestPath = new NestPath();

            for (int i = 0; i < path.Count; i++)
            {
                IntPoint lp   = path[i];
                NestCoor coor = CommonUtil.toNestCoor(lp.X, lp.Y);
                nestPath.add(new Segment(coor.getX(), coor.getY()));
            }
            return(nestPath);
        }
Beispiel #11
0
        public static Path NestPath2Path(NestPath nestPath)
        {
            Path path = new Path();

            foreach (Segment s in nestPath.getSegments())
            {
                ClipperCoor coor = CommonUtil.toClipperCoor(s.getX(), s.getY());
                var         lp   = new IntPoint(coor.getX(), coor.getY());
                path.Add(lp);
            }
            return(path);
        }
Beispiel #12
0
        public static List <NestPath> polygonOffset(NestPath polygon, double offset)
        {
            List <NestPath> result = new List <NestPath>();

            if (offset == 0 || GeometryUtil.almostEqual(offset, 0))
            {
                /**
                 * return EmptyResult
                 */
                return(result);
            }
            Path p = new Path();

            foreach (Segment s in polygon.getSegments())
            {
                ClipperCoor cc = toClipperCoor(s.getX(), s.getY());
                p.Add(new IntPoint(cc.getX(), cc.getY()));
            }

            int           miterLimit = 2;
            ClipperOffset co         = new ClipperOffset(miterLimit, Config.CURVE_TOLERANCE * Config.CLIIPER_SCALE);

            co.AddPath(p, JoinType.jtRound, EndType.etClosedPolygon);

            Paths newpaths = new Paths();

            co.Execute(ref newpaths, offset * Config.CLIIPER_SCALE);


            /**
             * 这里的length是1的话就是我们想要的
             */
            for (int i = 0; i < newpaths.Count; i++)
            {
                result.Add(CommonUtil.clipperToNestPath(newpaths[i]));
            }

            if (offset > 0)
            {
                NestPath from = result[0];
                if (GeometryUtil.polygonArea(from) > 0)
                {
                    from.reverse();
                }
                from.add(from.get(0)); from.getSegments().RemoveAt(0);
            }


            return(result);
        }
Beispiel #13
0
        public static List <NestPath> transferSvgIntoPolygons(string xmlFilePath)
        {
            List <NestPath> nestPaths = new List <NestPath>();

            XDocument       document    = XDocument.Load(xmlFilePath);
            List <XElement> elementList = document.Root.DescendantNodes().OfType <XElement>().ToList();
            int             count       = 0;

            foreach (XElement element in elementList)
            {
                count++;
                if ("polygon" == (element.Name))
                {
                    String   datalist = element.Attributes((XName)"points").ToList()[0].Value.ToString();
                    NestPath polygon  = new NestPath();
                    foreach (String s in datalist.Split(' '))
                    {
                        var temp = s.Trim();
                        if (temp.IndexOf(",") == -1)
                        {
                            continue;
                        }
                        String[] value = s.Split(',');
                        double   x     = Double.Parse(value[0]);
                        double   y     = Double.Parse(value[1]);
                        polygon.add(x, y);
                    }
                    polygon.bid = count;
                    polygon.setRotation(4);
                    nestPaths.Add(polygon);
                }
                else if ("rect" == element.Name)
                {
                    double   width  = Double.Parse(element.Attributes((XName)"width").ToList()[0].Value.ToString());
                    double   height = Double.Parse(element.Attributes((XName)"height").ToList()[0].Value.ToString());
                    double   x      = Double.Parse(element.Attributes((XName)"x").ToList()[0].Value.ToString());
                    double   y      = Double.Parse(element.Attributes((XName)"y").ToList()[0].Value.ToString());
                    NestPath rect   = new NestPath();
                    rect.add(x, y);
                    rect.add(x + width, y);
                    rect.add(x + width, y + height);
                    rect.add(x, y + height);
                    rect.bid = count;
                    rect.setRotation(4);
                    nestPaths.Add(rect);
                }
            }
            return(nestPaths);
        }
Beispiel #14
0
 public Individual(Individual individual)
 {
     fitness   = individual.fitness;
     placement = new List <NestPath>();
     rotation  = new List <double>();
     for (int i = 0; i < individual.placement.Count; i++)
     {
         NestPath cloneNestPath = new NestPath(individual.placement[i]);
         placement.Add(cloneNestPath);
     }
     for (int i = 0; i < individual.rotation.Count; i++)
     {
         double rotationAngle = individual.getRotation()[i];
         rotation.Add(rotationAngle);
     }
 }
Beispiel #15
0
        public static List <String> svgGenerator(List <NestPath> list, List <List <Placement> > applied, double binwidth, double binHeight)
        {
            List <String> strings = new List <String>();
            int           x       = 0; //代表离y轴初始边的距离
            int           y       = 0; //代表离轴初始边的距离

            foreach (List <Placement> binlist in applied)
            {
                String s = " <g transform=\"translate(" + x + "  " + y + ")\">" + "\n";
                s += "    <rect x=\"0\" y=\"0\" width=\"" + binwidth + "\" height=\"" + binHeight + "\"  fill=\"none\" stroke=\"#010101\" stroke-width=\"1\" />\n";
                foreach (Placement placement in binlist)
                {
                    int      bid      = placement.bid;
                    NestPath nestPath = getNestPathByBid(bid, list);
                    double   ox       = placement.translate.x;
                    double   oy       = placement.translate.y;
                    double   rotate   = placement.rotate;

                    var translateX = ox + x;
                    var translateY = oy + y;

                    s += "<g transform=\"translate(" + translateX + " " + translateY + ") rotate(" + rotate + ")\"> \n";
                    //s += "<path d=\"";
                    //for (int i = 0; i < nestPath.getSegments().Count; i++)
                    //{
                    //    if (i == 0)
                    //    {
                    //        s += "M";
                    //    }
                    //    else
                    //    {
                    //        s += "L";
                    //    }
                    //    Segment segment = nestPath.get(i);
                    //    s += segment.x + " " + segment.y + " ";
                    //}
                    //s += "Z\" fill=\"#8498d1\" stroke=\"#010101\" stroke-width=\"1\" />" + " \n";
                    s += nestPath.getElement();
                    s += "</g> \n";
                }
                s += "</g> \n";
                y += (int)(binHeight + 0);
                strings.Add(s);
            }
            return(strings);
        }
 public void checkAndUpdate(Individual individual)
 {
     for (int i = 0; i < individual.placement.Count; i++)
     {
         double   angle       = individual.getRotation()[i];
         NestPath nestPath    = individual.getPlacement()[i];
         Bound    rotateBound = GeometryUtil.rotatePolygon(nestPath, angle);
         if (rotateBound.width < binBounds.width && rotateBound.height < binBounds.height)
         {
             continue;
         }
         else
         {
             double safeAngle = randomAngle(nestPath);
             individual.getRotation()[i] = safeAngle;
         }
     }
 }
Beispiel #17
0
        /**
         * 对应于JS项目中的getParts
         */
        public static List <NestPath> BuildTree(List <NestPath> parts, double curve_tolerance)
        {
            List <NestPath> polygons = new List <NestPath>();

            for (int i = 0; i < parts.Count; i++)
            {
                NestPath cleanPoly = NestPath.cleanNestPath(parts[i]);
                cleanPoly.bid = parts[i].bid;
                if (cleanPoly.size() > 2 && Math.Abs(GeometryUtil.polygonArea(cleanPoly)) > curve_tolerance * curve_tolerance)
                {
                    cleanPoly.setSource(i);

                    polygons.Add(cleanPoly);
                }
            }

            CommonUtil.toTree(polygons, 0);
            return(polygons);
        }
Beispiel #18
0
        //图像偏置算法
        public static void offsetTree(List <NestPath> t, double offset)
        {
            for (int i = 0; i < t.Count; i++)
            {
                List <NestPath> offsetPaths = polygonOffset(t[i], offset);
                if (offsetPaths.Count == 1)
                {
                    t[i].clear();
                    NestPath from = offsetPaths[0];

                    foreach (Segment s in from.getSegments())
                    {
                        t[i].add(s);
                    }
                }
                if (t[i].getChildren().Count > 0)
                {
                    offsetTree(t[i].getChildren(), -offset);
                }
            }
        }
Beispiel #19
0
        /**
         *  通过id与bid将translate和rotate绑定到对应板件上
         * @param best
         * @param tree
         * @return
         */
        public static List <List <Placement> > applyPlacement(Result best, List <NestPath> tree)
        {
            List <List <Placement> > applyPlacement = new List <List <Placement> >();

            for (int i = 0; i < best.placements.Count; i++)
            {
                List <Placement> binTranslate = new List <Placement>();
                for (int j = 0; j < best.placements[i].Count; j++)
                {
                    Vector   v        = best.placements[i][j];
                    NestPath nestPath = tree[v.id];
                    foreach (NestPath child in nestPath.getChildren())
                    {
                        Placement chPlacement = new Placement(child.bid, new Segment(v.x, v.y), v.rotation);
                        binTranslate.Add(chPlacement);
                    }
                    Placement placement = new Placement(nestPath.bid, new Segment(v.x, v.y), v.rotation);
                    binTranslate.Add(placement);
                }
                applyPlacement.Add(binTranslate);
            }
            return(applyPlacement);
        }
Beispiel #20
0
 public void add(NestPath np)
 {
     parts.Add(np);
 }
Beispiel #21
0
        //private static Gson gson = new GsonBuilder().create();

        /**
         *
         * @param binPolygon    底板参数
         * @param config    设置
         * @param nfpCache  nfp列表
         */
        public PlacementWorker(NestPath binPolygon, Config config, Dictionary <String, List <NestPath> > nfpCache)
        {
            this.binPolygon = binPolygon;
            this.config     = config;
            this.nfpCache   = nfpCache;
        }
Beispiel #22
0
        public static List <NestPath> transferSvgIntoPolygons(string xmlFilePath)
        {
            List <NestPath> nestPaths = new List <NestPath>();

            XDocument       document    = XDocument.Load(xmlFilePath);
            List <XElement> elementList = document.Root.DescendantNodes().OfType <XElement>().ToList();
            //对于测试库的数据,需要做一下筛选,如果是自己弄得测试数据,这句可以不要
            var elements = elementList.Where(p => p.Name == "polygon");
            int count    = 0;
            int index    = 0;

            foreach (XElement element in elements)
            {
                count++;
                //对于测试库的数据要加上这一句
                var elementFirstNode = (XElement)element.FirstNode;
                var rotation         = int.Parse(element.Attributes((XName)"nVertices").ToList()[0].Value.ToString());

                switch (elementFirstNode.Name.ToString())
                {
                case "polyline":
                case "polygon":
                {
                    String   datalist = element.Attributes((XName)"points").ToList()[0].Value.ToString();
                    NestPath polygon  = new NestPath();
                    polygon.setElement(element.ToString());
                    foreach (String s in datalist.Split(' '))
                    {
                        var temp = s.Trim();
                        if (temp.IndexOf(",") == -1)
                        {
                            continue;
                        }
                        String[] value = s.Split(',');
                        double   x     = Double.Parse(value[0]);
                        double   y     = Double.Parse(value[1]);
                        polygon.add(x, y);      //点的坐标
                    }
                    polygon.bid = count;        //多边形的序号
                    polygon.setRotation(4);     //旋转角度,值设为4时代表角度可以旋转90、180、270,该值一般为360的倍数
                    nestPaths.Add(polygon);
                    break;
                }

                case "lines":
                {
                    index++;
                    var      piesCount = int.Parse(elementFirstNode.Attributes((XName)"count").ToList()[0].Value.ToString());
                    var      dataList  = elementFirstNode.DescendantNodes().OfType <XElement>().ToList();
                    NestPath polygon   = new NestPath();
                    string   point     = null;
                    foreach (var data in dataList)
                    {
                        if (data.Name == "segment")
                        {
                            //为了保证在排样前各个图形的坐标不重合,所以后面增加2000 * index
                            var x0 = Double.Parse(data.Attributes((XName)"x0").ToList()[0].Value.ToString()) + 20 * index;
                            var y0 = Double.Parse(data.Attributes((XName)"y0").ToList()[0].Value.ToString()) + 20 * index;
                            var x1 = Double.Parse(data.Attributes((XName)"x1").ToList()[0].Value.ToString()) + 20 * index;
                            var y1 = Double.Parse(data.Attributes((XName)"y1").ToList()[0].Value.ToString()) + 20 * index;
                            point += x0 + "," + y0 + " ";
                            polygon.add(x0, y0);
                            polygon.add(x1, y1);
                        }
                    }

                    var listTemp = polygon.getSegments();
                    var newList  = new List <Segment>();
                    for (int i = 0; i < listTemp.Count; i++)
                    {
                        if (i % 2 == 0)
                        {
                            newList.Add(listTemp[i]);
                        }
                    }
                    polygon.setSegments(newList);
                    polygon.bid = count;           //多边形的序号
                    polygon.setRotation(rotation); //旋转角度,值设为4时代表角度可以旋转90、180、270,该值一般为360的倍数
                    var elementTemp = " <polygon fill=\"none\" stroke=\"#010101\" stroke-miterlimit=\"10\" points= \"" + point + " \"></polygon>";
                    for (int i = 0; i < piesCount; i++)
                    {
                        polygon.setElement(elementTemp);
                        nestPaths.Add(polygon);
                    }
                    break;
                }

                case "rect":
                {
                    double   width  = Double.Parse(element.Attributes((XName)"width").ToList()[0].Value.ToString());
                    double   height = Double.Parse(element.Attributes((XName)"height").ToList()[0].Value.ToString());
                    double   x      = Double.Parse(element.Attributes((XName)"x").ToList()[0].Value.ToString());
                    double   y      = Double.Parse(element.Attributes((XName)"y").ToList()[0].Value.ToString());
                    NestPath rect   = new NestPath();
                    rect.setElement(element.ToString());
                    rect.add(x, y);
                    rect.add(x + width, y);
                    rect.add(x + width, y + height);
                    rect.add(x, y + height);
                    rect.bid = count;
                    rect.setRotation(4);
                    nestPaths.Add(rect);
                    break;
                }

                case "circle":    //对于圆形,给转换成坐标形式
                {
                    double cx     = Double.Parse(element.Attributes((XName)"cx").ToList()[0].Value.ToString());
                    double cy     = Double.Parse(element.Attributes((XName)"cy").ToList()[0].Value.ToString());
                    double radius = Double.Parse(element.Attributes((XName)"r").ToList()[0].Value.ToString());

                    // num is the smallest number of segments required to approximate the circle to the given tolerance
                    var num = Math.Ceiling((2 * Math.PI) / Math.Acos(1 - (ToleranceConfig.tolerance / radius)));

                    if (num < 3)
                    {
                        num = 3;
                    }

                    NestPath circle = new NestPath();
                    circle.setElement(element.ToString());
                    circle.bid = count;
                    circle.setRotation(4);

                    for (var i = 0; i < num; i++)
                    {
                        var    theta = i * ((2 * Math.PI) / num);
                        double x     = radius * Math.Cos(theta) + cx;
                        double y     = radius * Math.Sin(theta) + cy;
                        circle.add(x, y);
                    }
                    nestPaths.Add(circle);

                    break;
                }

                case "ellipse":    //对于椭圆,给转换成坐标形式
                {
                    // same as circle case. There is probably a way to reduce points but for convenience we will just flatten the equivalent circular polygon
                    var rx = Double.Parse(element.Attributes((XName)"rx").ToList()[0].Value.ToString());

                    var ry        = Double.Parse(element.Attributes((XName)"ry").ToList()[0].Value.ToString());
                    var maxradius = Math.Max(rx, ry);

                    var cx = Double.Parse(element.Attributes((XName)"cx").ToList()[0].Value.ToString());
                    var cy = Double.Parse(element.Attributes((XName)"cy").ToList()[0].Value.ToString());

                    var num = Math.Ceiling((2 * Math.PI) / Math.Acos(1 - (ToleranceConfig.tolerance / maxradius)));

                    if (num < 3)
                    {
                        num = 3;
                    }

                    NestPath ellipse = new NestPath();
                    ellipse.setElement(element.ToString());
                    ellipse.bid = count;
                    ellipse.setRotation(4);
                    for (var i = 0; i < num; i++)
                    {
                        var    theta = i * ((2 * Math.PI) / num);
                        double x     = maxradius * Math.Cos(theta) + cx;
                        double y     = maxradius * Math.Sin(theta) + cy;
                        ellipse.add(x, y);
                    }
                    nestPaths.Add(ellipse);
                    break;
                }

                case "path":    //对于带弧形的多边形,给转换成坐标形式
                {
                    var      path           = element.Attributes((XName)"d").ToList()[0].Value.ToString();
                    var      pathNumbers    = transferPathToNumber(path);
                    string   pathNumberType = "MLHVCSQTA";
                    NestPath pathPloy       = new NestPath();
                    pathPloy.setElement(element.ToString());
                    pathPloy.bid = count;
                    pathPloy.setRotation(4);

                    double x, y, x0, y0, x1, y1, x2, y2, prevx, prevy, prevx1, prevy1, prevx2, prevy2;
                    x = y = x0 = y0 = x1 = y1 = x2 = y2 = prevx = prevy = prevx1 = prevy1 = prevx2 = prevy2 = 0;

                    for (var i = 0; i < pathNumbers.Count; i++)
                    {
                        var s       = pathNumbers[i].Numbers;  ////对应C#中的pathNumber的Numbers
                        var command = pathNumbers[i].Type;     //对应C#中的pathNumber的path type

                        prevx = x;
                        prevy = y;

                        prevx1 = x1;
                        prevy1 = y1;

                        prevx2 = x2;
                        prevy2 = y2;

                        if (pathNumberType.Contains(command))
                        {
                            switch (command)
                            {
                            case "M":
                            case "L":
                            case "T":
                            {
                                x = s[0];
                                y = s[1];
                                break;
                            }

                            case "H":
                            {
                                x = s[0];
                                break;
                            }

                            case "V":
                            {
                                y = s[0];
                                break;
                            }

                            case "Q":
                            {
                                x1 = s[0];
                                y1 = s[1];
                                x  = s[2];
                                y  = s[3];
                                break;
                            }

                            case "S":
                            {
                                x2 = s[0];
                                y2 = s[1];
                                x  = s[2];
                                y  = s[3];
                                break;
                            }

                            case "C":
                            {
                                x1 = s[0];
                                y1 = s[1];
                                x2 = s[2];
                                y2 = s[3];
                                x  = s[4];
                                y  = s[5];
                                break;
                            }
                            }
                        }
                        else
                        {
                            switch (command)
                            {
                            case "m":
                            case "l":
                            case "t":
                            {
                                x += s[0];
                                y += s[1];
                                break;
                            }

                            case "h":
                            {
                                x += s[0];
                                break;
                            }

                            case "v":
                            {
                                y += s[0];
                                break;
                            }

                            case "q":
                            {
                                x1 = x + s[0];
                                y1 = y + s[1];
                                x += s[2];
                                y += s[3];
                                break;
                            }

                            case "s":
                            {
                                x2 = x + s[0];
                                y2 = y + s[1];
                                x += s[2];
                                y += s[3];
                                break;
                            }

                            case "c":
                            {
                                x1 = x + s[0];
                                y1 = y + s[1];
                                x2 = x + s[2];
                                y2 = y + s[3];
                                x += s[4];
                                y += s[5];
                                break;
                            }
                            }
                        }

                        switch (command)
                        {
                        // linear line types
                        case "m":
                        case "M":
                        case "l":
                        case "L":
                        case "h":
                        case "H":
                        case "v":
                        case "V":
                            pathPloy.add(x, y);
                            break;

                        // Quadratic Beziers
                        case "t":
                        case "T":
                        {
                            // implicit control point
                            var tPathNumberType = "QqTt";
                            if (i > 0 && tPathNumberType.Contains(pathNumbers[i - 1].Type))
                            {
                                x1 = prevx + (prevx - prevx1);
                                y1 = prevy + (prevy - prevy1);
                            }
                            else
                            {
                                x1 = prevx;
                                y1 = prevy;
                            }
                            break;
                        }

                        case "q":
                        case "Q":
                        {
                            var pointlist = GeometryUtil.QuadraticBezierLinearize(new Segment(x: prevx, y: prevy), new Segment(x: x, y: y), new Segment(x: x1, y: y1), ToleranceConfig.tolerance);
                            pointlist.Remove(pointlist[0]);                 // firstpoint would already be in the poly
                            for (var j = 0; j < pointlist.Count; j++)
                            {
                                pathPloy.add(pointlist[j].x, pointlist[j].y);
                            }
                            break;
                        }

                        case "s":
                        case "S":
                        {
                            var sPathNumberType = "CcSs";
                            if (i > 0 && sPathNumberType.Contains(pathNumbers[i - 1].Type))
                            {
                                x1 = prevx + (prevx - prevx2);
                                y1 = prevy + (prevy - prevy2);
                            }
                            else
                            {
                                x1 = prevx;
                                y1 = prevy;
                            }
                            break;
                        }

                        case "c":
                        case "C":
                        {
                            var pointlist = GeometryUtil.CubicBezierLinearize(new Segment(x: prevx, y: prevy), new Segment(x: x, y: y), new Segment(x: x1, y: y1), new Segment(x: x2, y: y2), ToleranceConfig.tolerance);
                            pointlist.Remove(pointlist[0]);                 // firstpoint would already be in the poly
                            for (var j = 0; j < pointlist.Count; j++)
                            {
                                pathPloy.add(pointlist[j].x, pointlist[j].y);
                            }
                            break;
                        }

                        case "a":
                        case "A":
                        {
                            //var pointlist = GeometryUtil.Arc.linearize({ x: prevx, y: prevy}, { x: x, y: y}, s.r1, s.r2, s.angle, s.largeArcFlag,s.sweepFlag, this.conf.tolerance
                            //pointlist.shift();

                            //for (var j = 0; j < pointlist.length; j++)
                            //{
                            //    var point = { };
                            //    point.x = pointlist[j].x;
                            //    point.y = pointlist[j].y;
                            //    poly.push(point);
                            //}
                            break;
                        }

                        case "z":
                        case "Z":
                        {
                            x = x0;
                            y = y0;
                            break;
                        }
                        }
                        // Record the start of a subpath
                        if (command == "M" || command == "m")
                        {
                            x0 = x;
                            y0 = y;
                        }
                    }


                    // 判断最后一个点是不是和第一个点一样,如果一样,就去除最后一个点
                    while (pathPloy.getSegments().Count > 0 && GeometryUtil.almostEqual(pathPloy.getSegments()[0].x, pathPloy.getSegments()[pathPloy.getSegments().Count - 1].x, ToleranceConfig.toleranceSvg) && GeometryUtil.almostEqual(pathPloy.getSegments()[0].y, pathPloy.getSegments()[pathPloy.getSegments().Count - 1].y, ToleranceConfig.toleranceSvg))
                    {
                        pathPloy.getSegments().RemoveAt(pathPloy.getSegments().Count - 1);
                    }

                    nestPaths.Add(pathPloy);
                    break;
                }
                }
            }
            return(nestPaths);
        }
 public void setBin(NestPath bin)
 {
     this.bin = bin;
 }
Beispiel #24
0
 /**
  * binPath是作为底板的NestPath , polys则为板件的Path列表
  * 这个方法是为了将binPath和polys在不改变自身形状,角度的情况下放置在一个坐标系内,保证两两之间不交叉
  * @param binPath
  * @param polys
  */
 public static void ChangePosition(NestPath binPath, List <NestPath> polys)
 {
 }
Beispiel #25
0
 public void setBinPath(NestPath binPath)
 {
     this.binPath = binPath;
 }
Beispiel #26
0
        /**
         *  一次迭代计算
         * @param tree  板件列表(去掉了带孔的多边形内孔的点集)
         * @param binPolygon    底板
         * @param config    设置
         * @return
         */
        public Result launchWorkers(List <NestPath> tree, NestPath binPolygon, Config config)
        {
            launchcount++;
            if (GA == null)
            {
                List <NestPath> adam = new List <NestPath>();
                foreach (var nestPath in tree)
                {
                    var clone = new NestPath(nestPath);
                    adam.Add(clone);
                }
                foreach (NestPath nestPath in adam)
                {
                    nestPath.area = GeometryUtil.polygonArea(nestPath);
                }
                //按零件的面积由大到小排序
                adam.Sort((x, y) => x.area.CompareTo(y.area));
                //Collections.sort(adam);
                GA = new GeneticAlgorithm(adam, binPolygon, config);
            }

            Individual individual = null;

            for (int i = 0; i < GA.population.Count; i++)
            {
                if (GA.population[i].getFitness() < 0)
                {
                    individual = GA.population[i];
                    break;
                }
            }
            //        if(individual == null ){
            //            GA.generation();
            //            individual = GA.population.get(1);
            //        }
            if (launchcount > 1 && individual == null)
            {
                GA.generation();
                individual = GA.population[1];
            }

            // 以上为GA

            List <NestPath> placelist = individual.getPlacement();
            List <double>   rotations = individual.getRotation();

            List <int> ids = new List <int>();

            for (int i = 0; i < placelist.Count; i++)
            {
                ids.Add(placelist[i].getId());
                placelist[i].setRotation(rotations[i]);
            }
            List <NfpPair> nfpPairs = new List <NfpPair>();
            NfpKey         key      = null;

            /**
             * 如果在nfpCache里没找到nfpKey 则添加进nfpPairs
             */
            for (int i = 0; i < placelist.Count; i++)
            {
                NestPath part = placelist[i];
                //这个是零件和底板之间形成的nfp,所以inside这个参数为true
                key = new NfpKey(binPolygon.getId(), part.getId(), true, 0, part.getRotation());
                if (!nfpCache.ContainsKey(serialize.Serialize(key)))
                {
                    nfpPairs.Add(new NfpPair(binPolygon, part, key));
                }
                else
                {
                }

                //这个是零件之间相互形成的nfp,所以inside这个参数为false
                for (int j = 0; j < i; j++)
                {
                    NestPath placed = placelist[j];
                    NfpKey   keyed  = new NfpKey(placed.getId(), part.getId(), false, rotations[j], rotations[i]);
                    nfpPairs.Add(new NfpPair(placed, part, keyed));
                }
            }


            /**
             * 第一次nfpCache为空 ,nfpCache存的是nfpKey所对应的两个polygon所形成的Nfp( List<NestPath> )
             */
            List <ParallelData> generatedNfp = new List <ParallelData>();

            foreach (NfpPair nfpPair in nfpPairs)
            {
                ParallelData dataTemp = NfpUtil.nfpGenerator(nfpPair, config);
                generatedNfp.Add(dataTemp);
            }
            for (int i = 0; i < generatedNfp.Count; i++)
            {
                ParallelData Nfp = generatedNfp[i];
                //TODO remove gson & generate a new key algorithm
                String tkey = serialize.Serialize(Nfp.getKey()); //gson.toJson(Nfp.getKey());
                if (!nfpCache.ContainsKey(tkey))
                {
                    nfpCache.Add(tkey, Nfp.value);
                }
                else
                {
                }
            }

            PlacementWorker worker         = new PlacementWorker(binPolygon, config, nfpCache);
            List <NestPath> placeListSlice = new List <NestPath>();



            for (int i = 0; i < placelist.Count; i++)
            {
                placeListSlice.Add(new NestPath(placelist[i]));
            }
            List <List <NestPath> > data = new List <List <NestPath> >();

            data.Add(placeListSlice);
            List <Result> placements = new List <Result>();

            for (int i = 0; i < data.Count; i++)
            {
                Result result = worker.placePaths(data[i]);
                placements.Add(result);
            }
            if (placements.Count == 0)
            {
                return(null);
            }
            individual.fitness = placements[0].fitness;
            Result bestResult = placements[0];

            for (int i = 1; i < placements.Count; i++)
            {
                if (placements[i].fitness < bestResult.fitness)
                {
                    bestResult = placements[i];
                }
            }
            return(bestResult);
        }
Beispiel #27
0
        /**
         *  开始进行Nest计算
         * @return
         */
        public List <List <Placement> > startNest()
        {
            //去除parts点中有孔的点,只对最外围的零件进行排样
            List <NestPath> tree = CommonUtil.BuildTree(parts, Config.CURVE_TOLERANCE);

            //根据设定的零件之间的距离,将图像由内向外进行偏置
            CommonUtil.offsetTree(tree, 0.5 * config.SPACING);
            binPath.config = config;
            foreach (NestPath nestPath in parts)
            {
                nestPath.config = config;
            }
            //自相交多边形的清理
            NestPath binPolygon = NestPath.cleanNestPath(binPath);
            Bound    binBound   = GeometryUtil.getPolygonBounds(binPolygon);

            //如果零件之间设定了间距,则底板也需要进行偏置
            if (config.SPACING > 0)
            {
                List <NestPath> offsetBin = CommonUtil.polygonOffset(binPolygon, -0.5 * config.SPACING);
                if (offsetBin.Count == 1)
                {
                    binPolygon = offsetBin[0];
                }
            }
            binPolygon.setId(-1);//这个是用来干嘛的?可能是为了让底板的编号特殊一些

            //判断零件是否都能在底板中放置,如果零件的大小超过底板的大小,则直接清除
            List <int>      integers = checkIfCanBePlaced(binPolygon, tree);
            List <NestPath> safeTree = new List <NestPath>();

            foreach (int i in integers)
            {
                safeTree.Add(tree[i]);
            }
            tree = safeTree;
            //计算多边形的面积。如果面积值大于零,说明多边形方向为反方向,需要进行方向转换,但是为什么要做这个操作呢?
            if (GeometryUtil.polygonArea(binPolygon) > 0)
            {
                binPolygon.reverse();
            }

            /**
             * 确保为逆时针
             */
            for (int i = 0; i < tree.Count; i++)
            {
                Segment start = tree[i].get(0);
                Segment end   = tree[i].get(tree[i].size() - 1);
                if (start == end || GeometryUtil.almostEqual(start.x, end.x) && GeometryUtil.almostEqual(start.y, end.y))
                {
                    tree[i].pop();
                }
                if (GeometryUtil.polygonArea(tree[i]) > 0)
                {
                    tree[i].reverse();
                }
            }

            launchcount = 0;
            Result best = null;


            // Tree Modification based on nest4J
            //List<NestPath> modifiedTree = new List<NestPath>();

            //for (int i = 0; i < tree.Count; i++)
            //{
            //    List<Segment> modifiedSegment = new List<Segment>();
            //    NestPath currentTree = tree[i];
            //    List<Segment> currentTreeSegments = currentTree.getSegments();
            //    modifiedSegment.Add(currentTreeSegments[currentTreeSegments.Count-1]);
            //    for (int j = 0; j < currentTreeSegments.Count-1; j++)
            //    {
            //        modifiedSegment.Add(currentTreeSegments[j]);
            //    }
            //    currentTree.setSegments(modifiedSegment);
            //    modifiedTree.Add(currentTree);
            //}
            //tree = modifiedTree;



            for (int i = 0; i < loopCount; i++)
            {
                Result result = launchWorkers(tree, binPolygon, config);

                if (i == 0)
                {
                    best = result;
                }
                else
                {
                    if (best.fitness > result.fitness)
                    {
                        best = result;
                    }
                }
            }
            double sumarea   = 0; //底板多边形的面积
            double totalarea = 0; //放置所有零件的面积

            //placements中的Count数据就代表了使用了几个底板的数量,如果一个底板大小不够放置所有零件,那系统会自动增加一个底板
            for (int i = 0; i < best.placements.Count; i++)
            {
                totalarea += Math.Abs(GeometryUtil.polygonArea(binPolygon));
                for (int j = 0; j < best.placements[i].Count; j++)
                {
                    try
                    {
                        sumarea += Math.Abs(GeometryUtil.polygonArea(tree[best.placements[i][j].id]));
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }
            double rate = (sumarea / totalarea) * 100;
            List <List <Placement> > appliedPlacement = applyPlacement(best, tree);

            return(appliedPlacement);
        }
Beispiel #28
0
        /**
         * 根据板件列表与旋转角列表,通过nfp,计算板件在底板上的位置,并返回这个种群的fitness
         * @param paths
         * @return
         */
        public Result placePaths(List <NestPath> paths)
        {
            List <NestPath> rotated = new List <NestPath>();

            for (int i = 0; i < paths.Count; i++)
            {
                NestPath r = GeometryUtil.rotatePolygon2Polygon(paths[i], paths[i].getRotation());
                r.setRotation(paths[i].getRotation());
                r.setSource(paths[i].getSource());
                r.setId(paths[i].getId());
                rotated.Add(r);
            }
            paths = rotated;

            List <List <Vector> > allplacements = new List <List <Vector> >();
            double          fitness             = 0;
            double          binarea             = Math.Abs(GeometryUtil.polygonArea(this.binPolygon));
            String          key = null;
            List <NestPath> nfp = null;

            while (paths.Count > 0)
            {
                List <NestPath> placed     = new List <NestPath>();
                List <Vector>   placements = new List <Vector>();

                fitness += 1;
                double minwidth = Double.MaxValue;
                for (int i = 0; i < paths.Count; i++)
                {
                    NestPath path = paths[i];

                    //inner NFP
                    key = new JavaScriptSerializer().Serialize(new NfpKey(-1, path.getId(), true, 0, path.getRotation()));

                    //key = gson.toJson(new NfpKey(-1, path.getId(), true, 0, path.getRotation()));

                    if (!nfpCache.ContainsKey(key))
                    {
                        continue;
                    }

                    List <NestPath> binNfp = nfpCache[key];



                    // ensure exists
                    bool error = false;
                    for (int j = 0; j < placed.Count; j++)
                    {
                        key = new JavaScriptSerializer().Serialize(new NfpKey(placed[j].getId(), path.getId(), false, placed[j].getRotation(), path.getRotation()));
                        // key = gson.toJson(new NfpKey(placed[j].getId(), path.getId(), false, placed[j].getRotation(), path.getRotation()));
                        if (nfpCache.ContainsKey(key))
                        {
                            nfp = nfpCache[key];
                        }
                        else
                        {
                            error = true;
                            break;
                        }
                    }
                    if (error)
                    {
                        continue;
                    }


                    Vector position = null;
                    if (placed.Count == 0)
                    {
                        // first placement , put it on the lefth
                        for (int j = 0; j < binNfp.Count; j++)
                        {
                            for (int k = 0; k < binNfp[j].size(); k++)
                            {
                                if (position == null || binNfp[j].get(k).x - path.get(0).x < position.x)
                                {
                                    position = new Vector(
                                        binNfp[j].get(k).x - path.get(0).x,
                                        binNfp[j].get(k).y - path.get(0).y,
                                        path.getId(),
                                        path.getRotation()
                                        );
                                }
                            }
                        }
                        placements.Add(position);
                        placed.Add(path);
                        continue;
                    }

                    Paths clipperBinNfp = new Paths();

                    for (int j = 0; j < binNfp.Count; j++)
                    {
                        NestPath binNfpj = binNfp[j];
                        clipperBinNfp.Add(scaleUp2ClipperCoordinates(binNfpj));
                    }
                    Clipper clipper     = new Clipper();
                    Paths   combinedNfp = new Paths();


                    for (int j = 0; j < placed.Count; j++)
                    {
                        key = new JavaScriptSerializer().Serialize(new NfpKey(placed[j].getId(), path.getId(), false, placed[j].getRotation(), path.getRotation()));
                        //key = gson.toJson(new NfpKey(placed[j].getId(), path.getId(), false, placed[j].getRotation(), path.getRotation()));
                        nfp = nfpCache[key];
                        if (nfp == null)
                        {
                            continue;
                        }

                        for (int k = 0; k < nfp.Count; k++)
                        {
                            Path clone = PlacementWorker.scaleUp2ClipperCoordinates(nfp[k]);
                            for (int m = 0; m < clone.Count; m++)
                            {
                                long     clx      = (long)clone[m].X;
                                long     cly      = (long)clone[m].Y;
                                IntPoint intPoint = clone[m];
                                intPoint.X = (clx + (long)(placements[j].x * Config.CLIIPER_SCALE));
                                intPoint.Y = (cly + (long)(placements[j].y * Config.CLIIPER_SCALE));
                                clone[m]   = intPoint;
                            }
                            //clone = clone.Cleaned(0.0001 * Config.CLIIPER_SCALE);
                            clone = Clipper.CleanPolygon(clone, 0.0001 * Config.CLIIPER_SCALE);
                            double areaPoly = Math.Abs(Clipper.Area(clone));
                            if (clone.Count > 2 && areaPoly > 0.1 * Config.CLIIPER_SCALE * Config.CLIIPER_SCALE)
                            {
                                clipper.AddPath(clone, PolyType.ptSubject, true);
                            }
                        }
                    }
                    if (!clipper.Execute(ClipType.ctUnion, combinedNfp, PolyFillType.pftNonZero, PolyFillType.pftNonZero))
                    {
                        continue;
                    }

                    //difference with bin polygon
                    Paths finalNfp = new Paths();
                    clipper = new Clipper();

                    clipper.AddPaths(combinedNfp, PolyType.ptClip, true);
                    clipper.AddPaths(clipperBinNfp, PolyType.ptSubject, true);
                    if (!clipper.Execute(ClipType.ctDifference, finalNfp, PolyFillType.pftNonZero, PolyFillType.pftNonZero))
                    {
                        continue;
                    }

                    // finalNfp = finalNfp.Cleaned(0.0001 * Config.CLIIPER_SCALE);
                    finalNfp = Clipper.CleanPolygons(finalNfp, 0.0001 * Config.CLIIPER_SCALE);
                    for (int j = 0; j < finalNfp.Count(); j++)
                    {
                        //double areaPoly = Math.Abs(finalNfp[j].Area);
                        double areaPoly = Math.Abs(Clipper.Area(finalNfp[j]));
                        if (finalNfp[j].Count < 3 || areaPoly < 0.1 * Config.CLIIPER_SCALE * Config.CLIIPER_SCALE)
                        {
                            finalNfp.RemoveAt(j);
                            j--;
                        }
                    }

                    if (finalNfp == null || finalNfp.Count == 0)
                    {
                        continue;
                    }

                    List <NestPath> f = new List <NestPath>();
                    for (int j = 0; j < finalNfp.Count; j++)
                    {
                        f.Add(toNestCoordinates(finalNfp[j]));
                    }

                    List <NestPath> finalNfpf  = f;
                    double          minarea    = Double.MinValue;
                    double          minX       = Double.MaxValue;
                    NestPath        nf         = null;
                    double          area       = Double.MinValue;
                    Vector          shifvector = null;
                    for (int j = 0; j < finalNfpf.Count; j++)
                    {
                        nf = finalNfpf[j];
                        if (Math.Abs(GeometryUtil.polygonArea(nf)) < 2)
                        {
                            continue;
                        }
                        for (int k = 0; k < nf.size(); k++)
                        {
                            NestPath allpoints = new NestPath();
                            for (int m = 0; m < placed.Count; m++)
                            {
                                for (int n = 0; n < placed[m].size(); n++)
                                {
                                    allpoints.add(new Segment(placed[m].get(n).x + placements[m].x,
                                                              placed[m].get(n).y + placements[m].y));
                                }
                            }
                            shifvector = new Vector(nf.get(k).x - path.get(0).x, nf.get(k).y - path.get(0).y, path.getId(), path.getRotation(), combinedNfp);
                            for (int m = 0; m < path.size(); m++)
                            {
                                allpoints.add(new Segment(path.get(m).x + shifvector.x, path.get(m).y + shifvector.y));
                            }
                            Bound rectBounds = GeometryUtil.getPolygonBounds(allpoints);

                            area = rectBounds.getWidth() * 2 + rectBounds.getHeight();
                            if (minarea == Double.MinValue ||
                                area < minarea ||
                                (GeometryUtil.almostEqual(minarea, area) &&
                                 (minX == Double.MinValue || shifvector.x < minX)))
                            {
                                minarea  = area;
                                minwidth = rectBounds.getWidth();
                                position = shifvector;
                                minX     = shifvector.x;
                            }
                        }
                    }
                    if (position != null)
                    {
                        placed.Add(path);
                        placements.Add(position);
                    }
                }
                if (minwidth != Double.MinValue)
                {
                    fitness += minwidth / binarea;
                }



                for (int i = 0; i < placed.Count; i++)
                {
                    int index = paths.IndexOf(placed[i]);
                    if (index >= 0)
                    {
                        paths.RemoveAt(index);
                    }
                }

                if (placements != null && placements.Count > 0)
                {
                    allplacements.Add(placements);
                }
                else
                {
                    break; // something went wrong
                }
            }
            // there were paths that couldn't be placed
            fitness += 2 * paths.Count;
            return(new Result(allplacements, fitness, paths, binarea));
        }
Beispiel #29
0
        /**
         * 获取一对多边形,并生成nfp
         * @param pair
         * @param config
         * @return
         */
        public static ParallelData nfpGenerator(NfpPair pair, Config config)
        {
            bool searchEdges = config.isCONCAVE();
            bool useHoles    = config.isUSE_HOLE();

            NestPath A = GeometryUtil.rotatePolygon2Polygon(pair.getA(), pair.getKey().getArotation());
            NestPath B = GeometryUtil.rotatePolygon2Polygon(pair.getB(), pair.getKey().getBrotation());

            List <NestPath> nfp;

            if (pair.getKey().isInside())
            {
                if (GeometryUtil.isRectangle(A, 0.001))
                {
                    nfp = GeometryUtil.noFitPolygonRectangle(A, B);
                    if (nfp == null)
                    {
                    }
                }
                else
                {
                    nfp = GeometryUtil.noFitPolygon(A, B, true, searchEdges);
                }
                if (nfp != null && nfp.Count > 0)
                {
                    for (int i = 0; i < nfp.Count; i++)
                    {
                        if (GeometryUtil.polygonArea(nfp[i]) > 0)
                        {
                            nfp[i].reverse();
                        }
                    }
                }
                else
                {
                    //Warning on null inner NFP
                }
            }
            else
            {
                int count = 0;
                if (searchEdges)
                {
                    // NFP Generator TODO  double scale contorl
                    nfp = GeometryUtil.noFitPolygon(A, B, false, searchEdges);
                    if (nfp == null)
                    {
                    }
                }
                else
                {
                    nfp = GeometryUtil.minkowskiDifference(A, B);
                }
                // sanity check
                if (nfp == null || nfp.Count == 0)
                {
                    return(null);
                }
                for (int i = 0; i < nfp.Count; i++)
                {
                    if (!searchEdges || i == 0)
                    {
                        if (Math.Abs(GeometryUtil.polygonArea(nfp[i])) < Math.Abs(GeometryUtil.polygonArea(A)))
                        {
                            nfp.RemoveAt(i);

                            return(null);
                        }
                    }
                }
                if (nfp.Count == 0)
                {
                    return(null);
                }

                for (int i = 0; i < nfp.Count; i++)
                {
                    if (GeometryUtil.polygonArea(nfp[i]) > 0)
                    {
                        nfp[i].reverse();
                    }

                    if (i > 0)
                    {
                        if ((bool)GeometryUtil.pointInPolygon(nfp[i].get(0), nfp[0]))
                        {
                            if (GeometryUtil.polygonArea(nfp[i]) < 0)
                            {
                                nfp[i].reverse();
                            }
                        }
                    }
                }

                if (useHoles && A.getChildren().Count > 0)
                {
                    Bound Bbounds = GeometryUtil.getPolygonBounds(B);
                    for (int i = 0; i < A.getChildren().Count; i++)
                    {
                        Bound Abounds = GeometryUtil.getPolygonBounds(A.getChildren()[i]);

                        if (Abounds.width > Bbounds.width && Abounds.height > Bbounds.height)
                        {
                            List <NestPath> cnfp = GeometryUtil.noFitPolygon(A.getChildren()[i], B, true, searchEdges);
                            // ensure all interior NFPs have the same winding direction

                            if (cnfp != null && cnfp.Count > 0)
                            {
                                for (int j = 0; j < cnfp.Count; j++)
                                {
                                    if (GeometryUtil.polygonArea(cnfp[j]) < 0)
                                    {
                                        cnfp[j].reverse();
                                    }
                                    nfp.Add(cnfp[j]);
                                }
                            }
                        }
                    }
                }
            }
            if (nfp == null)
            {
            }
            return(new ParallelData(pair.getKey(), nfp));
        }
Beispiel #30
0
        /**
         *  开始进行Nest计算
         * @return
         */
        public List <List <Placement> > startNest()
        {
            List <NestPath> tree = CommonUtil.BuildTree(parts, Config.CURVE_TOLERANCE);

            CommonUtil.offsetTree(tree, 0.5 * config.SPACING);
            binPath.config = config;
            foreach (NestPath nestPath in parts)
            {
                nestPath.config = config;
            }
            NestPath binPolygon = NestPath.cleanNestPath(binPath);
            Bound    binBound   = GeometryUtil.getPolygonBounds(binPolygon);

            if (config.SPACING > 0)
            {
                List <NestPath> offsetBin = CommonUtil.polygonOffset(binPolygon, -0.5 * config.SPACING);
                if (offsetBin.Count == 1)
                {
                    binPolygon = offsetBin[0];
                }
            }
            binPolygon.setId(-1);

            List <int>      integers = checkIfCanBePlaced(binPolygon, tree);
            List <NestPath> safeTree = new List <NestPath>();

            foreach (int i in integers)
            {
                safeTree.Add(tree[i]);
            }
            tree = safeTree;

            double xbinmax = binPolygon.get(0).x;
            double xbinmin = binPolygon.get(0).x;
            double ybinmax = binPolygon.get(0).y;
            double ybinmin = binPolygon.get(0).y;

            for (int i = 1; i < binPolygon.size(); i++)
            {
                if (binPolygon.get(i).x > xbinmax)
                {
                    xbinmax = binPolygon.get(i).x;
                }
                else if (binPolygon.get(i).x < xbinmin)
                {
                    xbinmin = binPolygon.get(i).x;
                }

                if (binPolygon.get(i).y > ybinmax)
                {
                    ybinmax = binPolygon.get(i).y;
                }
                else if (binPolygon.get(i).y < ybinmin)
                {
                    ybinmin = binPolygon.get(i).y;
                }
            }
            for (int i = 0; i < binPolygon.size(); i++)
            {
                binPolygon.get(i).x -= xbinmin;
                binPolygon.get(i).y -= ybinmin;
            }


            double binPolygonWidth  = xbinmax - xbinmin;
            double binPolygonHeight = ybinmax - ybinmin;

            if (GeometryUtil.polygonArea(binPolygon) > 0)
            {
                binPolygon.reverse();
            }

            /**
             * 确保为逆时针
             */
            for (int i = 0; i < tree.Count; i++)
            {
                Segment start = tree[i].get(0);
                Segment end   = tree[i].get(tree[i].size() - 1);
                if (start == end || GeometryUtil.almostEqual(start.x, end.x) && GeometryUtil.almostEqual(start.y, end.y))
                {
                    tree[i].pop();
                }
                if (GeometryUtil.polygonArea(tree[i]) > 0)
                {
                    tree[i].reverse();
                }
            }

            launchcount = 0;
            Result best = null;


            // Tree Modification based on nest4J
            //List<NestPath> modifiedTree = new List<NestPath>();

            //for (int i = 0; i < tree.Count; i++)
            //{
            //    List<Segment> modifiedSegment = new List<Segment>();
            //    NestPath currentTree = tree[i];
            //    List<Segment> currentTreeSegments = currentTree.getSegments();
            //    modifiedSegment.Add(currentTreeSegments[currentTreeSegments.Count-1]);
            //    for (int j = 0; j < currentTreeSegments.Count-1; j++)
            //    {
            //        modifiedSegment.Add(currentTreeSegments[j]);
            //    }
            //    currentTree.setSegments(modifiedSegment);
            //    modifiedTree.Add(currentTree);
            //}
            //tree = modifiedTree;



            for (int i = 0; i < loopCount; i++)
            {
                Result result = launchWorkers(tree, binPolygon, config);

                if (i == 0)
                {
                    best = result;
                }
                else
                {
                    if (best.fitness > result.fitness)
                    {
                        best = result;
                    }
                }
            }
            double sumarea   = 0;
            double totalarea = 0;

            for (int i = 0; i < best.placements.Count; i++)
            {
                totalarea += Math.Abs(GeometryUtil.polygonArea(binPolygon));
                for (int j = 0; j < best.placements[i].Count; j++)
                {
                    try
                    {
                        sumarea += Math.Abs(GeometryUtil.polygonArea(tree[best.placements[i][j].id]));
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }
            double rate = (sumarea / totalarea) * 100;
            List <List <Placement> > appliedPlacement = applyPlacement(best, tree);

            return(appliedPlacement);
        }