Beispiel #1
0
        private void DoOffset(double delta)
        {
            _destinationPolygons = new PolygonPath();
            _delta = delta;

            //if Zero offset, just copy any CLOSED polygons to m_p and return ...
            if (GeometryHelper.NearZero(delta))
            {
                _destinationPolygons.Capacity = _polygonNodes.Children.Count;
                foreach (var node in _polygonNodes.Children)
                {
                    if (node.EndType == EndType.ClosedPolygon)
                    {
                        _destinationPolygons.Add(node.Polygon);
                    }
                }
                return;
            }

            // see offset_triginometry3.svg in the documentation folder ...
            if (MiterLimit > 2)
            {
                _miterLim = 2 / (MiterLimit * MiterLimit);
            }
            else
            {
                _miterLim = 0.5;
            }

            double y;

            if (ArcTolerance <= 0.0)
            {
                y = DefaulArcTolerance;
            }
            else if (ArcTolerance > Math.Abs(delta) * DefaulArcTolerance)
            {
                y = Math.Abs(delta) * DefaulArcTolerance;
            }
            else
            {
                y = ArcTolerance;
            }

            // see offset_triginometry2.svg in the documentation folder ...
            var steps = Math.PI / Math.Acos(1 - y / Math.Abs(delta));

            _sin         = Math.Sin(TwpPi / steps);
            _cos         = Math.Cos(TwpPi / steps);
            _stepsPerRad = steps / TwpPi;
            if (delta < 0.0)
            {
                _sin = -_sin;
            }

            _destinationPolygons.Capacity = _polygonNodes.Children.Count * 2;

            foreach (var node in _polygonNodes.Children)
            {
                _sourcePolygon = node.Polygon;

                var len = _sourcePolygon.Count;

                if (len == 0 ||
                    delta <= 0 &&
                    (len < 3 || node.EndType != EndType.ClosedPolygon))
                {
                    continue;
                }

                _destinationPolygon = new Polygon();

                if (len == 1)
                {
                    if (node.JoinType == JoinType.Round)
                    {
                        var x = 1.0;
                        var Y = 0.0;
                        for (var j = 1; j <= steps; j++)
                        {
                            _destinationPolygon.Add(new IntPoint(
                                                        (_sourcePolygon[0].X + x * delta).RoundToLong(),
                                                        (_sourcePolygon[0].Y + Y * delta).RoundToLong()));
                            var x2 = x;
                            x = x * _cos - _sin * Y;
                            Y = x2 * _sin + Y * _cos;
                        }
                    }
                    else
                    {
                        var x = -1.0;
                        var Y = -1.0;

                        for (var j = 0; j < 4; ++j)
                        {
                            _destinationPolygon.Add(new IntPoint(
                                                        (_sourcePolygon[0].X + x * delta).RoundToLong(),
                                                        (_sourcePolygon[0].Y + Y * delta).RoundToLong()));

                            if (x < 0)
                            {
                                x = 1;
                            }
                            else if (Y < 0)
                            {
                                Y = 1;
                            }
                            else
                            {
                                x = -1;
                            }
                        }
                    }
                    _destinationPolygons.Add(_destinationPolygon);
                    continue;
                }

                //build _normals ...
                _normals.Clear();
                _normals.Capacity = len;
                for (int j = 0; j < len - 1; j++)
                {
                    _normals.Add(GetUnitNormal(_sourcePolygon[j], _sourcePolygon[j + 1]));
                }
                if (node.EndType == EndType.ClosedLine ||
                    node.EndType == EndType.ClosedPolygon)
                {
                    _normals.Add(GetUnitNormal(_sourcePolygon[len - 1], _sourcePolygon[0]));
                }
                else
                {
                    _normals.Add(new DoublePoint(_normals[len - 2]));
                }

                if (node.EndType == EndType.ClosedPolygon)
                {
                    int k = len - 1;
                    for (int j = 0; j < len; j++)
                    {
                        OffsetPoint(j, ref k, node.JoinType);
                    }
                    _destinationPolygons.Add(_destinationPolygon);
                }
                else if (node.EndType == EndType.ClosedLine)
                {
                    int k = len - 1;
                    for (int j = 0; j < len; j++)
                    {
                        OffsetPoint(j, ref k, node.JoinType);
                    }
                    _destinationPolygons.Add(_destinationPolygon);
                    _destinationPolygon = new Polygon();
                    //re-build _normals ...
                    DoublePoint n = _normals[len - 1];
                    for (int j = len - 1; j > 0; j--)
                    {
                        _normals[j] = new DoublePoint(-_normals[j - 1].X, -_normals[j - 1].Y);
                    }
                    _normals[0] = new DoublePoint(-n.X, -n.Y);
                    k           = 0;
                    for (int j = len - 1; j >= 0; j--)
                    {
                        OffsetPoint(j, ref k, node.JoinType);
                    }
                    _destinationPolygons.Add(_destinationPolygon);
                }
                else
                {
                    var k = 0;
                    for (var j = 1; j < len - 1; ++j)
                    {
                        OffsetPoint(j, ref k, node.JoinType);
                    }

                    IntPoint pt1;
                    if (node.EndType == EndType.OpenButt)
                    {
                        var j = len - 1;
                        pt1 = new IntPoint(
                            (_sourcePolygon[j].X + _normals[j].X * delta).RoundToLong(),
                            (_sourcePolygon[j].Y + _normals[j].Y * delta).RoundToLong());

                        _destinationPolygon.Add(pt1);

                        pt1 = new IntPoint(
                            (_sourcePolygon[j].X - _normals[j].X * delta).RoundToLong(),
                            (_sourcePolygon[j].Y - _normals[j].Y * delta).RoundToLong());

                        _destinationPolygon.Add(pt1);
                    }
                    else
                    {
                        var j = len - 1;
                        k           = len - 2;
                        _sinA       = 0;
                        _normals[j] = new DoublePoint(-_normals[j].X, -_normals[j].Y);
                        if (node.EndType == EndType.OpenSquare)
                        {
                            DoSquare(j, k);
                        }
                        else
                        {
                            DoRound(j, k);
                        }
                    }

                    //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);

                    k = len - 1;
                    for (int j = k - 1; j > 0; --j)
                    {
                        OffsetPoint(j, ref k, node.JoinType);
                    }

                    if (node.EndType == EndType.OpenButt)
                    {
                        pt1 = new IntPoint(
                            (_sourcePolygon[0].X - _normals[0].X * delta).RoundToLong(),
                            (_sourcePolygon[0].Y - _normals[0].Y * delta).RoundToLong());

                        _destinationPolygon.Add(pt1);

                        pt1 = new IntPoint(
                            (_sourcePolygon[0].X + _normals[0].X * delta).RoundToLong(),
                            (_sourcePolygon[0].Y + _normals[0].Y * delta).RoundToLong());

                        _destinationPolygon.Add(pt1);
                    }
                    else
                    {
                        _sinA = 0;
                        if (node.EndType == EndType.OpenSquare)
                        {
                            DoSquare(0, 1);
                        }
                        else
                        {
                            DoRound(0, 1);
                        }
                    }
                    _destinationPolygons.Add(_destinationPolygon);
                }
            }
        }
