Ejemplo n.º 1
0
        public void CalcCap(IVertexDest <T> vc, VertexDist <T> v0, VertexDist <T> v1, T len)
        {
            vc.RemoveAll();

            T dx1 = v1.Y.Subtract(v0.Y).Divide(len);
            T dy1 = v1.X.Subtract(v0.X).Divide(len);
            T dx2 = M.Zero <T>();
            T dy2 = M.Zero <T>();

            dx1.MultiplyEquals(m_width);
            dy1.MultiplyEquals(m_width);

            if (LineCap != LineCap.Round)
            {
                if (LineCap == LineCap.Square)
                {
                    dx2 = dy1.Multiply(m_width_sign);
                    dy2 = dx1.Multiply(m_width_sign);
                }
                AddVertex(vc, v0.X.Subtract(dx1).Subtract(dx2), v0.Y.Add(dy1).Subtract(dy2));
                AddVertex(vc, v0.X.Add(dx1).Subtract(dx2), v0.Y.Subtract(dy1).Subtract(dy2));
            }
            else
            {
                T   da = m_width_abs.Divide(m_width_abs.Add(M.New <T>(0.125).Divide(m_approx_scale))).Acos().Multiply(2);
                T   a1;
                int i;
                int n = M.PI <T>().Divide(da).ToInt();

                da = M.PI <T>().Divide(n + 1);
                AddVertex(vc, v0.X.Subtract(dx1), v0.Y.Add(dy1));
                if (m_width_sign > 0)
                {
                    a1 = M.Atan2(dy1, dx1.Negative());
                    a1.AddEquals(da);
                    for (i = 0; i < n; i++)
                    {
                        AddVertex(vc, v0.X.Add(a1.Cos().Multiply(m_width)),
                                  v0.Y.Add(a1.Sin().Multiply(m_width)));
                        a1.AddEquals(da);
                    }
                }
                else
                {
                    a1 = M.Atan2(dy1.Negative(), dx1);
                    a1.SubtractEquals(da);
                    for (i = 0; i < n; i++)
                    {
                        AddVertex(vc, v0.X.Add(a1.Cos().Multiply(m_width)),
                                  v0.Y.Add(a1.Sin().Multiply(m_width)));
                        a1.SubtractEquals(da);
                    }
                }
                AddVertex(vc, v0.X.Add(dx1), v0.Y.Subtract(dy1));
            }
        }
Ejemplo n.º 2
0
        public void CaluclateCap(IVertexDest vc, VertexDistance v0, VertexDistance v1, double len)
        {
            vc.RemoveAll();

            double dx1 = (v1.y - v0.y) / len;
            double dy1 = (v1.x - v0.x) / len;
            double dx2 = 0;
            double dy2 = 0;

            dx1 *= m_width;
            dy1 *= m_width;

            if (m_line_cap != ELineCap.round_cap)
            {
                if (m_line_cap == ELineCap.square_cap)
                {
                    dx2 = dy1 * m_width_sign;
                    dy2 = dx1 * m_width_sign;
                }
                AddVertex(vc, v0.x - dx1 - dx2, v0.y + dy1 - dy2);
                AddVertex(vc, v0.x + dx1 - dx2, v0.y - dy1 - dy2);
            }
            else
            {
                double da = Math.Acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2;
                double a1;
                int    i;
                int    n = (int)(Math.PI / da);

                da = Math.PI / (n + 1);
                AddVertex(vc, v0.x - dx1, v0.y + dy1);
                if (m_width_sign > 0)
                {
                    a1  = Math.Atan2(dy1, -dx1);
                    a1 += da;
                    for (i = 0; i < n; i++)
                    {
                        AddVertex(vc, v0.x + Math.Cos(a1) * m_width,
                                  v0.y + Math.Sin(a1) * m_width);
                        a1 += da;
                    }
                }
                else
                {
                    a1  = Math.Atan2(-dy1, dx1);
                    a1 -= da;
                    for (i = 0; i < n; i++)
                    {
                        AddVertex(vc, v0.x + Math.Cos(a1) * m_width,
                                  v0.y + Math.Sin(a1) * m_width);
                        a1 -= da;
                    }
                }
                AddVertex(vc, v0.x + dx1, v0.y - dy1);
            }
        }
