Exemplo n.º 1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Polygon" /> class.
 /// </summary>
 /// <param name="segment">The segment.</param>
 public Polygon(ILineSegment segment)
 {
     this.LineSegments = ImmutableArray.Create(segment);
     this.innerPath    = new InternalPath(segment, true);
     this.path         = new PolygonPath(this);
     this.Paths        = ImmutableArray.Create <IPath>(this.path);
 }
Exemplo n.º 2
0
    private void ReducePath(PolygonPath polyPath, ReductionSettings settings, ReductionSettings toughestSettings = null)
    {
        if (settings.ReduceByMinDistance &&
            (toughestSettings == null || !toughestSettings.ReduceByMinDistance || settings.MinDistance > toughestSettings.MinDistance)
            )
        {
            polyPath.ReduceByMinDistance(settings.MinDistance, settings.MinVertexCount);
        }

        if (settings.ReduceByMinTriangleArea &&
            (toughestSettings == null || !toughestSettings.ReduceByMinTriangleArea || settings.MinTriangleArea > toughestSettings.MinTriangleArea)
            )
        {
            float worldScale    = Common.WorldScale(transform);
            float globalScaleSq = worldScale * worldScale;

            polyPath.ReduceByMinTriangleArea(settings.MinTriangleArea / globalScaleSq, settings.MinVertexCount);
        }

        if (settings.ReduceCodirected &&
            (toughestSettings == null || !toughestSettings.ReduceCodirected || settings.MinAngle > toughestSettings.MinAngle)
            )
        {
            polyPath.ReduceCodirected(settings.MinAngle * Mathf.Deg2Rad, settings.MinVertexCount);
        }
    }
Exemplo n.º 3
0
        private static void WritePath(StringBuilder builder, string name, PolygonPath path)
        {
            // Write path type
            builder.Append($"{name.ToUpper()}{Environment.NewLine}");

            var first = true;

            // Write polygons
            foreach (var polygon in path)
            {
                var copy = new Polygon(polygon);

                if (first && name == "SOLUTION" && copy.Orientation != PolygonOrientation.CounterClockwise)
                {
                    first            = false;
                    copy.Orientation = PolygonOrientation.CounterClockwise;
                }

                copy.OrderBottomLeftFirst();

                // Write points for polygon
                foreach (var point in copy)
                {
                    builder.Append($"{point.X},{point.Y} ");
                }

                // New line at end of polygon
                builder.Append(Environment.NewLine);
            }
        }
Exemplo n.º 4
0
        public void NewClipperFileBasedTest()
        {
            var testData = LoadTestHelper.LoadFromFile("TestData/tests.txt");

            foreach (var test in testData.Values)
            {
                var clipper = new Clipper.Clipper();

                clipper.AddPath(test.Subjects, PolygonKind.Subject);
                clipper.AddPath(test.Clips, PolygonKind.Clip);

                var solution = new PolygonTree();
                Assert.IsTrue(clipper.Execute(test.ClipOperation, solution, false, test.FillType));

                var path = new PolygonPath(solution.AllPolygons.Select(n => n.Polygon).ToList());

                // TODO: reinclude these tests once test data is verified.
                var ignoreTestNumbers = new[] { 36, 38, 39, 44, 46, 48, 51, 52, 59, 64, 67, 69 };
                if (ignoreTestNumbers.Contains(test.TestNumber))
                {
                    continue;
                }

                Assert.AreEqual(test.Solution.Count, path.Count, $"{test.TestNumber}: {test.Caption}");

                // Match points, THIS IS DESTRUCTIVE TO BOTH THE TEST DATA AND RESULT DATA.
                Assert.IsTrue(AreSame(test, path));

                // If we had an exact match then both solutions should now be empty.
                Assert.AreEqual(0, test.Solution.Count, $"{test.TestNumber}: {test.Caption}");
                Assert.AreEqual(0, path.Count, $"{test.TestNumber}: {test.Caption}");
            }
        }
Exemplo n.º 5
0
 public static List <List <ClipperLib.IntPoint> > ToOriginal(this PolygonPath path)
 {
     return(path
            .Select(subject =>
                    subject
                    .Select(s => new ClipperLib.IntPoint(s.X, s.Y))
                    .ToList())
            .ToList());
 }
