Beispiel #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="EllipseGeometry"/> class.
        /// </summary>
        /// <param name="rect">The rectangle that the ellipse should fill.</param>
        public EllipseGeometry(Rect rect)
        {
            IPlatformRenderInterface factory = PerspexLocator.Current.GetService <IPlatformRenderInterface>();
            IStreamGeometryImpl      impl    = factory.CreateStreamGeometry();

            using (IStreamGeometryContextImpl ctx = impl.Open())
            {
                double controlPointRatio = (Math.Sqrt(2) - 1) * 4 / 3;
                var    center            = rect.Center;
                var    radius            = new Vector(rect.Width / 2, rect.Height / 2);

                var x0 = center.X - radius.X;
                var x1 = center.X - (radius.X * controlPointRatio);
                var x2 = center.X;
                var x3 = center.X + (radius.X * controlPointRatio);
                var x4 = center.X + radius.X;

                var y0 = center.Y - radius.Y;
                var y1 = center.Y - (radius.Y * controlPointRatio);
                var y2 = center.Y;
                var y3 = center.Y + (radius.Y * controlPointRatio);
                var y4 = center.Y + radius.Y;

                ctx.BeginFigure(new Point(x2, y0), true);
                ctx.BezierTo(new Point(x3, y0), new Point(x4, y1), new Point(x4, y2));
                ctx.BezierTo(new Point(x4, y3), new Point(x3, y4), new Point(x2, y4));
                ctx.BezierTo(new Point(x1, y4), new Point(x0, y3), new Point(x0, y2));
                ctx.BezierTo(new Point(x0, y1), new Point(x1, y0), new Point(x2, y0));
                ctx.EndFigure(true);
            }

            PlatformImpl = impl;
        }
Beispiel #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="LineGeometry"/> class.
        /// </summary>
        /// <param name="startPoint">The start point.</param>
        /// <param name="endPoint">The end point.</param>
        public LineGeometry(Point startPoint, Point endPoint)
        {
            _startPoint = startPoint;
            _endPoint   = endPoint;
            IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService <IPlatformRenderInterface>();
            IStreamGeometryImpl      impl    = factory.CreateStreamGeometry();

            using (IStreamGeometryContextImpl context = impl.Open())
            {
                context.BeginFigure(_startPoint, false);
                context.LineTo(_endPoint);
                context.EndFigure(false);
            }

            PlatformImpl = impl;
        }
Beispiel #3
0
        public RectangleGeometry(Rect rect)
        {
            IPlatformRenderInterface factory = Locator.Current.GetService <IPlatformRenderInterface>();
            IStreamGeometryImpl      impl    = factory.CreateStreamGeometry();

            using (IStreamGeometryContextImpl context = impl.Open())
            {
                context.BeginFigure(rect.TopLeft, true);
                context.LineTo(rect.TopRight);
                context.LineTo(rect.BottomRight);
                context.LineTo(rect.BottomLeft);
                context.EndFigure(true);
            }

            this.PlatformImpl = impl;
        }
Beispiel #4
0
        public PolylineGeometry(IList <Point> points, bool isFilled)
        {
            _points   = points;
            _isFilled = isFilled;
            IPlatformRenderInterface factory = PerspexLocator.Current.GetService <IPlatformRenderInterface>();
            IStreamGeometryImpl      impl    = factory.CreateStreamGeometry();

            using (IStreamGeometryContextImpl context = impl.Open())
            {
                if (points.Count > 0)
                {
                    context.BeginFigure(points[0], isFilled);
                    for (int i = 1; i < points.Count; i++)
                    {
                        context.LineTo(points[i]);
                    }
                    context.EndFigure(isFilled);
                }
            }

            PlatformImpl = impl;
        }
 public static void QuadTo(IStreamGeometryContextImpl context, Point current, Point controlPoint, Point endPoint)
 {
     //(s, (s + 2c)/ 3, (e + 2c)/ 3, e)
     context.BezierTo((current + 2*controlPoint)/3, (endPoint + 2*controlPoint)/3, endPoint);
 }
Beispiel #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="StreamGeometryContext"/> class.
 /// </summary>
 /// <param name="impl">The platform-specific implementation.</param>
 public StreamGeometryContext(IStreamGeometryContextImpl impl)
 {
     _impl = impl;
 }
