示例#1
0
        public void CleanPolygonsTest()
        {
            var polygon = new Polygon();

            var length = 500;

            for (int i = 0; i < 360; i++)
            {
                var angle = MathHelper.DegreesToRadians(i);
                polygon.Add(new IntPoint(Math.Cos(angle) * length, Math.Sin(angle) * length));
            }

            var cleanedPolygon = Clipper.CleanPolygon(polygon, 2);

            var originalPolygons = new Polygons()
            {
                polygon
            };
            var cleanPolygons = new Polygons()
            {
                cleanedPolygon
            };

            //this.WriteSvg("before.svg", originalPolygons.CreateVertexStorage(1).GetSvgDString());
            //this.WriteSvg("after.svg", cleanPolygons.CreateVertexStorage(1).GetSvgDString());

            // Ensure mid-point between points is within threshold
            for (int i = 0; i < cleanedPolygon.Count - 1; i++)
            {
                var centerPoint  = (cleanedPolygon[i + 1] + cleanedPolygon[i]) / 2;
                var distToCenter = centerPoint.Length();
                Assert.AreEqual(length, distToCenter, 3);
            }
        }
示例#2
0
        public static Mesh triangulate(Paths paths, AXTexCoords tex)
        {
            //Debug.Log ("B");
            List <Mesh> meshes = new List <Mesh>();

            foreach (Path path in paths)
            {
                meshes.Add(AXPolygon.triangulate(Clipper.CleanPolygon(path), tex));
            }

            // combine
            CombineInstance[] combine = new CombineInstance[meshes.Count];
            for (int i = 0; i < meshes.Count; i++)
            {
                combine[i].mesh      = meshes[i];
                combine[i].transform = Matrix4x4.identity;
            }

            Mesh mesh = new Mesh();

            mesh.CombineMeshes(combine);

            mesh.RecalculateNormals();

            return(mesh);
        }
        public static void Prune(this PolyNode polyTree, double actorRadius, double areaPruneThreshold = kMinAreaPrune)
        {
            var cleaned = Clipper.CleanPolygon(polyTree.Contour, actorRadius / 5 + 2);

            if (cleaned.Count > 0)
            {
                polyTree.Contour.Clear();
                polyTree.Contour.AddRange(cleaned);
            }

            for (var i = polyTree.Childs.Count - 1; i >= 0; i--)
            {
                var child     = polyTree.Childs[i];
                var childArea = Math.Abs(Clipper.Area(child.Contour));
                if (childArea < areaPruneThreshold)
                {
                    // Console.WriteLine("Prune: " + Clipper.Area(child.Contour) + " " + child.Contour.Count);
                    polyTree.Childs.RemoveAt(i);
                    continue;
                }

                var kMinimumChildRelativeArea = 1 / 1000.0; // prev 1 / 1000, 1 / 1000000
                child.Prune(actorRadius, Math.Max(kMinAreaPrune, childArea * kMinimumChildRelativeArea));
            }
        }
