Beispiel #1
0
        //------------------------------------------------------------------------------
        private void DoOffset(double d)
        {
            solution = null;
            delta    = d;
            double absDelta = Math.Abs(d);

            //if a Zero offset, then just copy CLOSED polygons to FSolution and return ...
            if (absDelta < Tolerance)
            {
                solution = new Paths(nodes.Count);
                foreach (PathNode node in nodes)
                {
                    if (node.endType == EndType.Polygon)
                    {
                        solution.Add(node.path);
                    }
                }
                return;
            }

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

            double arcTol;

            if (ArcTolerance < DefaultArcFrac)
            {
                arcTol = absDelta * DefaultArcFrac;
            }
            else
            {
                arcTol = ArcTolerance;
            }

            //see offset_triginometry2.svg in the documentation folder ...
            double steps = Math.PI / Math.Acos(1 - arcTol / absDelta); //steps per 360 degrees

            if (steps > absDelta * Math.PI)
            {
                steps = absDelta * Math.PI;                       //ie excessive precision check
            }
            sin = Math.Sin(TwoPi / steps);
            cos = Math.Cos(TwoPi / steps);
            if (d < 0)
            {
                sin = -sin;
            }
            stepsPerRad = steps / TwoPi;

            solution = new Paths(nodes.Count * 2);
            foreach (PathNode node in nodes)
            {
                pathIn  = node.path;
                pathOut = new Path();
                int pathInCnt = pathIn.Count;

                //if a single vertex then build circle or a square ...
                if (pathInCnt == 1)
                {
                    if (node.joinType == JoinType.Round)
                    {
                        double X = 1.0, Y = 0.0;
                        for (int j = 1; j <= steps; j++)
                        {
                            pathOut.Add(new Point(
                                            Round(pathIn[0].X + X * delta),
                                            Round(pathIn[0].Y + Y * delta)));
                            double X2 = X;
                            X = X * cos - sin * Y;
                            Y = X2 * sin + Y * cos;
                        }
                    }
                    else
                    {
                        double X = -1.0, Y = -1.0;
                        for (int j = 0; j < 4; ++j)
                        {
                            pathOut.Add(new Point(
                                            Round(pathIn[0].X + X * delta),
                                            Round(pathIn[0].Y + Y * delta)));
                            if (X < 0)
                            {
                                X = 1;
                            }
                            else if (Y < 0)
                            {
                                Y = 1;
                            }
                            else
                            {
                                X = -1;
                            }
                        }
                    }
                    solution.Add(pathOut);
                    continue;
                } //end of single vertex offsetting

                //build norms ...
                norms.Clear();
                norms.Capacity = pathInCnt;
                for (int j = 0; j < pathInCnt - 1; j++)
                {
                    norms.Add(GetUnitNormal(pathIn[j], pathIn[j + 1]));
                }
                if (node.endType == EndType.OpenJoined || node.endType == EndType.Polygon)
                {
                    norms.Add(GetUnitNormal(pathIn[pathInCnt - 1], pathIn[0]));
                }
                else
                {
                    norms.Add(new PointD(norms[pathInCnt - 2]));
                }

                if (node.endType == EndType.Polygon)
                {
                    int k = pathInCnt - 1;
                    for (int j = 0; j < pathInCnt; j++)
                    {
                        OffsetPoint(j, ref k, node.joinType);
                    }
                    solution.Add(pathOut);
                }
                else if (node.endType == EndType.OpenJoined)
                {
                    int k = pathInCnt - 1;
                    for (int j = 0; j < pathInCnt; j++)
                    {
                        OffsetPoint(j, ref k, node.joinType);
                    }
                    solution.Add(pathOut);
                    pathOut = new Path();
                    //re-build norms ...
                    PointD n = norms[pathInCnt - 1];
                    for (int j = pathInCnt - 1; j > 0; j--)
                    {
                        norms[j] = new PointD(-norms[j - 1].X, -norms[j - 1].Y);
                    }
                    norms[0] = new PointD(-n.X, -n.Y);
                    k        = 0;
                    for (int j = pathInCnt - 1; j >= 0; j--)
                    {
                        OffsetPoint(j, ref k, node.joinType);
                    }
                    solution.Add(pathOut);
                }
                else
                {
                    int k = 0;
                    for (int j = 1; j < pathInCnt - 1; j++)
                    {
                        OffsetPoint(j, ref k, node.joinType);
                    }

                    Point pt1;
                    if (node.endType == EndType.OpenButt)
                    {
                        int j = pathInCnt - 1;
                        pt1 = new Point((int)Round(pathIn[j].X + norms[j].X *
                                                   delta), (int)Round(pathIn[j].Y + norms[j].Y * delta));
                        pathOut.Add(pt1);
                        pt1 = new Point((int)Round(pathIn[j].X - norms[j].X *
                                                   delta), (int)Round(pathIn[j].Y - norms[j].Y * delta));
                        pathOut.Add(pt1);
                    }
                    else
                    {
                        int j = pathInCnt - 1;
                        k        = pathInCnt - 2;
                        sinA     = 0;
                        norms[j] = new PointD(-norms[j].X, -norms[j].Y);
                        if (node.endType == EndType.OpenSquare)
                        {
                            DoSquare(j, k);
                        }
                        else
                        {
                            DoRound(j, k);
                        }
                    }

                    //reverse norms ...
                    for (int j = pathInCnt - 1; j > 0; j--)
                    {
                        norms[j] = new PointD(-norms[j - 1].X, -norms[j - 1].Y);
                    }
                    norms[0] = new PointD(-norms[1].X, -norms[1].Y);

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

                    if (node.endType == EndType.OpenButt)
                    {
                        pt1 = new Point(Round(pathIn[0].X - norms[0].X * delta),
                                        Round(pathIn[0].Y - norms[0].Y * delta));
                        pathOut.Add(pt1);
                        pt1 = new Point(Round(pathIn[0].X + norms[0].X * delta),
                                        Round(pathIn[0].Y + norms[0].Y * delta));
                        pathOut.Add(pt1);
                    }
                    else
                    {
                        k    = 1;
                        sinA = 0;
                        if (node.endType == EndType.OpenSquare)
                        {
                            DoSquare(0, 1);
                        }
                        else
                        {
                            DoRound(0, 1);
                        }
                    }
                    solution.Add(pathOut);
                }
            }
        }
Beispiel #2
0
 public PointD(PointD dp)
 {
     this.X = dp.X; this.Y = dp.Y;
 }