示例#1
0
        //+------------------------------------------------------------------------------------------------- 
        //
        //  Function: ArcToBezier 
        //
        //  Synopsis: Compute the Bezier approximation of an arc
        //
        //  Notes:    This utilitycomputes the Bezier approximation for an elliptical arc as it is defined 
        //            in the SVG arc spec. The ellipse from which the arc is carved is axis-aligned in its
        //            own coordinates, and defined there by its x and y radii. The rotation angle defines 
        //            how the ellipse's axes are rotated relative to our x axis. The start and end points 
        //            define one of 4 possible arcs; the sweep and large-arc flags determine which one of
        //            these arcs will be chosen. See SVG spec for details. 
        //
        //            Returning pieces = 0 indicates a line instead of an arc
        //                      pieces = -1 indicates that the arc degenerates to a point
        // 
        //--------------------------------------------------------------------------------------------------
        public static PointCollection ArcToBezier(double xStart, double yStart, double xRadius, double yRadius, double rotationAngle,
            bool isLargeArc, bool isClockwise, double xEnd, double yEnd, out int pieces)
        {
            double cosArcAngle, sinArcAngle, xCenter, yCenter, r, bezDist;
            XVector vecToBez1, vecToBez2;
            XMatrix matToEllipse;

            double fuzz2 = FUZZ * FUZZ;
            bool isZeroCenter = false;

            pieces = -1;

            // In the following, the line segment between between the arc's start and
            // end points is referred to as "the chord".

            // Transform 1: Shift the origin to the chord's midpoint 
            double x = (xEnd - xStart) / 2;
            double y = (yEnd - yStart) / 2;

            double halfChord2 = x * x + y * y;     // (half chord length)^2

            // Degenerate case: single point
            if (halfChord2 < fuzz2)
            {
                // The chord degeneartes to a point, the arc will be ignored 
                return null;
            }

            // Degenerate case: straight line
            if (!AcceptRadius(halfChord2, fuzz2, ref xRadius) || !AcceptRadius(halfChord2, fuzz2, ref yRadius))
            {
                // We have a zero radius, add a straight line segment instead of an arc
                pieces = 0;
                return null;
            }

            if (xRadius == 0 || yRadius == 0)
            {
                // We have a zero radius, add a straight line segment instead of an arc
                pieces = 0;
                return null;
            }

            // Transform 2: Rotate to the ellipse's coordinate system
            rotationAngle = -rotationAngle * Calc.Deg2Rad;

            double cos = Math.Cos(rotationAngle);
            double sin = Math.Sin(rotationAngle);

            r = x * cos - y * sin;
            y = x * sin + y * cos;
            x = r;

            // Transform 3: Scale so that the ellipse will become a unit circle 
            x /= xRadius;
            y /= yRadius;

            // We get to the center of that circle along a verctor perpendicular to the chord 
            // from the origin, which is the chord's midpoint. By Pythagoras, the length of that
            // vector is sqrt(1 - (half chord)^2). 

            halfChord2 = x * x + y * y;   // now in the circle coordinates

            if (halfChord2 > 1)
            {
                // The chord is longer than the circle's diameter; we scale the radii uniformly so
                // that the chord will be a diameter. The center will then be the chord's midpoint, 
                // which is now the origin.
                r = Math.Sqrt(halfChord2);
                xRadius *= r;
                yRadius *= r;
                xCenter = yCenter = 0;
                isZeroCenter = true;

                // Adjust the unit-circle coordinates x and y
                x /= r;
                y /= r;
            }
            else
            {
                // The length of (-y,x) or (x,-y) is sqrt(rHalfChord2), and we want a vector 
                // of length sqrt(1 - rHalfChord2), so we'll multiply it by:
                r = Math.Sqrt((1 - halfChord2) / halfChord2);
                //if (isLargeArc != (eSweepDirection == SweepDirection.Clockwise))
                if (isLargeArc != isClockwise)
                // Going to the center from the origin=chord-midpoint 
                {
                    // in the direction of (-y, x) 
                    xCenter = -r * y;
                    yCenter = r * x;
                }
                else
                {
                    // in the direction of (y, -x)
                    xCenter = r * y;
                    yCenter = -r * x;
                }
            }

            // Transformation 4: shift the origin to the center of the circle, which then becomes 
            // the unit circle. Since the chord's midpoint is the origin, the start point is (-x, -y)
            // and the endpoint is (x, y).
            XPoint ptStart = new XPoint(-x - xCenter, -y - yCenter);
            XPoint ptEnd = new XPoint(x - xCenter, y - yCenter);

            // Set up the matrix that will take us back to our coordinate system.  This matrix is 
            // the inverse of the combination of transformation 1 thru 4. 
            matToEllipse = new XMatrix(cos * xRadius, -sin * xRadius,
                                      sin * yRadius, cos * yRadius,
                                      (xEnd + xStart) / 2, (yEnd + yStart) / 2);

            if (!isZeroCenter)
            {
                // Prepend the translation that will take the origin to the circle's center
                matToEllipse.OffsetX += (matToEllipse.M11 * xCenter + matToEllipse.M21 * yCenter);
                matToEllipse.OffsetY += (matToEllipse.M12 * xCenter + matToEllipse.M22 * yCenter);
            }

            // Get the sine & cosine of the angle that will generate the arc pieces
            GetArcAngle(ptStart, ptEnd, isLargeArc, isClockwise, out cosArcAngle, out sinArcAngle, out pieces);

            // Get the vector to the first Bezier control point 
            bezDist = GetBezierDistance(cosArcAngle, 1);

            //if (eSweepDirection == SweepDirection.Counterclockwise)
            if (!isClockwise)
                bezDist = -bezDist;

            vecToBez1 = new XVector(-bezDist * ptStart.Y, bezDist * ptStart.X);

            PointCollection result = new PointCollection();

            // Add the arc pieces, except for the last 
            for (int idx = 1; idx < pieces; idx++)
            {
                // Get the arc piece's endpoint
                XPoint ptPieceEnd = new XPoint(ptStart.X * cosArcAngle - ptStart.Y * sinArcAngle, ptStart.X * sinArcAngle + ptStart.Y * cosArcAngle);
                vecToBez2 = new XVector(-bezDist * ptPieceEnd.Y, bezDist * ptPieceEnd.X);

                result.Add(matToEllipse.Transform(ptStart + vecToBez1));
                result.Add(matToEllipse.Transform(ptPieceEnd - vecToBez2));
                result.Add(matToEllipse.Transform(ptPieceEnd));

                // Move on to the next arc
                ptStart = ptPieceEnd;
                vecToBez1 = vecToBez2;
            }

            // Last arc - we know the endpoint 
            vecToBez2 = new XVector(-bezDist * ptEnd.Y, bezDist * ptEnd.X);

            result.Add(matToEllipse.Transform(ptStart + vecToBez1));
            result.Add(matToEllipse.Transform(ptEnd - vecToBez2));
            result.Add(new XPoint(xEnd, yEnd));

            return result;
        }