Beispiel #7
0
            /// <summary>
            /// Builds the arc outline using given StreamGeometryContext
            /// </summary>
            /// <param name="path">A StreamGeometryContext to output the path commands to</param>
            /// <param name="degree">degree of the Bezier curve to use</param>
            /// <param name="threshold">acceptable error</param>
            /// <param name="openNewFigure">if true, a new figure will be started in the specified StreamGeometryContext</param>
            public void BuildArc(IStreamGeometryContextImpl path, int degree, double threshold, bool openNewFigure)
            {
                if (degree < 1 || degree > _maxDegree)
                    throw new ArgumentException($"degree should be between {1} and {_maxDegree}", nameof(degree));

                // find the number of Bezier curves needed
                bool found = false;
                int n = 1;
                double dEta;
                double etaB;
                while (!found && n < 1024)
                {
                    dEta = (Eta2 - Eta1) / n;
                    if (dEta <= 0.5 * Math.PI)
                    {
                        etaB = Eta1;
                        found = true;
                        for (int i = 0; found && i < n; ++i)
                        {
                            double etaA = etaB;
                            etaB += dEta;
                            found = EstimateError(degree, etaA, etaB) <= threshold;
                        }
                    }
                    n = n << 1;
                }
                dEta = (Eta2 - Eta1) / n;
                etaB = Eta1;
                double cosEtaB = Math.Cos(etaB);
                double sinEtaB = Math.Sin(etaB);
                double aCosEtaB = A * cosEtaB;
                double bSinEtaB = B * sinEtaB;
                double aSinEtaB = A * sinEtaB;
                double bCosEtaB = B * cosEtaB;
                double xB = Cx + aCosEtaB * _cosTheta - bSinEtaB * _sinTheta;
                double yB = Cy + aCosEtaB * _sinTheta + bSinEtaB * _cosTheta;
                double xBDot = -aSinEtaB * _cosTheta - bCosEtaB * _sinTheta;
                double yBDot = -aSinEtaB * _sinTheta + bCosEtaB * _cosTheta;

                /*
                  This controls the drawing in case of pies
                if (openNewFigure)
                {
                    if (IsPieSlice)
                    {
                        path.BeginFigure(new Point(Cx, Cy), false, false);
                        path.LineTo(new Point(xB, yB), true, true);
                    }
                    else
                    {
                        path.BeginFigure(new Point(xB, yB), false, false);
                    }
                }
                else
                {
                    //path.LineTo(new Point(xB, yB), true, true);
                }
                */

                //otherwise we're supposed to be already at the (xB,yB)

                double t = Math.Tan(0.5 * dEta);
                double alpha = Math.Sin(dEta) * (Math.Sqrt(4 + 3 * t * t) - 1) / 3;
                for (int i = 0; i < n; ++i)
                {
                    //double etaA = etaB;
                    double xA = xB;
                    double yA = yB;
                    double xADot = xBDot;
                    double yADot = yBDot;
                    etaB += dEta;
                    cosEtaB = Math.Cos(etaB);
                    sinEtaB = Math.Sin(etaB);
                    aCosEtaB = A * cosEtaB;
                    bSinEtaB = B * sinEtaB;
                    aSinEtaB = A * sinEtaB;
                    bCosEtaB = B * cosEtaB;
                    xB = Cx + aCosEtaB * _cosTheta - bSinEtaB * _sinTheta;
                    yB = Cy + aCosEtaB * _sinTheta + bSinEtaB * _cosTheta;
                    xBDot = -aSinEtaB * _cosTheta - bCosEtaB * _sinTheta;
                    yBDot = -aSinEtaB * _sinTheta + bCosEtaB * _cosTheta;
                    if (degree == 1)
                    {
                        path.LineTo(new Point(xB, yB));
                    }
                    else if (degree == 2)
                    {
                        double k = (yBDot * (xB - xA) - xBDot * (yB - yA)) / (xADot * yBDot - yADot * xBDot);
                        path.QuadTo(new Point(xA + k * xADot, yA + k * yADot), new Point(xB, yB));
                    }
                    else
                    {
                        path.BezierTo(
                            new Point(xA + alpha * xADot, yA + alpha * yADot),
                            new Point(xB - alpha * xBDot, yB - alpha * yBDot),
                            new Point(xB, yB)
                            );
                    }
                }
                if (IsPieSlice)
                {
                    path.LineTo(new Point(Cx, Cy));
                }
            }
Beispiel #8
0
 /// <summary>
 /// Builds the arc outline using given StreamGeometryContext and default (max) Bezier curve degree and acceptable error of half a pixel (0.5)
 /// </summary>
 /// <param name="path">A StreamGeometryContext to output the path commands to</param>
 public void BuildArc(IStreamGeometryContextImpl path)
 {
     BuildArc(path, _maxDegree, _defaultFlatness, true);
 }
Beispiel #9
0
 public static void ArcTo(IStreamGeometryContextImpl streamGeometryContextImpl, Point currentPoint, Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection)
 {
     EllipticalArc.BuildArc(streamGeometryContextImpl, currentPoint, point, size, rotationAngle*Math.PI/180,
         isLargeArc,
         sweepDirection == SweepDirection.Clockwise);
 }
