Example #1
0
        /// <summary>
        ///  Conduct a clip operation on this profile.
        /// </summary>
        internal void Clip(IEnumerable <Profile> additionalHoles = null)
        {
            var clipper = new ClipperLib.Clipper();

            clipper.AddPath(this.Perimeter.ToClipperPath(), ClipperLib.PolyType.ptSubject, true);
            if (this.Voids != null)
            {
                clipper.AddPaths(this.Voids.Select(p => p.ToClipperPath()).ToList(), ClipperLib.PolyType.ptClip, true);
            }
            if (additionalHoles != null)
            {
                clipper.AddPaths(additionalHoles.Select(h => h.Perimeter.ToClipperPath()).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()).ToArray();
                this.Perimeter = polys[0];
                this.Voids     = polys.Skip(1).ToArray();
            }
        }
Example #2
0
 private void AddPoints(ClipperLib.Clipper clipper, IShape[] shapes, bool[] shouldInclude, ClipperLib.PolyType polyType)
 {
     for (var i = 0; i < shapes.Length; i++)
     {
         if (shouldInclude[i])
         {
             this.AddPoints(clipper, shapes[i], polyType);
         }
     }
 }
Example #3
0
    public void ExecuteClip(IClip clip)
    {
        BlockSimplification.epsilon = (int64)(simplifyEpsilonPercent / 100f * blockSize * VectorEx.float2int64);

        List <Vector2i> clipVertices = clip.GetVertices();

        ClipBounds bounds = clip.GetBounds();
        int        x1     = Mathf.Max(0, (int)(bounds.lowerPoint.x / blockSize));

        if (x1 > resolutionX - 1)
        {
            return;
        }
        int y1 = Mathf.Max(0, (int)(bounds.lowerPoint.y / blockSize));

        if (y1 > resolutionY - 1)
        {
            return;
        }
        int x2 = Mathf.Min(resolutionX - 1, (int)(bounds.upperPoint.x / blockSize));

        if (x2 < 0)
        {
            return;
        }
        int y2 = Mathf.Min(resolutionY - 1, (int)(bounds.upperPoint.y / blockSize));

        if (y2 < 0)
        {
            return;
        }

        for (int x = x1; x <= x2; x++)
        {
            for (int y = y1; y <= y2; y++)
            {
                if (clip.CheckBlockOverlapping(new Vector2f((x + 0.5f) * blockSize, (y + 0.5f) * blockSize), blockSize))
                {
                    DestructibleBlock block = blocks[x + resolutionX * y];

                    List <List <Vector2i> > solutions = new List <List <Vector2i> >();

                    ClipperLib.Clipper clipper = new ClipperLib.Clipper();
                    clipper.AddPolygons(block.Polygons, ClipperLib.PolyType.ptSubject);
                    clipper.AddPolygon(clipVertices, ClipperLib.PolyType.ptClip);
                    clipper.Execute(ClipperLib.ClipType.ctDifference, solutions,
                                    ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero);

                    UpdateBlockBounds(x, y);

                    block.UpdateGeometryWithMoreVertices(solutions, width, height, depth);
                }
            }
        }
    }
Example #4
0
        private RawCharacterOutline InternalGetCharacterOutlineForCaching(char textChar, FontX font)
        {
            var glyphTypeface = font.InvariantDescriptionStringWithoutSizeInformation;

            var rawOutline = GetRawCharacterOutline(textChar, font, FontSizeForCaching);

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

            var sharpPoints = new HashSet <ClipperLib.IntPoint>();
            var allPoints   = new HashSet <ClipperLib.IntPoint>(); // allPoints to determine whether after the simplification new points were added

            foreach (var polygon in rawOutline.Outline)
            {
                foreach (var p in polygon.SharpPoints)
                {
                    sharpPoints.Add(new ClipperLib.IntPoint(p.X * 65536, p.Y * 65536));
                }

                var clipperPolygon = new List <ClipperLib.IntPoint>(polygon.Points.Select((x) => new ClipperLib.IntPoint(x.X * 65536, x.Y * 65536)));
                clipperPolygonsInput.Add(clipperPolygon);

                foreach (var clipperPoint in clipperPolygon)
                {
                    allPoints.Add(clipperPoint);
                }
            }

            //clipperPolygons = ClipperLib.Clipper.SimplifyPolygons(clipperPolygons, ClipperLib.PolyFillType.pftEvenOdd);

            var clipperPolygons = new ClipperLib.PolyTree();
            var clipper         = new ClipperLib.Clipper
            {
                StrictlySimple = true
            };

            clipper.AddPaths(clipperPolygonsInput, ClipperLib.PolyType.ptSubject, true);
            clipper.Execute(ClipperLib.ClipType.ctUnion, clipperPolygons, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNegative);

            var polygons = new List <PolygonClosedD2D>();
            var dictClipperNodeToNode = new Dictionary <ClipperLib.PolyNode, PolygonClosedD2D>(); // helper dictionary

            ClipperPolyTreeToPolygonListRecursively(clipperPolygons, sharpPoints, allPoints, polygons, dictClipperNodeToNode);

            var result = rawOutline;

            result.Outline = polygons;

            return(result);
        }
    public void Clip(TurningChisel chisel)
    {
        if (polygon == null)
        {
            return;
        }

        List <Polygon> solution = new List <Polygon>();

        ClipperLib.Clipper clipper = new ClipperLib.Clipper();
        clipper.AddPolygon(polygon, ClipperLib.PolyType.ptSubject);
        clipper.AddPolygon(chisel.Polygon, ClipperLib.PolyType.ptClip);
        clipper.Execute(ClipperLib.ClipType.ctDifference, solution, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero);

        polygon = null;
        if (solution.Count > 0)
        {
            Vector2i basePosition = transform.localPosition.ToVector2i();

            polygon = null;
            for (int i = 0; i < solution.Count; i++)
            {
                var   poly = solution[i];
                float xA   = (float)(poly[1].X - basePosition.X);
                float xB   = (float)(poly[poly.Count - 2].X - basePosition.Y);

                if (xA * xB < 0f)
                {
                    polygon = poly;
                }
                else
                {
                    StartCoroutine(CreateDetachedObject(poly));
                }
            }
        }

        if (polygon != null)
        {
            ExtractEdge();
            PostShapeChange();
        }
        else
        {
            polygon = null;
            ExtractEdge();
            PostShapeChange();
        }
    }