Exemplo n.º 6
0
        /// <summary>
        /// Test to see if the two paths are the same in that:
        /// 1. They have the same polygon count.
        /// 2. There are matching polygons in that:
        ///    a. Same point count.
        ///    b. Same orientation.
        /// </summary>
        public static bool AreSame(ClipExecutionData test, PolygonPath path2)
        {
            if (test.Solution.Count != path2.Count)
            {
                return(false);
            }

            for (var i = 0; i < path2.Count; i++)
            {
                var polygon1 = path2[i];

                // Order to make comparison easier.
                polygon1.OrderBottomLeftFirst();

                for (var j = 0; j < test.Solution.Count; j++)
                {
                    var polygon2 = test.Solution[j];

                    // Vertex counts need to match
                    if (polygon1.Count != polygon2.Count)
                    {
                        continue;
                    }

                    // Orientations need to match
                    if (polygon1.Orientation != polygon2.Orientation)
                    {
                        continue;
                    }

                    // Count the number of points that match in order across the polygons.
                    // Given both polygons are ordered by bottom left, then
                    // points at each index should match if they are the same polygon.
                    var pointMatchCount = polygon1
                                          .Where((point, k) => point == polygon2[k])
                                          .Count();

                    // Did the point match count equal the vertex count?
                    if (pointMatchCount != polygon1.Count)
                    {
                        continue;
                    }

                    // This is a matching polygon so remove from both solutions
                    // and decrement outer loop index.
                    path2.RemoveAt(i--);
                    test.Solution.RemoveAt(j);

                    // break from inner loop to outer loop
                    break;
                }
            }

            return(true);
        }
Exemplo n.º 7
0
        private static bool ReadPolygon(PolygonPath path, IReadOnlyList <string> lines, ref int lineNumber)
        {
            const string matchPolygonPointLine = @"^\s*[\+-]?\s*\d+\s*,\s*[\+-]?\s*\d+\s*";
            const string matchPointValues      = @"\s*([\+-]?\s*\d+\s*),\s*([\+-]?\s*\d+)\s*";

            // EOF?
            if (lineNumber == lines.Count)
            {
                return(false);
            }

            var match = Regex.Match(lines[lineNumber], matchPolygonPointLine);

            if (!match.Success)
            {
                return(false);
            }

            var line = lines[lineNumber++].Trim();

            var polygon = new Polygon();

            while (line.Length > 0)
            {
                // Read point
                match = Regex.Match(line, matchPointValues);

                // It should be a match for valid values as we only get here if line has length > 0, and we remove whitespace from begining.
                if (!match.Success)
                {
                    throw new Exception($"Invalid point value at line {lineNumber} ==> {line}");
                }

                var x = int.Parse(match.Groups[1].Value.Replace(" ", ""));
                var y = int.Parse(match.Groups[2].Value.Replace(" ", ""));

                polygon.Add(new PointL(x, y));

                // Skip past match
                line = line.Substring(match.Length);
            }

            // Order to make comparison easier.
            polygon.OrderBottomLeftFirst();

            path.Add(polygon);

            return(true);
        }
Exemplo n.º 8
0
    private void PerformTrace()
    {
        var spriteRenderer = GetComponent <SpriteRenderer> ();
        var sprite         = spriteRenderer.sprite;

        var ms = new MarchingSquares(
            sprite.texture,
            alphaThreshold: AlphaThreshold,
            clockWise: ClockWise,
            mipLevel: MipLevel
            );

        polyPath = ms.TraceContours();
        float pixelsPerUnit = RasterHelper.GetPixelsPerUnit(sprite);
        float scale         = (1 << MipLevel) / pixelsPerUnit;
        var   pivot         = RasterHelper.GetPivot(sprite);
        var   offset        = -Vector2.Scale(sprite.bounds.size, pivot);

        polyPath.Scale(scale);
        polyPath.Translate(offset);

        int   pointCountBeforeOpt = polyPath.TotalPointCount;
        float worldScale          = Common.WorldScale(spriteRenderer.transform);

        if (ReduceByMinDistance)
        {
            polyPath.ReduceByMinDistance(MinDistance, MinVertexCount);
        }

        if (ReduceByMinTriangleArea)
        {
            float globalScaleSq = worldScale * worldScale;

            polyPath.ReduceByMinTriangleArea(MinTriangleArea / globalScaleSq, MinVertexCount);
        }

        if (ReduceCodirected)
        {
            polyPath.ReduceCodirected(MinAngle * Mathf.Deg2Rad, MinVertexCount);
        }

        int pointCountAfterOpt = polyPath.TotalPointCount;

        print(string.Format(
                  "Reduction: {0}/{1} ({2:P})",
                  pointCountAfterOpt, pointCountBeforeOpt, 1.0f - ( float )pointCountAfterOpt / pointCountBeforeOpt
                  ));
    }