示例#4
0
        public void CleanPolygons()
        {
            // remove a single point that is going to be coincident
            {
                List <IntPoint> testPath = new List <IntPoint>();
                testPath.Add(new IntPoint(0, 0));
                testPath.Add(new IntPoint(5, 0));
                testPath.Add(new IntPoint(11, 0));
                testPath.Add(new IntPoint(5, 20));

                List <IntPoint> cleanedPath = Clipper.CleanPolygon(testPath, 10);
                Assert.IsTrue(cleanedPath.Count == 3);
            }

            // don't remove a non collinear point
            {
                List <IntPoint> testPath = new List <IntPoint>();
                testPath.Add(new IntPoint(0, 0));
                testPath.Add(new IntPoint(50, 5));
                testPath.Add(new IntPoint(100, 0));
                testPath.Add(new IntPoint(50, 200));

                List <IntPoint> cleanedPath = Clipper.CleanPolygon(testPath, 4);
                Assert.IsTrue(cleanedPath.Count == 4);
            }

            // now remove that point with a higher tolerance
            {
                List <IntPoint> testPath = new List <IntPoint>();
                testPath.Add(new IntPoint(0, 0));
                testPath.Add(new IntPoint(50, 5));
                testPath.Add(new IntPoint(100, 0));
                testPath.Add(new IntPoint(50, 200));

                List <IntPoint> cleanedPath = Clipper.CleanPolygon(testPath, 6);
                Assert.IsTrue(cleanedPath.Count == 3);
            }

            // now remove a bunch of points
            {
                int             mergeDist = 10;
                List <IntPoint> testPath  = new List <IntPoint>();
                testPath.Add(new IntPoint(0, 0));
                Random randY = new Random(0);
                for (int i = 2; i < 58; i++)
                //	for (int i = 2; i < 98; i++)
                {
                    testPath.Add(new IntPoint(i, (int)(randY.NextDouble() * mergeDist - mergeDist / 2)));
                }
                testPath.Add(new IntPoint(100, 0));
                testPath.Add(new IntPoint(50, 200));

                List <IntPoint> cleanedPath = Clipper.CleanPolygon(testPath, mergeDist);
                Assert.IsTrue(cleanedPath.Count == 3);
                //Assert.IsTrue(cleanedPath.Contains(new IntPoint(0, 0)));
                //Assert.IsTrue(cleanedPath.Contains(new IntPoint(100, 0)));
                //Assert.IsTrue(cleanedPath.Contains(new IntPoint(50, 200)));
            }
        }
        // GROUPER::GENERATE
        public override GameObject generate(bool makeGameObjects, AXParametricObject initiator_po, bool isReplica)
        {
            //if (ArchimatixUtils.doDebug)
            //Debug.Log (parametricObject.Name + " generate +++++++++++++++++++++++++++++++++++++++++++++++++ " + inputs.Count);


            if (!parametricObject.isActive)
            {
                return(null);
            }



            preGenerate();

            Path path = new Path();



            if (inputs != null && inputs.Count > 0)
            {
                for (int i = 0; i < inputs.Count; i++)
                {
                    AXParameter input = inputs[i];

                    if (input != null && input.DependsOn != null)
                    {
                        if (input.DependsOn.parametricObject.generator is FreeCurve)
                        {
                            FreeCurve fc = (FreeCurve)input.DependsOn.parametricObject.generator;

                            Path output = AX.Generators.Generator2D.transformPath(fc.getPathFromCurve(), fc.localMatrix);

                            path.AddRange(output);
                        }
                        else
                        {
                            Paths tmpPaths = input.DependsOn.getPaths();
                            if (tmpPaths != null)
                            {
                                for (int j = 0; j < tmpPaths.Count; j++)
                                {
                                    path.AddRange(tmpPaths[j]);
                                }
                            }
                        }
                    }
                }

                path = Clipper.CleanPolygon(path);

                P_Output.paths = new Paths();

                P_Output.paths.Add(path);
            }

            return(null);
        }
示例#6
0
        //将自相交多边形转化为简单多边形
        public static NestPath cleanNestPath(NestPath srcPath)
        {
            /**
             * Convert NestPath 2 Clipper
             */
            Path  path   = CommonUtil.NestPath2Path(srcPath);
            Paths simple = Clipper.SimplifyPolygon(path, PolyFillType.pftEvenOdd);

            if (simple.Count == 0)
            {
                return(null);
            }
            Path   biggest     = simple[0];
            double biggestArea = Math.Abs(Clipper.Area(biggest));

            for (int i = 0; i < simple.Count; i++)
            {
                double area = Math.Abs(Clipper.Area(simple[i]));
                if (area > biggestArea)
                {
                    biggest     = simple[i];
                    biggestArea = area;
                }
            }
            //Path clean = biggest.Cleaned(Config.CURVE_TOLERANCE * Config.CLIIPER_SCALE);
            Path clean = Clipper.CleanPolygon(biggest, Config.CURVE_TOLERANCE * Config.CLIIPER_SCALE);

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

            /**
             *  Convert Clipper 2 NestPath
             */
            NestPath cleanPath = CommonUtil.Path2NestPath(clean);

            cleanPath.bid = srcPath.bid;
            cleanPath.setRotation(srcPath.rotation);
            return(cleanPath);
        }