Example #6
0
        private Zones.TPolygon[] CalcOutOfBoundsPoly(Zones.TPolygon Tile, Zones.TPolygon BoxRect, ClipperLib.ClipType clipType)
        {
            List <List <ClipperLib.IntPoint> > subj = new List <List <ClipperLib.IntPoint> >();

            subj.Add(new List <ClipperLib.IntPoint>());
            for (int i = 0; i < Tile.Dots.Length; i++)
            {
                subj[0].Add(new ClipperLib.IntPoint((long)Tile[i].X, (long)Tile[i].Y));
            }

            List <List <ClipperLib.IntPoint> > clip = new List <List <ClipperLib.IntPoint> >();

            clip.Add(new List <ClipperLib.IntPoint>(4));
            for (int i = 0; i < BoxRect.Dots.Length; i++)
            {
                clip[0].Add(new ClipperLib.IntPoint((long)BoxRect[i].X, (long)BoxRect[i].Y));
            }

            List <ClipperLib.ExPolygon> solution = new List <ClipperLib.ExPolygon>();

            ClipperLib.Clipper c = new ClipperLib.Clipper();
            c.AddPolygons(clip, ClipperLib.PolyType.ptSubject);
            c.AddPolygons(subj, ClipperLib.PolyType.ptClip);

            bool res = (c.Execute(clipType, solution)); // , ClipperLib.PolyFillType.pftEvenOdd, ClipperLib.PolyFillType.pftEvenOdd

            if (res)
            {
                if (solution.Count > 0)
                {
                    List <Zones.TPolygon> pols = new List <Zones.TPolygon>();
                    for (int s = 0; s < solution.Count; s++)
                    {
                        Zones.TPolygon poly = new Zones.TPolygon((ushort)solution[s].outer.Count);
                        for (int i = 0; i < poly.Dots.Length; i++)
                        {
                            poly[i] = new Zones.TPoint((double)solution[s].outer[i].X, (double)solution[s].outer[i].Y);
                        }
                        pols.Add(poly);
                    }
                    ;
                    return(pols.ToArray());
                }
            }
            ;

            return(null);
        }
Example #7
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(1024.0, 2));
        }
Example #8
0
        private void AddPoints(ClipperLib.Clipper clipper, IShape shape, ClipperLib.PolyType polyType)
        {
            foreach (var path in shape)
            {
                var points        = path.AsSimpleLinearPath();
                var clipperPoints = new List <ClipperLib.IntPoint>();
                foreach (var point in points)
                {
                    var p = point * ClipperScaleFactor;

                    clipperPoints.Add(new ClipperLib.IntPoint((long)p.X, (long)p.Y));
                }

                clipper.AddPath(
                    clipperPoints,
                    polyType,
                    path.IsClosed);
            }
        }
        public static long ExecuteOriginalClipper(int testIterationCount, List <ClipExecutionData> executionData)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            for (var i = 0; i < testIterationCount; i++)
            {
                foreach (var clipPath in executionData)
                {
                    var subject = new List <List <ClipperLib.IntPoint> >(
                        clipPath
                        .Subject
                        .Select(poly => new List <ClipperLib.IntPoint>(poly.Select(pt =>
                                                                                   new ClipperLib.IntPoint(
                                                                                       pt.X * Scale,
                                                                                       pt.Y * Scale)))));

                    var clip = new List <List <ClipperLib.IntPoint> >(
                        clipPath
                        .Clip
                        .Select(poly => new List <ClipperLib.IntPoint>(poly.Select(pt =>
                                                                                   new ClipperLib.IntPoint(
                                                                                       pt.X * Scale,
                                                                                       pt.Y * Scale)))));

                    var solution = new ClipperLib.PolyTree();
                    var clipper  = new ClipperLib.Clipper();

                    clipper.AddPaths(subject, ClipperLib.PolyType.ptSubject, true);
                    clipper.AddPaths(clip, ClipperLib.PolyType.ptClip, true);

                    // Convert performance test library operation enum to ClipperLib operation enum.
                    var operation = (ClipperLib.ClipType)Enum.Parse(typeof(ClipperLib.ClipType), $"ct{clipPath.Operation}", true);
                    Assert.IsTrue(clipper.Execute(operation, solution));
                }
            }

            stopwatch.Stop();

            return(stopwatch.Elapsed.Ticks);
        }
