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; }
/// <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; }
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; }
/// <summary> /// Draws a line to the specified point. /// </summary> /// <param name="point">The destination point.</param> public void LineTo(Point point) { _impl.LineTo(point); }
/// <summary> /// Draws a line to the specified point. /// </summary> /// <param name="point">The destination point.</param> public void LineTo(Point point) { _impl.LineTo(point); _currentPoint = point; }
/// <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)); } }
/// <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); }