示例#2
0
 /// <summary>
 /// Multiplies a point with a matrix.
 /// </summary>
 public static XPoint Multiply(XPoint point, XMatrix matrix)
 {
   return matrix.Transform(point);
 }
示例#3
0
        /// <summary>
        /// Appends a Bézier curve for an arc within a full quadrant.
        /// </summary>
        static void AppendPartialArcQuadrant(List<XPoint> points, double x, double y, double width, double height, double α, double β, PathStart pathStart, XMatrix matrix)
        {
            Debug.Assert(α >= 0 && α <= 360);
            Debug.Assert(β >= 0);
            if (β > 360)
                β = β - Math.Floor(β / 360) * 360;
            Debug.Assert(Math.Abs(α - β) <= 90);

            // Scanling factor.
            double δx = width / 2;
            double δy = height / 2;

            // Center of ellipse.
            double x0 = x + δx;
            double y0 = y + δy;

            // We have the following quarters:
            //     |
            //   2 | 3
            // ----+-----
            //   1 | 0
            //     |
            // If the angles lie in quarter 2 or 3, their values are subtracted by 180 and the
            // resulting curve is reflected at the center. This algorithm works as expected (simply tried out).
            // There may be a mathematically more elegant solution...
            bool reflect = false;
            if (α >= 180 && β >= 180)
            {
                α -= 180;
                β -= 180;
                reflect = true;
            }

            double cosα, cosβ, sinα, sinβ;
            if (width == height)
            {
                // Circular arc needs no correction.
                α = α * Calc.Deg2Rad;
                β = β * Calc.Deg2Rad;
            }
            else
            {
                // Elliptic arc needs the angles to be adjusted such that the scaling transformation is compensated.
                α = α * Calc.Deg2Rad;
                sinα = Math.Sin(α);
                if (Math.Abs(sinα) > 1E-10)
                    α = Math.PI / 2 - Math.Atan(δy * Math.Cos(α) / (δx * sinα));
                β = β * Calc.Deg2Rad;
                sinβ = Math.Sin(β);
                if (Math.Abs(sinβ) > 1E-10)
                    β = Math.PI / 2 - Math.Atan(δy * Math.Cos(β) / (δx * sinβ));
            }

            double κ = 4 * (1 - Math.Cos((α - β) / 2)) / (3 * Math.Sin((β - α) / 2));
            sinα = Math.Sin(α);
            cosα = Math.Cos(α);
            sinβ = Math.Sin(β);
            cosβ = Math.Cos(β);

            //XPoint pt1, pt2, pt3;
            if (!reflect)
            {
                // Calculation for quarter 0 and 1.
                switch (pathStart)
                {
                    case PathStart.MoveTo1st:
                        points.Add(matrix.Transform(new XPoint(x0 + δx * cosα, y0 + δy * sinα)));
                        break;

                    case PathStart.LineTo1st:
                        points.Add(matrix.Transform(new XPoint(x0 + δx * cosα, y0 + δy * sinα)));
                        break;

                    case PathStart.Ignore1st:
                        break;
                }
                points.Add(matrix.Transform(new XPoint(x0 + δx * (cosα - κ * sinα), y0 + δy * (sinα + κ * cosα))));
                points.Add(matrix.Transform(new XPoint(x0 + δx * (cosβ + κ * sinβ), y0 + δy * (sinβ - κ * cosβ))));
                points.Add(matrix.Transform(new XPoint(x0 + δx * cosβ, y0 + δy * sinβ)));
            }
            else
            {
                // Calculation for quarter 2 and 3.
                switch (pathStart)
                {
                    case PathStart.MoveTo1st:
                        points.Add(matrix.Transform(new XPoint(x0 - δx * cosα, y0 - δy * sinα)));
                        break;

                    case PathStart.LineTo1st:
                        points.Add(matrix.Transform(new XPoint(x0 - δx * cosα, y0 - δy * sinα)));
                        break;

                    case PathStart.Ignore1st:
                        break;
                }
                points.Add(matrix.Transform(new XPoint(x0 - δx * (cosα - κ * sinα), y0 - δy * (sinα + κ * cosα))));
                points.Add(matrix.Transform(new XPoint(x0 - δx * (cosβ + κ * sinβ), y0 - δy * (sinβ - κ * cosβ))));
                points.Add(matrix.Transform(new XPoint(x0 - δx * cosβ, y0 - δy * sinβ)));
            }
        }