Exemplo n.º 9
0
        private static PolygonPath ReadPath(string pathName, IReadOnlyList <string> lines, ref int lineNumber)
        {
            // Get the path name
            var name = lines[lineNumber++].Trim();

            if (!name.Equals(pathName, StringComparison.CurrentCultureIgnoreCase))
            {
                throw new Exception($"Expecting path name '{pathName}' at line {lineNumber}.");
            }

            // Create a new path
            var path = new PolygonPath();

            // Read polygons into path.
            while (ReadPolygon(path, lines, ref lineNumber))
            {
            }

            return(path);
        }
Exemplo n.º 10
0
    public void ParsePolygonsFromFile()
    {
        this.ClearBodiesList();
        if (PlistPath == null)
        {
            return;
        }

        Hashtable plistData = new Hashtable();

        PListManager.ParsePListFile(PlistPath.text, ref plistData);

        Hashtable bodies = plistData["bodies"] as Hashtable;

        if (bodies == null)
        {
            Debug.Log("Bodies not found");
        }

        ArrayList keyNames = new ArrayList(bodies.Keys);

        _totalPolygonsinFile = new PolygonObject[keyNames.Count];


        if (keyNames != null)
        {
            for (int i = 0; i < keyNames.Count; i++)
            {
                _totalPolygonsinFile[i]          = new PolygonObject();
                _totalPolygonsinFile[i].bodyname = keyNames[i] as String;

                Hashtable bodyDic  = bodies[keyNames[i]] as Hashtable;
                ArrayList fixtures = bodyDic["fixtures"] as ArrayList;

                var totalPaths = new List <PolygonPath>();

                for (var f = 0; f < fixtures.Count; f++)
                {
                    var fixture = fixtures[f] as Hashtable;
                    if (fixture == null)
                    {
                        continue;
                    }

                    var polygonsArray = fixture["polygons"] as ArrayList;
                    if (polygonsArray == null)
                    {
                        continue;
                    }

                    for (int j = 0; j < polygonsArray.Count; j++)
                    {
                        ArrayList   pointArray   = polygonsArray[j] as ArrayList;
                        PolygonPath tempPath     = new PolygonPath();
                        Vector2[]   pointsVector = new Vector2[pointArray.Count];
                        for (int k = 0; k < pointsVector.Length; k++)
                        {
                            string pointInString = pointArray[k] as String;
                            pointsVector[k] = this.ConvertToVector2FromString(pointInString);
                        }

                        tempPath.points = pointsVector;

                        totalPaths.Add(tempPath);
                    }
                }

                _totalPolygonsinFile[i].paths = totalPaths.ToArray();
            }


            Array.Sort(_totalPolygonsinFile);
            this.setPolygonOfIndex(selectedIndex);
        }
        else
        {
            Debug.Log("Keys not found");
        }
    }
Exemplo n.º 11
0
        private void SetTest()
        {
            if (!_testData.ContainsKey(_testNumber))
            {
                return;
            }

            // Get test of interest.
            var test = _testData[_testNumber];

            _testSubject  = test.Subjects.FirstOrDefault();
            _testClip     = test.Clips.FirstOrDefault();
            _testSolution = test.Solution;

            _newClipperSolution = new PolygonPath();

            var clipper = new Clipper.Clipper();

            clipper.AddPath(test.Subjects, PolygonKind.Subject);
            clipper.AddPath(test.Clips, PolygonKind.Clip);
            clipper.Execute(ClipOperation.Union, _newClipperSolution);

            _testBoundary = _testSolution.Any()
                ? BoundaryBuilder
                            .BuildPolygonBoundary(_testSolution.First(), PolygonKind.Subject)
                            .ToList()
                : null;

            _newClipperBoundary = _newClipperSolution.Any()
                ? BoundaryBuilder
                                  .BuildPolygonBoundary(_newClipperSolution.First(), PolygonKind.Subject)
                                  .ToList()
                : null;

            var originalClipperSolution = new List <List <IntPoint> >();
            var originalClipper         = new ClipperLib.Clipper();

            originalClipper.AddPaths(test.Subjects.ToOriginal(), PolyType.ptSubject, true);
            originalClipper.AddPaths(test.Clips.ToOriginal(), PolyType.ptClip, true);
            originalClipper.Execute(ClipType.ctUnion, originalClipperSolution);
            _originalClipperSolution = originalClipperSolution.ToNew();

            _originalClipperBoundary = _originalClipperSolution.Any()
                ? BoundaryBuilder
                                       .BuildPolygonBoundary(_originalClipperSolution.First(), PolygonKind.Subject)
                                       .ToList()
                : null;

            Program.VisualizerForm.ClipperViewControl.Subjects = new[]
            {
                new PolygonViewModel
                {
                    IsOpen      = false,
                    EdgeColor   = Color.LawnGreen,
                    VertexColor = Color.DarkGreen,
                    Items       = _testSubject?.ToVertices()
                }
            };

            Program.VisualizerForm.ClipperViewControl.Clips = new[]
            {
                new PolygonViewModel
                {
                    IsOpen      = false,
                    EdgeColor   = Color.Blue,
                    VertexColor = Color.DarkBlue,
                    Items       = _testClip?.ToVertices()
                }
            };

            _solutionType = SolutionType.Test;
            SetSolution();
            solutionComboBox.SelectedIndex = 0;
        }