示例#7
0
        /// <summary>
        /// This will find the largest turn in a given models. It prefers concave turns to convex turns.
        /// If turn amount is the same bias towards the smallest y position.
        /// </summary>
        /// <param name="inputPolygon"></param>
        /// <param name="considerAsSameY">Range to treat y positions as the same value.</param>
        /// <returns></returns>
        public static IntPoint FindGreatestTurnPosition(this Polygon inputPolygon, long considerAsSameY, int layerIndex, IntPoint?startPosition = null)
        {
            Polygon currentPolygon = Clipper.CleanPolygon(inputPolygon, considerAsSameY / 8);

            // collect & bucket options and then choose the closest
            if (currentPolygon.Count == 0)
            {
                return(inputPolygon[0]);
            }

            double         totalTurns    = 0;
            CandidateGroup positiveGroup = new CandidateGroup(DegreesToRadians(35));
            CandidateGroup negativeGroup = new CandidateGroup(DegreesToRadians(10));

            IntPoint currentFurthestBack = new IntPoint(long.MaxValue, long.MinValue);
            int      furthestBackIndex   = 0;

            double minTurnToChoose = DegreesToRadians(1);
            long   minSegmentLengthToConsiderSquared = 50 * 50;

            int pointCount = currentPolygon.Count;

            for (int pointIndex = 0; pointIndex < pointCount; pointIndex++)
            {
                int      prevIndex    = ((pointIndex + pointCount - 1) % pointCount);
                int      nextIndex    = ((pointIndex + 1) % pointCount);
                IntPoint prevPoint    = currentPolygon[prevIndex];
                IntPoint currentPoint = currentPolygon[pointIndex];
                IntPoint nextPoint    = currentPolygon[nextIndex];

                if (currentPoint.Y >= currentFurthestBack.Y)
                {
                    if (currentPoint.Y > currentFurthestBack.Y ||
                        currentPoint.X < currentFurthestBack.X)
                    {
                        furthestBackIndex   = pointIndex;
                        currentFurthestBack = currentPoint;
                    }
                }

                long lengthPrevToCurSquared = (prevPoint - currentPoint).LengthSquared();
                long lengthCurToNextSquared = (nextPoint - currentPoint).LengthSquared();
                bool distanceLongeEnough    = lengthCurToNextSquared > minSegmentLengthToConsiderSquared && lengthPrevToCurSquared > minSegmentLengthToConsiderSquared;

                double turnAmount = currentPoint.GetTurnAmount(prevPoint, nextPoint);

                totalTurns += turnAmount;

                if (turnAmount < 0)
                {
                    // threshold angles, don't pick angles that are too shallow
                    // threshold line lengths, don't pick big angles hiding in TINY lines
                    if (Math.Abs(turnAmount) > minTurnToChoose &&
                        distanceLongeEnough)
                    {
                        negativeGroup.ConditionalAdd(new CandidatePoint(turnAmount, pointIndex, currentPoint));
                    }
                }
                else
                {
                    if (Math.Abs(turnAmount) > minTurnToChoose &&
                        distanceLongeEnough)
                    {
                        positiveGroup.ConditionalAdd(new CandidatePoint(turnAmount, pointIndex, currentPoint));
                    }
                }
            }

            if (negativeGroup.Count > 0)
            {
                if (positiveGroup.Count > 0
                    // the negative group is a small turn and the positive group is a big turn
                    && ((Math.Abs(negativeGroup[0].turnAmount) < Math.PI / 4 &&
                         Math.Abs(positiveGroup[0].turnAmount) > Math.PI / 4)
                        // the negative turn amount is very small
                        || Math.Abs(negativeGroup[0].turnAmount) < Math.PI / 8))
                {
                    // return the positive rather than the negative turn
                    return(currentPolygon[positiveGroup.GetBestIndex(layerIndex, startPosition)]);
                }

                return(currentPolygon[negativeGroup.GetBestIndex(layerIndex, startPosition)]);
            }
            else if (positiveGroup.Count > 0)
            {
                return(currentPolygon[positiveGroup.GetBestIndex(layerIndex, startPosition)]);
            }
            else
            {
                // If can't find good candidate go with vertex most in a single direction
                return(currentPolygon[furthestBackIndex]);
            }
        }
        public static IntPoint GetBestPosition(Polygon inputPolygon, long lineWidth)
        {
            IntPoint currentFurthestBackActual = new IntPoint(long.MaxValue, long.MinValue);
            {
                int actualFurthestBack = 0;
                for (int pointIndex = 0; pointIndex < inputPolygon.Count; pointIndex++)
                {
                    IntPoint currentPoint = inputPolygon[pointIndex];

                    if (currentPoint.Y >= currentFurthestBackActual.Y)
                    {
                        if (currentPoint.Y > currentFurthestBackActual.Y ||
                            currentPoint.X < currentFurthestBackActual.X)
                        {
                            actualFurthestBack        = pointIndex;
                            currentFurthestBackActual = currentPoint;
                        }
                    }
                }
            }

            Polygon currentPolygon = Clipper.CleanPolygon(inputPolygon, lineWidth / 4);

            // TODO: other considerations
            // collect & bucket options and then choose the closest

            if (currentPolygon.Count == 0)
            {
                return(inputPolygon[0]);
            }

            double         totalTurns    = 0;
            CandidateGroup positiveGroup = new CandidateGroup(DegreesToRadians(35));
            CandidateGroup negativeGroup = new CandidateGroup(DegreesToRadians(10));

            IntPoint currentFurthestBack = new IntPoint(long.MaxValue, long.MinValue);
            int      furthestBackIndex   = 0;

            double minTurnToChoose = DegreesToRadians(1);
            long   minSegmentLengthToConsiderSquared = 50 * 50;

            int pointCount = currentPolygon.Count;

            for (int pointIndex = 0; pointIndex < pointCount; pointIndex++)
            {
                int      prevIndex    = ((pointIndex + pointCount - 1) % pointCount);
                int      nextIndex    = ((pointIndex + 1) % pointCount);
                IntPoint prevPoint    = currentPolygon[prevIndex];
                IntPoint currentPoint = currentPolygon[pointIndex];
                IntPoint nextPoint    = currentPolygon[nextIndex];

                if (currentPoint.Y >= currentFurthestBack.Y)
                {
                    if (currentPoint.Y > currentFurthestBack.Y ||
                        currentPoint.X < currentFurthestBack.X)
                    {
                        furthestBackIndex   = pointIndex;
                        currentFurthestBack = currentPoint;
                    }
                }

                long lengthPrevToCurSquared = (prevPoint - currentPoint).LengthSquared();
                long lengthCurToNextSquared = (nextPoint - currentPoint).LengthSquared();
                bool distanceLongeEnough    = lengthCurToNextSquared > minSegmentLengthToConsiderSquared && lengthPrevToCurSquared > minSegmentLengthToConsiderSquared;

                double turnAmount = GetTurnAmount(prevPoint, currentPoint, nextPoint);

                totalTurns += turnAmount;

                if (turnAmount < 0)
                {
                    // threshold angles, don't pick angles that are too shallow
                    // threshold line lengths, don't pick big angles hiding in TINY lines
                    if (Math.Abs(turnAmount) > minTurnToChoose &&
                        distanceLongeEnough)
                    {
                        negativeGroup.ConditionalAdd(new CandidatePoint(turnAmount, pointIndex, currentPoint));
                    }
                }
                else
                {
                    if (Math.Abs(turnAmount) > minTurnToChoose &&
                        distanceLongeEnough)
                    {
                        positiveGroup.ConditionalAdd(new CandidatePoint(turnAmount, pointIndex, currentPoint));
                    }
                }
            }

            IntPoint positionToReturn = new IntPoint();

            if (totalTurns > 0)             // ccw
            {
                if (negativeGroup.Count > 0)
                {
                    positionToReturn = currentPolygon[negativeGroup.BestIndex];
                }
                else if (positiveGroup.Count > 0)
                {
                    positionToReturn = currentPolygon[positiveGroup.BestIndex];
                }
                else
                {
                    // If can't find good candidate go with vertex most in a single direction
                    positionToReturn = currentPolygon[furthestBackIndex];
                }
            }
            else             // cw
            {
                if (negativeGroup.Count > 0)
                {
                    positionToReturn = currentPolygon[negativeGroup.BestIndex];
                }
                else if (positiveGroup.Count > 0)
                {
                    positionToReturn = currentPolygon[positiveGroup.BestIndex];
                }
                else
                {
                    // If can't find good candidate go with vertex most in a single direction
                    positionToReturn = currentPolygon[furthestBackIndex];
                }
            }

            if (Math.Abs(currentFurthestBackActual.Y - positionToReturn.Y) < lineWidth)
            {
                return(currentFurthestBackActual);
            }

            return(positionToReturn);
        }
