Exemplo n.º 1
0
        /// <summary>
        /// Retrieve an elipse in its center-radius form using parameters from the SVG specification
        /// </summary>
        /// <param name="cur">Current point</param>
        /// <param name="radii">The ellipse radius</param>
        /// <param name="xRotation">The rotation of the ellipse in relation to the x-axis</param>
        /// <param name="largeArc">Wheter the large arc should be selected or not</param>
        /// <param name="sweep">Sweep direction (false for clockwise, true for counterclockwise)</param>
        /// <param name="target">The target point</param>
        /// <returns></returns>
        public static Curve EllipticArc(Double2 cur, Double2 radii, double xRotation, bool largeArc, bool sweep, Double2 target)
        {
            // The algorithm used here is presented on this link: https://svgwg.org/svg2-draft/implnote.html
            var xpun = (cur - target) / 2;
            var xpr  = xpun.Rotate(-xRotation);

            // Guarantee that the radii are positive
            radii.X = Math.Abs(radii.X); radii.Y = Math.Abs(radii.Y);

            // Guarantee that the radius are large enough
            var    rr = radii.X * radii.X * xpr.Y * xpr.Y + radii.Y * radii.Y * xpr.X * xpr.X;
            var    r2 = radii.X * radii.X * radii.Y * radii.Y;
            double skr;

            if (rr > r2)
            {
                radii *= Math.Sqrt(rr / r2);
                skr    = 0;
            }
            else
            {
                skr = Math.Sqrt((r2 - rr) / rr);
            }

            var cpr = new Double2(skr * radii.X * xpr.Y / radii.Y, -skr * radii.Y * xpr.X / radii.X);

            if (largeArc == sweep)
            {
                cpr = -cpr;
            }

            // Calculate the center
            var cpun = cpr.Rotate(xRotation) + (target + cur) / 2;

            // Calculate the angle
            var t1 = Math.Atan2(radii.X * (xpr.Y - cpr.Y), radii.Y * (xpr.X - cpr.X));
            var t2 = Math.Atan2(radii.X * (-xpr.Y - cpr.Y), radii.Y * (-xpr.X - cpr.X));

            var dt = t2 - t1;

            if (!sweep && dt > 0)
            {
                dt -= TwoPi;
            }
            else if (sweep && dt < 0)
            {
                dt += TwoPi;
            }

            return(EllipticArcInternal(cpun, radii, Double2.FromAngle(xRotation), t1, dt));
        }