Example #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);
        }
Example #2
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);
        }
Example #3
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);
        }
Example #4
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);
        }
Example #5
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       = 10;
            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;
                    s += "<g transform=\"translate(" + ox + x + " " + oy + y + ") 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 += "</g> \n";
                }
                s += "</g> \n";
                y += (int)(binHeight + 50);
                strings.Add(s);
            }
            return(strings);
        }
Example #6
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);
                }
            }
        }
Example #7
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);
        }