Example #10
0
        /// <summary>
        /// Tessellate the Floor.
        /// </summary>
        public Mesh Mesh()
        {
            var clipper = new ClipperLib.Clipper();

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

            if (polys.Count > 1)
            {
                return(Hypar.Geometry.Mesh.Extrude(polys.First(), this.ElementType.Thickness, polys.Skip(1).ToList(), true));
            }
            else
            {
                return(Hypar.Geometry.Mesh.Extrude(polys.First(), this.ElementType.Thickness, null, true));
            }
        }
Example #11
0
        /// <summary>
        /// Generate Colliders based on Tile Collisions
        /// </summary>
        /// <param name="isTrigger">True for Trigger Collider, false otherwise</param>
        /// <param name="zDepth">Z Depth of the collider.</param>
        /// <param name="colliderWidth">Width of the collider, in Units</param>
        /// <param name="used2DColider">True to generate a 2D collider, false to generate a 3D collider.</param>
        /// <param name="innerCollision">If true, calculate normals facing the anchor of the collider (inside collisions), else, outside collisions.</param>
        /// <returns>A GameObject containing all generated colliders</returns>
        public GameObject GenerateTileCollisions(bool used2DColider = true, bool isTrigger = false, float zDepth = 0, float colliderWidth = 1, bool innerCollision = false)
        {
            GameObject tileColisions = new GameObject("Tile Collisions");
            tileColisions.transform.parent = MapObject.transform;
            tileColisions.transform.localPosition = Vector3.zero;

            ClipperLib.Clipper clipper = new ClipperLib.Clipper();
            List<List<ClipperLib.IntPoint>> pathsList = new List<List<ClipperLib.IntPoint>>();
            List<List<ClipperLib.IntPoint>> solution = new List<List<ClipperLib.IntPoint>>();
            // Iterate over each Tile Layer, grab all TileObjects inside this layer and use their Paths with ClipperLib to generate one polygon collider
            foreach (var layer in Layers)
            {
                if (layer is TileLayer)
                {
                    clipper.Clear();
                    solution.Clear();
                    pathsList.Clear();
                    TileLayer tileLayer = layer as TileLayer;
                    for (int x = 0; x < tileLayer.Tiles.Width; x++)
                    {
                        for (int y = 0; y < tileLayer.Tiles.Height; y++)
                        {
                            Tile t = tileLayer.Tiles[x, y];
                            if (t == null || t.TileSet == null || t.TileSet.TilesObjects == null)
                                continue;
                            if (t.TileSet.TilesObjects.ContainsKey(t.OriginalID))
                            {
                                List<TileObject> tileObjs = t.TileSet.TilesObjects[t.OriginalID];
                                foreach (var tileObj in tileObjs)
                                {
                                    pathsList.Add(tileObj.GetPath(x, y, t.SpriteEffects, _tileObjectEllipsePrecision));
                                }
                            }
                        }
                    }
                    // Add the paths to be merged to ClipperLib
                    clipper.AddPaths(pathsList, ClipperLib.PolyType.ptSubject, true);
                    // Merge it!
                    //clipper.PreserveCollinear = false;
                    //clipper.ReverseSolution = true;
                    clipper.StrictlySimple = _simpleTileObjectCalculation;
                    if (!clipper.Execute(ClipperLib.ClipType.ctUnion, solution))
                        continue;
                    clipper.Execute(ClipperLib.ClipType.ctUnion, solution);
                    // Now solution should contain all vertices of the collision object, but they are still multiplied by TileObject.ClipperScale!

                    #region Implementation of increase and decrease offset polygon.
                    if(_simpleTileObjectCalculation == false) {
                        // Link of the example of ClipperLib:
                        // http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/_Body.htm

                        ClipperLib.ClipperOffset co = new ClipperLib.ClipperOffset(_clipperMiterLimit,_clipperArcTolerance);
                        foreach(List<ClipperLib.IntPoint> item in solution) {
                            co.AddPath(item, _clipperJoinType,_clipperEndType);
                        }
                        solution.Clear();
                        co.Execute(ref solution, _clipperDeltaOffset*TileObject.ClipperScale);
                    }
                    #endregion

                    // Generate this path's collision
                    GameObject newCollider = new GameObject("Tile Collisions " + layer.Name);
                    newCollider.transform.parent = tileColisions.transform;
                    newCollider.transform.localPosition = new Vector3(0, 0, zDepth);

                    // Finally, generate the edge collider
                    int counter = 0;

                    for (int i = 0; i < solution.Count; i++)
                    {
                        if (solution[i].Count < 1)
                            continue;

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

                        for (int j = 0; j < solution[i].Count; j++)
                        {
                            points.Add(
                                new Vector2(
                                    solution[i][j].X / (float)TileObject.ClipperScale,
                                    solution[i][j].Y / (float)TileObject.ClipperScale
                                )
                            );
                        }

                        if (used2DColider)
                            Generate2DTileCollision(tileLayer, counter, newCollider.transform, points, isTrigger, zDepth);
                        else
                            Generate3DTileCollision(tileLayer, counter, newCollider.transform, points, isTrigger, zDepth, colliderWidth, innerCollision);

                        counter++;
                    }

                    newCollider.isStatic = true;
                }
            }

            return tileColisions;
        }