Ejemplo n.º 3
0
        void CalculateArc(IVertexDest vc,
                          double x, double y,
                          double dx1, double dy1,
                          double dx2, double dy2)
        {
            double a1 = Math.Atan2(dy1 * m_width_sign, dx1 * m_width_sign);
            double a2 = Math.Atan2(dy2 * m_width_sign, dx2 * m_width_sign);
            double da = a1 - a2;
            int    i, n;

            da = Math.Acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2;

            AddVertex(vc, x + dx1, y + dy1);
            if (m_width_sign > 0)
            {
                if (a1 > a2)
                {
                    a2 += 2 * Math.PI;
                }
                n   = (int)((a2 - a1) / da);
                da  = (a2 - a1) / (n + 1);
                a1 += da;
                for (i = 0; i < n; i++)
                {
                    AddVertex(vc, x + Math.Cos(a1) * m_width, y + Math.Sin(a1) * m_width);
                    a1 += da;
                }
            }
            else
            {
                if (a1 < a2)
                {
                    a2 -= 2 * Math.PI;
                }
                n   = (int)((a1 - a2) / da);
                da  = (a1 - a2) / (n + 1);
                a1 -= da;
                for (i = 0; i < n; i++)
                {
                    AddVertex(vc, x + Math.Cos(a1) * m_width, y + Math.Sin(a1) * m_width);
                    a1 -= da;
                }
            }
            AddVertex(vc, x + dx2, y + dy2);
        }
Ejemplo n.º 4
0
        void CalcArc(IVertexDest <T> vc,
                     T x, T y,
                     T dx1, T dy1,
                     T dx2, T dy2)
        {
            T   a1 = M.Atan2(dy1.Multiply(m_width_sign), dx1.Multiply(m_width_sign));
            T   a2 = M.Atan2(dy2.Multiply(m_width_sign), dx2.Multiply(m_width_sign));
            T   da = a1.Subtract(a2);
            int i, n;

            da = m_width_abs.Divide(m_width_abs.Add(M.New <T>(0.125).Divide(m_approx_scale))).Acos().Multiply(2);

            AddVertex(vc, x.Add(dx1), y.Add(dy1));
            if (m_width_sign > 0)
            {
                if (a1.GreaterThan(a2))
                {
                    a2.AddEquals(M.PI <T>().Multiply(2));
                }
                n  = (int)a2.Subtract(a1).Divide(da).ToInt();
                da = a2.Subtract(a1).Divide(n + 1);
                a1.AddEquals(da);
                for (i = 0; i < n; i++)
                {
                    AddVertex(vc, x.Add(a1.Cos().Multiply(m_width)), y.Add(a1.Sin().Multiply(m_width)));
                    a1.AddEquals(da);
                }
            }
            else
            {
                if (a1.LessThan(a2))
                {
                    a2.SubtractEquals(M.PI <T>().Multiply(2));
                }
                n  = (int)a1.Subtract(a2).Divide(da).ToInt();
                da = a1.Subtract(a2).Divide(n + 1);
                a1.SubtractEquals(da);
                for (i = 0; i < n; i++)
                {
                    AddVertex(vc, x.Add(a1.Cos().Multiply(m_width)), y.Add(a1.Sin().Multiply(m_width)));
                    a1.SubtractEquals(da);
                }
            }
            AddVertex(vc, x.Add(dx2), y.Add(dy2));
        }