Beispiel #2
0
        public Polygon Cleaned(double distance = 1.415)
        {
            // distance = proximity in units/pixels below which vertices will be stripped.
            // Default ~= sqrt(2) so when adjacent vertices or semi-adjacent vertices have
            // both x & y coords within 1 unit, then the second vertex will be stripped.

            var pointCount = Count;

            if (pointCount == 0)
            {
                return(new Polygon());
            }

            var outputPoints = new OutputPoint[pointCount];

            for (var i = 0; i < pointCount; ++i)
            {
                outputPoints[i] = new OutputPoint();
            }

            for (var i = 0; i < pointCount; ++i)
            {
                outputPoints[i].Point     = this[i];
                outputPoints[i].Next      = outputPoints[(i + 1) % pointCount];
                outputPoints[i].Next.Prev = outputPoints[i];
                outputPoints[i].Index     = 0;
            }

            var distSqrd = distance * distance;
            var op       = outputPoints[0];

            while (op.Index == 0 && op.Next != op.Prev)
            {
                if (GeometryHelper.PointsAreClose(op.Point, op.Prev.Point, distSqrd))
                {
                    op = ExcludeOutputPoint(op);
                    pointCount--;
                }
                else if (GeometryHelper.PointsAreClose(op.Prev.Point, op.Next.Point, distSqrd))
                {
                    ExcludeOutputPoint(op.Next);
                    op          = ExcludeOutputPoint(op);
                    pointCount -= 2;
                }
                else if (GeometryHelper.SlopesNearCollinear(op.Prev.Point, op.Point, op.Next.Point, distSqrd))
                {
                    op = ExcludeOutputPoint(op);
                    pointCount--;
                }
                else
                {
                    op.Index = 1;
                    op       = op.Next;
                }
            }

            if (pointCount < 3)
            {
                pointCount = 0;
            }

            var result = new Polygon(pointCount);

            for (var i = 0; i < pointCount; ++i)
            {
                result.Add(op.Point);
                op = op.Next;
            }

            return(result);
        }