Re: Circular Ring Gradient
Adrian Johnson <[email protected]>
| Newsgroups | gmane.comp.lib.cairo |
|---|---|
| Message-ID | <[email protected]> |
On 11/05/17 07:20, Adrian Johnson wrote: > On 11/05/17 06:27, [email protected] wrote: >> Hi Cairo folks, >> >> What is the best way to make a circular gradient in a ring? I have tried >> using both a Bezier approximation to a circle and just using trapezoids. >> The trapezoids work fine if I have 16 of them and then clip the ring. A >> little problem with not having continuous values in a ring so if I cut >> the ring at a particular location it has to be at the end of a trapezoid >> section if I want the gradient to fill to the end. Otherwise it looks to >> work well. Think there might be an easier way to do this though so I am >> asking about it. Has anyone had good success drawing circular gradients >> in a ring? I am looking to be able to add some Cairo gradients to a >> gauge widget so efficiency would be a good thing if the gauge needed to >> work with a frame clock. > > Mesh patches can have Bézier curved sides. A circle can be approximated > with 8 Bézier curves. A ring can be created with 8 patches. See attached > example and output. I attached the executable instead of the code. Here is the code. -- cairo mailing list [email protected] https://lists.cairographics.org/mailman/listinfo/cairo
ring_gradient.c
(text/x-csrc, 3.2 KB)
#include <cairo.h>
#include <math.h>
#define WIDTH 300
#define HEIGHT 300
#define CENTER_X 150
#define CENTER_Y 150
#define RADIUS_1 60
#define RADIUS_2 120
static void
sector_patch (cairo_pattern_t *pattern,
double angle_A,
double A_r, double A_g, double A_b,
double angle_B,
double B_r, double B_g, double B_b)
{
double r1_sin_A, r1_cos_A;
double r1_sin_B, r1_cos_B;
double r2_sin_A, r2_cos_A;
double r2_sin_B, r2_cos_B;
double h;
r1_sin_A = RADIUS_1 * sin (angle_A);
r1_cos_A = RADIUS_1 * cos (angle_A);
r1_sin_B = RADIUS_1 * sin (angle_B);
r1_cos_B = RADIUS_1 * cos (angle_B);
r2_sin_A = RADIUS_2 * sin (angle_A);
r2_cos_A = RADIUS_2 * cos (angle_A);
r2_sin_B = RADIUS_2 * sin (angle_B);
r2_cos_B = RADIUS_2 * cos (angle_B);
h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
cairo_mesh_pattern_begin_patch (pattern);
cairo_mesh_pattern_move_to (pattern,
CENTER_X + r1_cos_A,
CENTER_Y + r1_sin_A);
cairo_mesh_pattern_line_to (pattern,
CENTER_X + r2_cos_A,
CENTER_Y + r2_sin_A);
cairo_mesh_pattern_curve_to (pattern,
CENTER_X + r2_cos_A - h * r2_sin_A,
CENTER_Y + r2_sin_A + h * r2_cos_A,
CENTER_X + r2_cos_B + h * r2_sin_B,
CENTER_Y + r2_sin_B - h * r2_cos_B,
CENTER_X + r2_cos_B,
CENTER_Y + r2_sin_B);
cairo_mesh_pattern_line_to (pattern,
CENTER_X + r1_cos_B,
CENTER_Y + r1_sin_B);
cairo_mesh_pattern_curve_to (pattern,
CENTER_X + r1_cos_B + h * r1_sin_B,
CENTER_Y + r1_sin_B - h * r1_cos_B,
CENTER_X + r1_cos_A - h * r1_sin_A,
CENTER_Y + r1_sin_A + h * r1_cos_A,
CENTER_X + r1_cos_A,
CENTER_Y + r1_sin_B);
cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, A_r*0.5, A_g*0.5, A_b*0.5);
cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, A_r, A_g, A_b);
cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, B_r, B_g, B_b);
cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, B_r*0.5, B_g*0.5, B_b*0.5);
cairo_mesh_pattern_end_patch (pattern);
}
static void
draw (cairo_t *cr)
{
cairo_pattern_t *pattern;
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
pattern = cairo_pattern_create_mesh ();
sector_patch (pattern,
0, 1, 0, 0,
M_PI/4, 1, 1, 0);
sector_patch (pattern,
M_PI/4, 1, 1, 0,
M_PI/2, 0, 1, 0);
sector_patch (pattern,
M_PI/2, 0, 1, 0,
3*M_PI/4, 0, 1, 1);
sector_patch (pattern,
3*M_PI/4, 0, 1, 1,
M_PI, 0, 0, 1);
sector_patch (pattern,
-M_PI, 0, 0, 1,
-3*M_PI/4, 1, 1, 0);
sector_patch (pattern,
-3*M_PI/4, 1, 1, 0,
-M_PI/2, 0, 1, 0);
sector_patch (pattern,
-M_PI/2, 0, 1, 0,
-M_PI/4, 0, 1, 1);
sector_patch (pattern,
-M_PI/4, 0, 1, 1,
0, 1, 0, 0);
cairo_set_source (cr, pattern);
cairo_paint (cr);
cairo_pattern_destroy (pattern);
}
int main()
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
cr = cairo_create (surface);
draw (cr);
cairo_destroy (cr);
cairo_surface_write_to_png (surface, "ring_gradient.png");
cairo_surface_destroy (surface);
return 0;
}