Ejemplo n.º 5
0
        public void CalculateJoin(IVertexDest vc, VertexDistance v0,
										VertexDistance v1,
										VertexDistance v2,
										double len1,
										double len2)
        {
            double dx1 = m_width * (v1.y - v0.y) / len1;
            double dy1 = m_width * (v1.x - v0.x) / len1;
            double dx2 = m_width * (v2.y - v1.y) / len2;
            double dy2 = m_width * (v2.x - v1.x) / len2;

            vc.RemoveAll();

            double cp = PictorMath.CrossProduct(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y);
            if (cp != 0 && (cp > 0) == (m_width > 0))
            {
                // Inner join
                //---------------
                double limit = ((len1 < len2) ? len1 : len2) / m_width_abs;
                if (limit < m_inner_miter_limit)
                {
                    limit = m_inner_miter_limit;
                }

                switch (m_inner_join)
                {
                    default: // inner_bevel
                        AddVertex(vc, v1.x + dx1, v1.y - dy1);
                        AddVertex(vc, v1.x + dx2, v1.y - dy2);
                        break;

                    case EInnerJoin.inner_miter:
                        CalculateMiter(vc,
                                   v0, v1, v2, dx1, dy1, dx2, dy2,
                                   ELineJoin.miter_join_revert,
                                   limit, 0);
                        break;

                    case EInnerJoin.inner_jag:
                    case EInnerJoin.inner_round:
                        cp = (dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2);
                        if (cp < len1 * len1 && cp < len2 * len2)
                        {
                            CalculateMiter(vc,
                                       v0, v1, v2, dx1, dy1, dx2, dy2,
                                       ELineJoin.miter_join_revert,
                                       limit, 0);
                        }
                        else
                        {
                            if (m_inner_join == EInnerJoin.inner_jag)
                            {
                                AddVertex(vc, v1.x + dx1, v1.y - dy1);
                                AddVertex(vc, v1.x, v1.y);
                                AddVertex(vc, v1.x + dx2, v1.y - dy2);
                            }
                            else
                            {
                                AddVertex(vc, v1.x + dx1, v1.y - dy1);
                                AddVertex(vc, v1.x, v1.y);
                                CalculateArc(vc, v1.x, v1.y, dx2, -dy2, dx1, -dy1);
                                AddVertex(vc, v1.x, v1.y);
                                AddVertex(vc, v1.x + dx2, v1.y - dy2);
                            }
                        }
                        break;
                }
            }
            else
            {
                // Outer join
                //---------------

                // Calculate the distance between v1 and
                // the central point of the bevel Line segment
                //---------------
                double dx = (dx1 + dx2) / 2;
                double dy = (dy1 + dy2) / 2;
                double dbevel = Math.Sqrt(dx * dx + dy * dy);

                if (m_line_join == ELineJoin.round_join || m_line_join == ELineJoin.bevel_join)
                {
                    // This is an optimization that reduces the number of points
                    // in cases of almost collinear segments. If there's no
                    // visible difference between bevel and miter joins we'd rather
                    // use miter join because it adds only one point instead of two.
                    //
                    // Here we Calculate the middle point between the bevel points
                    // and then, the distance between v1 and this middle point.
                    // At outer joins this distance always less than stroke Width,
                    // because it's actually the Height of an isosceles triangle of
                    // v1 and its two bevel points. If the difference between this
                    // Width and this Value is small (no visible bevel) we can
                    // Add just one point.
                    //
                    // The constant in the expression makes the result approximately
                    // the same as in round joins and caps. You can safely comment
                    // out this entire "if".
                    //-------------------
                    if (m_approx_scale * (m_width_abs - dbevel) < m_width_eps)
                    {
                        if (PictorMath.CalculateIntersection(v0.x + dx1, v0.y - dy1,
                                             v1.x + dx1, v1.y - dy1,
                                             v1.x + dx2, v1.y - dy2,
                                             v2.x + dx2, v2.y - dy2,
                                             out dx, out dy))
                        {
                            AddVertex(vc, dx, dy);
                        }
                        else
                        {
                            AddVertex(vc, v1.x + dx1, v1.y - dy1);
                        }
                        return;
                    }
                }

                switch (m_line_join)
                {
                    case ELineJoin.miter_join:
                    case ELineJoin.miter_join_revert:
                    case ELineJoin.miter_join_round:
                        CalculateMiter(vc,
                                   v0, v1, v2, dx1, dy1, dx2, dy2,
                                   m_line_join,
                                   m_miter_limit,
                                   dbevel);
                        break;

                    case ELineJoin.round_join:
                        CalculateArc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2);
                        break;

                    default: // Bevel join
                        AddVertex(vc, v1.x + dx1, v1.y - dy1);
                        AddVertex(vc, v1.x + dx2, v1.y - dy2);
                        break;
                }
            }
        }
Ejemplo n.º 6
0
        void CalculateMiter(IVertexDest vc,
                            VertexDistance v0,
                            VertexDistance v1,
                            VertexDistance v2,
                            double dx1, double dy1,
                            double dx2, double dy2,
                            ELineJoin lj,
                            double mlimit,
                            double dbevel)
        {
            double xi  = v1.x;
            double yi  = v1.y;
            double di  = 1;
            double lim = m_width_abs * mlimit;
            bool   miter_limit_exceeded = true;          // Assume the worst
            bool   intersection_failed  = true;          // Assume the worst

            if (PictorMath.CalculateIntersection(v0.x + dx1, v0.y - dy1,
                                                 v1.x + dx1, v1.y - dy1,
                                                 v1.x + dx2, v1.y - dy2,
                                                 v2.x + dx2, v2.y - dy2,
                                                 out xi, out yi))
            {
                // Calculation of the intersection succeeded
                //---------------------
                di = PictorMath.CalculateDistance(v1.x, v1.y, xi, yi);
                if (di <= lim)
                {
                    // Inside the miter limit
                    //---------------------
                    AddVertex(vc, xi, yi);
                    miter_limit_exceeded = false;
                }
                intersection_failed = false;
            }
            else
            {
                // Calculation of the intersection failed, most probably
                // the three points lie one straight Line.
                // First check if v0 and v2 lie on the opposite sides of vector:
                // (v1.x, v1.y) -> (v1.x+dx1, v1.y-dy1), that is, the perpendicular
                // to the Line determined by vertices v0 and v1.
                // This condition determines whether the next Line segments continues
                // the previous one or goes back.
                //----------------
                double x2 = v1.x + dx1;
                double y2 = v1.y - dy1;
                if ((PictorMath.CrossProduct(v0.x, v0.y, v1.x, v1.y, x2, y2) < 0.0) ==
                    (PictorMath.CrossProduct(v1.x, v1.y, v2.x, v2.y, x2, y2) < 0.0))
                {
                    // This case means that the next segment continues
                    // the previous one (straight Line)
                    //-----------------
                    AddVertex(vc, v1.x + dx1, v1.y - dy1);
                    miter_limit_exceeded = false;
                }
            }

            if (miter_limit_exceeded)
            {
                // Miter limit exceeded
                //------------------------
                switch (lj)
                {
                case ELineJoin.miter_join_revert:
                    // For the compatibility with SVG, PDF, etc,
                    // we use a simple bevel join instead of
                    // "smart" bevel
                    //-------------------
                    AddVertex(vc, v1.x + dx1, v1.y - dy1);
                    AddVertex(vc, v1.x + dx2, v1.y - dy2);
                    break;

                case ELineJoin.miter_join_round:
                    CalculateArc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2);
                    break;

                default:
                    // If no miter-revert, Calculate new dx1, dy1, dx2, dy2
                    //----------------
                    if (intersection_failed)
                    {
                        mlimit *= m_width_sign;
                        AddVertex(vc, v1.x + dx1 + dy1 * mlimit,
                                  v1.y - dy1 + dx1 * mlimit);
                        AddVertex(vc, v1.x + dx2 - dy2 * mlimit,
                                  v1.y - dy2 - dx2 * mlimit);
                    }
                    else
                    {
                        double x1 = v1.x + dx1;
                        double y1 = v1.y - dy1;
                        double x2 = v1.x + dx2;
                        double y2 = v1.y - dy2;
                        di = (lim - dbevel) / (di - dbevel);
                        AddVertex(vc, x1 + (xi - x1) * di,
                                  y1 + (yi - y1) * di);
                        AddVertex(vc, x2 + (xi - x2) * di,
                                  y2 + (yi - y2) * di);
                    }
                    break;
                }
            }
        }