Example #12
0
		private RawCharacterOutline InternalGetCharacterOutlineForCaching(char textChar, FontX font)
		{
			var glyphTypeface = font.InvariantDescriptionStringWithoutSizeInformation;

			var rawOutline = GetRawCharacterOutline(textChar, font, FontSizeForCaching);

			List<List<ClipperLib.IntPoint>> clipperPolygonsInput = new List<List<ClipperLib.IntPoint>>();

			var sharpPoints = new HashSet<ClipperLib.IntPoint>();
			var allPoints = new HashSet<ClipperLib.IntPoint>(); // allPoints to determine whether after the simplification new points were added

			foreach (var polygon in rawOutline.Outline)
			{
				foreach (var p in polygon.SharpPoints)
				{
					sharpPoints.Add(new ClipperLib.IntPoint(p.X * 65536, p.Y * 65536));
				}

				var clipperPolygon = new List<ClipperLib.IntPoint>(polygon.Points.Select((x) => new ClipperLib.IntPoint(x.X * 65536, x.Y * 65536)));
				clipperPolygonsInput.Add(clipperPolygon);

				foreach (var clipperPoint in clipperPolygon)
					allPoints.Add(clipperPoint);
			}

			//clipperPolygons = ClipperLib.Clipper.SimplifyPolygons(clipperPolygons, ClipperLib.PolyFillType.pftEvenOdd);

			var clipperPolygons = new ClipperLib.PolyTree();
			ClipperLib.Clipper clipper = new ClipperLib.Clipper();
			clipper.StrictlySimple = true;
			clipper.AddPaths(clipperPolygonsInput, ClipperLib.PolyType.ptSubject, true);
			clipper.Execute(ClipperLib.ClipType.ctUnion, clipperPolygons, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNegative);

			var polygons = new List<PolygonClosedD2D>();
			var dictClipperNodeToNode = new Dictionary<ClipperLib.PolyNode, PolygonClosedD2D>(); // helper dictionary
			ClipperPolyTreeToPolygonListRecursively(clipperPolygons, sharpPoints, allPoints, polygons, dictClipperNodeToNode);

			var result = rawOutline;
			result.Outline = polygons;

			return result;
		}
Example #13
0
        public static ClipperLib.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.Name, (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 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"
                    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(ClipperLib.Clipper.ClosedPathsFromPolyTree(solution), ClipperLib.PolyType.ptSubject, true);
                fullClipper.AddPaths(ClipperLib.Clipper.OpenPathsFromPolyTree(solution), ClipperLib.PolyType.ptSubject, false);
            }
            progFunc(String.Format("Clipping '{0}' polygons: 100%", tmxLayer.Name));

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

            return(fullSolution);
        }
        public static List<List<Vector2>> GenerateClipperPathPoints(TileLayer tileLayer,
			bool simpleTileObjectCalculation = true,
			double clipperArcTolerance = 0.25, double clipperMiterLimit = 2.0,
			ClipperLib.JoinType clipperJoinType = ClipperLib.JoinType.jtRound,
			ClipperLib.EndType clipperEndType = ClipperLib.EndType.etClosedPolygon,
			float clipperDeltaOffset = 0)
        {
            ClipperLib.Clipper clipper = new ClipperLib.Clipper();
            List<List<ClipperLib.IntPoint>> pathsList = new List<List<ClipperLib.IntPoint>>();
            List<List<ClipperLib.IntPoint>> solution = new List<List<ClipperLib.IntPoint>>();
            List<List<Vector2>> points = new List<List<Vector2>>();

            for (int x = 0; x < tileLayer.Tiles.Width; x++)
            {
                for (int y = 0; y < tileLayer.Tiles.Height; y++)
                {
                    Tile t = tileLayer.Tiles[x, y];
                    if (t == null || t.TileSet == null || t.TileSet.TilesObjects == null)
                        continue;
                    if (t.TileSet.TilesObjects.ContainsKey(t.OriginalID))
                    {
                        List<TileObject> tileObjs = t.TileSet.TilesObjects[t.OriginalID];
                        foreach (var tileObj in tileObjs)
                        {
                            pathsList.Add(tileObj.GetPath(x, y, t.SpriteEffects, tileLayer.BaseMap.MapRenderParameter.TileWidth, tileLayer.BaseMap.MapRenderParameter.TileHeight));
                        }
                    }
                }
            }
            // Add the paths to be merged to ClipperLib
            clipper.AddPaths(pathsList, ClipperLib.PolyType.ptSubject, true);
            // Merge it!
            //clipper.PreserveCollinear = false;
            //clipper.ReverseSolution = true;
            clipper.StrictlySimple = simpleTileObjectCalculation;
            if (!clipper.Execute(ClipperLib.ClipType.ctUnion, solution))
                return points;
            clipper.Execute(ClipperLib.ClipType.ctUnion, solution);
            // Now solution should contain all vertices of the collision object, but they are still multiplied by TileObject.ClipperScale!

            #region Implementation of increase and decrease offset polygon.
            if (simpleTileObjectCalculation == false)
            {
                // Link of the example of ClipperLib:
                // http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/_Body.htm

                ClipperLib.ClipperOffset co = new ClipperLib.ClipperOffset(clipperMiterLimit, clipperArcTolerance);
                foreach (List<ClipperLib.IntPoint> item in solution)
                {
                    co.AddPath(item, clipperJoinType, clipperEndType);
                }
                solution.Clear();
                co.Execute(ref solution, clipperDeltaOffset * TileObject.ClipperScale);
            }
            #endregion

            for (int i = 0; i < solution.Count; i++)
            {
                if (solution[i].Count < 1)
                    continue;
                points.Add(new List<Vector2>());
                for (int j = 0; j < solution[i].Count; j++)
                {
                    points[i].Add(
                        new Vector2(
                            solution[i][j].X / (float)TileObject.ClipperScale,
                            solution[i][j].Y / (float)TileObject.ClipperScale
                        )
                    );
                }
            }

            return points;
        }