示例#9
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));
        }
示例#10
0
        /// <summary>
        /// Create shell over the line
        /// </summary>
        /// <param name="polygons"></param>
        /// <param name="length"></param>
        /// <param name="scale"></param>
        /// <param name="threshold"></param>
        /// <returns></returns>
        public static List <List <Vector2> > MakeShell(this List <List <Vector2> > polygons, float length, float scale = 1000, float threshold = 0.2f)
        {
            List <List <IntPoint> > solution = new List <List <IntPoint> >();
            ClipperOffset           co       = new ClipperOffset();

            for (int i = 0; i < polygons.Count; ++i)
            {
                co.AddPath(ToIntPoint(polygons[i], scale), JoinType.jtRound, EndType.etClosedPolygon);
            }
            co.Execute(ref solution, length * scale);

            if (solution.Count == 0)
            {
                return(new List <List <Vector2> >());
            }
            solution = Clipper.SimplifyPolygons(solution);
            if (solution.Count == 0)
            {
                return(new List <List <Vector2> >());
            }
            for (int i = 0; i < solution.Count; ++i)
            {
                solution[i] = Clipper.CleanPolygon(solution[i], -1);
            }
            if (solution.Count == 0)
            {
                return(new List <List <Vector2> >());
            }

            List <List <Vector2> > current = new List <List <Vector2> >();

            for (int s = 0; s < solution.Count; ++s)
            {
                List <Vector2> level = ToVector2(solution[s], 1.0f / scale);

                for (int i = 1; i < level.Count; ++i)
                {
                    if ((level[i] - level[i - 1]).magnitude < Mathf.Abs(length) * (1 - threshold))
                    {
                        level.RemoveAt(i);
                        i = 0;
                        continue;
                    }
                }
                if (level.Count <= 1)
                {
                    return(new List <List <Vector2> >());
                }
                if ((level[0] - level[level.Count - 1]).magnitude < Mathf.Abs(length) * (1 - threshold))
                {
                    level.RemoveAt(level.Count - 1);
                }
                if (level.Count <= 1)
                {
                    return(new List <List <Vector2> >());
                }
                for (int i = 1; i < level.Count; ++i)
                {
                    if ((level[i] - level[i - 1]).magnitude > Mathf.Abs(length) * (1 + threshold))
                    {
                        level.Insert(i, level[i - 1] + (level[i] - level[i - 1]) / 2 + Vector2.one * 0.01f);
                        i = 0;
                        continue;
                    }
                }
                if ((level[0] - level[level.Count - 1]).magnitude > Mathf.Abs(length) * (1 + threshold))
                {
                    level.Insert(0, level[level.Count - 1] + (level[0] - level[level.Count - 1]) / 2 + Vector2.one * 0.01f);
                }

                current.Add(level);
            }
            return(current);
        }