Ejemplo n.º 7
0
 private void AddVertex(IVertexDest vc, double x, double y)
 {
     vc.Add(new PointD(x, y));
 }
Ejemplo n.º 8
0
        public void CalculateJoin(IVertexDest vc, VertexDistance v0,
                                  VertexDistance v1,
                                  VertexDistance v2,
                                  double len1,
                                  double len2)
        {
            double dx1 = m_width * (v1.y - v0.y) / len1;
            double dy1 = m_width * (v1.x - v0.x) / len1;
            double dx2 = m_width * (v2.y - v1.y) / len2;
            double dy2 = m_width * (v2.x - v1.x) / len2;

            vc.RemoveAll();

            double cp = PictorMath.CrossProduct(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y);

            if (cp != 0 && (cp > 0) == (m_width > 0))
            {
                // Inner join
                //---------------
                double limit = ((len1 < len2) ? len1 : len2) / m_width_abs;
                if (limit < m_inner_miter_limit)
                {
                    limit = m_inner_miter_limit;
                }

                switch (m_inner_join)
                {
                default:                         // inner_bevel
                    AddVertex(vc, v1.x + dx1, v1.y - dy1);
                    AddVertex(vc, v1.x + dx2, v1.y - dy2);
                    break;

                case EInnerJoin.inner_miter:
                    CalculateMiter(vc,
                                   v0, v1, v2, dx1, dy1, dx2, dy2,
                                   ELineJoin.miter_join_revert,
                                   limit, 0);
                    break;

                case EInnerJoin.inner_jag:
                case EInnerJoin.inner_round:
                    cp = (dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2);
                    if (cp < len1 * len1 && cp < len2 * len2)
                    {
                        CalculateMiter(vc,
                                       v0, v1, v2, dx1, dy1, dx2, dy2,
                                       ELineJoin.miter_join_revert,
                                       limit, 0);
                    }
                    else
                    {
                        if (m_inner_join == EInnerJoin.inner_jag)
                        {
                            AddVertex(vc, v1.x + dx1, v1.y - dy1);
                            AddVertex(vc, v1.x, v1.y);
                            AddVertex(vc, v1.x + dx2, v1.y - dy2);
                        }
                        else
                        {
                            AddVertex(vc, v1.x + dx1, v1.y - dy1);
                            AddVertex(vc, v1.x, v1.y);
                            CalculateArc(vc, v1.x, v1.y, dx2, -dy2, dx1, -dy1);
                            AddVertex(vc, v1.x, v1.y);
                            AddVertex(vc, v1.x + dx2, v1.y - dy2);
                        }
                    }
                    break;
                }
            }
            else
            {
                // Outer join
                //---------------

                // Calculate the distance between v1 and
                // the central point of the bevel Line segment
                //---------------
                double dx     = (dx1 + dx2) / 2;
                double dy     = (dy1 + dy2) / 2;
                double dbevel = Math.Sqrt(dx * dx + dy * dy);

                if (m_line_join == ELineJoin.round_join || m_line_join == ELineJoin.bevel_join)
                {
                    // This is an optimization that reduces the number of points
                    // in cases of almost collinear segments. If there's no
                    // visible difference between bevel and miter joins we'd rather
                    // use miter join because it adds only one point instead of two.
                    //
                    // Here we Calculate the middle point between the bevel points
                    // and then, the distance between v1 and this middle point.
                    // At outer joins this distance always less than stroke Width,
                    // because it's actually the Height of an isosceles triangle of
                    // v1 and its two bevel points. If the difference between this
                    // Width and this Value is small (no visible bevel) we can
                    // Add just one point.
                    //
                    // The constant in the expression makes the result approximately
                    // the same as in round joins and caps. You can safely comment
                    // out this entire "if".
                    //-------------------
                    if (m_approx_scale * (m_width_abs - dbevel) < m_width_eps)
                    {
                        if (PictorMath.CalculateIntersection(v0.x + dx1, v0.y - dy1,
                                                             v1.x + dx1, v1.y - dy1,
                                                             v1.x + dx2, v1.y - dy2,
                                                             v2.x + dx2, v2.y - dy2,
                                                             out dx, out dy))
                        {
                            AddVertex(vc, dx, dy);
                        }
                        else
                        {
                            AddVertex(vc, v1.x + dx1, v1.y - dy1);
                        }
                        return;
                    }
                }

                switch (m_line_join)
                {
                case ELineJoin.miter_join:
                case ELineJoin.miter_join_revert:
                case ELineJoin.miter_join_round:
                    CalculateMiter(vc,
                                   v0, v1, v2, dx1, dy1, dx2, dy2,
                                   m_line_join,
                                   m_miter_limit,
                                   dbevel);
                    break;

                case ELineJoin.round_join:
                    CalculateArc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2);
                    break;

                default:                         // Bevel join
                    AddVertex(vc, v1.x + dx1, v1.y - dy1);
                    AddVertex(vc, v1.x + dx2, v1.y - dy2);
                    break;
                }
            }
        }