Example #15
0
		public void CalculatePolygons(
			double? overrideRelativeStructureWidth,
			out List<List<ClipperLib.IntPoint>> framePolygon,
			out List<List<ClipperLib.IntPoint>> insetPolygon,
			out List<List<ClipperLib.IntPoint>> fillPolygon)

		{
			insetPolygon = null;
			framePolygon = null;
			fillPolygon = null;

			// get outer polygon
			var outerPolygon = GetCopyOfOuterPolygon();

			List<List<ClipperLib.IntPoint>> innerFramePolygon = null;
			double relativeStructureWidth = overrideRelativeStructureWidth ?? _relativeStructureWidth;
			if (null != _frame && relativeStructureWidth > 0)
			{
				// get frame polygon
				innerFramePolygon = _frame.GetCopyOfClipperPolygon(relativeStructureWidth, outerPolygon);
			}

			if (null != _inset)
			{
				// get inset polygon
				insetPolygon = _inset.GetCopyOfClipperPolygon(relativeStructureWidth);
			}

			// if null != insetPolygon
			// clip with innerPolygon ?? outerPolygon;
			// store clipped inset polygon / draw it with inset color
			if (null != insetPolygon)
			{
				var clipper = new ClipperLib.Clipper();
				var solution = new List<List<ClipperLib.IntPoint>>();
				clipper.AddPaths(insetPolygon, ClipperLib.PolyType.ptSubject, true);
				clipper.AddPaths(innerFramePolygon ?? outerPolygon, ClipperLib.PolyType.ptClip, true);
				clipper.Execute(ClipperLib.ClipType.ctIntersection, solution);
				insetPolygon = solution;
			}

			// if null != framePolygon
			// clip with outer polygon ????
			// draw combined path of outer polygon and frame polygon as a hole with frame color
			if (null != innerFramePolygon)
			{
				var clipper = new ClipperLib.Clipper();
				clipper.AddPaths(outerPolygon, ClipperLib.PolyType.ptSubject, true);
				clipper.AddPaths(innerFramePolygon, ClipperLib.PolyType.ptClip, true);
				framePolygon = new List<List<ClipperLib.IntPoint>>();
				clipper.Execute(ClipperLib.ClipType.ctDifference, framePolygon);
			}

			// calculate
			// if null != insetPolygon
			//	(framePolygon ?? outerPolygon ) - insetPolygon
			// or else use (framePolygon ?? outerPolygon ) directly
			// draw result with fillColor

			if (null != insetPolygon)
			{
				var clipper = new ClipperLib.Clipper();
				clipper.AddPaths(innerFramePolygon ?? outerPolygon, ClipperLib.PolyType.ptSubject, true);
				clipper.AddPaths(insetPolygon, ClipperLib.PolyType.ptClip, true);
				fillPolygon = new List<List<ClipperLib.IntPoint>>();
				clipper.Execute(ClipperLib.ClipType.ctDifference, fillPolygon);
			}
			else
			{
				fillPolygon = innerFramePolygon ?? outerPolygon;
			}
		}