示例#4
0
        /// <summary>
        /// Creates between 1 and 5 Béziers curves from parameters specified like in WPF.
        /// </summary>
        public static List<XPoint> BezierCurveFromArc(XPoint point1, XPoint point2, XSize size,
            double rotationAngle, bool isLargeArc, bool clockwise, PathStart pathStart)
        {
            // See also http://www.charlespetzold.com/blog/blog.xml from January 2, 2008: 
            // http://www.charlespetzold.com/blog/2008/01/Mathematics-of-ArcSegment.html
            double δx = size.Width;
            double δy = size.Height;
            Debug.Assert(δx * δy > 0);
            double factor = δy / δx;
            bool isCounterclockwise = !clockwise;

            // Adjust for different radii and rotation angle.
            XMatrix matrix = new XMatrix();
            matrix.RotateAppend(-rotationAngle);
            matrix.ScaleAppend(δy / δx, 1);
            XPoint pt1 = matrix.Transform(point1);
            XPoint pt2 = matrix.Transform(point2);

            // Get info about chord that connects both points.
            XPoint midPoint = new XPoint((pt1.X + pt2.X) / 2, (pt1.Y + pt2.Y) / 2);
            XVector vect = pt2 - pt1;
            double halfChord = vect.Length / 2;

            // Get vector from chord to center.
            XVector vectRotated;

            // (comparing two Booleans here!)
            if (isLargeArc == isCounterclockwise)
                vectRotated = new XVector(-vect.Y, vect.X);
            else
                vectRotated = new XVector(vect.Y, -vect.X);

            vectRotated.Normalize();

            // Distance from chord to center.
            double centerDistance = Math.Sqrt(δy * δy - halfChord * halfChord);
            if (double.IsNaN(centerDistance))
                centerDistance = 0;

            // Calculate center point.
            XPoint center = midPoint + centerDistance * vectRotated;

            // Get angles from center to the two points.
            double α = Math.Atan2(pt1.Y - center.Y, pt1.X - center.X);
            double β = Math.Atan2(pt2.Y - center.Y, pt2.X - center.X);

            // (another comparison of two Booleans!)
            if (isLargeArc == (Math.Abs(β - α) < Math.PI))
            {
                if (α < β)
                    α += 2 * Math.PI;
                else
                    β += 2 * Math.PI;
            }

            // Invert matrix for final point calculation.
            matrix.Invert();
            double sweepAngle = β - α;

            // Let the algorithm of GDI+ DrawArc to Bézier curves do the rest of the job
            return BezierCurveFromArc(center.X - δx * factor, center.Y - δy, 2 * δx * factor, 2 * δy,
              α / Calc.Deg2Rad, sweepAngle / Calc.Deg2Rad, pathStart, ref matrix);
        }