Ejemplo n.º 9
0
 public void CalculateCap(IVertexDest vc, vertex_dist v0, vertex_dist v1, double len)
 {
     _innerstroke.calc_cap(vc, v0, v1, len);
 }
Ejemplo n.º 10
0
        void CalculateArc(IVertexDest vc,
					  double x, double y,
					  double dx1, double dy1,
					  double dx2, double dy2)
        {
            double a1 = Math.Atan2(dy1 * m_width_sign, dx1 * m_width_sign);
            double a2 = Math.Atan2(dy2 * m_width_sign, dx2 * m_width_sign);
            double da = a1 - a2;
            int i, n;

            da = Math.Acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2;

            AddVertex(vc, x + dx1, y + dy1);
            if (m_width_sign > 0)
            {
                if (a1 > a2) a2 += 2 * Math.PI;
                n = (int)((a2 - a1) / da);
                da = (a2 - a1) / (n + 1);
                a1 += da;
                for (i = 0; i < n; i++)
                {
                    AddVertex(vc, x + Math.Cos(a1) * m_width, y + Math.Sin(a1) * m_width);
                    a1 += da;
                }
            }
            else
            {
                if (a1 < a2) a2 -= 2 * Math.PI;
                n = (int)((a1 - a2) / da);
                da = (a1 - a2) / (n + 1);
                a1 -= da;
                for (i = 0; i < n; i++)
                {
                    AddVertex(vc, x + Math.Cos(a1) * m_width, y + Math.Sin(a1) * m_width);
                    a1 -= da;
                }
            }
            AddVertex(vc, x + dx2, y + dy2);
        }
Ejemplo n.º 11
0
 private void AddVertex(IVertexDest <T> vc, T x, T y)
 {
     vc.Add(MatrixFactory <T> .CreateVector2D(x, y));
 }