Example #16
0
        public void CalculatePolygons(
            double?overrideRelativeStructureWidth,
            out List <List <ClipperLib.IntPoint> > framePolygon,
            out List <List <ClipperLib.IntPoint> > insetPolygon,
            out List <List <ClipperLib.IntPoint> > fillPolygon)

        {
            insetPolygon = null;
            framePolygon = null;
            fillPolygon  = null;

            // get outer polygon
            var outerPolygon = GetCopyOfOuterPolygon();

            List <List <ClipperLib.IntPoint> > innerFramePolygon = null;
            double relativeStructureWidth = overrideRelativeStructureWidth ?? _relativeStructureWidth;

            if (null != _frame && relativeStructureWidth > 0)
            {
                // get frame polygon
                innerFramePolygon = _frame.GetCopyOfClipperPolygon(relativeStructureWidth, outerPolygon);
            }

            if (null != _inset)
            {
                // get inset polygon
                insetPolygon = _inset.GetCopyOfClipperPolygon(relativeStructureWidth);
            }

            // if null != insetPolygon
            // clip with innerPolygon ?? outerPolygon;
            // store clipped inset polygon / draw it with inset color
            if (null != insetPolygon)
            {
                var clipper  = new ClipperLib.Clipper();
                var solution = new List <List <ClipperLib.IntPoint> >();
                clipper.AddPaths(insetPolygon, ClipperLib.PolyType.ptSubject, true);
                clipper.AddPaths(innerFramePolygon ?? outerPolygon, ClipperLib.PolyType.ptClip, true);
                clipper.Execute(ClipperLib.ClipType.ctIntersection, solution);
                insetPolygon = solution;
            }

            // if null != framePolygon
            // clip with outer polygon ????
            // draw combined path of outer polygon and frame polygon as a hole with frame color
            if (null != innerFramePolygon)
            {
                var clipper = new ClipperLib.Clipper();
                clipper.AddPaths(outerPolygon, ClipperLib.PolyType.ptSubject, true);
                clipper.AddPaths(innerFramePolygon, ClipperLib.PolyType.ptClip, true);
                framePolygon = new List <List <ClipperLib.IntPoint> >();
                clipper.Execute(ClipperLib.ClipType.ctDifference, framePolygon);
            }

            // calculate
            // if null != insetPolygon
            //	(framePolygon ?? outerPolygon ) - insetPolygon
            // or else use (framePolygon ?? outerPolygon ) directly
            // draw result with fillColor

            if (null != insetPolygon)
            {
                var clipper = new ClipperLib.Clipper();
                clipper.AddPaths(innerFramePolygon ?? outerPolygon, ClipperLib.PolyType.ptSubject, true);
                clipper.AddPaths(insetPolygon, ClipperLib.PolyType.ptClip, true);
                fillPolygon = new List <List <ClipperLib.IntPoint> >();
                clipper.Execute(ClipperLib.ClipType.ctDifference, fillPolygon);
            }
            else
            {
                fillPolygon = innerFramePolygon ?? outerPolygon;
            }
        }
Example #17
0
        public static Mesh P2TTriangulate(TTFTextOutline outline, Mesh outMesh)
        {
            float Z = outline.Min.z;     // Assume all vertices have the same Z coord

            List <List <ClipperLib.IntPoint> > ipolygones = new List <List <ClipperLib.IntPoint> >();

            foreach (TTFTextOutline.Boundary lv in outline.boundaries)
            {
                if (Intersection.isSimple(lv))
                {
                    ipolygones.Add(Vec2LIP(lv));
                }
                else
                {
                    //Debug.LogWarning("Complex Contour");

                    try {
                        foreach (List <Vector3> p in Intersection.Decompose(lv))                  // decompose outlines

                        {
                            ipolygones.Add(Vec2LIP(p));
                        }
                    } catch (System.Exception) {             // parallel segments
                        //Debug.LogWarning("Bad contour:" + ex.ToString());
                    }
                }
            }


            ClipperLib.Clipper          c   = new ClipperLib.Clipper();
            List <ClipperLib.ExPolygon> res = new List <ClipperLib.ExPolygon>();


            c.AddPolygons(ipolygones, ClipperLib.PolyType.ptSubject);
            c.Execute(ClipperLib.ClipType.ctUnion, res, ClipperLib.PolyFillType.pftNonZero, ClipperLib.PolyFillType.pftNonZero);

            //c.Execute(ClipperLib.ClipType.ctUnion,res,ClipperLib.PolyFillType.pftEvenOdd,ClipperLib.PolyFillType.pftEvenOdd);
            //c.Execute(ClipperLib.ClipType.ctUnion,res,ClipperLib.PolyFillType.pftPositive,ClipperLib.PolyFillType.pftPositive);
            //c.Execute(ClipperLib.ClipType.ctUnion,res,ClipperLib.PolyFillType.pftPositive,ClipperLib.PolyFillType.pftPositive);


            List <Vector3> vertices  = new List <Vector3>();
            List <int>     triangles = new List <int>();

            Dictionary <Vector3, int> vDic = new Dictionary <Vector3, int>();


            foreach (ClipperLib.ExPolygon p in res)
            {
                Vector3 mv = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
                Vector3 Mv = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);

                List <Vector3> np = LIP2Vec(p.outer);

                for (int i = 0; i < np.Count; i++)
                {
                    mv = Vector3.Min(mv, np[i]);
                    Mv = Vector3.Max(Mv, np[i]);
                }

                Vector3 sv = (Mv - mv);
                //int oc=np.Count;
                np = Simplify(np, 0.05f);

                // set of all vertices for this triangulation step
                HashSet <Vector3> whole = new HashSet <Vector3>();

                if ((np.Count >= 4) && ((sv.x * sv.y) > 0.001f) && Intersection.isSimple(np) && !HasDup(np))
                {
                    foreach (Vector3 v in np)
                    {
                        whole.Add(v);
                    }

                    Polygon cp = new Polygon(Vec2PP(np));

                    foreach (List <ClipperLib.IntPoint> h in p.holes)
                    {
                        List <Vector3> ph = Simplify(LIP2Vec(h), 0.05f);

                        // Poli2tri doesnt support intersection and dupplicate vertices
                        // skip all holes which does not respect thoses conditions

                        if ((!Intersection.isSimple(ph)) || HasDup(ph))
                        {
                            //Debug.LogWarning("Skipping Complex hole");
                        }
                        else if (ContainsAny(whole, ph))
                        {
                            //Debug.LogWarning("Duplicate vertices in holes");
                        }
                        else
                        {
                            foreach (Vector3 v in ph)
                            {
                                whole.Add(v);
                            }

                            cp.AddHole(new Polygon(Vec2PP(ph)));
                        }
                    }


                    try {
                        P2T.Triangulate(cp);

                        foreach (DelaunayTriangle dt in cp.Triangles)
                        {
                            Vector3 v;
                            int     idx;

                            for (int i = 0; i < 3; ++i)
                            {
                                v = new Vector3(dt.Points[i].Xf, dt.Points[i].Yf, Z);
                                if (!vDic.TryGetValue(v, out idx))
                                {
                                    idx = vertices.Count;
                                    vertices.Add(v);
                                    vDic.Add(v, idx);
                                }
                                triangles.Add(idx);
                            }
                        }
                    } catch (System.Exception e) {
                        Debug.LogWarning(e);
                    }
                }
                else
                {
                    //Debug.LogWarning("Skip Polygon: count=" + np.Count + " size=" + sv + " simple=" + Intersection.isSimple(np) + " dup:" + HasDup(np));
                }
            }

            outMesh.Clear();

            outMesh.vertices  = vertices.ToArray();
            outMesh.triangles = triangles.ToArray();
            outMesh.RecalculateBounds();
            outMesh.RecalculateNormals();
            outMesh.Optimize();

            return(outMesh);
        }
