Пример #1
0
        private double ClippedArea()
        {
            if (this.Voids == null || this.Voids.Count == 0)
            {
                return(this.Perimeter.Area());
            }

            var clipper = new ClipperLib.Clipper();
            var normal  = Perimeter.Normal();

            if (normal.IsAlmostEqualTo(Vector3.ZAxis))
            {
                clipper.AddPath(Perimeter.ToClipperPath(), ClipperLib.PolyType.ptSubject, true);
                clipper.AddPaths(this.Voids.Select(p => p.ToClipperPath()).ToList(), ClipperLib.PolyType.ptClip, true);
            }
            else
            {
                var transform = new Transform(Perimeter.Start, normal);
                transform.Invert();
                var perimeter = Perimeter.TransformedPolygon(transform);
                clipper.AddPath(perimeter.ToClipperPath(), ClipperLib.PolyType.ptSubject, true);
                clipper.AddPaths(this.Voids.Select(p => p.TransformedPolygon(transform).ToClipperPath()).ToList(), ClipperLib.PolyType.ptClip, true);
            }

            var solution = new List <List <ClipperLib.IntPoint> >();

            clipper.Execute(ClipperLib.ClipType.ctDifference, solution, ClipperLib.PolyFillType.pftEvenOdd);
            return(solution.Sum(s => ClipperLib.Clipper.Area(s)) / Math.Pow(1.0 / Vector3.EPSILON, 2));
        }
Пример #2
0
    public static Vector3[] MeshDifference(Vector3[] mesh1, Vector3[] mesh2)
    {
        List<IntPoint> subj = MeshToPath3D(mesh1);
        List<IntPoint> clip = MeshToPath3D(mesh2);
        List<List<IntPoint>> solution = new List<List<IntPoint>>();

        Clipper c = new Clipper();
        c.AddPath(subj, PolyType.ptSubject, true);
        c.AddPath(clip, PolyType.ptClip, true);
        c.Execute(ClipType.ctDifference, solution,
          PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd);

        return PathToMesh3D(solution[0]);
    }
Пример #3
0
        /// <summary>
        ///  Conduct a clip operation on this profile.
        /// </summary>
        internal void Clip(IEnumerable <Profile> additionalHoles = null, double tolerance = Vector3.EPSILON)
        {
            var clipper = new ClipperLib.Clipper();

            clipper.AddPath(this.Perimeter.ToClipperPath(tolerance), ClipperLib.PolyType.ptSubject, true);
            if (this.Voids != null)
            {
                clipper.AddPaths(this.Voids.Select(p => p.ToClipperPath(tolerance)).ToList(), ClipperLib.PolyType.ptClip, true);
            }
            if (additionalHoles != null)
            {
                clipper.AddPaths(additionalHoles.Select(h => h.Perimeter.ToClipperPath(tolerance)).ToList(), ClipperLib.PolyType.ptClip, true);
            }
            var solution = new List <List <ClipperLib.IntPoint> >();
            var result   = clipper.Execute(ClipperLib.ClipType.ctDifference, solution, ClipperLib.PolyFillType.pftEvenOdd);

            // Completely disjoint polygons like a circular pipe
            // profile will result in an empty solution.
            if (solution.Count > 0)
            {
                var polys = solution.Select(s => s.ToPolygon(tolerance)).ToArray();
                this.Perimeter = polys[0];
                this.Voids     = polys.Skip(1).ToArray();
            }
        }
Пример #4
0
        /// <summary>
        /// Perform a union operation, returning a new profile that is the union of the current profile with the other profile
        /// <param name="profile">The profile with which to create a union.</param>
        /// <param name="tolerance">An optional tolerance.</param>
        /// </summary>
        public Profile Union(Profile profile, double tolerance = Vector3.EPSILON)
        {
            var clipper = new ClipperLib.Clipper();

            clipper.AddPath(this.Perimeter.ToClipperPath(tolerance), PolyType.ptSubject, true);
            clipper.AddPath(profile.Perimeter.ToClipperPath(tolerance), PolyType.ptClip, true);

            if (this.Voids != null && this.Voids.Count > 0)
            {
                clipper.AddPaths(this.Voids.Select(v => v.ToClipperPath(tolerance)).ToList(), PolyType.ptSubject, true);
            }
            if (profile.Voids != null && profile.Voids.Count > 0)
            {
                clipper.AddPaths(profile.Voids.Select(v => v.ToClipperPath(tolerance)).ToList(), PolyType.ptClip, true);
            }
            var solution = new List <List <ClipperLib.IntPoint> >();

            clipper.Execute(ClipType.ctUnion, solution);
            return(new Profile(solution.Select(s => s.ToPolygon(tolerance)).ToList()));
        }
Пример #5
0
        private double ClippedArea()
        {
            if (this.Voids == null || this.Voids.Count == 0)
            {
                return(this.Perimeter.Area());
            }

            var clipper = new ClipperLib.Clipper();

            clipper.AddPath(this.Perimeter.ToClipperPath(), ClipperLib.PolyType.ptSubject, true);
            clipper.AddPaths(this.Voids.Select(p => p.ToClipperPath()).ToList(), ClipperLib.PolyType.ptClip, true);
            var solution = new List <List <ClipperLib.IntPoint> >();

            clipper.Execute(ClipperLib.ClipType.ctDifference, solution, ClipperLib.PolyFillType.pftEvenOdd);
            return(solution.Sum(s => ClipperLib.Clipper.Area(s)) / Math.Pow(1.0 / Vector3.EPSILON, 2));
        }
Пример #6
0
        public void Clip(double x0, double x1, double y0, double y1)
        {
            var p00 = new Point3d(x0, y0, 0.0);
            var p01 = new Point3d(x0, y1, 0.0);
            var p11 = new Point3d(x1, y1, 0.0);
            var p10 = new Point3d(x1, y0, 0.0);

            var clip = new[] { p00, p10, p11, p01, p00 }.ToPolygon(Plane.WorldXY, Unit);

            var clipper = new Clipper();

            clipper.AddPaths(Polygons, PolyType.ptSubject, true);
            clipper.AddPath(clip, PolyType.ptClip, true);

            var solution = new List<List<IntPoint>>();

            clipper.Execute(ClipType.ctIntersection, solution, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero);

            Polygons = solution;
            Curves = Polygons.ToCurves(Plane, Unit);
        }
Пример #7
0
      //------------------------------------------------------------------------------
#endif

    //------------------------------------------------------------------------------
      // SimplifyPolygon functions ...
      // Convert self-intersecting polygons into simple polygons
      //------------------------------------------------------------------------------

      public static Paths SimplifyPolygon(Path poly, 
            PolyFillType fillType = PolyFillType.pftEvenOdd)
      {
          Paths result = new Paths();
          Clipper c = new Clipper();
          c.StrictlySimple = true;
          c.AddPath(poly, PolyType.ptSubject, true);
          c.Execute(ClipType.ctUnion, result, fillType, fillType);
          return result;
      }