Ejemplo n.º 12
0
        public void CalcJoin(
            IVertexDest <T> vc,
            VertexDist <T> v0,
            VertexDist <T> v1,
            VertexDist <T> v2,
            T len1,
            T len2)
        {
            T dx1 = m_width.Multiply(v1.Y.Subtract(v0.Y)).Divide(len1);
            T dy1 = m_width.Multiply(v1.X.Subtract(v0.X)).Divide(len1);
            T dx2 = m_width.Multiply(v2.Y.Subtract(v1.Y)).Divide(len2);
            T dy2 = m_width.Multiply(v2.X.Subtract(v1.X)).Divide(len2);

            vc.RemoveAll();

            T cp = MathUtil.CrossProduct(v0.X, v0.Y, v1.X, v1.Y, v2.X, v2.Y);

            if (cp.NotEqual(0) && cp.GreaterThan(0) == m_width.GreaterThan(0))
            {
                // Inner join
                //---------------
                T limit = (len1.LessThan(len2) ? len1 : len2).Divide(m_width_abs);
                if (limit.LessThan(m_inner_miter_limit))
                {
                    limit = m_inner_miter_limit;
                }

                switch (InnerJoin)
                {
                default:     // inner_bevel
                    AddVertex(vc, v1.X.Add(dx1), v1.Y.Subtract(dy1));
                    AddVertex(vc, v1.X.Add(dx2), v1.Y.Subtract(dy2));
                    break;

                case InnerJoin.InnerMiter:
                    CalcMiter(vc,
                              v0, v1, v2, dx1, dy1, dx2, dy2,
                              LineJoin.MiterJoinRevert,
                              limit, M.Zero <T>());
                    break;

                case InnerJoin.InnerJag:
                case InnerJoin.InnerRound:
                    cp = M.LengthSquared(dx1.Subtract(dx2), dy1.Subtract(dy2));    // (dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2);
                    if (cp.LessThan(len1.Multiply(len1)) && cp.LessThan(len2.Multiply(len2)))
                    {
                        CalcMiter(vc,
                                  v0, v1, v2, dx1, dy1, dx2, dy2,
                                  LineJoin.MiterJoinRevert,
                                  limit, M.Zero <T>());
                    }
                    else
                    {
                        if (InnerJoin == InnerJoin.InnerJag)
                        {
                            AddVertex(vc, v1.X.Add(dx1), v1.Y.Subtract(dy1));
                            AddVertex(vc, v1.X, v1.Y);
                            AddVertex(vc, v1.X.Add(dx2), v1.Y.Subtract(dy2));
                        }
                        else
                        {
                            AddVertex(vc, v1.X.Add(dx1), v1.Y.Subtract(dy1));
                            AddVertex(vc, v1.X, v1.Y);
                            CalcArc(vc, v1.X, v1.Y, dx2, dy2.Negative(), dx1, dy1.Negative());
                            AddVertex(vc, v1.X, v1.Y);
                            AddVertex(vc, v1.X.Add(dx2), v1.Y.Add(dy2));
                        }
                    }
                    break;
                }
            }
            else
            {
                // Outer join
                //---------------

                // Calculate the distance between v1 and
                // the central point of the bevel line segment
                //---------------
                T dx     = dx1.Add(dx2).Divide(2);
                T dy     = dy1.Add(dy2).Divide(2);
                T dbevel = M.Length(dx, dy);// Math.Sqrt(dx * dx + dy * dy);

                if (LineJoin == LineJoin.RoundJoin || LineJoin == LineJoin.BevelJoin)
                {
                    // This is an optimization that reduces the number of points
                    // in cases of almost collinear segments. If there's no
                    // visible difference between bevel and miter joins we'd rather
                    // use miter join because it adds only one point instead of two.
                    //
                    // Here we calculate the middle point between the bevel points
                    // and then, the distance between v1 and this middle point.
                    // At outer joins this distance always less than stroke width,
                    // because it's actually the height of an isosceles triangle of
                    // v1 and its two bevel points. If the difference between this
                    // width and this Value is small (no visible bevel) we can
                    // add just one point.
                    //
                    // The constant in the expression makes the result approximately
                    // the same as in round joins and caps. You can safely comment
                    // out this entire "if".
                    //-------------------
                    if (m_approx_scale.Multiply(m_width_abs.Subtract(dbevel)).LessThan(m_width_eps))
                    {
                        if (MathUtil.CalcIntersection(v0.X.Add(dx1), v0.Y.Subtract(dy1),
                                                      v1.X.Add(dx1), v1.Y.Subtract(dy1),
                                                      v1.X.Add(dx2), v1.Y.Subtract(dy2),
                                                      v2.X.Add(dx2), v2.Y.Subtract(dy2),
                                                      out dx, out dy))
                        {
                            AddVertex(vc, dx, dy);
                        }
                        else
                        {
                            AddVertex(vc, v1.X.Add(dx1), v1.Y.Subtract(dy1));
                        }
                        return;
                    }
                }

                switch (LineJoin)
                {
                case LineJoin.MiterJoin:
                case LineJoin.MiterJoinRevert:
                case LineJoin.MiterJoinRound:
                    CalcMiter(vc,
                              v0, v1, v2, dx1, dy1, dx2, dy2,
                              LineJoin,
                              m_miter_limit,
                              dbevel);
                    break;

                case LineJoin.RoundJoin:
                    CalcArc(vc, v1.X, v1.Y, dx1, dy1.Negative(), dx2, dy2.Negative());
                    break;

                default:     // Bevel join
                    AddVertex(vc, v1.X.Add(dx1), v1.Y.Subtract(dy1));
                    AddVertex(vc, v1.X.Add(dx2), v1.Y.Subtract(dy2));
                    break;
                }
            }
        }
Ejemplo n.º 13
0
 private void add_vertex(IVertexDest vc, double x, double y)
 {
     vc.add(new Vector2D(x, y));
 }
Ejemplo n.º 14
0
 private void add_vertex(IVertexDest vc, double x, double y)
 {
     vc.add(new Vector2(x, y));
 }
