//======================================================================= //TODO: implement arc to *** /* * public void arc_to(double rx, double ry, * double angle, * bool large_arc_flag, * bool sweep_flag, * double x, double y) * { * if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command())) * { * double epsilon = 1e-30; * double x0 = 0.0; * double y0 = 0.0; * m_vertices.last_vertex(&x0, &y0); * * rx = fabs(rx); * ry = fabs(ry); * * // Ensure radii are valid * //------------------------- * if(rx < epsilon || ry < epsilon) * { * line_to(x, y); * return; * } * * if(calc_distance(x0, y0, x, y) < epsilon) * { * // If the endpoints (x, y) and (x0, y0) are identical, then this * // is equivalent to omitting the elliptical arc segment entirely. * return; * } * bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y); * if(a.radii_ok()) * { * join_path(a); * } * else * { * line_to(x, y); * } * } * else * { * move_to(x, y); * } * } * public void arc_rel(double rx, double ry, * double angle, * bool large_arc_flag, * bool sweep_flag, * double dx, double dy) * { * rel_to_abs(&dx, &dy); * arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy); * } */ //======================================================================= /// <summary> /// approximate arc with curve4, cubic curve /// </summary> /// <param name="r1"></param> /// <param name="r2"></param> /// <param name="xAxisRotation"></param> /// <param name="largeArcFlag"></param> /// <param name="sweepFlags"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="isRelative"></param> public static void SvgArcToCurve4(this PathWriter _writer, float r1, float r2, float xAxisRotation, int largeArcFlag, int sweepFlags, float x, float y, bool isRelative) { using (VectorToolBox.Borrow(out SvgArcSegment svgArc)) { if (isRelative) { svgArc.Set( (float)_writer.CurrentX, (float)_writer.CurrentY, r1, r2, xAxisRotation, (SvgArcSize)largeArcFlag, (SvgArcSweep)sweepFlags, (float)(_writer.CurrentX + x), (float)(_writer.CurrentY + y)); // svgArc.AddToPath(_writer); } else { //approximate with bezier curve svgArc.Set( (float)_writer.CurrentX, (float)_writer.CurrentY, r1, r2, xAxisRotation, (SvgArcSize)largeArcFlag, (SvgArcSweep)sweepFlags, x, y); // svgArc.AddToPath(_writer); } } }
public static void CatmullRomToCurve4Rel(this PathWriter _writer, double dx0, double dy0, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3) { //https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline //relative point double curX = _writer.CurrentX; double curY = _writer.CurrentY; CatmullRomSegmentToCurve4(_writer, curX + dx0, curY + dy0, curX + dx1, curY + dy1, curX + dx2, curY + dy2, curX + dx3, curY + dy3); }
static TempContext <PixelFarm.CpuBlit.PathWriter> Borrow(out PixelFarm.CpuBlit.PathWriter pathWriter) { if (!Temp <PixelFarm.CpuBlit.PathWriter> .IsInit()) { Temp <PixelFarm.CpuBlit.PathWriter> .SetNewHandler( () => new PixelFarm.CpuBlit.PathWriter(), w => w.UnbindVxs()); } return(Temp <PixelFarm.CpuBlit.PathWriter> .Borrow(out pathWriter)); }
public static bool CatmullRomSegmentToCurve4(this PathWriter _writer, double x0, double y0, //p0 //explicit x0 y0 double x1, double y1, //p1 double x2, double y2, //p2 double x3, double y3) //p3 { //just experiment only, //not correct now //https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline //https://stackoverflow.com/questions/30748316/catmull-rom-interpolation-on-svg-paths double t0 = 0.0f, t1 = CatmullRomGetT(t0, x0, y0, x1, y1), t2 = CatmullRomGetT(t1, x1, y1, x2, y2), t3 = CatmullRomGetT(t2, x2, y2, x3, y3); if ((t0 == t1) || (t1 == t2) || (t2 == t3)) { //invalid _writer.LineTo(x1, y1); _writer.LineTo(x2, y2); return(false); } double c1 = (t2 - t1) / (t2 - t0), c2 = (t1 - t0) / (t2 - t0), d1 = (t3 - t2) / (t3 - t1), d2 = (t2 - t1) / (t3 - t1); double m1x = (t2 - t1) * (c1 * (x1 - x0) / (t1 - t0) + c2 * (x2 - x1) / (t2 - t1)); double m2x = (t2 - t1) * (d1 * (x2 - x1) / (t2 - t1) + d2 * (x3 - x2) / (t3 - t2)); double m1y = (t2 - t1) * (c1 * (y1 - y0) / (t1 - t0) + c2 * (y2 - y1) / (t2 - t1)); double m2y = (t2 - t1) * (d1 * (y2 - y1) / (t2 - t1) + d2 * (y3 - y2) / (t3 - t2)); //Q0 = P1 //Q1 = P1 + M1 / 3 //Q2 = P2 - M2 / 3 //Q3 = P2 _writer.LineTo(x1, y1); _writer.Curve4(x1 + m1x / 3, y1 + m1y / 3, x2 - m2x / 3, y2 - m2y / 3, x2, y2); return(true); }
public static void UnsafeDirectGetData( PathWriter pathStore, out int m_allocated_vertices, out int m_num_vertices, out double[] m_coord_xy, out byte[] m_CommandAndFlags) { VertexStore.UnsafeDirectGetData( pathStore.Vxs, out m_allocated_vertices, out m_num_vertices, out m_coord_xy, out m_CommandAndFlags); }
/// <summary> /// Draws a Cardinal spline (cubic) defined by a point collection. /// The cardinal spline passes through each point in the collection. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="points">The points for the curve in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, x3, y3, x4, y4, x1, x2 ..., xn, yn).</param> /// <param name="tension">The tension of the curve defines the shape. Usually between 0 and 1. 0 would be a straight line.</param> /// <param name="color">The color for the spline.</param> public static void DrawCurve(this PathWriter writer, float[] points, float tension) { // First segment SplineCurveSegment(writer, points[0], points[1], points[0], points[1], points[2], points[3], points[4], points[5], tension); // Middle segments int i = 2; for (; i < points.Length - 4; i += 2) { SplineCurveSegment(writer, points[i - 2], points[i - 1], points[i], points[i + 1], points[i + 2], points[i + 3], points[i + 4], points[i + 5], tension); } // Last segment SplineCurveSegment(writer, points[i - 2], points[i - 1], points[i], points[i + 1], points[i + 2], points[i + 3], points[i + 2], points[i + 3], tension); }
public static void Hermite(this PathWriter pw, double[] xyCoords) { Curve4Points curve4_points = pw._c4_points; pw.MoveTo(xyCoords[0], xyCoords[1]); for (int i = 0; i < xyCoords.Length - (4 * 2);) { Curves.HermiteToBezier( xyCoords[i], xyCoords[i + 1], xyCoords[i + 2], xyCoords[i + 3], xyCoords[i + 4], xyCoords[i + 5], xyCoords[i + 6], xyCoords[i + 7], curve4_points ); pw.Curve4(curve4_points.x1, curve4_points.y1, curve4_points.x2, curve4_points.y2, curve4_points.x3, curve4_points.y3 ); i += 2; } }
public static void CatmulRom(this PathWriter pw, double[] xyCoords) { Curve4Points curve4_points = pw._c4_points; pw.MoveTo(xyCoords[2], xyCoords[3]);//*** for (int i = 0; i < xyCoords.Length - (4 * 2);) { Curves.CatromToBezier( xyCoords[i], xyCoords[i + 1], xyCoords[i + 2], xyCoords[i + 3], xyCoords[i + 4], xyCoords[i + 5], xyCoords[i + 6], xyCoords[i + 7], pw._c4_points ); pw.Curve4(curve4_points.x1, curve4_points.y1, curve4_points.x2, curve4_points.y2, curve4_points.x3, curve4_points.y3 ); i += 2; } }
public static TempContext <PathWriter> BorrowPathWriter(VertexStore vxs, out PathWriter pathWriter) => VectorToolBox.Borrow(vxs, out pathWriter);
public static TempContext <PixelFarm.CpuBlit.PathWriter> Borrow(VertexStore vxs, out PixelFarm.CpuBlit.PathWriter pathWriter) { var tmpPw = Borrow(out pathWriter); tmpPw._tool.BindVxs(vxs); return(tmpPw); }
static void SplineCurveSegment( PathWriter writer, double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, float tension) { //from SplineExtensions.cs //MIT, 2009-2015, Rene Schulte and WriteableBitmapEx Contributors, https://github.com/teichgraf/WriteableBitmapEx // // Project: WriteableBitmapEx - WriteableBitmap extensions // Description: Collection of draw spline extension methods for the WriteableBitmap class. // // Changed by: $Author: unknown $ // Changed on: $Date: 2015-03-05 18:18:24 +0100 (Do, 05 Mrz 2015) $ // Changed in: $Revision: 113191 $ // Project: $URL: https://writeablebitmapex.svn.codeplex.com/svn/trunk/Source/WriteableBitmapEx/WriteableBitmapSplineExtensions.cs $ // Id: $Id: WriteableBitmapSplineExtensions.cs 113191 2015-03-05 17:18:24Z unknown $ // // // Copyright © 2009-2015 Rene Schulte and WriteableBitmapEx Contributors // Determine distances between controls points (bounding rect) to find the optimal stepsize double minX = Math.Min(x1, Math.Min(x2, Math.Min(x3, x4))); double minY = Math.Min(y1, Math.Min(y2, Math.Min(y3, y4))); double maxX = Math.Max(x1, Math.Max(x2, Math.Max(x3, x4))); double maxY = Math.Max(y1, Math.Max(y2, Math.Max(y3, y4))); // Get slope double lenx = maxX - minX; double len = maxY - minY; if (lenx > len) { len = lenx; } // Prevent division by zero if (len != 0) { // Init vars double step = STEP_FACTOR / len; double tx1 = x2; double ty1 = y2; // Calculate factors double sx1 = tension * (x3 - x1); double sy1 = tension * (y3 - y1); double sx2 = tension * (x4 - x2); double sy2 = tension * (y4 - y2); double ax = sx1 + sx2 + 2 * x2 - 2 * x3; double ay = sy1 + sy2 + 2 * y2 - 2 * y3; double bx = -2 * sx1 - sx2 - 3 * x2 + 3 * x3; double by = -2 * sy1 - sy2 - 3 * y2 + 3 * y3; // Interpolate writer.LineTo(tx1, ty1); double tx2, ty2; for (double t = step; t <= 1; t += step) { double tSq = t * t; tx2 = (ax * tSq * t + bx * tSq + sx1 * t + x2); ty2 = (ay * tSq * t + by * tSq + sy1 * t + y2); // Draw line // //DrawLine(context, w, h, tx1, ty1, tx2, ty2, color); writer.LineTo(tx2, ty2); tx1 = tx2; ty1 = ty2; } // Prevent rounding gap writer.LineTo(x3, y3); //DrawLine(context, w, h, tx1, ty1, x3, y3, color); } }