Exemple #1
0
        /// <summary>
        /// Convert self intersecting polygons into simple polygons
        /// </summary>
        /// <param name="polys"></param>
        /// <param name="fillType"></param>
        /// <returns></returns>
        public static List<List<IntPoint>> SimplifyPolygons(IEnumerable<List<IntPoint>> polys, PolyFillType fillType = PolyFillType.EvenOdd)
        {
            Contract.Requires(polys != null);
            Contract.Requires(Contract.ForAll(polys, a => a != null));
            Contract.Ensures(Contract.Result<List<List<IntPoint>>>() != null);

            var result = new List<List<IntPoint>>();
            var c = new Clipper { ForceSimple = true };
            c.AddPolygons(polys, PolyType.Subject);
            c.Execute(ClipType.Union, result, fillType, fillType);
            return result;
        }
        private PolyOffsetBuilder(IReadOnlyList<IReadOnlyList<IntPoint>> points, List<List<IntPoint>> solution, bool isPolygon, double delta, JoinType jointype, EndType endtype, double limit = 0)
        {
            Contract.Requires(points != null);
            Contract.Requires(solution != null);

            if (ReferenceEquals(solution, points))
                throw new ArgumentException("Input and Output parameters cannot be the same", nameof(solution));
            if (delta == 0)
                return;

            _p = points;
            _delta = delta;
            _rmin = 0.5;

            if (jointype == JoinType.Miter)
            {
                if (limit > 2)
                    _rmin = 2.0 / (limit * limit);
                limit = 0.25; //just in case endtype == etRound
            }
            else
            {
                if (limit <= 0)
                    limit = 0.25;
                else if (limit > Math.Abs(delta))
                    limit = Math.Abs(delta);
            }

            solution.Clear();
            for (_i = 0; _i < points.Count; _i++)
            {
                var len = points[_i].Count;
                if (len == 0 || (len < 3 && delta <= 0))
                    continue;
                else if (len == 1)
                {
                    _currentPoly = new List<IntPoint>();
                    _currentPoly = InternalHelpers.BuildArc(points[_i][0], 0, 2 * Math.PI, delta, limit);
                    solution.Add(_currentPoly);
                    continue;
                }

                var forceClose = points[_i][0].Equals(points[_i][len - 1]);
                if (forceClose)
                    len--;

                //build normals ...
                _normals.Clear();
                for (var j = 0; j < len - 1; ++j)
                    _normals.Add(points[_i][j].UnitNormal(points[_i][j + 1]));
                if (isPolygon || forceClose)
                    _normals.Add(points[_i][len - 1].UnitNormal(points[_i][0]));
                else
                    _normals.Add(_normals[len - 2]);

                _currentPoly = new List<IntPoint>();
                if (isPolygon || forceClose)
                {
                    _k = len - 1;
                    for (_j = 0; _j < len; ++_j)
                        OffsetPoint(jointype, limit);
                    solution.Add(_currentPoly);
                    if (!isPolygon)
                    {
                        _currentPoly = new List<IntPoint>();
                        _delta = -_delta;
                        _k = len - 1;
                        for (_j = 0; _j < len; ++_j)
                            OffsetPoint(jointype, limit);
                        _delta = -_delta;
                        _currentPoly.Reverse();
                        solution.Add(_currentPoly);
                    }
                }
                else
                {
                    _k = 0;
                    for (_j = 1; _j < len - 1; ++_j)
                        OffsetPoint(jointype, limit);

                    IntPoint pt1;
                    if (endtype == EndType.OpenButt)
                    {
                        _j = len - 1;
                        pt1 = new IntPoint(InternalHelpers.Round(points[_i][_j].X + _normals[_j].X * delta), InternalHelpers.Round(points[_i][_j].Y + _normals[_j].Y * delta));
                        AddPoint(pt1);
                        pt1 = new IntPoint(InternalHelpers.Round(points[_i][_j].X - _normals[_j].X * delta), InternalHelpers.Round(points[_i][_j].Y - _normals[_j].Y * delta));
                        AddPoint(pt1);
                    }
                    else
                    {
                        _j = len - 1;
                        _k = len - 2;
                        _normals[_j] = new DoublePoint(-_normals[_j].X, -_normals[_j].Y);

                        if (endtype == EndType.OpenSquare)
                            DoSquare();
                        else
                            DoRound(limit);
                    }

                    //re-build Normals ...
                    for (var 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);

                    _k = len - 1;
                    for (_j = _k - 1; _j > 0; --_j)
                        OffsetPoint(jointype, limit);

                    if (endtype == EndType.OpenButt)
                    {
                        pt1 = new IntPoint(InternalHelpers.Round(points[_i][0].X - _normals[0].X * delta), InternalHelpers.Round(points[_i][0].Y - _normals[0].Y * delta));
                        AddPoint(pt1);
                        pt1 = new IntPoint(InternalHelpers.Round(points[_i][0].X + _normals[0].X * delta), InternalHelpers.Round(points[_i][0].Y + _normals[0].Y * delta));
                        AddPoint(pt1);
                    }
                    else
                    {
                        _k = 1;
                        if (endtype == EndType.OpenSquare)
                            DoSquare();
                        else
                            DoRound(limit);
                    }
                    solution.Add(_currentPoly);
                }
            }

            //finally, clean up untidy corners ...
            var clpr = new Clipper();
            clpr.AddPolygons(solution, PolyType.Subject);
            if (delta > 0)
            {
                clpr.Execute(ClipType.Union, solution, PolyFillType.Positive, PolyFillType.Positive);
            }
            else
            {
                var r = clpr.GetBounds();
                var outer = new List<IntPoint>(4) {
                    new IntPoint(r.Left - 10, r.Bottom + 10),
                    new IntPoint(r.Right + 10, r.Bottom + 10),
                    new IntPoint(r.Right + 10, r.Top - 10),
                    new IntPoint(r.Left - 10, r.Top - 10)
                };

                clpr.AddPolygon(outer, PolyType.Subject);
                clpr.ReverseSolution = true;
                clpr.Execute(ClipType.Union, solution, PolyFillType.Negative, PolyFillType.Negative);
                if (solution.Count > 0)
                    solution.RemoveAt(0);
            }
        }