Ejemplo n.º 15
0
        public void CaluclateCap(IVertexDest vc, VertexDistance v0, VertexDistance v1, double len)
        {
            vc.RemoveAll();

            double dx1 = (v1.y - v0.y) / len;
            double dy1 = (v1.x - v0.x) / len;
            double dx2 = 0;
            double dy2 = 0;

            dx1 *= m_width;
            dy1 *= m_width;

            if (m_line_cap != ELineCap.round_cap)
            {
                if (m_line_cap == ELineCap.square_cap)
                {
                    dx2 = dy1 * m_width_sign;
                    dy2 = dx1 * m_width_sign;
                }
                AddVertex(vc, v0.x - dx1 - dx2, v0.y + dy1 - dy2);
                AddVertex(vc, v0.x + dx1 - dx2, v0.y - dy1 - dy2);
            }
            else
            {
                double da = Math.Acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2;
                double a1;
                int i;
                int n = (int)(Math.PI / da);

                da = Math.PI / (n + 1);
                AddVertex(vc, v0.x - dx1, v0.y + dy1);
                if (m_width_sign > 0)
                {
                    a1 = Math.Atan2(dy1, -dx1);
                    a1 += da;
                    for (i = 0; i < n; i++)
                    {
                        AddVertex(vc, v0.x + Math.Cos(a1) * m_width,
                                       v0.y + Math.Sin(a1) * m_width);
                        a1 += da;
                    }
                }
                else
                {
                    a1 = Math.Atan2(-dy1, dx1);
                    a1 -= da;
                    for (i = 0; i < n; i++)
                    {
                        AddVertex(vc, v0.x + Math.Cos(a1) * m_width,
                                       v0.y + Math.Sin(a1) * m_width);
                        a1 -= da;
                    }
                }
                AddVertex(vc, v0.x + dx1, v0.y - dy1);
            }
        }
Ejemplo n.º 16
0
 private void AddVertex(IVertexDest vc, double x, double y)
 {
     vc.Add(new PointD(x, y));
 }
Ejemplo n.º 17
0
        void CalcMiter(IVertexDest <T> vc,
                       VertexDist <T> v0,
                       VertexDist <T> v1,
                       VertexDist <T> v2,
                       T dx1, T dy1,
                       T dx2, T dy2,
                       LineJoin lj,
                       T mlimit,
                       T dbevel)
        {
            T    xi  = v1.X;
            T    yi  = v1.Y;
            T    di  = M.One <T>();
            T    lim = m_width_abs.Multiply(mlimit);
            bool miter_limit_exceeded = true; // Assume the worst
            bool intersection_failed  = true; // Assume the worst

            if (MathUtil.CalcIntersection(v0.X.Add(dx1), v0.Y.Subtract(dy1),
                                          v1.X.Add(dx1), v1.Y.Subtract(dy1),
                                          v1.X.Add(dx2), v1.Y.Subtract(dy2),
                                          v2.X.Add(dx2), v2.Y.Subtract(dy2),
                                          out xi, out yi))
            {
                // Calculation of the intersection succeeded
                //---------------------
                di = MathUtil.CalcDistance(v1.X, v1.Y, xi, yi);
                if (di.LessThanOrEqualTo(lim))
                {
                    // Inside the miter limit
                    //---------------------
                    AddVertex(vc, xi, yi);
                    miter_limit_exceeded = false;
                }
                intersection_failed = false;
            }
            else
            {
                // Calculation of the intersection failed, most probably
                // the three points lie one straight line.
                // First check if v0 and v2 lie on the opposite sides of vector:
                // (v1.x, v1.y) -> (v1.x+dx1, v1.y-dy1), that is, the perpendicular
                // to the line determined by vertices v0 and v1.
                // This condition determines whether the next line segments continues
                // the previous one or goes back.
                //----------------
                T x2 = v1.X.Add(dx1);
                T y2 = v1.Y.Subtract(dy1);
                if ((MathUtil.CrossProduct(v0.X, v0.Y, v1.X, v1.Y, x2, y2).LessThan(0.0)) ==
                    (MathUtil.CrossProduct(v1.X, v1.Y, v2.X, v2.Y, x2, y2).LessThan(0.0)))
                {
                    // This case means that the next segment continues
                    // the previous one (straight line)
                    //-----------------
                    AddVertex(vc, v1.X.Add(dx1), v1.Y.Subtract(dy1));
                    miter_limit_exceeded = false;
                }
            }

            if (miter_limit_exceeded)
            {
                // Miter limit exceeded
                //------------------------
                switch (lj)
                {
                case LineJoin.MiterJoinRevert:
                    // For the compatibility with SVG, PDF, etc,
                    // we use a simple bevel join instead of
                    // "smart" bevel
                    //-------------------
                    AddVertex(vc, v1.X.Add(dx1), v1.Y.Subtract(dy1));
                    AddVertex(vc, v1.X.Add(dx2), v1.Y.Subtract(dy2));
                    break;

                case LineJoin.MiterJoinRound:
                    CalcArc(vc, v1.X, v1.Y, dx1, dy1.Negative(), dx2, dy2.Negative());
                    break;

                default:
                    // If no miter-revert, calculate new dx1, dy1, dx2, dy2
                    //----------------
                    if (intersection_failed)
                    {
                        mlimit.MultiplyEquals(m_width_sign);
                        AddVertex(vc, v1.X.Add(dx1).Add(dy1.Multiply(mlimit)),
                                  v1.Y.Subtract(dy1).Add(dx1.Multiply(mlimit)));
                        AddVertex(vc, v1.X.Add(dx2).Subtract(dy2.Multiply(mlimit)),
                                  v1.Y.Subtract(dy2).Subtract(dx2.Multiply(mlimit)));
                    }
                    else
                    {
                        T x1 = v1.X.Add(dx1);
                        T y1 = v1.Y.Subtract(dy1);
                        T x2 = v1.X.Add(dx2);
                        T y2 = v1.Y.Subtract(dy2);
                        di = lim.Subtract(dbevel).Divide(di.Subtract(dbevel));
                        AddVertex(vc, x1.Add(xi.Subtract(x1).Multiply(di)),
                                  y1.Add(yi.Subtract(y1).Multiply(di)));
                        AddVertex(vc, x2.Add(xi.Subtract(x2).Multiply(di)),
                                  y2.Add(yi.Subtract(y2).Multiply(di)));
                    }
                    break;
                }
            }
        }