Beispiel #10
0
            /// <summary>
            /// ArcTo Helper for StreamGeometryContext
            /// </summary>
            /// <param name="path">Target path</param>
            /// <param name="p1">Start point</param>
            /// <param name="p2">End point</param>
            /// <param name="size">Ellipse radii</param>
            /// <param name="theta">Ellipse theta (angle measured from the abscissa)</param>
            /// <param name="isLargeArc">Large Arc Indicator</param>
            /// <param name="clockwise">Clockwise direction flag</param>
            public static void BuildArc(IStreamGeometryContextImpl path, Point p1, Point p2, Size size, double theta, bool isLargeArc, bool clockwise)
            {

                // var orthogonalizer = new RotateTransform(-theta);
                var orth = new SimpleMatrix(Math.Cos(theta), Math.Sin(theta), -Math.Sin(theta), Math.Cos(theta));
                var rest = new SimpleMatrix(Math.Cos(theta), -Math.Sin(theta), Math.Sin(theta), Math.Cos(theta));

                // var restorer = orthogonalizer.Inverse;
                // if(restorer == null) throw new InvalidOperationException("Can't get a restorer!");

                Point p1S = orth * (new Point((p1.X - p2.X) / 2, (p1.Y - p2.Y) / 2));

                double rx = size.Width;
                double ry = size.Height;
                double rx2 = rx * rx;
                double ry2 = ry * ry;
                double y1S2 = p1S.Y * p1S.Y;
                double x1S2 = p1S.X * p1S.X;

                double numerator = rx2*ry2 - rx2*y1S2 - ry2*x1S2;
                double denominator = rx2*y1S2 + ry2*x1S2;

                if (Math.Abs(denominator) < 1e-8)
                {
                    path.LineTo(p2);
                    return;
                }
                if ((numerator / denominator) < 0)
                {
                    double lambda = x1S2/rx2 + y1S2/ry2;
                    double lambdaSqrt = Math.Sqrt(lambda);
                    if (lambda > 1)
                    {
                        rx *= lambdaSqrt;
                        ry *= lambdaSqrt;
                        rx2 = rx*rx;
                        ry2 = ry*ry;
                        numerator = rx2 * ry2 - rx2 * y1S2 - ry2 * x1S2;
                        if (numerator < 0)
                            numerator = 0;

                        denominator = rx2 * y1S2 + ry2 * x1S2;
                    }

                }

                double multiplier = Math.Sqrt(numerator / denominator);
                Point mulVec = new Point(rx * p1S.Y / ry, -ry * p1S.X / rx);

                int sign = (clockwise != isLargeArc) ? 1 : -1;

                Point cs = new Point(mulVec.X * multiplier * sign, mulVec.Y * multiplier * sign);

                Vector translation = new Vector((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);

                Point c = rest * (cs) + translation;

                // See "http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter" to understand
                // how the ellipse center is calculated 


                // from here, W3C recommendations from the above link make less sense than Darth Vader pouring
                // some sea water in a water filter while standing in the water confused 

                // Therefore, we are on our own with our task of finding out lambda1 and lambda2
                // matching our points p1 and p2.

                // Fortunately it is not so difficult now, when we already know the ellipse centre.

                // We eliminate the offset, making our ellipse zero-centered, then we eliminate the theta,
                // making its Y and X axes the same as global axes. Then we can easily get our angles using
                // good old school formula for angles between vectors.

                // We should remember that this class expects true angles, and not the t-values for ellipse equation.
                // To understand how t-values are obtained, one should see Etas calculation in the constructor code.

                var p1NoOffset = orth * (p1-c);
                var p2NoOffset = orth * (p2-c);

                // if the arc is drawn clockwise, we swap start and end points
                var revisedP1 = clockwise ? p1NoOffset : p2NoOffset;
                var revisedP2 = clockwise ? p2NoOffset : p1NoOffset;


                var thetaStart = GetAngle(new Vector(1, 0), revisedP1);
                var thetaEnd = GetAngle(new Vector(1, 0), revisedP2);


                // Uncomment this to draw a pie
                // path.LineTo(c, true, true);
                // path.LineTo(clockwise ? p1 : p2, true,true);

                path.LineTo(clockwise ? p1 : p2);
                var arc = new EllipticalArc(c.X, c.Y, rx, ry, theta, thetaStart, thetaEnd, false);
                arc.BuildArc(path, arc._maxDegree, arc._defaultFlatness, false);

                //uncomment this to draw a pie
                //path.LineTo(c, true, true);
            }
Beispiel #11
0
 public static void QuadraticBezierTo(IStreamGeometryContextImpl context, Point current, Point controlPoint, Point endPoint)
 {
     //(s, (s + 2c)/ 3, (e + 2c)/ 3, e)
     context.CubicBezierTo((current + 2 * controlPoint) / 3, (endPoint + 2 * controlPoint) / 3, endPoint);
 }