Пример #8
0
 public static List<List<IntPoint>> ClipPolygon(List<List<IntPoint>> polygons, List<IntPoint> clipPath)
 {
     Clipper clipper = new Clipper();
     clipper.AddPaths(polygons, PolyType.ptSubject, true);
     clipper.AddPath(clipPath, PolyType.ptClip, true);            
     List<List<IntPoint>> solution = new List<List<IntPoint>>();
     clipper.Execute(ClipType.ctIntersection, solution);
     return solution;
 } 
    public void Generate()
    {
        generationMessage = "Generating points...";

        //Generate some points...
        List<Point> generationPoints = new List<Point>();

        for(int i = 0; i < numberOfPoints; i++) {
            Point randomPoint = new Point(Random.Range(-levelRadius, levelRadius), Random.Range(-levelRadius, levelRadius));
            randomPoint = new Point( (randomPoint.x * delaunayPointSnap) / delaunayPointSnap, (randomPoint.y * delaunayPointSnap) / delaunayPointSnap);
            if(!generationPoints.Contains(randomPoint)) {
                generationPoints.Add(randomPoint);
            }
        }

        //Clean up duplicates

        generationMessage = "Triangulating...";
        //Generate a delaunay triangulation of the points
        Poly2Tri.PointSet ps = new Poly2Tri.PointSet(generationPoints.Select(d=>(Poly2Tri.TriangulationPoint)d).ToList());
        Poly2Tri.P2T.Triangulate (ps);
        List<Poly2Tri.DelaunayTriangle> delaunayTriangles = ps.Triangles.ToList();

        generationMessage = "Performing Brownian Walk through triangulation...";
        //Brownian Walk through the triangles.
        Poly2TriDelaunayTriangulationWalker walker = new Poly2TriDelaunayTriangulationWalker (delaunayTriangles);
        List<Poly2Tri.DelaunayTriangle> levelTriangleSet = new List<Poly2Tri.DelaunayTriangle>();

        for (int i = 0; i < numberOfStepsForBrownianWalk; i++) {
            Poly2Tri.DelaunayTriangle nextTriangle = walker.Next();
            if(!levelTriangleSet.Contains(nextTriangle)) {
                levelTriangleSet.Add(nextTriangle);
            }
        }

        generationMessage = "Performing Tendril Walks...";
        for (int i = 0; i < numberOfTendrilWalksToComplete; i++) {
            generationMessage = "Performing Tendril Walk: " + i;
            walker.SetCurrentTriangleIndex(delaunayTriangles.IndexOf(levelTriangleSet[Mathf.FloorToInt(Random.value * levelTriangleSet.Count)]));
            for (int j = 0; j < numberOfStepsForBrownianWalk; j++) {
                Poly2Tri.DelaunayTriangle nextTriangle = walker.Next();
                if(!levelTriangleSet.Contains(nextTriangle)) {
                    levelTriangleSet.Add(nextTriangle);
                }
            }
        }

        generationMessage = "Getting level boolean...";
        //List<Poly2Tri.DelaunayTriangle> booleanFromLevelSet = delaunayTriangles.Where (x => !levelTriangleSet.Contains (x)).ToList ();

        /* Debugging delaunay triangulation
        foreach (Poly2Tri.DelaunayTriangle tri in booleanFromLevelSet) {
            Gizmos.DrawLine(new Vector2(tri.Points[0].Xf, tri.Points[0].Yf), new Vector2(tri.Points[1].Xf, tri.Points[1].Yf));
            Gizmos.DrawLine(new Vector2(tri.Points[1].Xf, tri.Points[1].Yf), new Vector2(tri.Points[2].Xf, tri.Points[2].Yf));
            Gizmos.DrawLine(new Vector2(tri.Points[2].Xf, tri.Points[2].Yf), new Vector2(tri.Points[0].Xf, tri.Points[0].Yf));
        }
        */

        //Generate colliders...
        ClipperLib.Clipper clipper = new ClipperLib.Clipper ();
        foreach(Poly2Tri.DelaunayTriangle tri in levelTriangleSet) {
            Polygon trianglePoints = new Polygon();
            for(int i = 0; i < 3; i++) {
                trianglePoints.points.Add(tri.Points[i]);
            }
            clipper.AddPath(trianglePoints, ClipperLib.PolyType.ptSubject, true);

        }

        List<List<ClipperLib.IntPoint>> solution = new List<List<ClipperLib.IntPoint>> ();
        clipper.Execute (ClipperLib.ClipType.ctUnion, solution, ClipperLib.PolyFillType.pftPositive, ClipperLib.PolyFillType.pftPositive);

        generationMessage = "Generating mesh from boolean...";
        DestructibleLevel level = GetComponent<DestructibleLevel> ();
        if (level == null) {
            level = gameObject.AddComponent<DestructibleLevel>();
        }

        foreach (List<ClipperLib.IntPoint> polygon in solution) {
            level.booleanPolygons.Add(new Tinkerbox.Geometry.Polygon(polygon));
        }

        level.UpdateMesh();

        generationMessage = "Calling Callback..";
        OnFinishedGeneration();
        GameObject[] players = GameObject.FindGameObjectsWithTag ("Player");
        Poly2Tri.DelaunayTriangle spawnTriangle = levelTriangleSet [Mathf.FloorToInt (Random.value * levelTriangleSet.Count)];

        generationMessage = "Spawning Players...";
        Vector2 spawnPoint = new Vector2 (spawnTriangle.Centroid ().Xf, spawnTriangle.Centroid ().Yf);

        foreach (GameObject player in players) {
            player.transform.position = spawnPoint + Random.insideUnitCircle;

        }

        generationMessage = "Spawning Decorations...";
        for (int i = 0; i < decorationsToSpawn; i++) {
            GameObject decoration = (GameObject) Instantiate(decorations[Mathf.FloorToInt(Random.value * decorations.Length)]);
            Poly2Tri.DelaunayTriangle decorSpawnTriangle = levelTriangleSet [Mathf.FloorToInt (Random.value * levelTriangleSet.Count)];
            Point decorSpawnPoint = decorSpawnTriangle.Centroid();
            decoration.transform.position = decorSpawnPoint + Random.insideUnitCircle;
        }

        //yield return 0;
    }
Пример #10
0
 //------------------------------------------------------------------------------
 public static List<List<IntPoint>> MinkowskiSum(List<IntPoint> pattern, List<List<IntPoint>> paths, bool pathIsClosed)
 {
     List<List<IntPoint>> solution = new List<List<IntPoint>>();
     Clipper c = new Clipper();
     for (int i = 0; i < paths.Count; ++i)
     {
         List<List<IntPoint>> tmp = Minkowski(pattern, paths[i], true, pathIsClosed);
         c.AddPaths(tmp, PolyType.ptSubject, true);
         if (pathIsClosed)
         {
             List<IntPoint> path = TranslatePath(paths[i], pattern[0]);
             c.AddPath(path, PolyType.ptClip, true);
         }
     }
     c.Execute(ClipType.ctUnion, solution,
       PolyFillType.pftNonZero, PolyFillType.pftNonZero);
     return solution;
 }
Пример #11
0
        /// <summary>
        /// Returns a list of fixtures and their shapes with regions inside portals clipped away.  
        /// This excludes portal fixtures and the shapes are in world coordinates.
        /// </summary>
        /// <param name="body"></param>
        /// <returns></returns>
        private static List<Tuple<Fixture, Vector2[]>> GetClippedFixtures(Body body)
        {
            BodyData data = GetData(body);

            /* If this body isn't colliding with any portals then we just return a list of
             * fixtures and vertices.*/
            if (data.PortalCollisions().Count <= 0)
            {
                List<Tuple<Fixture, Vector2[]>> fixtures = new List<Tuple<Fixture, Vector2[]>>();
                foreach (Fixture f in body.FixtureList)
                {
                    fixtures.Add(new Tuple<Fixture, Vector2[]>(f, FixtureExt.GetWorldPoints(f)));
                }
                return fixtures;
            }

            Vector2 center = GetLocalOrigin(body);

            List<List<IntPoint>> clipPaths = new List<List<IntPoint>>();
            foreach (IPortal p in data.PortalCollisions())
            {
                Vector2[] verts = Portal.GetWorldVerts(p);
                float scale = 100;

                Vector2 v0 = verts[0] + (verts[1] - verts[0]).Normalized() * scale;
                Vector2 v1 = verts[1] - (verts[1] - verts[0]).Normalized() * scale;
                Vector2 depth = (verts[1] - verts[0]).PerpendicularLeft.Normalized() * scale;
                if (new LineF(v0, v1).GetSideOf(v1 + depth) == new LineF(v0, v1).GetSideOf(center))
                {
                    depth *= -1;
                }

                Vector2[] box = new Vector2[]
                {
                    v0, v1, v1 + depth, v0 + depth
                };
                box = MathExt.SetWinding(box, true);

                clipPaths.Add(ClipperConvert.ToIntPoint(box));
            }

            List<Tuple<Fixture, Vector2[]>> clippedFixtures = new List<Tuple<Fixture, Vector2[]>>();

            Clipper clipper = new Clipper();
            foreach (Fixture f in body.FixtureList)
            {
                if (!FixtureExt.GetData(f).IsPortalParentless())
                {
                    continue;
                }

                clipper.Clear();
                clipper.AddPaths(clipPaths, PolyType.ptClip, true);

                clipper.AddPath(
                    ClipperConvert.ToIntPoint(FixtureExt.GetWorldPoints(f)),
                    PolyType.ptSubject,
                    true);

                List<List<IntPoint>> result = new List<List<IntPoint>>();
                clipper.Execute(ClipType.ctDifference, result, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero);
                Debug.Assert(
                    result.Count <= 1,
                    "This fixture is too large for the portal masking or something has gone wrong with the clipper.");

                if (result.Count > 0)
                {
                    clippedFixtures.Add(new Tuple<Fixture, Vector2[]>(f, ClipperConvert.ToVector2(result[0])));
                }
            }

            Debug.Assert(clippedFixtures.Count > 0);
            return clippedFixtures;
        }