Ejemplo n.º 18
0
        void CalculateMiter(IVertexDest vc,
						VertexDistance v0,
						VertexDistance v1,
						VertexDistance v2,
						double dx1, double dy1,
						double dx2, double dy2,
						ELineJoin lj,
						double mlimit,
						double dbevel)
        {
            double xi = v1.x;
            double yi = v1.y;
            double di = 1;
            double lim = m_width_abs * mlimit;
            bool miter_limit_exceeded = true; // Assume the worst
            bool intersection_failed = true; // Assume the worst

            if (PictorMath.CalculateIntersection(v0.x + dx1, v0.y - dy1,
                                 v1.x + dx1, v1.y - dy1,
                                 v1.x + dx2, v1.y - dy2,
                                 v2.x + dx2, v2.y - dy2,
                                 out xi, out yi))
            {
                // Calculation of the intersection succeeded
                //---------------------
                di = PictorMath.CalculateDistance(v1.x, v1.y, xi, yi);
                if (di <= lim)
                {
                    // Inside the miter limit
                    //---------------------
                    AddVertex(vc, xi, yi);
                    miter_limit_exceeded = false;
                }
                intersection_failed = false;
            }
            else
            {
                // Calculation of the intersection failed, most probably
                // the three points lie one straight Line.
                // First check if v0 and v2 lie on the opposite sides of vector:
                // (v1.x, v1.y) -> (v1.x+dx1, v1.y-dy1), that is, the perpendicular
                // to the Line determined by vertices v0 and v1.
                // This condition determines whether the next Line segments continues
                // the previous one or goes back.
                //----------------
                double x2 = v1.x + dx1;
                double y2 = v1.y - dy1;
                if ((PictorMath.CrossProduct(v0.x, v0.y, v1.x, v1.y, x2, y2) < 0.0) ==
                   (PictorMath.CrossProduct(v1.x, v1.y, v2.x, v2.y, x2, y2) < 0.0))
                {
                    // This case means that the next segment continues
                    // the previous one (straight Line)
                    //-----------------
                    AddVertex(vc, v1.x + dx1, v1.y - dy1);
                    miter_limit_exceeded = false;
                }
            }

            if (miter_limit_exceeded)
            {
                // Miter limit exceeded
                //------------------------
                switch (lj)
                {
                    case ELineJoin.miter_join_revert:
                        // For the compatibility with SVG, PDF, etc,
                        // we use a simple bevel join instead of
                        // "smart" bevel
                        //-------------------
                        AddVertex(vc, v1.x + dx1, v1.y - dy1);
                        AddVertex(vc, v1.x + dx2, v1.y - dy2);
                        break;

                    case ELineJoin.miter_join_round:
                        CalculateArc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2);
                        break;

                    default:
                        // If no miter-revert, Calculate new dx1, dy1, dx2, dy2
                        //----------------
                        if (intersection_failed)
                        {
                            mlimit *= m_width_sign;
                            AddVertex(vc, v1.x + dx1 + dy1 * mlimit,
                                           v1.y - dy1 + dx1 * mlimit);
                            AddVertex(vc, v1.x + dx2 - dy2 * mlimit,
                                           v1.y - dy2 - dx2 * mlimit);
                        }
                        else
                        {
                            double x1 = v1.x + dx1;
                            double y1 = v1.y - dy1;
                            double x2 = v1.x + dx2;
                            double y2 = v1.y - dy2;
                            di = (lim - dbevel) / (di - dbevel);
                            AddVertex(vc, x1 + (xi - x1) * di,
                                           y1 + (yi - y1) * di);
                            AddVertex(vc, x2 + (xi - x2) * di,
                                           y2 + (yi - y2) * di);
                        }
                        break;
                }
            }
        }
Ejemplo n.º 19
0
 public void CalculateJoin(IVertexDest vc, vertex_dist v0, vertex_dist v1, vertex_dist v2, double len1, double len2)
 {
     _innerstroke.calc_join(vc, v0, v1, v2, len1, len2);
 }