示例#11
0
        public static Mesh triangulatePolyNode(PolyNode node, AXTexCoords tex, int seglenBigInt = 1000000)
        {
            //Debug.Log ("D " + seglenBigInt);
            Polygon _polygon = null;

            if (seglenBigInt < 10)
            {
                seglenBigInt = 999999;
            }


            List <Mesh> meshes = new List <Mesh>();

            // Contour is Solid

            PolygonPoints _points = null;

            if (seglenBigInt > 0 && seglenBigInt != 9999999)
            {
                _points = AXGeometryTools.Utilities.path2polygonPts(Pather.segmentPath(Clipper.CleanPolygon(node.Contour), seglenBigInt));
            }
            else
            {
                _points = AXGeometryTools.Utilities.path2polygonPts(Clipper.CleanPolygon(node.Contour));
            }

            // POLYGON
            if (_points.Count >= 3)
            {
                _polygon = new Polygon(_points);
            }

            //Debug.Log ("_polygon="+_points.Count);
            // ADD HOLES TO POLYGON
            foreach (PolyNode subnode in node.Childs)
            {
                PolygonPoints hpoints = null;

                if (seglenBigInt > 0 && seglenBigInt != 9999999)
                {
                    hpoints = AXGeometryTools.Utilities.path2polygonPts(Pather.segmentPath(Clipper.CleanPolygon(subnode.Contour), seglenBigInt));
                }
                else
                {
                    hpoints = AXGeometryTools.Utilities.path2polygonPts(Clipper.CleanPolygon(subnode.Contour));
                }



                if (hpoints.Count >= 3)
                {
                    _polygon.AddHole(new Polygon(hpoints));
                }
            }

            try {
                // STEINER POINTS

                ClipperOffset co = new ClipperOffset();
                co.AddPath(node.Contour, AXClipperLib.JoinType.jtSquare, AXClipperLib.EndType.etClosedPolygon);

                //addSteinerPointsAtAllOffsets(ref _polygon, ref co, seglenBigInt/AXGeometryTools.Utilities.IntPointPrecision, seglenBigInt);
                addSteinerPointsAtAllOffsets(ref _polygon, ref co, (float)seglenBigInt / ((float)AXGeometryTools.Utilities.IntPointPrecision), seglenBigInt);



                P2T.Triangulate(_polygon);

                meshes.Add(polygon2mesh(_polygon, tex));
            } catch {
                //Debug.Log ("Can't triangulate: probably point on edge.");
            }


            // Continue down the tree...

            /*
             * foreach(PolyNode cnode in node.Childs)
             * {
             *      Mesh submesh = triangulatePolyNode(cnode, tex);
             *      if (submesh != null)
             *              meshes.Add(submesh);
             * }
             */



            CombineInstance[] combine = new CombineInstance[meshes.Count];
            for (int i = 0; i < meshes.Count; i++)
            {
                combine[i].mesh      = meshes[i];
                combine[i].transform = Matrix4x4.identity;
            }



            Mesh mesh = new Mesh();

            mesh.CombineMeshes(combine);

            mesh.RecalculateNormals();

            return(mesh);
        }
