public static void Arc(Cairo.Context context, PointF p, double r, double a1, double a2, bool clockwise, Color color, bool filled, double width = 1.0) { context.Save(); context.Translate(p.X, p.Y); if (!filled) { context.LineWidth = width; context.LineCap = Cairo.LineCap.Butt; context.LineJoin = Cairo.LineJoin.Bevel; } var c = color.ToCairo(); context.SetSourceRGBA(c.R, c.G, c.B, c.A); if (clockwise) { context.Arc(0, 0, r, a1, a2); } else { context.ArcNegative(0, 0, r, a1, a2); } if (filled) { context.Fill(); } else { context.Stroke(); } context.Restore(); }
private void DrawArcSegment(double xm1, double ym1, double xm2, double ym2, double xr, double yr, double alpha, bool isLargeArc, SweepDirection direction) { if (xr <= 0.000000001 || yr <= 0.000000001) { return; } var x1 = xm1 * Math.Cos(-alpha) - ym1 * Math.Sin(-alpha); var y1 = xm1 * Math.Sin(-alpha) + ym1 * Math.Cos(-alpha); var x2 = xm2 * Math.Cos(-alpha) - ym2 * Math.Sin(-alpha); var y2 = xm2 * Math.Sin(-alpha) + ym2 * Math.Cos(-alpha); var r = 0.0; if (xr > yr) { y1 = y1 * xr / yr; y2 = y2 * xr / yr; r = xr; } else { x1 = x1 * yr / xr; x2 = x2 * yr / xr; r = yr; } if (4 * r * r < (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)) { return; } var xc1 = 0.0; var xc2 = 0.0; var yc1 = 0.0; var yc2 = 0.0; if (Math.Abs(y1 - y2) > 0.000000001) { var A = (x1 - x2) / (y2 - y1); var B = (x2 * x2 - x1 * x1 + y2 * y2 - y1 * y1) / (2 * (y2 - y1)); var a = A * A + 1; var b = -2 * x1 + 2 * A * B - 2 * A * y1; var c = x1 * x1 + B * B - 2 * B * y1 + y1 * y1 - r * r; xc1 = (-b + Math.Sqrt(b * b - 4 * a * c)) / (2 * a); yc1 = A * xc1 + B; xc2 = (-b - Math.Sqrt(b * b - 4 * a * c)) / (2 * a); yc2 = A * xc2 + B; } else { xc1 = (x1 + x2) / 2; yc1 = y1 + Math.Sqrt(r * r - (xc1 - x1) * (xc1 - x1)); xc2 = (x1 + x2) / 2; yc2 = y1 - Math.Sqrt(r * r - (xc2 - x1) * (xc2 - x1)); } var angle1 = Math.Abs(y1 - yc1) / r > 1 ? Math.PI / 2 : Math.Asin(Math.Abs(y1 - yc1) / r); if ((x1 < xc1) && (y1 >= yc1)) { angle1 = Math.PI - angle1; } if (y1 < yc1) { if (x1 < xc1) { angle1 = Math.PI + angle1; } else { angle1 = -angle1; } } var angle2 = Math.Abs(y2 - yc1) / r > 1 ? Math.PI / 2 : Math.Asin(Math.Abs(y2 - yc1) / r); if ((x2 < xc1) && (y2 >= yc1)) { angle2 = Math.PI - angle2; } if (y2 < yc1) { if (x2 < xc1) { angle2 = Math.PI + angle2; } else { angle2 = -angle2; } } var alfa1 = Math.Abs(y1 - yc2) / r > 1 ? Math.PI / 2 : Math.Asin(Math.Abs(y1 - yc2) / r); if ((x1 < xc2) && (y1 >= yc2)) { alfa1 = Math.PI - alfa1; } if (y1 < yc2) { if (x1 < xc2) { alfa1 = Math.PI + alfa1; } else { alfa1 = -alfa1; } } var alfa2 = Math.Abs(y2 - yc2) / r > 1 ? Math.PI / 2 : Math.Asin(Math.Abs(y2 - yc2) / r); if ((x2 < xc2) && (y2 >= yc2)) { alfa2 = Math.PI - alfa2; } if (y2 < yc2) { if (x2 < xc2) { alfa2 = Math.PI + alfa2; } else { alfa2 = -alfa2; } } cr.Save(); cr.Rotate(alpha); if (xr > yr) { cr.Scale(1, yr / xr); } else { cr.Scale(xr / yr, 1); } if (direction == SweepDirection.Clockwise) { if (isLargeArc) { if ((y1 < y2) || ((Math.Abs(y1 - y2) < 0.00000001) && (x1 > x2))) { cr.Arc(xc1, yc1, r, angle1, angle2); } else { cr.Arc(xc2, yc2, r, alfa1, alfa2); } } else { if ((y1 > y2) || ((Math.Abs(y1 - y2) < 0.00000001) && (x1 < x2))) { cr.Arc(xc1, yc1, r, angle1, angle2); } else { cr.Arc(xc2, yc2, r, alfa1, alfa2); } } } else { if (isLargeArc) { if ((y1 > y2) || ((Math.Abs(y1 - y2) < 0.00000001) && (x1 < x2))) { cr.ArcNegative(xc1, yc1, r, angle1, angle2); } else { cr.ArcNegative(xc2, yc2, r, alfa1, alfa2); } } else { if ((y1 < y2) || ((Math.Abs(y1 - y2) < 0.00000001) && (x1 > x2))) { cr.ArcNegative(xc1, yc1, r, angle1, angle2); } else { cr.ArcNegative(xc2, yc2, r, alfa1, alfa2); } } } cr.Restore(); }