/// <summary> /// Initializes a new instance of the <see cref="XLinearGradientBrush"/> class. /// </summary> public XLinearGradientBrush(XPoint point1, XPoint point2, XColor color1, XColor color2) : base(color1, color2) { _point1 = point1; _point2 = point2; }
/// <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)); }
/// <summary> /// Returns the intersection of a rectangle and a point. /// </summary> public static XRect Union(XRect rect, XPoint point) { rect.Union(new XRect(point, point)); return(rect); }
/// <summary> /// Initializes a new instance of the XRect class. /// </summary> public XRect(XPoint point, XVector vector) : this(point, point + vector) { }
/// <summary> /// Appends a Bézier segment from a curve. /// </summary> public static BezierSegment CreateCurveSegment(XPoint pt0, XPoint pt1, XPoint pt2, XPoint pt3, double tension3) { #if !SILVERLIGHT && !NETFX_CORE return(new BezierSegment( new SysPoint(pt1.X + tension3 * (pt2.X - pt0.X), pt1.Y + tension3 * (pt2.Y - pt0.Y)), new SysPoint(pt2.X - tension3 * (pt3.X - pt1.X), pt2.Y - tension3 * (pt3.Y - pt1.Y)), new SysPoint(pt2.X, pt2.Y), true)); #else BezierSegment bezierSegment = new BezierSegment(); bezierSegment.Point1 = new SysPoint(pt1.X + tension3 * (pt2.X - pt0.X), pt1.Y + tension3 * (pt2.Y - pt0.Y)); bezierSegment.Point2 = new SysPoint(pt2.X - tension3 * (pt3.X - pt1.X), pt2.Y - tension3 * (pt3.Y - pt1.Y)); bezierSegment.Point3 = new SysPoint(pt2.X, pt2.Y); return(bezierSegment); #endif }
/// <summary> /// Sets current rectangle to the union of the current rectangle and the specified point. /// </summary> public void Union(XPoint point) { Union(new XRect(point, point)); }
/// <summary> /// Indicates whether the specified points are equal. /// </summary> public static bool Equals(XPoint point1, XPoint point2) { return(point1.X.Equals(point2.X) && point1.Y.Equals(point2.Y)); }
// ----- AddString ---------------------------------------------------------------------------- /// <summary> /// Adds a text string to this path. /// </summary> public void AddString(string s, XFontFamily family, XFontStyle style, double emSize, XPoint origin, XStringFormat format) { try { DiagnosticsHelper.HandleNotImplemented("XGraphicsPath.AddString"); } catch { throw; } }
/// <summary> /// Subtracts a point from a point. /// </summary> public static XVector Subtract(XPoint point1, XPoint point2) { return(new XVector(point1._x - point2._x, point1._y - point2._y)); }
/// <summary> /// Multiplies a point with a matrix. /// </summary> public static XPoint Multiply(XPoint point, XMatrix matrix) { return(matrix.Transform(point)); }
/// <summary> /// Subtracts a vector from a point. /// </summary> public static XPoint Subtract(XPoint point, XVector vector) { return(new XPoint(point._x - vector.X, point._y - vector.Y)); }
/// <summary> /// Adds a point and a vector. /// </summary> public static XPoint Add(XPoint point, XVector vector) { return(new XPoint(point._x + vector.X, point._y + vector.Y)); }
//+------------------------------------------------------------------------------------------------- // // 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); }
// ----- AddBezier ---------------------------------------------------------------------------- /// <summary> /// Adds a cubic Bézier curve to the current figure. /// </summary> public void AddBezier(XPoint pt1, XPoint pt2, XPoint pt3, XPoint pt4) { AddBezier(pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y, pt4.X, pt4.Y); }
/// <summary> /// Indicates whether this instance and a specified point are equal. /// </summary> public bool Equals(XPoint value) { return(Equals(this, value)); }
/// <summary> /// Adds an elliptical arc to the current figure. The arc is specified WPF like. /// </summary> public void AddArc(XPoint point1, XPoint point2, XSize size, double rotationAngle, bool isLargeArg, XSweepDirection sweepDirection) { _corePath.AddArc(point1, point2, size, rotationAngle, isLargeArg, sweepDirection); }
/// <summary> /// Indicates whether the rectangle contains the specified point. /// </summary> public bool Contains(XPoint point) { return(Contains(point.X, point.Y)); }
// ----- AddLine ------------------------------------------------------------------------------ /// <summary> /// Adds a line segment to current figure. /// </summary> public void AddLine(XPoint pt1, XPoint pt2) { AddLine(pt1.X, pt1.Y, pt2.X, pt2.Y); }
GetArcAngle( XPoint startPoint, // Start point XPoint endPoint, // End point bool isLargeArc, // Choose the larger of the 2 possible arcs if TRUE //SweepDirection sweepDirection, // Direction n which to sweep the arc. bool isClockwise, out double cosArcAngle, // Cosine of a the sweep angle of one arc piece out double sinArcAngle, // Sine of a the sweep angle of one arc piece out int pieces) // Out: The number of pieces { double angle; // The points are on the unit circle, so: cosArcAngle = startPoint.X * endPoint.X + startPoint.Y * endPoint.Y; sinArcAngle = startPoint.X * endPoint.Y - startPoint.Y * endPoint.X; if (cosArcAngle >= 0) { if (isLargeArc) { // The angle is between 270 and 360 degrees, so pieces = 4; } else { // The angle is between 0 and 90 degrees, so pieces = 1; return; // We already have the cosine and sine of the angle } } else { if (isLargeArc) { // The angle is between 180 and 270 degrees, so pieces = 3; } else { // The angle is between 90 and 180 degrees, so pieces = 2; } } // We have to chop the arc into the computed number of pieces. For cPieces=2 and 4 we could // have uses the half-angle trig formulas, but for pieces=3 it requires solving a cubic // equation; the performance difference is not worth the extra code, so we'll get the angle, // divide it, and get its sine and cosine. Debug.Assert(pieces > 0); angle = Math.Atan2(sinArcAngle, cosArcAngle); if (isClockwise) { if (angle < 0) { angle += Math.PI * 2; } } else { if (angle > 0) { angle -= Math.PI * 2; } } angle /= pieces; cosArcAngle = Math.Cos(angle); sinArcAngle = Math.Sin(angle); }