Пример #12
0
        private PolyTreeEdgesRetained PrepairPolyTree(Collider2D[] floorColliders, Collider2D[] wallColliders)
        {
            if(floorColliders.Length == 0)
            {
                throw new System.Exception("No colliders in the scene on the floor layer.");
            }

            PolyTreeEdgesRetained TreeAndEdges = new PolyTreeEdgesRetained();

            TreeAndEdges.Edges = new List<List<IntPoint>>();
            TreeAndEdges.Tree = new PolyTree();

            Clipper finalClipper = new Clipper();

            if (floorColliders.Length > 0)
            {
                Clipper tempC = new Clipper();
                ClipperOffset tempCo = new ClipperOffset();

                foreach (Collider2D d in floorColliders)
                {
                    List<IntPoint> p = PolygonFromCollider2D(d, false);
                    if (p != null && p.Count != 0)
                    {
                        if (ClipperLib.Clipper.Orientation(p))
                            p.Reverse();

                        tempC.AddPath(p, PolyType.ptSubject, true);
                    }
                }

                List<List<IntPoint>> solution = new List<List<IntPoint>>();
                tempC.Execute(ClipType.ctUnion, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
                tempC.Clear();

                foreach (List<IntPoint> intPoints in solution)
                {
                    tempCo.AddPath(intPoints, (JoinType)GenerationInformation.JoinType, EndType.etClosedPolygon);
                    TreeAndEdges.Edges.Add(intPoints);
                }
                solution.Clear();
                tempCo.Execute(ref solution, -GenerationInformation.ColliderPadding * GenerationInformation.CalculationScaleFactor);
                finalClipper.AddPaths(solution, PolyType.ptSubject, true);
            }

            if(wallColliders.Length > 0)
            {
                Clipper tempC = new Clipper();
                ClipperOffset tempCo = new ClipperOffset();

                foreach (Collider2D d in wallColliders)
                {
                    List<IntPoint> p = PolygonFromCollider2D(d, false);
                    if (p != null && p.Count != 0)
                    {
                        if (ClipperLib.Clipper.Orientation(p))
                            p.Reverse();

                        tempC.AddPath(p, PolyType.ptSubject, true);
                    }
                }

                List<List<IntPoint>> solution = new List<List<IntPoint>>();
                tempC.Execute(ClipType.ctUnion, solution, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
                tempC.Clear();

                foreach (List<IntPoint> intPoints in solution)
                {
                    tempCo.AddPath(intPoints, (JoinType)GenerationInformation.JoinType, EndType.etClosedPolygon);
                    TreeAndEdges.Edges.Add(intPoints);
                }
                solution.Clear();

                tempCo.Execute(ref solution, GenerationInformation.ColliderPadding * GenerationInformation.CalculationScaleFactor);
                finalClipper.AddPaths(solution, PolyType.ptClip, true);
            }

            finalClipper.Execute(ClipType.ctDifference, TreeAndEdges.Tree, PolyFillType.pftPositive, PolyFillType.pftEvenOdd);

            return TreeAndEdges;
        }
Пример #13
0
        public static PolyTree ExecuteClipper(TmxMap tmxMap, TmxLayer tmxLayer, TransformPointFunc xfFunc, ProgressFunc progFunc)
        {
            // The "fullClipper" combines the clipper results from the smaller pieces
            ClipperLib.Clipper fullClipper = new ClipperLib.Clipper();

            // From the perspective of Clipper lines are polygons too
            // Closed paths == polygons
            // Open paths == lines
            var polygonGroups = from y in Enumerable.Range(0, tmxLayer.Height)
                                from x in Enumerable.Range(0, tmxLayer.Width)
                                let rawTileId = tmxLayer.GetRawTileIdAt(x, y)
                                                let tileId = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                                             where tileId != 0
                                                             let tile = tmxMap.Tiles[tileId]
                                                                        from polygon in tile.ObjectGroup.Objects
                                                                        where (polygon as TmxHasPoints) != null
                                                                        let groupX = x / LayerClipper.GroupBySize
                                                                                     let groupY = y / LayerClipper.GroupBySize
                                                                                                  group new
            {
                PositionOnMap         = tmxMap.GetMapPositionAt(x, y, tile),
                HasPointsInterface    = polygon as TmxHasPoints,
                TmxObjectInterface    = polygon,
                IsFlippedDiagnoally   = TmxMath.IsTileFlippedDiagonally(rawTileId),
                IsFlippedHorizontally = TmxMath.IsTileFlippedHorizontally(rawTileId),
                IsFlippedVertically   = TmxMath.IsTileFlippedVertically(rawTileId),
                TileCenter            = new PointF(tile.TileSize.Width * 0.5f, tile.TileSize.Height * 0.5f),
            }
            by Tuple.Create(groupX, groupY);

            int groupIndex = 0;
            int groupCount = polygonGroups.Count();

            foreach (var polyGroup in polygonGroups)
            {
                if (groupIndex % 5 == 0)
                {
                    progFunc(String.Format("Clipping '{0}' polygons: {1}%", tmxLayer.UniqueName, (groupIndex / (float)groupCount) * 100));
                }
                groupIndex++;

                // The "groupClipper" clips the polygons in a smaller part of the world
                ClipperLib.Clipper groupClipper = new ClipperLib.Clipper();

                // Add all our polygons to the Clipper library so it can reduce all the polygons to a (hopefully small) number of paths
                foreach (var poly in polyGroup)
                {
                    // Create a clipper library polygon out of each and add it to our collection
                    ClipperPolygon clipperPolygon = new ClipperPolygon();

                    // Our points may be transformed due to tile flipping/rotation
                    // Before we transform then we put all the points into local space relative to the tile
                    SizeF    offset            = new SizeF(poly.TmxObjectInterface.Position);
                    PointF[] transformedPoints = poly.HasPointsInterface.Points.Select(pt => PointF.Add(pt, offset)).ToArray();

                    // Now transform the points relative to the tile
                    TmxMath.TransformPoints(transformedPoints, poly.TileCenter, poly.IsFlippedDiagnoally, poly.IsFlippedHorizontally, poly.IsFlippedVertically);

                    foreach (var pt in transformedPoints)
                    {
                        float x = poly.PositionOnMap.X + pt.X;
                        float y = poly.PositionOnMap.Y + pt.Y;

                        ClipperLib.IntPoint point = xfFunc(x, y);
                        clipperPolygon.Add(point);
                    }

                    // Because of Unity's cooridnate system, the winding order of the polygons must be reversed
                    clipperPolygon.Reverse();

                    // Add the "subject"
                    groupClipper.AddPath(clipperPolygon, ClipperLib.PolyType.ptSubject, poly.HasPointsInterface.ArePointsClosed());
                }

                // Get a solution for this group
                ClipperLib.PolyTree solution = new ClipperLib.PolyTree();
                groupClipper.Execute(ClipperLib.ClipType.ctUnion, solution);

                // Combine the solutions into the full clipper
                fullClipper.AddPaths(Clipper.ClosedPathsFromPolyTree(solution), PolyType.ptSubject, true);
                fullClipper.AddPaths(Clipper.OpenPathsFromPolyTree(solution), PolyType.ptSubject, false);
            }
            progFunc(String.Format("Clipping '{0}' polygons: 100%", tmxLayer.UniqueName));

            ClipperLib.PolyTree fullSolution = new ClipperLib.PolyTree();
            fullClipper.Execute(ClipperLib.ClipType.ctUnion, fullSolution);

            return(fullSolution);
        }
    public void UpdateMesh()
    {
        //clean up
        booleanUnionSolution.Clear ();
        //solutions.Clear ();
        EdgeCollider2D[] cols = GetComponents<EdgeCollider2D> ();
        foreach (EdgeCollider2D col in cols) {
            DestroyImmediate(col);
        }

        PolygonCollider2D[] polyCols = GetComponents<PolygonCollider2D> ();
        foreach (PolygonCollider2D polyCol in polyCols) {
            DestroyImmediate(polyCol);
        }

        //Wind the square to boolean from.
        levelArea.points.Clear ();
        levelArea.points.Add (new Point (-1000f, 1000f));
        levelArea.points.Add (new Point (1000f, 1000f));
        levelArea.points.Add (new Point (1000f, -1000f));
        levelArea.points.Add (new Point (-1000f, -1000f));
        ClipperLib.Clipper clipper = new ClipperLib.Clipper ();
        //Strictly simple is computationally expensive, but prevents points from appearing too close together and making Poly2Tri Shit the bed.
        clipper.StrictlySimple = true;
        foreach (Polygon polygon in booleanPolygons) {
            clipper.AddPath(polygon,ClipperLib.PolyType.ptClip, true);
        }

        clipper.Execute (ClipperLib.ClipType.ctUnion, booleanUnionSolution, ClipperLib.PolyFillType.pftNonZero,ClipperLib.PolyFillType.pftNonZero);
        clipper.Clear ();
        clipper.AddPath (levelArea, ClipperLib.PolyType.ptSubject, true);
        foreach (List<ClipperLib.IntPoint> polygon in booleanUnionSolution) {
            clipper.AddPath(polygon,ClipperLib.PolyType.ptClip, true);
        }
        List<List<ClipperLib.IntPoint>> solution = new List<List<ClipperLib.IntPoint>> ();
        clipper.Execute (ClipperLib.ClipType.ctDifference, solution, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero);
        mesh = Utils.PolygonsToMesh (solution.Select(x=> (Polygon)x).ToList());
        solutions = solution.Select (x => (Polygon)x).ToList ();
        GetComponent<MeshFilter> ().sharedMesh = mesh;

        foreach (Polygon polygon in solution) {
            Vector2[] unityPoints = new Vector2[polygon.points.Count + 1];
            for(int i = 0; i < polygon.points.Count; i++) {
                unityPoints[i] = new Vector2(polygon.points[i].x,polygon.points[i].y);
            }
            unityPoints[polygon.points.Count] = new Vector2(polygon.points[0].x,polygon.points[0].y);
            EdgeCollider2D collider = gameObject.AddComponent<EdgeCollider2D>();
            collider.points = unityPoints;
        }

        solutionCount = booleanUnionSolution.Count;
        //No need to store polygons that we won't need to reference...
        booleanPolygons = booleanUnionSolution.Select(x=>(Polygon)x).ToList();
    }
Пример #15
0
      public void FillPath(Color fillColor) {
         var fillClipper = new Clipper(Clipper.ioStrictlySimple);
         var points = pathSegments.SelectMany(s => new[] { new IntPoint(s.Head.Location.X * 1000, s.Head.Location.Y * 1000), new IntPoint(s.Tail.Location.X * 1000, s.Tail.Location.Y * 1000) });
         fillClipper.AddPath(points.ToList(), PolyType.ptSubject, true);
         var polytree = new PolyTree();
         fillClipper.Execute(ClipType.ctUnion, polytree, PolyFillType.pftEvenOdd, PolyFillType.pftNonZero);
         var triangles = new Triangulator().TriangulateComplex(polytree);

         using (RenderTargetSwap()) {
            GraphicsDevice.SetRasterizerState(rasterizerState);

            foreach (var pass in effect.CurrentTechnique.Passes) {
               pass.Apply();
               var x = new PrimitiveBatch<VertexPositionColor>(GraphicsDevice);
               x.Begin();
               foreach (var triangle in triangles) {
                  var p1 = triangle.Points[0];
                  var p2 = triangle.Points[1];
                  var p3 = triangle.Points[2];
                  x.DrawTriangle(
                     new VertexPositionColor(new Vector3((float)p1.X, (float)p1.Y, 100), fillColor),
                     new VertexPositionColor(new Vector3((float)p2.X, (float)p2.Y, 100), fillColor),
                     new VertexPositionColor(new Vector3((float)p3.X, (float)p3.Y, 100), fillColor)
                     );
               }
               x.End();
            }
         }
      }
Пример #16
0
        /// <summary>
        /// Applies a buoyant force, drag and lift to an object submerged in the water.
        /// </summary>
        /// <param name="subjectPoly"> The polygon of the object in the water.</param>
        /// <param name="minIndex"> The min index for a value in the "waterLinePoints" list. </param>
        /// <param name="maxIndex"> The max index for a value in the "waterLinePoints" list. </param>
        /// <param name="isIntersecting"> Are the subject and clipping polygon intersecting?. </param>
        private List<List<Vector2>> GetIntersectionPolygon(Vector2[] subjectPoly, int minIndex, int maxIndex, out bool isIntersecting)
        {
            Vector2 bottomHandleGlobalPos = transform.TransformPoint(water2D.handlesPosition[1]);
            List<List<Vector2>> intersectionPoly = new List<List<Vector2>>();
            List<Vector2> clipPolygon = new List<Vector2>();
            Clipper clipper = new Clipper();
            Paths solutionPath = new Paths();
            Path subjPath = new Path();
            Path clipPath = new Path();
            int len, len2, min, max;
            isIntersecting = true;

            if (surfaceVertsCount > meshSegmentsPerWaterLineSegment)
            {
                min = (int)Mathf.Floor(minIndex / meshSegmentsPerWaterLineSegment);
                max = (int)Mathf.Floor(maxIndex / meshSegmentsPerWaterLineSegment) + 1;

                if (max > waterLinePoints.Count - 2)
                    max = waterLinePoints.Count - 2;

                for (int i = min; i <= max; i++)
                {
                    clipPolygon.Add(waterLinePoints[i]);
                }

                int last = clipPolygon.Count - 1;
                clipPolygon.Add(new Vector2(clipPolygon[last].x, bottomHandleGlobalPos.y));
                clipPolygon.Add(new Vector2(clipPolygon[0].x, bottomHandleGlobalPos.y));
            }
            else
            {
                Vector2 vertGlobalPos = transform.TransformPoint(vertices[surfaceVertsCount]);
                clipPolygon.Add(vertGlobalPos);
                vertGlobalPos = transform.TransformPoint(vertices[surfaceVertsCount + surfaceVertsCount - 1]);
                clipPolygon.Add(new Vector2(vertGlobalPos.x, vertGlobalPos.y));

                int last = clipPolygon.Count - 1;
                clipPolygon.Add(new Vector2(clipPolygon[last].x, bottomHandleGlobalPos.y));
                clipPolygon.Add(new Vector2(clipPolygon[0].x, bottomHandleGlobalPos.y));
            }

            if (showClippingPlolygon)
            {
                for (int i = 0; i < clipPolygon.Count; i++)
                {
                    if (i < clipPolygon.Count - 1)
                        Debug.DrawLine(clipPolygon[i], clipPolygon[i + 1], Color.green);
                    else
                        Debug.DrawLine(clipPolygon[i], clipPolygon[0], Color.green);
                }
            }

            len = subjectPoly.Length;
            for (int i = 0; i < len; i++)
            {
                subjPath.Add(new IntPoint(subjectPoly[i].x * scaleFactor, subjectPoly[i].y * scaleFactor));
            }

            len = clipPolygon.Count;
            for (int i = 0; i < len; i++)
            {
                clipPath.Add(new IntPoint(clipPolygon[i].x * scaleFactor, clipPolygon[i].y * scaleFactor));
            }

            clipper.AddPath(subjPath, PolyType.ptSubject, true);
            clipper.AddPath(clipPath, PolyType.ptClip, true);
            clipper.Execute(ClipType.ctIntersection, solutionPath, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd);

            if (solutionPath.Count != 0)
            {
                len = solutionPath.Count;

                for (int i = 0; i < len; i++)
                {
                    len2 = solutionPath[i].Count;
                    List<Vector2> list = new List<Vector2>();

                    for (int j = 0; j < len2; j++)
                    {
                        list.Add(new Vector2(solutionPath[i][j].X / scaleFactor, solutionPath[i][j].Y / scaleFactor));
                    }

                    intersectionPoly.Add(list);
                }
                return intersectionPoly;
            }
            else
            {
                isIntersecting = false;
                return null;
            }
        }
Пример #17
0
        public PolyTree UnionPolygonsToTree(IReadOnlyList<IReadOnlyList<TriangulationPoint>> polygons)
        {
            if (polygons == null) return null;

             var clipper = new Clipper(Clipper.ioStrictlySimple);
             foreach (var polygon in polygons) {
            clipper.AddPath(polygon.MapList(UpscalePoint), PolyType.ptSubject, true);
             }
             PolyTree polyTree = new PolyTree();
             clipper.Execute(ClipType.ctUnion, polyTree, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd);
            //         Console.WriteLine(polygons.Count + " vs " + polyTree.Total + " " + polyTree.Childs.Count);
             return polyTree;
        }
        private static List<List<Point>> Remove_Overlap_In_XY_Plane(List<Point> points1, List<List<Point>> otherPolygonsPoints)
        {
            var clipper = new Clipper();
            
            clipper.StrictlySimple = true; //we only handle so-called simple polygons, this helps ensure that the only results clipper returns are simple polygons
            
            clipper.AddPath(ToClipperPath(points1), PolyType.ptSubject, true);
            foreach (var pointList in otherPolygonsPoints)
            { 
                clipper.AddPath(ToClipperPath(pointList), PolyType.ptClip, true);
            }

            var soln = new Paths();
            // clipper offers 4 operations: http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/ClipType.htm
            var success = clipper.Execute(ClipType.ctDifference, soln);
            
            var resultantPolygonPoints = new List<List<Point>>();
            if (success.Not())
            {
                return null;
            }
            foreach (var pointList in soln)
            {
                resultantPolygonPoints.Add(ToPoints(pointList));
            }
            return resultantPolygonPoints;
        }
Пример #19
0
 private PolyTree Punch(PolyTree input, PolyTree hole)
 {
     var subtractClipper = new Clipper(Clipper.ioStrictlySimple);
      for (var it = input.GetFirst(); it != null; it = it.GetNext()) {
     subtractClipper.AddPath(it.Contour, PolyType.ptSubject, true);
      }
      for (var it = hole.GetFirst(); it != null; it = it.GetNext()) {
     subtractClipper.AddPath(it.Contour, PolyType.ptClip, true);
      }
      var result = new PolyTree();
      subtractClipper.Execute(ClipType.ctDifference, result, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
      return result;
 }
Пример #20
0
 //------------------------------------------------------------------------------
 // SimplifyPolygon functions ...
 // Convert self-intersecting polygons into simple polygons
 //------------------------------------------------------------------------------
 public static List<List<IntPoint>> SimplifyPolygon(List<IntPoint> poly,
       PolyFillType fillType = PolyFillType.pftEvenOdd)
 {
     List<List<IntPoint>> result = new List<List<IntPoint>>();
     Clipper c = new Clipper();
     c.StrictlySimple = true;
     c.AddPath(poly, PolyType.ptSubject, true);
     c.Execute(ClipType.ctUnion, result, fillType, fillType);
     return result;
 }
Пример #21
0
 private PolyTree Union(PolyTree a, PolyTree b)
 {
     var landUnionClipper = new Clipper(Clipper.ioStrictlySimple);
      var s = new Stack<PolyNode>();
      s.Push(a);
      s.Push(b);
      while (s.Any()) {
     var node = s.Pop();
     if (!node.IsHole) {
        landUnionClipper.AddPath(node.Contour, PolyType.ptSubject, true);
     }
     node.Childs.ForEach(s.Push);
      }
      PolyTree landUnionPolyTree = new PolyTree();
      landUnionClipper.Execute(ClipType.ctUnion, landUnionPolyTree, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
      return landUnionPolyTree;
 }
Пример #22
0
        /// <summary>
        /// Checks whether this key overlaps with another specified key definition.
        /// </summary>
        /// <param name="otherKey">The other key to check for overlapping on.</param>
        /// <returns><c>True</c> if the keys overlap, <c>false</c> otherwise.</returns>
        public bool BordersWith(KeyDefinition otherKey)
        {
            var clipper = new Clipper();

            clipper.AddPath(this.GetPath(), PolyType.ptSubject, true);
            clipper.AddPath(otherKey.GetPath(), PolyType.ptClip, true);

            var union = new List<List<IntPoint>>();
            clipper.Execute(ClipType.ctUnion, union);

            return union.Count == 1;
        }
Пример #23
0
        public static PolyTree ExecuteClipper(TmxMap tmxMap, TmxLayer tmxLayer, TransformPointFunc xfFunc, ProgressFunc progFunc)
        {
            // The "fullClipper" combines the clipper results from the smaller pieces
            ClipperLib.Clipper fullClipper = new ClipperLib.Clipper();

            // From the perspective of Clipper lines are polygons too
            // Closed paths == polygons
            // Open paths == lines
            var polygonGroups = from y in Enumerable.Range(0, tmxLayer.Height)
                                from x in Enumerable.Range(0, tmxLayer.Width)
                                let rawTileId = tmxLayer.GetRawTileIdAt(x, y)
                                let tileId = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                where tileId != 0
                                let tile = tmxMap.Tiles[tileId]
                                from polygon in tile.ObjectGroup.Objects
                                where (polygon as TmxHasPoints) != null
                                let groupX = x / LayerClipper.GroupBySize
                                let groupY = y / LayerClipper.GroupBySize
                                group new
                                {
                                    PositionOnMap = tmxMap.GetMapPositionAt(x, y, tile),
                                    HasPointsInterface = polygon as TmxHasPoints,
                                    TmxObjectInterface = polygon,
                                    IsFlippedDiagnoally = TmxMath.IsTileFlippedDiagonally(rawTileId),
                                    IsFlippedHorizontally = TmxMath.IsTileFlippedHorizontally(rawTileId),
                                    IsFlippedVertically = TmxMath.IsTileFlippedVertically(rawTileId),
                                    TileCenter = new PointF(tile.TileSize.Width * 0.5f, tile.TileSize.Height * 0.5f),
                                }
                                by Tuple.Create(groupX, groupY);

            int groupIndex = 0;
            int groupCount = polygonGroups.Count();

            foreach (var polyGroup in polygonGroups)
            {
                if (groupIndex % 5 == 0)
                {
                    progFunc(String.Format("Clipping '{0}' polygons: {1}%", tmxLayer.UniqueName, (groupIndex / (float)groupCount) * 100));
                }
                groupIndex++;

                // The "groupClipper" clips the polygons in a smaller part of the world
                ClipperLib.Clipper groupClipper = new ClipperLib.Clipper();

                // Add all our polygons to the Clipper library so it can reduce all the polygons to a (hopefully small) number of paths
                foreach (var poly in polyGroup)
                {
                    // Create a clipper library polygon out of each and add it to our collection
                    ClipperPolygon clipperPolygon = new ClipperPolygon();

                    // Our points may be transformed due to tile flipping/rotation
                    // Before we transform then we put all the points into local space relative to the tile
                    SizeF offset = new SizeF(poly.TmxObjectInterface.Position);
                    PointF[] transformedPoints = poly.HasPointsInterface.Points.Select(pt => PointF.Add(pt, offset)).ToArray();

                    // Now transform the points relative to the tile
                    TmxMath.TransformPoints(transformedPoints, poly.TileCenter, poly.IsFlippedDiagnoally, poly.IsFlippedHorizontally, poly.IsFlippedVertically);

                    foreach (var pt in transformedPoints)
                    {
                        float x = poly.PositionOnMap.X + pt.X;
                        float y = poly.PositionOnMap.Y + pt.Y;

                        ClipperLib.IntPoint point = xfFunc(x, y);
                        clipperPolygon.Add(point);
                    }

                    // Because of Unity's cooridnate system, the winding order of the polygons must be reversed
                    clipperPolygon.Reverse();

                    // Add the "subject"
                    groupClipper.AddPath(clipperPolygon, ClipperLib.PolyType.ptSubject, poly.HasPointsInterface.ArePointsClosed());
                }

                // Get a solution for this group
                ClipperLib.PolyTree solution = new ClipperLib.PolyTree();
                groupClipper.Execute(ClipperLib.ClipType.ctUnion, solution, LayerClipper.SubjectFillRule, LayerClipper.ClipFillRule);

                // Combine the solutions into the full clipper
                fullClipper.AddPaths(Clipper.ClosedPathsFromPolyTree(solution), PolyType.ptSubject, true);
                fullClipper.AddPaths(Clipper.OpenPathsFromPolyTree(solution), PolyType.ptSubject, false);
            }
            progFunc(String.Format("Clipping '{0}' polygons: 100%", tmxLayer.UniqueName));

            ClipperLib.PolyTree fullSolution = new ClipperLib.PolyTree();
            fullClipper.Execute(ClipperLib.ClipType.ctUnion, fullSolution, LayerClipper.SubjectFillRule, LayerClipper.ClipFillRule);

            return fullSolution;
        }
Пример #24
0
 public static List<List<IntPoint>> MergePolygon(List<List<IntPoint>> polygonA, List<IntPoint> polygonB)
 {
     Clipper clipper = new Clipper();
     clipper.AddPaths(polygonA, PolyType.ptSubject, true);
     clipper.AddPath(polygonB, PolyType.ptClip, true);            
     List<List<IntPoint>> solution = new List<List<IntPoint>>();
     clipper.Execute(ClipType.ctUnion, solution);
     return solution;
 }
Пример #25
0
        public static PolyTree ExecuteClipper(TmxMap map, TmxChunk chunk, TransformPointFunc xfFunc)
        {
            ////for(int i=0;i<chunk.Height;i++)
            //// {
            ////     for(int j=0; j<chunk.Width;j++)
            ////     {
            ////         var raw = chunk.GetRawTileIdAt(j, i);
            ////      if(raw!=0)
            ////         {
            ////             var tid = TmxMath.GetTileIdWithoutFlags(raw);
            ////             var tile = map.Tiles[tid];
            ////             foreach(var p in tile.ObjectGroup.Objects)
            ////             {
            ////                 if(p is TmxHasPoints)
            ////                 {
            ////                     p.ToEnumerable().Where((x) =>
            ////                     {
            ////                         if (!usingUnityLayerOverride)
            ////                         {


            ////                             return string.Compare(tuple.Item1.Type, chunk.ParentData.ParentLayer.Name, true) == 0;
            ////                         }

            ////                         return true;
            ////                     });
            ////                 }

            ////             }
            ////         }
            ////     }
            //// }

            //     Clipper clipper = new Clipper(0);
            //     Tuple<TmxObject, TmxTile, uint> tuple = new Tuple<TmxObject, TmxTile, uint>(null, null, 0);
            //     bool usingUnityLayerOverride = !string.IsNullOrEmpty(chunk.ParentData.ParentLayer.UnityLayerOverrideName);
            //     foreach (var item2 in from h__TransparentIdentifier4 in (from y in Enumerable.Range(0, chunk.Height)
            //                                                              from x in Enumerable.Range(0, chunk.Width)
            //                                                              let rawTileId = chunk.GetRawTileIdAt(x, y)
            //                                                              where rawTileId != 0
            //                                                              let tileId = TmxMath.GetTileIdWithoutFlags(rawTileId)
            //                                                              let tile = map.Tiles[tileId]

            //                                                              from polygon in tile.ObjectGroup.Objects
            //                                                              where polygon is TmxHasPoints

            //                                                              select polygon.ToEnumerable().ToList().TrueForAll
            //                                                              (h__TransparentIdentifier4 =>

            //                    {
            //                        UnityEngine.Debug.Log("liudaodelh");
            //                        tuple = new Tuple<TmxObject, TmxTile, uint>(polygon, tile, rawTileId);
            //                        if (!usingUnityLayerOverride)
            //                        {


            //                            return string.Compare(tuple.Item1.Type, chunk.ParentData.ParentLayer.Name, true) == 0;
            //                        }

            //                        return true;
            //                    }))
            //                           select new
            //                           {

            //                               PositionOnMap = map.GetMapPositionAt((int)tuple.Item1.Position.X + chunk.X, (int)tuple.Item1.Position.Y + chunk.Y, tuple.Item2),
            //                               HasPointsInterface = (tuple.Item1 as TmxHasPoints),
            //                               TmxObjectInterface = tuple.Item1,
            //                               IsFlippedDiagnoally = TmxMath.IsTileFlippedDiagonally(tuple.Item3),
            //                               IsFlippedHorizontally = TmxMath.IsTileFlippedHorizontally(tuple.Item3),
            //                               IsFlippedVertically = TmxMath.IsTileFlippedVertically(tuple.Item3),
            //                               TileCenter = new PointF((float)tuple.Item2.TileSize.Width * 0.5f, (float)tuple.Item2.TileSize.Height * 0.5f)
            //                           })
            //     {
            //         List<IntPoint> list = new List<IntPoint>();
            //         SizeF offset = new SizeF(item2.TmxObjectInterface.Position);
            //         PointF[] array = item2.HasPointsInterface.Points.Select((PointF pt) => PointF.Add(pt, offset)).ToArray();
            //         TmxMath.TransformPoints(array, item2.TileCenter, item2.IsFlippedDiagnoally, item2.IsFlippedHorizontally, item2.IsFlippedVertically);
            //         PointF[] array2 = array;
            //         for (int i = 0; i < array2.Length; i++)
            //         {
            //             PointF pointF = array2[i];
            //             float x2 = (float)item2.PositionOnMap.X + pointF.X;
            //             float y2 = (float)item2.PositionOnMap.Y + pointF.Y;
            //             IntPoint item = xfFunc(x2, y2);
            //             list.Add(item);
            //         }
            //         list.Reverse();
            //         clipper.AddPath(list, PolyType.ptSubject, item2.HasPointsInterface.ArePointsClosed());
            //     }
            //     PolyTree polyTree = new PolyTree();
            //     clipper.Execute(ClipType.ctUnion, polyTree, SubjectFillRule, ClipFillRule);

            //     return polyTree;


            ClipperLib.Clipper clipper = new ClipperLib.Clipper();

            // Limit to polygon "type" that matches the collision layer name (unless we are overriding the whole layer to a specific Unity Layer Name)
            bool usingUnityLayerOverride = !String.IsNullOrEmpty(chunk.ParentData.ParentLayer.UnityLayerOverrideName);

            var polygons = from y in Enumerable.Range(0, chunk.Height)
                           from x in Enumerable.Range(0, chunk.Width)
                           let rawTileId = chunk.GetRawTileIdAt(x, y)
                                           where rawTileId != 0
                                           let tileId                       = TmxMath.GetTileIdWithoutFlags(rawTileId)
                                                                   let tile = map.Tiles[tileId]
                                                                              from polygon in tile.ObjectGroup.Objects
                                                                              where (polygon as TmxHasPoints) != null
                                                                              where usingUnityLayerOverride || String.Compare(polygon.Type, chunk.ParentData.ParentLayer.Name, true) == 0
                                                                              select new
            {
                PositionOnMap         = map.GetMapPositionAt(x + chunk.X, y + chunk.Y, tile),
                HasPointsInterface    = polygon as TmxHasPoints,
                TmxObjectInterface    = polygon,
                IsFlippedDiagnoally   = TmxMath.IsTileFlippedDiagonally(rawTileId),
                IsFlippedHorizontally = TmxMath.IsTileFlippedHorizontally(rawTileId),
                IsFlippedVertically   = TmxMath.IsTileFlippedVertically(rawTileId),
                TileCenter            = new PointF(tile.TileSize.Width * 0.5f, tile.TileSize.Height * 0.5f),
            };

            // Add all our polygons to the Clipper library so it can reduce all the polygons to a (hopefully small) number of paths
            foreach (var poly in polygons)
            {
                // Create a clipper library polygon out of each and add it to our collection
                ClipperPolygon clipperPolygon = new ClipperPolygon();

                // Our points may be transformed due to tile flipping/rotation
                // Before we transform them we put all the points into local space relative to the tile
                SizeF    offset            = new SizeF(poly.TmxObjectInterface.Position);
                PointF[] transformedPoints = poly.HasPointsInterface.Points.Select(pt => PointF.Add(pt, offset)).ToArray();

                // Now transform the points relative to the tile
                TmxMath.TransformPoints(transformedPoints, poly.TileCenter, poly.IsFlippedDiagnoally, poly.IsFlippedHorizontally, poly.IsFlippedVertically);

                foreach (var pt in transformedPoints)
                {
                    float x = poly.PositionOnMap.X + pt.X;
                    float y = poly.PositionOnMap.Y + pt.Y;

                    ClipperLib.IntPoint point = xfFunc(x, y);
                    clipperPolygon.Add(point);
                }

                // Because of Unity's cooridnate system, the winding order of the polygons must be reversed
                clipperPolygon.Reverse();

                // Add the "subject"
                clipper.AddPath(clipperPolygon, ClipperLib.PolyType.ptSubject, poly.HasPointsInterface.ArePointsClosed());
            }

            ClipperLib.PolyTree solution = new ClipperLib.PolyTree();
            clipper.Execute(ClipperLib.ClipType.ctUnion, solution, LayerClipper.SubjectFillRule, LayerClipper.ClipFillRule);
            return(solution);
        }
Пример #26
0
          //------------------------------------------------------------------------------

          public PolyOffsetBuilder(Paths pts, out Paths solution, double delta,
              JoinType jointype, EndType endtype, double limit = 0)
          {
              //precondition: solution != pts
              solution = new Paths();
              if (ClipperBase.near_zero(delta)) {solution = pts; return; }
              m_p = pts;
              if (endtype != EndType.etClosed && delta < 0) delta = -delta;
              m_delta = delta;

              if (jointype == JoinType.jtMiter)
              {
                  //m_miterVal: see offset_triginometry.svg in the documentation folder ...
                  if (limit > 2) m_miterLim = 2 / (limit * limit);
                  else m_miterLim = 0.5;
                  if (endtype == EndType.etRound) limit = 0.25;
              }
              if (jointype == JoinType.jtRound || endtype == EndType.etRound)
              {
              if (limit <= 0) limit = 0.25;
              else if (limit > Math.Abs(delta)*0.25) limit = Math.Abs(delta)*0.25;
              //m_roundVal: see offset_triginometry2.svg in the documentation folder ...
              m_Steps360 = Math.PI / Math.Acos(1 - limit / Math.Abs(delta));
              m_sin = Math.Sin(2 * Math.PI / m_Steps360);
              m_cos = Math.Cos(2 * Math.PI / m_Steps360);
              m_Steps360 /= Math.PI * 2;
              if (delta < 0) m_sin = -m_sin;
              }

              double deltaSq = delta * delta;
              solution.Capacity = pts.Count;
              for (m_i = 0; m_i < pts.Count; m_i++)
              {
                  int len = pts[m_i].Count;
                  if (len == 0 || (len < 3 && delta <= 0)) continue;
                    
                  if (len == 1)
                  {
                      if (jointype == JoinType.jtRound)
                      {
                          double X = 1.0, Y = 0.0;
                          for (cInt j = 1; j <= Round(m_Steps360 * 2 * Math.PI); j++)
                          {
                              AddPoint(new IntPoint(
                                Round(m_p[m_i][0].X + X * delta),
                                Round(m_p[m_i][0].Y + Y * delta)));
                              double X2 = X;
                              X = X * m_cos - m_sin * Y;
                              Y = X2 * m_sin + Y * m_cos;
                          }
                      }
                      else
                      {
                          double X = -1.0, Y = -1.0;
                          for (int j = 0; j < 4; ++j)
                          {
                              AddPoint(new IntPoint(Round(m_p[m_i][0].X + X * delta),
                                Round(m_p[m_i][0].Y + Y * delta)));
                              if (X < 0) X = 1;
                              else if (Y < 0) Y = 1;
                              else X = -1;
                          }
                      }
                      continue;
                  }
                    
                  //build normals ...
                  normals.Clear();
                  normals.Capacity = len;
                  for (int j = 0; j < len -1; ++j)
                      normals.Add(GetUnitNormal(pts[m_i][j], pts[m_i][j+1]));
                  if (endtype == EndType.etClosed)
                      normals.Add(GetUnitNormal(pts[m_i][len - 1], pts[m_i][0]));
                  else
                      normals.Add(new DoublePoint(normals[len - 2]));

                  currentPoly = new Path();
                  if (endtype == EndType.etClosed)
                  {
                      m_k = len - 1;
                      for (m_j = 0; m_j < len; ++m_j)
                          OffsetPoint(jointype);
                      solution.Add(currentPoly); 
                  }
                  else
                  {
                      m_k = 0;
                      for (m_j = 1; m_j < len - 1; ++m_j)
                          OffsetPoint(jointype);

                      IntPoint pt1;
                      if (endtype == EndType.etButt)
                      {
                          m_j = len - 1;
                          pt1 = new IntPoint((cInt)Round(pts[m_i][m_j].X + normals[m_j].X *
                            delta), (cInt)Round(pts[m_i][m_j].Y + normals[m_j].Y * delta));
                          AddPoint(pt1);
                          pt1 = new IntPoint((cInt)Round(pts[m_i][m_j].X - normals[m_j].X *
                            delta), (cInt)Round(pts[m_i][m_j].Y - normals[m_j].Y * delta));
                          AddPoint(pt1);
                      }
                      else
                      {
                          m_j = len - 1;
                          m_k = len - 2;
                          m_sinA = 0;
                          normals[m_j] = new DoublePoint(-normals[m_j].X, -normals[m_j].Y);
                          if (endtype == EndType.etSquare)
                            DoSquare();
                          else
                            DoRound();
                      }

                      //re-build Normals ...
                      for (int j = len - 1; j > 0; j--)
                        normals[j] = new DoublePoint(-normals[j - 1].X, -normals[j - 1].Y);
                      
                      normals[0] = new DoublePoint(-normals[1].X, -normals[1].Y);

                      m_k = len - 1;
                      for (m_j = m_k - 1; m_j > 0; --m_j)
                          OffsetPoint(jointype);

                      if (endtype == EndType.etButt)
                      {
                          pt1 = new IntPoint((cInt)Round(pts[m_i][0].X - normals[0].X * delta),
                            (cInt)Round(pts[m_i][0].Y - normals[0].Y * delta));
                          AddPoint(pt1);
                          pt1 = new IntPoint((cInt)Round(pts[m_i][0].X + normals[0].X * delta),
                            (cInt)Round(pts[m_i][0].Y + normals[0].Y * delta));
                          AddPoint(pt1);
                      }
                      else
                      {
                          m_k = 1;
                          m_sinA = 0;
                          if (endtype == EndType.etSquare) 
                            DoSquare();
                          else
                            DoRound();
                      }
                      solution.Add(currentPoly);
                  }
              }

              //finally, clean up untidy corners ...
              Clipper clpr = new Clipper();
              clpr.AddPaths(solution, PolyType.ptSubject, true);
              if (delta > 0)
              {
                  clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftPositive, PolyFillType.pftPositive);
              }
              else
              {
                  IntRect r = clpr.GetBounds();
                  Path outer = new Path(4);

                  outer.Add(new IntPoint(r.left - 10, r.bottom + 10));
                  outer.Add(new IntPoint(r.right + 10, r.bottom + 10));
                  outer.Add(new IntPoint(r.right + 10, r.top - 10));
                  outer.Add(new IntPoint(r.left - 10, r.top - 10));

                  clpr.AddPath(outer, PolyType.ptSubject, true);
                  clpr.ReverseSolution = true;
                  clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative);
                  if (solution.Count > 0) solution.RemoveAt(0);
              }
          }
Пример #27
0
        private static bool CalculatePortalViews(IPortal portal, IPortal portalEnter, IList<IPortal> portals, Matrix4 viewMatrix, Vector2 viewPos, Vector2 viewPosPrevious, PortalView portalView, Matrix4 portalMatrix, List<Func<bool>> actionList)
        {
            const float AREA_EPSILON = 0.0001f;
            Clipper c = new Clipper();
            //The clipper must be set to strictly simple. Otherwise polygons might have duplicate vertices which causes poly2tri to generate incorrect results.
            c.StrictlySimple = true;

            if (!_isPortalValid(portalEnter, portal, viewPos))
            {
                return false;
            }

            Vector2[] fov = Vector2Ext.Transform(Portal.GetFov(portal, viewPos, 500, 3), portalMatrix);
            if (MathExt.GetArea(fov) < AREA_EPSILON)
            {
                return false;
            }
            List<IntPoint> pathFov = ClipperConvert.ToIntPoint(fov);

            var viewNew = new List<List<IntPoint>>();

            c.AddPath(pathFov, PolyType.ptSubject, true);
            c.AddPaths(portalView.Paths, PolyType.ptClip, true);
            c.Execute(ClipType.ctIntersection, viewNew);
            c.Clear();

            if (viewNew.Count <= 0)
            {
                return false;
            }
            c.AddPaths(viewNew, PolyType.ptSubject, true);
            foreach (IPortal other in portals)
            {
                if (other == portal)
                {
                    continue;
                }
                if (!_isPortalValid(portalEnter, other, viewPos))
                {
                    continue;
                }
                //Skip this portal if it's inside the current portal's FOV.
                LineF portalLine = new LineF(Portal.GetWorldVerts(portal));
                LineF portalOtherLine = new LineF(Portal.GetWorldVerts(other));
                if (portalLine.IsInsideFOV(viewPos, portalOtherLine))
                {
                    continue;
                }
                Vector2[] otherFov = Vector2Ext.Transform(Portal.GetFov(other, viewPos, 500, 3), portalMatrix);
                if (MathExt.GetArea(otherFov) < AREA_EPSILON)
                {
                    continue;
                }
                otherFov = MathExt.SetWinding(otherFov, true);
                List<IntPoint> otherPathFov = ClipperConvert.ToIntPoint(otherFov);
                c.AddPath(otherPathFov, PolyType.ptClip, true);
            }
            var viewNewer = new List<List<IntPoint>>();
            c.Execute(ClipType.ctDifference, viewNewer, PolyFillType.pftNonZero, PolyFillType.pftNonZero);
            c.Clear();
            if (viewNewer.Count <= 0)
            {
                return false;
            }

            Vector2 viewPosNew = Vector2Ext.Transform(viewPos, Portal.GetLinkedMatrix(portal, portal.Linked));
            Vector2 viewPosPreviousNew = Vector2Ext.Transform(viewPosPrevious, Portal.GetLinkedMatrix(portal, portal.Linked));

            Matrix4 portalMatrixNew = Portal.GetLinkedMatrix(portal.Linked, portal) * portalMatrix;
            Matrix4 viewMatrixNew = portalMatrixNew * viewMatrix;

            LineF[] lines = Portal.GetFovLines(portal, viewPos, 500);
            lines[0] = lines[0].Transform(portalMatrix);
            lines[1] = lines[1].Transform(portalMatrix);
            LineF[] linesPrevious = Portal.GetFovLines(portal, viewPosPrevious, 500);
            linesPrevious[0] = linesPrevious[0].Transform(portalMatrix);
            linesPrevious[1] = linesPrevious[1].Transform(portalMatrix);

            LineF portalWorldLine = new LineF(Portal.GetWorldVerts(portal));
            portalWorldLine = portalWorldLine.Transform(portalMatrix);
            PortalView portalViewNew = new PortalView(portalView, viewMatrixNew, viewNewer, lines, linesPrevious, portalWorldLine);

            foreach (IPortal p in portals)
            {
                actionList.Add(() =>
                    CalculatePortalViews(p, portal, portals, viewMatrix, viewPosNew, viewPosPreviousNew, portalViewNew, portalMatrixNew, actionList)
                );
            }
            return true;
        }
Пример #28
0
        public static NFP simplifyFunction(NFP polygon, bool inside)
        {
            var tolerance = 4 * Config.curveTolerance;

            // give special treatment to line segments above this length (squared)
            var fixedTolerance = 40 * Config.curveTolerance * 40 * Config.curveTolerance;
            int i, j, k;


            if (Config.simplify)
            {
                /*
                 *              // use convex hull
                 *              var hull = new ConvexHullGrahamScan();
                 *              for(var i=0; i<polygon.length; i++){
                 *                      hull.addPoint(polygon[i].x, polygon[i].y);
                 *              }
                 *
                 *              return hull.getHull();*/
                var hull = Background.getHull(polygon);
                if (hull != null)
                {
                    return(hull);
                }
                else
                {
                    return(polygon);
                }
            }

            var cleaned = cleanPolygon2(polygon);

            if (cleaned != null && cleaned.length > 1)
            {
                polygon = cleaned;
            }
            else
            {
                return(polygon);
            }
            // polygon to polyline
            var copy = polygon.slice(0);

            copy.push(copy[0]);
            // mark all segments greater than ~0.25 in to be kept
            // the PD simplification algo doesn't care about the accuracy of long lines, only the absolute distance of each point
            // we care a great deal
            for (i = 0; i < copy.length - 1; i++)
            {
                var p1  = copy[i];
                var p2  = copy[i + 1];
                var sqd = (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y);
                if (sqd > fixedTolerance)
                {
                    p1.marked = true;
                    p2.marked = true;
                }
            }

            var simple = Simplify.simplify(copy, tolerance, true);

            // now a polygon again
            //simple.pop();
            simple.Points = simple.Points.Take(simple.Points.Count() - 1).ToArray();

            // could be dirty again (self intersections and/or coincident points)
            simple = cleanPolygon2(simple);

            // simplification process reduced poly to a line or point
            if (simple == null)
            {
                simple = polygon;
            }



            var offsets = polygonOffsetDeepNest(simple, inside ? -tolerance : tolerance);

            NFP        offset     = null;
            double     offsetArea = 0;
            List <NFP> holes      = new List <NFP>();

            for (i = 0; i < offsets.Length; i++)
            {
                var area = GeometryUtil.polygonArea(offsets[i]);
                if (offset == null || area < offsetArea)
                {
                    offset     = offsets[i];
                    offsetArea = area;
                }
                if (area > 0)
                {
                    holes.Add(offsets[i]);
                }
            }

            // mark any points that are exact
            for (i = 0; i < simple.length; i++)
            {
                var seg = new NFP();
                seg.AddPoint(simple[i]);
                seg.AddPoint(simple[i + 1 == simple.length ? 0 : i + 1]);

                var index1 = find(seg[0], polygon);
                var index2 = find(seg[1], polygon);

                if (index1 + 1 == index2 || index2 + 1 == index1 || (index1 == 0 && index2 == polygon.length - 1) || (index2 == 0 && index1 == polygon.length - 1))
                {
                    seg[0].exact = true;
                    seg[1].exact = true;
                }
            }
            var numshells = 4;

            NFP[] shells = new NFP[numshells];

            for (j = 1; j < numshells; j++)
            {
                var delta = j * (tolerance / numshells);
                delta = inside ? -delta : delta;
                var shell = polygonOffsetDeepNest(simple, delta);
                if (shell.Count() > 0)
                {
                    shells[j] = shell.First();
                }
                else
                {
                    //shells[j] = shell;
                }
            }

            if (offset == null)
            {
                return(polygon);
            }
            // selective reversal of offset
            for (i = 0; i < offset.length; i++)
            {
                var o      = offset[i];
                var target = getTarget(o, simple, 2 * tolerance);

                // reverse point offset and try to find exterior points
                var test = clone(offset);
                test.Points[i] = new SvgPoint(target.x, target.y);

                if (!exterior(test, polygon, inside))
                {
                    o.x = target.x;
                    o.y = target.y;
                }
                else
                {
                    // a shell is an intermediate offset between simple and offset
                    for (j = 1; j < numshells; j++)
                    {
                        if (shells[j] != null)
                        {
                            var shell = shells[j];
                            var delta = j * (tolerance / numshells);
                            target         = getTarget(o, shell, 2 * delta);
                            test           = clone(offset);
                            test.Points[i] = new SvgPoint(target.x, target.y);
                            if (!exterior(test, polygon, inside))
                            {
                                o.x = target.x;
                                o.y = target.y;
                                break;
                            }
                        }
                    }
                }
            }

            // straighten long lines
            // a rounded rectangle would still have issues at this point, as the long sides won't line up straight

            var straightened = false;

            for (i = 0; i < offset.length; i++)
            {
                var p1 = offset[i];
                var p2 = offset[i + 1 == offset.length ? 0 : i + 1];

                var sqd = (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y);

                if (sqd < fixedTolerance)
                {
                    continue;
                }
                for (j = 0; j < simple.length; j++)
                {
                    var s1 = simple[j];
                    var s2 = simple[j + 1 == simple.length ? 0 : j + 1];

                    var sqds = (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y);

                    if (sqds < fixedTolerance)
                    {
                        continue;
                    }

                    if ((GeometryUtil._almostEqual(s1.x, s2.x) || GeometryUtil._almostEqual(s1.y, s2.y)) && // we only really care about vertical and horizontal lines
                        GeometryUtil._withinDistance(p1, s1, 2 * tolerance) &&
                        GeometryUtil._withinDistance(p2, s2, 2 * tolerance) &&
                        (!GeometryUtil._withinDistance(p1, s1, Config.curveTolerance / 1000) ||
                         !GeometryUtil._withinDistance(p2, s2, Config.curveTolerance / 1000)))
                    {
                        p1.x         = s1.x;
                        p1.y         = s1.y;
                        p2.x         = s2.x;
                        p2.y         = s2.y;
                        straightened = true;
                    }
                }
            }

            //if(straightened){

            var Ac = _Clipper.ScaleUpPaths(offset, 10000000);
            var Bc = _Clipper.ScaleUpPaths(polygon, 10000000);

            var combined = new List <List <IntPoint> >();
            var clipper  = new ClipperLib.Clipper();

            clipper.AddPath(Ac.ToList(), ClipperLib.PolyType.ptSubject, true);
            clipper.AddPath(Bc.ToList(), ClipperLib.PolyType.ptSubject, true);

            // the line straightening may have made the offset smaller than the simplified
            if (clipper.Execute(ClipperLib.ClipType.ctUnion, combined, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero))
            {
                double?largestArea = null;
                for (i = 0; i < combined.Count; i++)
                {
                    var n     = Background.toNestCoordinates(combined[i].ToArray(), 10000000);
                    var sarea = -GeometryUtil.polygonArea(n);
                    if (largestArea == null || largestArea < sarea)
                    {
                        offset      = n;
                        largestArea = sarea;
                    }
                }
            }
            //}

            cleaned = cleanPolygon2(offset);
            if (cleaned != null && cleaned.length > 1)
            {
                offset = cleaned;
            }

            // mark any points that are exact (for line merge detection)
            for (i = 0; i < offset.length; i++)
            {
                var seg    = new SvgPoint[] { offset[i], offset[i + 1 == offset.length ? 0 : i + 1] };
                var index1 = find(seg[0], polygon);
                var index2 = find(seg[1], polygon);
                if (index1 == null)
                {
                    index1 = 0;
                }
                if (index2 == null)
                {
                    index2 = 0;
                }
                if (index1 + 1 == index2 || index2 + 1 == index1 ||
                    (index1 == 0 && index2 == polygon.length - 1) ||
                    (index2 == 0 && index1 == polygon.length - 1))
                {
                    seg[0].exact = true;
                    seg[1].exact = true;
                }
            }

            if (!inside && holes != null && holes.Count > 0)
            {
                offset.children = holes;
            }

            return(offset);
        }
Пример #29
0
        /// <summary>
        /// Updates the key definition to occupy a region of itself plus the specified other keys.
        /// </summary>
        /// <param name="keys">The keys to union with.</param>
        /// <returns>A new key definition with the updated region.</returns>
        private MouseScrollDefinition UnionWith(IList<MouseScrollDefinition> keys)
        {
            var newBoundaries = this.Boundaries.Select(b => new TPoint(b.X, b.Y)).ToList();

            if (keys.Any())
            {
                var cl = new Clipper();
                cl.AddPath(this.GetPath(), PolyType.ptSubject, true);
                cl.AddPaths(keys.Select(x => x.GetPath()).ToList(), PolyType.ptClip, true);
                var union = new List<List<IntPoint>>();
                cl.Execute(ClipType.ctUnion, union);

                if (union.Count > 1)
                    throw new ArgumentException("Cannot union two non-overlapping keys.");

                newBoundaries = union.Single().ConvertAll<TPoint>(x => x);
            }

            return new MouseScrollDefinition(this.Id, newBoundaries, this.KeyCodes.Single(), this.Text);
        }
Пример #30
0
        //------------------------------------------------------------------------------
        public void Execute(ref List<List<IntPoint>> solution, double delta)
        {
            solution.Clear();
            FixOrientations();
            DoOffset(delta);
            //now clean up 'corners' ...
            Clipper clpr = new Clipper();
            clpr.AddPaths(m_destPolys, PolyType.ptSubject, true);
            if (delta > 0)
            {
                clpr.Execute(ClipType.ctUnion, solution,
                  PolyFillType.pftPositive, PolyFillType.pftPositive);
            }
            else
            {
                IntRect r = Clipper.GetBounds(m_destPolys);
                List<IntPoint> outer = new List<IntPoint>(4);

                outer.Add(new IntPoint(r.left - 10, r.bottom + 10));
                outer.Add(new IntPoint(r.right + 10, r.bottom + 10));
                outer.Add(new IntPoint(r.right + 10, r.top - 10));
                outer.Add(new IntPoint(r.left - 10, r.top - 10));

                clpr.AddPath(outer, PolyType.ptSubject, true);
                clpr.ReverseSolution = true;
                clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative);
                if (solution.Count > 0) solution.RemoveAt(0);
            }
        }
Пример #31
0
        //------------------------------------------------------------------------------
        public void Execute(ref PolyTree solution, double delta)
        {
            solution.Clear();
            FixOrientations();
            DoOffset(delta);

            //now clean up 'corners' ...
            Clipper clpr = new Clipper();
            clpr.AddPaths(m_destPolys, PolyType.ptSubject, true);
            if (delta > 0)
            {
                clpr.Execute(ClipType.ctUnion, solution,
                  PolyFillType.pftPositive, PolyFillType.pftPositive);
            }
            else
            {
                IntRect r = Clipper.GetBounds(m_destPolys);
                List<IntPoint> outer = new List<IntPoint>(4);

                outer.Add(new IntPoint(r.left - 10, r.bottom + 10));
                outer.Add(new IntPoint(r.right + 10, r.bottom + 10));
                outer.Add(new IntPoint(r.right + 10, r.top - 10));
                outer.Add(new IntPoint(r.left - 10, r.top - 10));

                clpr.AddPath(outer, PolyType.ptSubject, true);
                clpr.ReverseSolution = true;
                clpr.Execute(ClipType.ctUnion, solution, PolyFillType.pftNegative, PolyFillType.pftNegative);
                //remove the outer PolyNode rectangle ...
                if (solution.ChildCount == 1 && solution.Childs[0].ChildCount > 0)
                {
                    PolyNode outerNode = solution.Childs[0];
                    solution.Childs.Capacity = outerNode.ChildCount;
                    solution.Childs[0] = outerNode.Childs[0];
                    solution.Childs[0].m_Parent = solution;
                    for (int i = 1; i < outerNode.ChildCount; i++)
                        solution.AddChild(outerNode.Childs[i]);
                }
                else
                    solution.Clear();
            }
        }
Пример #32
0
		public static Polygons GetCorrectedWinding(this Polygons polygonsToFix)
		{
			polygonsToFix = Clipper.CleanPolygons(polygonsToFix);
			Polygon boundsPolygon = new Polygon();
			IntRect bounds = Clipper.GetBounds(polygonsToFix);
			bounds.left -= 10;
			bounds.bottom += 10;
			bounds.right += 10;
			bounds.top -= 10;

			boundsPolygon.Add(new IntPoint(bounds.left, bounds.top));
			boundsPolygon.Add(new IntPoint(bounds.right, bounds.top));
			boundsPolygon.Add(new IntPoint(bounds.right, bounds.bottom));
			boundsPolygon.Add(new IntPoint(bounds.left, bounds.bottom));

			Clipper clipper = new Clipper();

			clipper.AddPaths(polygonsToFix, PolyType.ptSubject, true);
			clipper.AddPath(boundsPolygon, PolyType.ptClip, true);

			PolyTree intersectionResult = new PolyTree();
			clipper.Execute(ClipType.ctIntersection, intersectionResult);

			Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult);

			return outputPolygons;
		}
        // Only works if the points are in the XY plane.
        // Link to their Documentation: http://www.angusj.com/delphi/clipper/documentation/Docs/_Body.htm
        private static List<Point> Overlap_In_XY_Plane(List<Point> points1, List<Point> points2)
        {
            var clipper = new Clipper();
            clipper.AddPath(ToClipperPath(points1), PolyType.ptClip, true);
            clipper.AddPath(ToClipperPath(points2), PolyType.ptSubject, true);

            var soln = new Paths();
            // clipper offers 4 operations: http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/ClipType.htm
            var success = clipper.Execute(ClipType.ctIntersection, soln);

            if (success.Not())
            {
                return null;
            }
            
            switch (soln.Count)
            {
                case 0:
                    return null;
                case 1:
                    return ToPoints(soln[0]);
                default:
                    throw new ArgumentException("The passed polygons had multiple regions of overlap.");
            }
           
        }