Exemplo n.º 12
0
    public PolygonPath TraceContours()
    {
        float traceStart = Time.realtimeSinceStartup;

        var polyPath       = new PolygonPath();
        var polysWithHoles = polyPath.PolysWithHoles;

        contoursByPoints = new Dictionary <int, Polygon> ();
        int i = 0;

        for (int y = 0; y < height; y++)
        {
            bool             prevWasSolid = false;
            PolygonWithHoles container    = null;

            for (int x = 0; x < width; x++, i++)
            {
                bool curIsSolid = IsSolidByIndex(i);

                if (prevWasSolid != curIsSolid)
                {
                    var contour = GetContourByPoint(x, y);

                    if (contour == null)
                    {
                        if (curIsSolid)
                        {
                            // This is the beginning of new outer contour.
                            contour           = TraceContour(x, y);
                            container         = new PolygonWithHoles(contour);
                            contour.Container = container;
                            polysWithHoles.Add(container);
                        }
                        else
                        {
                            // This is a new hole. It must be traced and linked with current container.
                            contour           = TraceContour(x, y);
                            contour.Container = container;
                            container.Holes.Add(contour);
                            container = null;
                        }
                    }
                    else
                    {
                        if (curIsSolid)
                        {
                            /* We've entered a contour.
                             * When contour is an outer -> store contour container in container var.
                             * When contour is a hole -> do the same thing. */

                            container = contour.Container;
                        }
                        else
                        {
                            /* We've exited a contour.
                             * When contour is an outer -> set container to null.
                             * When contour is a hole -> do the same thing. */

                            container = null;
                        }
                    }
                }

                prevWasSolid = curIsSolid;
            }
        }

        float traceTime = Time.realtimeSinceStartup - traceStart;

        // DEBUG
        if (false)
        {
            Debug.Log(
                "MarchingSquares.TraceContours ()" +
                " time: " + traceTime +
                ", width: " + width +
                ", height: " + height +
                ", numPixels: " + numPixels +
                ", pixels per sec: " + (numPixels / traceTime).ToString("F")
                );
        }

        return(polyPath);
    }
Exemplo n.º 13
0
    public void ParsePolygonsFromFile()
    {
        this.ClearBodiesList();
        if (PlistPath == null)
        {
            return;
        }

        Hashtable plistData = new Hashtable();

        PListManager.ParsePListFile(PlistPath.text, ref plistData);

        Hashtable bodies = plistData["bodies"] as Hashtable;

        if (bodies == null)
        {
            Debug.Log("Bodies not found");
        }

        ArrayList keyNames = new ArrayList(bodies.Keys);

        _totalPolygonsinFile = new PolygonObject[keyNames.Count];


        if (keyNames != null)
        {
            for (int i = 0; i < keyNames.Count; i++)
            {
                _totalPolygonsinFile[i]          = new PolygonObject();
                _totalPolygonsinFile[i].bodyname = keyNames[i] as String;

                Hashtable bodyDic = bodies[keyNames[i]] as Hashtable;
                /*Using single fixture because unity support single fixture*/
                ArrayList fixtures = bodyDic["fixtures"] as ArrayList;

                Hashtable fixture1 = fixtures[0] as Hashtable;

                ArrayList polygonsArray = fixture1["polygons"] as ArrayList;

                PolygonPath[] totalPaths = new PolygonPath[polygonsArray.Count];

                for (int j = 0; j < totalPaths.Length; j++)
                {
                    ArrayList   pointArray   = polygonsArray[j] as ArrayList;
                    PolygonPath tempPath     = new PolygonPath();
                    Vector2[]   pointsVector = new Vector2[pointArray.Count];
                    for (int k = 0; k < pointsVector.Length; k++)
                    {
                        string pointInString = pointArray[k] as String;
                        pointsVector[k] = this.ConvertToVector2FromString(pointInString);
                    }

                    tempPath.points = pointsVector;

                    totalPaths[j] = tempPath;
                }

                _totalPolygonsinFile[i].paths = totalPaths;
            }


            Array.Sort(_totalPolygonsinFile);
            this.setPolygonOfIndex(selectedIndex);
        }
        else
        {
            Debug.Log("Keys not found");
        }
    }