1
/* This is potentially great stuff, but fails against the test
2
program at the end. This would probably be much more
3
efficent than the implementation currently in gd.c if the
4
errors in the output were corrected. TBB */
11
/* Courtesy of F J Franklin. */
13
static gdPoint gdArcClosest (int width, int height, int angle);
16
gdImageFilledEllipse (gdImagePtr im, int cx, int cy, int width, int height, int color)
18
gdImageFilledArc (im, cx, cy, width, height, 0, 360, color, gdChord);
22
gdImageFilledArc (gdImagePtr im, int cx, int cy, int width, int height, int s, int e, int color, int style)
55
long lx2; /* x * 2 (line) */
56
long ly2; /* y * 2 (line) */
58
long ws; /* (a * 2)^2 */
59
long hs; /* (b * 2)^2 */
61
long whs; /* (a * 2)^2 * (b * 2)^2 */
63
long g; /* decision variable */
64
long lg; /* decision variable (line) */
66
width = (width & 1) ? (width + 1) : (width);
67
height = (height & 1) ? (height + 1) : (height);
102
/* I'm assuming a chord-rule at the moment. Need to add origin to get a
103
* pie-rule, but will need to set chord-rule before recursion...
106
for (i = 0; i < 4; i++)
108
if ((s < (i + 1) * 90) && (e > (i + 1) * 90))
110
gdImageFilledArc (im, cx, cy, width, height, s, (i + 1) * 90, color, gdChord);
111
pt[0] = gdArcClosest (width, height, s);
114
pt[1].x = cx + axis_pt[(i + 1) & 3].x;
115
pt[1].y = cy + axis_pt[(i + 1) & 3].y;
116
if (e <= (i + 2) * 90)
118
gdImageFilledArc (im, cx, cy, width, height, (i + 1) * 90, e, color, gdChord);
119
pt[2] = gdArcClosest (width, height, e);
122
if (style == gdChord)
124
gdImageFilledPolygon (im, pt, 3, color);
125
gdImagePolygon (im, pt, 3, color);
127
else if (style == gdPie)
131
gdImageFilledPolygon (im, pt, 4, color);
132
gdImagePolygon (im, pt, 4, color);
137
gdImageFilledArc (im, cx, cy, width, height, (i + 1) * 90, (i + 2) * 90, color, gdChord);
138
pt[2].x = cx + axis_pt[(i + 2) & 3].x;
139
pt[2].y = cy + axis_pt[(i + 2) & 3].y;
140
if (e <= (i + 3) * 90)
142
gdImageFilledArc (im, cx, cy, width, height, (i + 2) * 90, e, color, gdChord);
143
pt[3] = gdArcClosest (width, height, e);
146
if (style == gdChord)
148
gdImageFilledPolygon (im, pt, 4, color);
149
gdImagePolygon (im, pt, 4, color);
151
else if (style == gdPie)
155
gdImageFilledPolygon (im, pt, 5, color);
156
gdImagePolygon (im, pt, 5, color);
161
gdImageFilledArc (im, cx, cy, width, height, (i + 2) * 90, (i + 3) * 90, color, gdChord);
162
pt[3].x = cx + axis_pt[(i + 3) & 3].x;
163
pt[3].y = cy + axis_pt[(i + 3) & 3].y;
164
if (e <= (i + 4) * 90)
166
gdImageFilledArc (im, cx, cy, width, height, (i + 3) * 90, e, color, gdChord);
167
pt[4] = gdArcClosest (width, height, e);
170
if (style == gdChord)
172
gdImageFilledPolygon (im, pt, 5, color);
173
gdImagePolygon (im, pt, 5, color);
175
else if (style == gdPie)
179
gdImageFilledPolygon (im, pt, 6, color);
180
gdImagePolygon (im, pt, 6, color);
185
gdImageFilledArc (im, cx, cy, width, height, (i + 3) * 90, (i + 4) * 90, color, gdChord);
186
pt[4].x = cx + axis_pt[(i + 4) & 3].x;
187
pt[4].y = cy + axis_pt[(i + 4) & 3].y;
189
gdImageFilledArc (im, cx, cy, width, height, (i + 4) * 90, e, color, gdChord);
190
pt[5] = gdArcClosest (width, height, e);
193
if (style == gdChord)
195
gdImageFilledPolygon (im, pt, 6, color);
196
gdImagePolygon (im, pt, 6, color);
198
else if (style == gdPie)
202
gdImageFilledPolygon (im, pt, 7, color);
203
gdImagePolygon (im, pt, 7, color);
212
/* At this point we have only arcs that lies within a quadrant -
213
* map this to first quadrant...
216
if ((s >= 90) && (e <= 180))
223
if ((s >= 180) && (e <= 270))
230
if ((s >= 270) && (e <= 360))
241
s_cos = (long) ((double) 32768);
245
s_sin = (long) ((double) 32768 * sin ((double) s * M_PI / (double) 180));
246
s_cos = (long) ((double) 32768 * cos ((double) s * M_PI / (double) 180));
250
e_sin = (long) ((double) 32768);
255
e_sin = (long) ((double) 32768 * sin ((double) e * M_PI / (double) 180));
256
e_cos = (long) ((double) 32768 * cos ((double) e * M_PI / (double) 180));
266
while ((ws > 32768) || (hs > 32768))
268
ws = (ws + 1) / 2; /* Unfortunate limitations on integers makes */
269
hs = (hs + 1) / 2; /* drawing large ellipses problematic... */
272
while ((ws * hs) > (0x04000000L / whs))
295
y2 = 0; /* Starting point is exactly on ellipse */
298
g = g * g * hs + 4 * ws - whs;
300
while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */
303
g += ws * 4 * (y2 + 1);
305
if (g > 0) /* Need to drop */
311
if ((have_s == 0) && ((s_sin * x2) <= (y2 * s_cos)))
313
pt[0].x = (int) (x2 / 2);
314
pt[0].y = (int) (y2 / 2);
318
if ((have_e == 0) && ((e_sin * x2) <= (y2 * e_cos)))
320
pt[2].x = (int) (x2 / 2);
321
pt[2].y = (int) (y2 / 2);
325
pt[1].x = (int) (x2 / 2);
326
pt[1].y = (int) (y2 / 2);
329
y2 = h; /* Starting point is exactly on ellipse */
332
g = g * g * ws + 4 * hs - whs;
334
while ((x2 * hs) < (y2 * ws))
337
g += hs * 4 * (x2 + 1);
339
if (g > 0) /* Need to drop */
345
if ((have_s == 0) && ((s_sin * x2) >= (y2 * s_cos)))
347
pt[0].x = (int) (x2 / 2);
348
pt[0].y = (int) (y2 / 2);
352
if ((have_e == 0) && ((e_sin * x2) >= (y2 * e_cos)))
354
pt[2].x = (int) (x2 / 2);
355
pt[2].y = (int) (y2 / 2);
360
if ((have_s == 0) || (have_e == 0))
361
return; /* Bizarre case */
369
pt[0].x = cx + (flip_x ? (-pt[0].x) : pt[0].x);
370
pt[0].y = cy + (flip_y ? (-pt[0].y) : pt[0].y);
373
pt[2].x = cx + (flip_x ? (-pt[2].x) : pt[2].x);
374
pt[2].y = cy + (flip_y ? (-pt[2].y) : pt[2].y);
375
gdImageFilledPolygon (im, pt, 3, color);
376
gdImagePolygon (im, pt, 3, color);
383
if (((s_cos * hs) > (s_sin * ws)) && ((e_cos * hs) < (e_sin * ws)))
384
{ /* the points are on different parts of the curve...
385
* this is too tricky to try to handle, so divide and conquer:
391
pt[0].x = cx + (flip_x ? (-pt[0].x) : pt[0].x);
392
pt[0].y = cy + (flip_y ? (-pt[0].y) : pt[0].y);
393
pt[1].x = cx + (flip_x ? (-pt[1].x) : pt[1].x);
394
pt[1].y = cy + (flip_y ? (-pt[1].y) : pt[1].y);
395
pt[2].x = cx + (flip_x ? (-pt[2].x) : pt[2].x);
396
pt[2].y = cy + (flip_y ? (-pt[2].y) : pt[2].y);
397
gdImageFilledPolygon (im, pt, 3, color);
398
gdImagePolygon (im, pt, 3, color);
406
if (conquer || (((s_cos * hs) > (s_sin * ws)) && ((e_cos * hs) > (e_sin * ws))))
407
{ /* This is the best bit... */
408
/* steep line + ellipse */
409
/* go up & left from pt[0] to pt[2] */
412
y2 = 0; /* Starting point is exactly on ellipse */
415
g = g * g * hs + 4 * ws - whs;
417
while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */
419
if ((s_sin * x2) <= (y2 * s_cos))
423
g += ws * 4 * (y2 + 1);
425
if (g > 0) /* Need to drop */
435
lg = lx2 * (pt[0].y - pt[2].y) - ly2 * (pt[0].x - pt[2].x);
436
lg = (lx2 - 1) * (pt[0].y - pt[2].y) - (ly2 + 2) * (pt[0].x - pt[2].x) - lg;
438
while (y2 < (2 * pt[2].y))
441
g += ws * 4 * (y2 + 1);
443
if (g > 0) /* Need to drop */
450
lg -= 2 * (pt[0].x - pt[2].x);
452
if (lg < 0) /* Need to drop */
455
lg -= 2 * (pt[0].y - pt[2].y);
459
for (x = (int) (lx2 / 2); x <= (int) (x2 / 2); x++)
461
gdImageSetPixel (im, ((flip_x) ? (cx - x) : (cx + x)),
462
((flip_y) ? (cy - y) : (cy + y)), color);
471
if (conquer || (((s_cos * hs) < (s_sin * ws)) && ((e_cos * hs) < (e_sin * ws))))
472
{ /* This is the best bit... */
473
/* gradual line + ellipse */
474
/* go down & right from pt[2] to pt[0] */
477
y2 = h; /* Starting point is exactly on ellipse */
480
g = g * g * ws + 4 * hs - whs;
482
while ((x2 * hs) < (y2 * ws))
485
g += hs * 4 * (x2 + 1);
487
if (g > 0) /* Need to drop */
493
if ((e_sin * x2) >= (y2 * e_cos))
500
lg = lx2 * (pt[0].y - pt[2].y) - ly2 * (pt[0].x - pt[2].x);
501
lg = (lx2 + 2) * (pt[0].y - pt[2].y) - (ly2 - 1) * (pt[0].x - pt[2].x) - lg;
503
while (x2 < (2 * pt[0].x))
506
g += hs * 4 * (x2 + 1);
508
if (g > 0) /* Need to drop */
515
lg += 2 * (pt[0].y - pt[2].y);
517
if (lg < 0) /* Need to drop */
520
lg += 2 * (pt[0].x - pt[2].x);
524
for (y = (int) (ly2 / 2); y <= (int) (y2 / 2); y++)
526
gdImageSetPixel (im, ((flip_x) ? (cx - x) : (cx + x)),
527
((flip_y) ? (cy - y) : (cy + y)), color);
534
gdArcClosest (int width, int height, int angle)
550
long ws; /* (a * 2)^2 */
551
long hs; /* (b * 2)^2 */
553
long whs; /* (a * 2)^2 * (b * 2)^2 */
555
long g; /* decision variable */
557
w = (long) ((width & 1) ? (width + 1) : (width));
558
h = (long) ((height & 1) ? (height + 1) : (height));
593
if ((angle > 90) && (angle < 180))
598
if ((angle > 180) && (angle < 270))
604
if ((angle > 270) && (angle < 360))
610
a_sin = (long) ((double) 32768 * sin ((double) angle * M_PI / (double) 180));
611
a_cos = (long) ((double) 32768 * cos ((double) angle * M_PI / (double) 180));
617
while ((ws > 32768) || (hs > 32768))
619
ws = (ws + 1) / 2; /* Unfortunate limitations on integers makes */
620
hs = (hs + 1) / 2; /* drawing large ellipses problematic... */
623
while ((ws * hs) > (0x04000000L / whs))
631
if ((a_cos * hs) > (a_sin * ws))
634
y2 = 0; /* Starting point is exactly on ellipse */
637
g = g * g * hs + 4 * ws - whs;
639
while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */
642
g += ws * 4 * (y2 + 1);
644
if (g > 0) /* Need to drop */
650
if ((a_sin * x2) <= (y2 * a_cos))
652
pt.x = (int) (x2 / 2);
653
pt.y = (int) (y2 / 2);
661
y2 = h; /* Starting point is exactly on ellipse */
664
g = g * g * ws + 4 * hs - whs;
666
while ((x2 * hs) < (y2 * ws))
669
g += hs * 4 * (x2 + 1);
671
if (g > 0) /* Need to drop */
677
if ((a_sin * x2) >= (y2 * a_cos))
679
pt.x = (int) (x2 / 2);
680
pt.y = (int) (y2 / 2);
702
main (int argc, char *argv[])
704
gdImagePtr im = gdImageCreate (WIDTH, HEIGHT);
705
int white = gdImageColorResolve (im, 0xFF, 0xFF, 0xFF), black = gdImageColorResolve (im, 0, 0, 0),
706
red = gdImageColorResolve (im, 0xFF, 0xA0, 0xA0);
709
/* filled arc - circle */
710
gdImageFilledArc (im, WIDTH / 5, HEIGHT / 4, 200, 200, 45, 90, red, gdPie);
711
gdImageArc (im, WIDTH / 5, HEIGHT / 4, 200, 200, 45, 90, black);
713
/* filled arc - ellipse */
714
gdImageFilledArc (im, WIDTH / 2, HEIGHT / 4, 200, 150, 45, 90, red, gdPie);
715
gdImageArc (im, WIDTH / 2, HEIGHT / 4, 200, 150, 45, 90, black);
718
/* reference lines */
719
gdImageLine (im, 0, HEIGHT / 4, WIDTH, HEIGHT / 4, black);
720
gdImageLine (im, WIDTH / 5, 0, WIDTH / 5, HEIGHT, black);
721
gdImageLine (im, WIDTH / 2, 0, WIDTH / 2, HEIGHT, black);
722
gdImageLine (im, WIDTH / 2, HEIGHT / 4, WIDTH / 2 + 300, HEIGHT / 4 + 300, black);
723
gdImageLine (im, WIDTH / 5, HEIGHT / 4, WIDTH / 5 + 300, HEIGHT / 4 + 300, black);
725
/* TBB: Write img to test/arctest.png */
726
out = fopen ("test/arctest.png", "wb");
729
fprintf (stderr, "Can't create test/arctest.png\n");
732
gdImagePng (im, out);
734
fprintf (stderr, "Test image written to test/arctest.png\n");