Example #18
0
        public static ClipperLib.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();

            // 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(tmxLayer.UnityLayerOverrideName);

            // From the perspective of Clipper lines are polygons too
            // Closed paths == polygons
            // Open paths == lines
            Dictionary <TupleInt2, List <PolygonGroup> > polygonGroups = new Dictionary <TupleInt2, List <PolygonGroup> >();

            foreach (int y in Enumerable.Range(0, tmxLayer.Height))
            {
                foreach (int x in Enumerable.Range(0, tmxLayer.Width))
                {
                    uint rawTileId = tmxLayer.GetRawTileIdAt(x, y);
                    if (rawTileId == 0)
                    {
                        continue;
                    }

                    uint    tileId = TmxMath.GetTileIdWithoutFlags(rawTileId);
                    TmxTile tile   = tmxMap.Tiles[tileId];

                    foreach (TmxObject polygon in tile.ObjectGroup.Objects)
                    {
                        if (typeof(TmxHasPoints).IsAssignableFrom(polygon.GetType()) &&
                            (usingUnityLayerOverride || String.Compare(polygon.Type, tmxLayer.Name, true) == 0))
                        {
                            int groupX = x / LayerClipper.GroupBySize;
                            int groupY = y / LayerClipper.GroupBySize;

                            PolygonGroup poly = new PolygonGroup();
                            poly.PositionOnMap         = tmxMap.GetMapPositionAt(x, y, tile);
                            poly.HasPointsInterface    = polygon as TmxHasPoints;
                            poly.TmxObjectInterface    = polygon;
                            poly.IsFlippedDiagnoally   = TmxMath.IsTileFlippedDiagonally(rawTileId);
                            poly.IsFlippedHorizontally = TmxMath.IsTileFlippedHorizontally(rawTileId);
                            poly.IsFlippedVertically   = TmxMath.IsTileFlippedVertically(rawTileId);
                            poly.TileCenter            = new PointF(tile.TileSize.Width * 0.5f, tile.TileSize.Height * 0.5f);

                            TupleInt2 key = new TupleInt2(groupX, groupY);
                            if (!polygonGroups.ContainsKey(key))
                            {
                                polygonGroups[key] = new List <PolygonGroup>();
                            }
                            polygonGroups[key].Add(poly);
                        }
                    }
                }
            }
            // Tuple not supported in Mono 2.0 so doing this the old fashioned way, sorry
            //var polygonGroups = from y in Enumerable.Range(0, tmxLayer.Height)
            //                    from x in Enumerable.Range(0, tmxLayer.Width)
            //                    let rawTileId = tmxLayer.GetRawTileIdAt(x, y)
            //                    where rawTileId != 0
            //                    let tileId = TmxMath.GetTileIdWithoutFlags(rawTileId)
            //                    let tile = tmxMap.Tiles[tileId]
            //                    from polygon in tile.ObjectGroup.Objects
            //                    where (polygon as TmxHasPoints) != null
            //                    where  usingUnityLayerOverride || String.Compare(polygon.Type, tmxLayer.Name, true) == 0
            //                    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 (TupleInt2 key in polygonGroups.Keys)
            {
                if (groupIndex % 5 == 0)
                {
                    progFunc(String.Format("Clipping '{0}' polygons: {1}%", tmxLayer.Name, (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 (PolygonGroup poly in polygonGroups[key])
                {
                    // 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"
                    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(ClipperLib.Clipper.ClosedPathsFromPolyTree(solution), ClipperLib.PolyType.ptSubject, true);
                fullClipper.AddPaths(ClipperLib.Clipper.OpenPathsFromPolyTree(solution), ClipperLib.PolyType.ptSubject, false);
            }
            progFunc(String.Format("Clipping '{0}' polygons: 100%", tmxLayer.Name));

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

            return(fullSolution);
        }
Example #19
0
        public static ClipperLib.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.Name, (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 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"
                    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(ClipperLib.Clipper.ClosedPathsFromPolyTree(solution), ClipperLib.PolyType.ptSubject, true);
                fullClipper.AddPaths(ClipperLib.Clipper.OpenPathsFromPolyTree(solution), ClipperLib.PolyType.ptSubject, false);
            }
            progFunc(String.Format("Clipping '{0}' polygons: 100%", tmxLayer.Name));

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

            return fullSolution;
        }
Example #20
0
            public override List <List <Polygon> > GetPolygons()
            {
                //                if (FillEnabled == false) return new List<List<Polygon>>();

                List <Polygon> CombinedPolygons = new List <Polygon>();


                Polygons solution = new Polygons();


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


                int first = 0;

                foreach (var p in TransformedPolygons)
                {
                    Polygons clips = new Polygons();

                    List <ClipperLib.IntPoint> clipperpoly = new List <ClipperLib.IntPoint>();
                    foreach (var v in p.Vertices)
                    {
                        clipperpoly.Add(new ClipperLib.IntPoint((long)(v.x * 100000), (long)(v.y * 100000)));
                    }
                    clips.Add(clipperpoly);
                    //                    cp.AddPolygons(clips, (first != 0)?PolyType.ptClip:PolyType.ptSubject);
                    cp.AddPolygons(clips, ClipperLib.PolyType.ptSubject);
                    first++;
                }

                cp.Execute(ClipperLib.ClipType.ctUnion, solution, FillRule, FillRule);


                foreach (var l in solution)
                {
                    Polygon p = new Polygon("SVGPathCollection");

                    foreach (var v in l)
                    {
                        p.Vertices.Add(new vec2(v.X / 100000.0, v.Y / 100000.0));
                    }

                    p.r = FillColor.R;
                    p.g = FillColor.G;
                    p.b = FillColor.B;
                    // p.a = (byte)(FillColor.A/3);
                    // if (FillColor != Color.White) p.a = 0;
                    p.a           = FillColor.A;
                    p.Filled      = FillEnabled;
                    p.Stroke      = StrokeEnabled;
                    p.StrokeWidth = StrokeWidthInMM;
                    p.strokeR     = StrokeColor.R;
                    p.strokeG     = StrokeColor.G;
                    p.strokeB     = StrokeColor.B;
                    p.strokeA     = StrokeColor.A;
                    CombinedPolygons.Add(p);
                }


                List <List <Polygon> > P = new List <List <Polygon> >()
                {
                    CombinedPolygons
                };

                return(P);
            }
Example #21
0
        private void FixAndSetShapes(IShape[] outlines, IShape[] holes)
        {
            // if any outline doesn't overlap another shape then we don't have to bother with sending them through clipper
            // as sending then though clipper will turn them into generic polygons and loose thier shape specific optimisations
            int outlineLength = outlines.Length;
            int holesLength   = holes?.Length ?? 0;

            bool[] overlappingOutlines    = new bool[outlineLength];
            bool[] overlappingHoles       = new bool[holesLength];
            bool   anyOutlinesOverlapping = false;
            bool   anyHolesOverlapping    = false;

            for (int i = 0; i < outlineLength; i++)
            {
                for (int j = i + 1; j < outlineLength; j++)
                {
                    // skip the bounds check if they are already tested
                    if (overlappingOutlines[i] == false || overlappingOutlines[j] == false)
                    {
                        if (this.OverlappingBoundingBoxes(outlines[i], outlines[j]))
                        {
                            overlappingOutlines[i] = true;
                            overlappingOutlines[j] = true;
                            anyOutlinesOverlapping = true;
                        }
                    }
                }

                for (int k = 0; k < holesLength; k++)
                {
                    if (overlappingOutlines[i] == false || overlappingHoles[k] == false)
                    {
                        if (this.OverlappingBoundingBoxes(outlines[i], holes[k]))
                        {
                            overlappingOutlines[i] = true;
                            overlappingHoles[k]    = true;
                            anyOutlinesOverlapping = true;
                            anyHolesOverlapping    = true;
                        }
                    }
                }
            }

            if (anyOutlinesOverlapping)
            {
                var clipper = new ClipperLib.Clipper();

                // add the outlines and the holes to clipper, scaling up from the float source to the int based system clipper uses
                this.AddPoints(clipper, outlines, overlappingOutlines, ClipperLib.PolyType.ptSubject);
                if (anyHolesOverlapping)
                {
                    this.AddPoints(clipper, holes, overlappingHoles, ClipperLib.PolyType.ptClip);
                }

                var tree = new ClipperLib.PolyTree();
                clipper.Execute(ClipperLib.ClipType.ctDifference, tree);

                List <IShape> newShapes = new List <IShape>();

                // convert the 'tree' back to shapes
                this.ExtractOutlines(tree, newShapes);

                // add the origional outlines that where not overlapping
                for (int i = 0; i < outlineLength - 1; i++)
                {
                    if (!overlappingOutlines[i])
                    {
                        newShapes.Add(outlines[i]);
                    }
                }

                this.shapes = newShapes.ToArray();
            }
            else
            {
                this.shapes = outlines;
            }

            var paths = new List <IPath>();

            foreach (var o in this.shapes)
            {
                paths.AddRange(o);
            }

            this.paths = paths;
        }