示例#5
0
 internal static void TransformRect(ref XRect rect, ref XMatrix matrix)
 {
   if (!rect.IsEmpty)
   {
     XMatrixTypes types = matrix.type;
     if (types != XMatrixTypes.Identity)
     {
       if ((types & XMatrixTypes.Scaling) != XMatrixTypes.Identity)
       {
         rect.x *= matrix.m11;
         rect.y *= matrix.m22;
         rect.width *= matrix.m11;
         rect.height *= matrix.m22;
         if (rect.width < 0)
         {
           rect.x += rect.width;
           rect.width = -rect.width;
         }
         if (rect.height < 0)
         {
           rect.y += rect.height;
           rect.height = -rect.height;
         }
       }
       if ((types & XMatrixTypes.Translation) != XMatrixTypes.Identity)
       {
         rect.x += matrix.offsetX;
         rect.y += matrix.offsetY;
       }
       if (types == XMatrixTypes.Unknown)
       {
         XPoint point = matrix.Transform(rect.TopLeft);
         XPoint point2 = matrix.Transform(rect.TopRight);
         XPoint point3 = matrix.Transform(rect.BottomRight);
         XPoint point4 = matrix.Transform(rect.BottomLeft);
         rect.x = Math.Min(Math.Min(point.X, point2.X), Math.Min(point3.X, point4.X));
         rect.y = Math.Min(Math.Min(point.Y, point2.Y), Math.Min(point3.Y, point4.Y));
         rect.width = Math.Max(Math.Max(point.X, point2.X), Math.Max(point3.X, point4.X)) - rect.x;
         rect.height = Math.Max(Math.Max(point.Y, point2.Y), Math.Max(point3.Y, point4.Y)) - rect.y;
       }
     }
   }
 }