示例#12
0
        /* bridges to poly2tri
         *
         */



        public static Mesh triangulate(Path path, AXTexCoords tex, int seglen = 0)
        {
            /* Assume a single path with no holes
             * and return a mesh.
             */
            if (path == null || path.Count < 3)
            {
                return(null);
            }


            if (path[path.Count - 1].X == path[0].X && path[path.Count - 1].Y == path[0].Y)
            {
                path.RemoveAt(path.Count - 1);
            }

            else if (AXGeometryTools.Utilities.IntPointsAreNear(path[0], path[path.Count - 1]))
            {
                path.RemoveAt(path.Count - 1);
            }



            //Paths tmpPaths = Clipper.SimplifyPolygon (path);


            //CombineInstance[] combinator = new CombineInstance[tmpPaths.Count];

            //for (int i = 0; i < tmpPaths.Count; i++) {
            Mesh          mesh = null;
            PolygonPoints _points;            // = AXGeometryTools.Utilities.path2polygonPts (Pather.cleanPath(path));

            if (seglen > 0)
            {
                _points = AXGeometryTools.Utilities.path2polygonPts(Pather.segmentPath(Clipper.CleanPolygon(path), seglen));
            }
            else
            {
                _points = AXGeometryTools.Utilities.path2polygonPts(Clipper.CleanPolygon(path));
            }



            Polygon _polygon = null;

            if (_points.Count >= 3)
            {
                _polygon = new Polygon(_points);


                if (_polygon != null)
                {
                    try {
                        // Testing Steiner

//							for (int j = -10; j<10; j++)
//							{
//								for (int k = -10; k<10; k++)
//									_polygon.AddSteinerPoint(new TriangulationPoint(.1f*j, k*.1f));
//							}


                        P2T.Triangulate(_polygon);


                        //foreach (DelaunayTriangle triangle in _polygon.Triangles)
                        mesh = polygon2mesh(_polygon, tex);
                    } catch {
                        Debug.Log("Can't triangulate: probably point on edge.");
                    }
                }

                //combinator[i].mesh        = mesh;
                //combinator [i].transform = Matrix4x4.identity;
                //return mesh;

                //}
            }


//			Mesh returnMesh = new Mesh();
//				returnMesh.CombineMeshes(combinator);
//				return returnMesh;
            return(mesh);
        }