Пример #34
0
		static public PolyTree FindDistictObjectBounds(ImageBuffer image)
		{
			MarchingSquaresByte marchingSquaresData = new MarchingSquaresByte(image, 5, 0);
			marchingSquaresData.CreateLineSegments();
			Polygons lineLoops = marchingSquaresData.CreateLineLoops(1);

			if (lineLoops.Count == 1)
			{
				return null;
			}

			// create a bounding polygon to clip against
			IntPoint min = new IntPoint(long.MaxValue, long.MaxValue);
			IntPoint max = new IntPoint(long.MinValue, long.MinValue);
			foreach (Polygon polygon in lineLoops)
			{
				foreach (IntPoint point in polygon)
				{
					min.X = Math.Min(point.X - 10, min.X);
					min.Y = Math.Min(point.Y - 10, min.Y);
					max.X = Math.Max(point.X + 10, max.X);
					max.Y = Math.Max(point.Y + 10, max.Y);
				}
			}

			Polygon boundingPoly = new Polygon();
			boundingPoly.Add(min);
			boundingPoly.Add(new IntPoint(min.X, max.Y));
			boundingPoly.Add(max);
			boundingPoly.Add(new IntPoint(max.X, min.Y));

			// now clip the polygons to get the inside and outside polys
			Clipper clipper = new Clipper();
			clipper.AddPaths(lineLoops, PolyType.ptSubject, true);
			clipper.AddPath(boundingPoly, PolyType.ptClip, true);

			PolyTree polyTreeForPlate = new PolyTree();
			clipper.Execute(ClipType.ctIntersection, polyTreeForPlate);

			return polyTreeForPlate;
		}
Пример #35
0
        private Polygons FixWinding(Polygons polygonsToPathAround)
        {
            polygonsToPathAround = Clipper.CleanPolygons(polygonsToPathAround);
            Polygon boundsPolygon = new Polygon();
            IntRect bounds = Clipper.GetBounds(polygonsToPathAround);
            bounds.left -= 10;
            bounds.bottom += 10;
            bounds.right += 10;
            bounds.top -= 10;

            boundsPolygon.Add(new IntPoint(bounds.left, bounds.top));
            boundsPolygon.Add(new IntPoint(bounds.right, bounds.top));
            boundsPolygon.Add(new IntPoint(bounds.right, bounds.bottom));
            boundsPolygon.Add(new IntPoint(bounds.left, bounds.bottom));

            Clipper clipper = new Clipper();

            clipper.AddPaths(polygonsToPathAround, PolyType.ptSubject, true);
            clipper.AddPath(boundsPolygon, PolyType.ptClip, true);

            PolyTree intersectionResult = new PolyTree();
            clipper.Execute(ClipType.ctIntersection, intersectionResult);

            Polygons outputPolygons = Clipper.ClosedPathsFromPolyTree(intersectionResult);
            Clipper.ReversePaths(outputPolygons);

            return outputPolygons;
        }