示例#6
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="gfx"></param>
        /// <param name="line"></param>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        /// <param name="db"></param>
        /// <param name="r"></param>
        public void Draw(object gfx, Kaliber3D.Render.XLine line, double dx, double dy, ImmutableArray<Kaliber3D.Render.ShapeProperty> db, Kaliber3D.Render.Record r)
        {
            if (!line.IsStroked)
                return;

            var _gfx = gfx as XGraphics;

            XPen strokeLine = ToXPen(line.Style, _scaleToPage);

            XSolidBrush fillStartArrow = ToXSolidBrush(line.Style.StartArrowStyle.Fill);
            XPen strokeStartArrow = ToXPen(line.Style.StartArrowStyle, _scaleToPage);

            XSolidBrush fillEndArrow = ToXSolidBrush(line.Style.EndArrowStyle.Fill);
            XPen strokeEndArrow = ToXPen(line.Style.EndArrowStyle, _scaleToPage);

            double _x1 = line.Start.X + dx;
            double _y1 = line.Start.Y + dy;
            double _x2 = line.End.X + dx;
            double _y2 = line.End.Y + dy;

            Kaliber3D.Render.XLine.SetMaxLength(line, ref _x1, ref _y1, ref _x2, ref _y2);

            double x1 = _scaleToPage(_x1);
            double y1 = _scaleToPage(_y1);
            double x2 = _scaleToPage(_x2);
            double y2 = _scaleToPage(_y2);

            var sas = line.Style.StartArrowStyle;
            var eas = line.Style.EndArrowStyle;
            double a1 = Math.Atan2(y1 - y2, x1 - x2) * 180.0 / Math.PI;
            double a2 = Math.Atan2(y2 - y1, x2 - x1) * 180.0 / Math.PI;

            var t1 = new XMatrix();
            var c1 = new XPoint(x1, y1);
            t1.RotateAtPrepend(a1, c1);

            var t2 = new XMatrix();
            var c2 = new XPoint(x2, y2);
            t2.RotateAtPrepend(a2, c2);

            XPoint pt1;
            XPoint pt2;

            double radiusX1 = sas.RadiusX;
            double radiusY1 = sas.RadiusY;
            double sizeX1 = 2.0 * radiusX1;
            double sizeY1 = 2.0 * radiusY1;

            switch (sas.ArrowType)
            {
                default:
                case Kaliber3D.Render.ArrowType.None:
                    {
                        pt1 = new XPoint(x1, y1);
                    }
                    break;
                case Kaliber3D.Render.ArrowType.Rectangle:
                    {
                        pt1 = t1.Transform(new XPoint(x1 - sizeX1, y1));
                        var rect = new XRect(x1 - sizeX1, y1 - radiusY1, sizeX1, sizeY1);
                        _gfx.Save();
                        _gfx.RotateAtTransform(a1, c1);
                        DrawRectangleInternal(_gfx, fillStartArrow, strokeStartArrow, sas.IsStroked, sas.IsFilled, ref rect);
                        _gfx.Restore();
                    }
                    break;
                case Kaliber3D.Render.ArrowType.Ellipse:
                    {
                        pt1 = t1.Transform(new XPoint(x1 - sizeX1, y1));
                        _gfx.Save();
                        _gfx.RotateAtTransform(a1, c1);
                        var rect = new XRect(x1 - sizeX1, y1 - radiusY1, sizeX1, sizeY1);
                        DrawEllipseInternal(_gfx, fillStartArrow, strokeStartArrow, sas.IsStroked, sas.IsFilled, ref rect);
                        _gfx.Restore();
                    }
                    break;
                case Kaliber3D.Render.ArrowType.Arrow:
                    {
                        pt1 = t1.Transform(new XPoint(x1, y1));
                        var p11 = t1.Transform(new XPoint(x1 - sizeX1, y1 + sizeY1));
                        var p21 = t1.Transform(new XPoint(x1, y1));
                        var p12 = t1.Transform(new XPoint(x1 - sizeX1, y1 - sizeY1));
                        var p22 = t1.Transform(new XPoint(x1, y1));
                        DrawLineInternal(_gfx, strokeStartArrow, sas.IsStroked, ref p11, ref p21);
                        DrawLineInternal(_gfx, strokeStartArrow, sas.IsStroked, ref p12, ref p22);
                    }
                    break;
            }

            double radiusX2 = eas.RadiusX;
            double radiusY2 = eas.RadiusY;
            double sizeX2 = 2.0 * radiusX2;
            double sizeY2 = 2.0 * radiusY2;

            switch (eas.ArrowType)
            {
                default:
                case Kaliber3D.Render.ArrowType.None:
                    {
                        pt2 = new XPoint(x2, y2);
                    }
                    break;
                case Kaliber3D.Render.ArrowType.Rectangle:
                    {
                        pt2 = t2.Transform(new XPoint(x2 - sizeX2, y2));
                        var rect = new XRect(x2 - sizeX2, y2 - radiusY2, sizeX2, sizeY2);
                        _gfx.Save();
                        _gfx.RotateAtTransform(a2, c2);
                        DrawRectangleInternal(_gfx, fillEndArrow, strokeEndArrow, eas.IsStroked, eas.IsFilled, ref rect);
                        _gfx.Restore();
                    }
                    break;
                case Kaliber3D.Render.ArrowType.Ellipse:
                    {
                        pt2 = t2.Transform(new XPoint(x2 - sizeX2, y2));
                        _gfx.Save();
                        _gfx.RotateAtTransform(a2, c2);
                        var rect = new XRect(x2 - sizeX2, y2 - radiusY2, sizeX2, sizeY2);
                        DrawEllipseInternal(_gfx, fillEndArrow, strokeEndArrow, eas.IsStroked, eas.IsFilled, ref rect);
                        _gfx.Restore();
                    }
                    break;
                case Kaliber3D.Render.ArrowType.Arrow:
                    {
                        pt2 = t2.Transform(new XPoint(x2, y2));
                        var p11 = t2.Transform(new XPoint(x2 - sizeX2, y2 + sizeY2));
                        var p21 = t2.Transform(new XPoint(x2, y2));
                        var p12 = t2.Transform(new XPoint(x2 - sizeX2, y2 - sizeY2));
                        var p22 = t2.Transform(new XPoint(x2, y2));
                        DrawLineInternal(_gfx, strokeEndArrow, eas.IsStroked, ref p11, ref p21);
                        DrawLineInternal(_gfx, strokeEndArrow, eas.IsStroked, ref p12, ref p22);
                    }
                    break;
            }

            _gfx.DrawLine(strokeLine, pt1, pt2);
        }