示例#13
0
        public static Mesh triangulate(List <PolyNode> childs, AXTexCoords tex, int seglenBigInt = 1000000)
        {
            //Debug.Log ("C " + seglenBigInt);
            Polygon _polygon = null;


            List <Mesh> meshes = new List <Mesh>();

            if (seglenBigInt < 10)
            {
                seglenBigInt = 100000;
            }


            //int count = 0;
            foreach (PolyNode node in childs)
            {
                // Contour is Solid
//				List<TriangulationPoint> tripoints = new List<TriangulationPoint>();
//
//				// Testing Steiner
//				int cells = 6;
//				for (int j = -cells/2; j<cells/2; j++)
//				{
//					for (int k = -cells/3; k<cells/2; k++)
//						if (Clipper.PointInPolygon( AXGeometryTools.Utilities.Vec2_2_IntPt(new Vector2(2f*j, k*2f)), node.Contour) > 0)
//						{
//							//Debug.Log("add steiner " + .4f*j +", " + k*.2f);
//							tripoints.Add(new TriangulationPoint(.4f*j, k*.2f));
//						}
//				}


                PolygonPoints _points = null;

                if (seglenBigInt > 0 && seglenBigInt != 9999999)
                {
                    _points = AXGeometryTools.Utilities.path2polygonPts(Pather.segmentPath(Clipper.CleanPolygon(node.Contour), seglenBigInt));
                }
                else
                {
                    _points = AXGeometryTools.Utilities.path2polygonPts(Clipper.CleanPolygon(node.Contour));
                }

                // POLYGON
                if (_points.Count >= 3)
                {
                    _polygon = new Polygon(_points);
                }

                // ADD HOLES TO POLYGON
                foreach (PolyNode subnode in node.Childs)
                {
                    PolygonPoints hpoints = null;

                    if (seglenBigInt > 0 && seglenBigInt != 9999999)
                    {
                        hpoints = AXGeometryTools.Utilities.path2polygonPts(Pather.segmentPath(Clipper.CleanPolygon(subnode.Contour), seglenBigInt));
                    }
                    else
                    {
                        hpoints = AXGeometryTools.Utilities.path2polygonPts(Clipper.CleanPolygon(subnode.Contour));
                    }

                    if (hpoints.Count >= 3)
                    {
                        _polygon.AddHole(new Polygon(hpoints));
                    }
                }

                try {
                    // STEINER POINTS

                    ClipperOffset co = new ClipperOffset();
                    co.AddPath(node.Contour, AXClipperLib.JoinType.jtSquare, AXClipperLib.EndType.etClosedPolygon);

                    addSteinerPointsAtAllOffsets(ref _polygon, ref co, (float)seglenBigInt / ((float)AXGeometryTools.Utilities.IntPointPrecision), seglenBigInt);



                    P2T.Triangulate(_polygon);
                    meshes.Add(polygon2mesh(_polygon, tex));
                } catch {
                    //Debug.Log ("Can't triangulate: probably point on edge.");
                }


                // Continue down the tree...
                foreach (PolyNode cnode in node.Childs)
                {
                    Mesh submesh = triangulate(cnode, tex);
                    if (submesh != null)
                    {
                        meshes.Add(submesh);
                    }
                }
            }

            CombineInstance[] combine = new CombineInstance[meshes.Count];
            for (int i = 0; i < meshes.Count; i++)
            {
                combine[i].mesh      = meshes[i];
                combine[i].transform = Matrix4x4.identity;
            }



            Mesh mesh = new Mesh();

            mesh.CombineMeshes(combine);

            mesh.RecalculateNormals();

            return(mesh);
        }