示例#7
0
 public static XVector Multiply(XVector vector, XMatrix matrix)
 {
   return matrix.Transform(vector);
 }
示例#8
0
        private static XPoint DrawLineArrowInternal(XGraphics gfx, XPen pen, XSolidBrush brush, double x, double y, double angle, Core2D.Style.ArrowStyle style)
        {
            XPoint pt;
            var rt = new XMatrix();
            var c = new XPoint(x, y);
            rt.RotateAtPrepend(angle, c);
            double rx = style.RadiusX;
            double ry = style.RadiusY;
            double sx = 2.0 * rx;
            double sy = 2.0 * ry;

            switch (style.ArrowType)
            {
                default:
                case Core2D.Style.ArrowType.None:
                    {
                        pt = new XPoint(x, y);
                    }
                    break;
                case Core2D.Style.ArrowType.Rectangle:
                    {
                        pt = rt.Transform(new XPoint(x - sx, y));
                        var rect = new XRect(x - sx, y - ry, sx, sy);
                        gfx.Save();
                        gfx.RotateAtTransform(angle, c);
                        DrawRectangleInternal(gfx, brush, pen, style.IsStroked, style.IsFilled, ref rect);
                        gfx.Restore();
                    }
                    break;
                case Core2D.Style.ArrowType.Ellipse:
                    {
                        pt = rt.Transform(new XPoint(x - sx, y));
                        gfx.Save();
                        gfx.RotateAtTransform(angle, c);
                        var rect = new XRect(x - sx, y - ry, sx, sy);
                        DrawEllipseInternal(gfx, brush, pen, style.IsStroked, style.IsFilled, ref rect);
                        gfx.Restore();
                    }
                    break;
                case Core2D.Style.ArrowType.Arrow:
                    {
                        pt = rt.Transform(new XPoint(x, y));
                        var p11 = rt.Transform(new XPoint(x - sx, y + sy));
                        var p21 = rt.Transform(new XPoint(x, y));
                        var p12 = rt.Transform(new XPoint(x - sx, y - sy));
                        var p22 = rt.Transform(new XPoint(x, y));
                        DrawLineInternal(gfx, pen, style.IsStroked, ref p11, ref p21);
                        DrawLineInternal(gfx, pen, style.IsStroked, ref p12, ref p22);
                    }
                    break;
            }

            return pt;
        }
示例#9
0
    void AddCapToPath(Path path, PathFigure figure, double length, double lineWidthHalf, LineCap lineCap, XMatrix matrix)
    {
      // sketch:
      // 1. create Transform that make a horizontal line with start in 0,0
      // 2. create a Polygon with the shape of the line including its caps
      // 3. render the shape with the brush of the pen
      //PolyLineSegment seg;
      switch (lineCap)
      {
        case LineCap.Flat:
          matrix.Transform(new XPoint(length + lineWidthHalf, -lineWidthHalf));
          break;

        case LineCap.Square:
          matrix.Transform(new XPoint(length + lineWidthHalf, -lineWidthHalf));
          break;

        case LineCap.Round:
          break;

        case LineCap.Triangle:
          break;
      }
    }