Annotation of embedaddon/php/ext/gd/libgd/gd_arc_f_buggy.c, revision 1.1.1.1
1.1 misho 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 */
5:
6: #if 0
7:
8: #include "gd.h"
9: #include <math.h>
10:
11: /* Courtesy of F J Franklin. */
12:
13: static gdPoint gdArcClosest (int width, int height, int angle);
14:
15: void
16: gdImageFilledEllipse (gdImagePtr im, int cx, int cy, int width, int height, int color)
17: {
18: gdImageFilledArc (im, cx, cy, width, height, 0, 360, color, gdChord);
19: }
20:
21: void
22: gdImageFilledArc (gdImagePtr im, int cx, int cy, int width, int height, int s, int e, int color, int style)
23: {
24: gdPoint pt[7];
25: gdPoint axis_pt[4];
26:
27: int angle;
28:
29: int have_s = 0;
30: int have_e = 0;
31:
32: int flip_x = 0;
33: int flip_y = 0;
34:
35: int conquer = 0;
36:
37: int i;
38:
39: int a;
40: int b;
41:
42: int x;
43: int y;
44:
45: long s_sin = 0;
46: long s_cos = 0;
47: long e_sin = 0;
48: long e_cos = 0;
49:
50: long w; /* a * 2 */
51: long h; /* b * 2 */
52:
53: long x2; /* x * 2 */
54: long y2; /* y * 2 */
55: long lx2; /* x * 2 (line) */
56: long ly2; /* y * 2 (line) */
57:
58: long ws; /* (a * 2)^2 */
59: long hs; /* (b * 2)^2 */
60:
61: long whs; /* (a * 2)^2 * (b * 2)^2 */
62:
63: long g; /* decision variable */
64: long lg; /* decision variable (line) */
65:
66: width = (width & 1) ? (width + 1) : (width);
67: height = (height & 1) ? (height + 1) : (height);
68:
69: a = width / 2;
70: b = height / 2;
71:
72: axis_pt[0].x = a;
73: axis_pt[0].y = 0;
74: axis_pt[1].x = 0;
75: axis_pt[1].y = b;
76: axis_pt[2].x = -a;
77: axis_pt[2].y = 0;
78: axis_pt[3].x = 0;
79: axis_pt[3].y = -b;
80:
81: if (s == e)
82: return;
83:
84: if ((e - s) >= 360)
85: {
86: s = 0;
87: e = 0;
88: }
89:
90: while (s < 0)
91: s += 360;
92: while (s >= 360)
93: s -= 360;
94: while (e < 0)
95: e += 360;
96: while (e >= 360)
97: e -= 360;
98:
99: if (e <= s)
100: e += 360;
101:
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...
104: */
105:
106: for (i = 0; i < 4; i++)
107: {
108: if ((s < (i + 1) * 90) && (e > (i + 1) * 90))
109: {
110: gdImageFilledArc (im, cx, cy, width, height, s, (i + 1) * 90, color, gdChord);
111: pt[0] = gdArcClosest (width, height, s);
112: pt[0].x += cx;
113: pt[0].y += cy;
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)
117: {
118: gdImageFilledArc (im, cx, cy, width, height, (i + 1) * 90, e, color, gdChord);
119: pt[2] = gdArcClosest (width, height, e);
120: pt[2].x += cx;
121: pt[2].y += cy;
122: if (style == gdChord)
123: {
124: gdImageFilledPolygon (im, pt, 3, color);
125: gdImagePolygon (im, pt, 3, color);
126: }
127: else if (style == gdPie)
128: {
129: pt[3].x = cx;
130: pt[3].y = cy;
131: gdImageFilledPolygon (im, pt, 4, color);
132: gdImagePolygon (im, pt, 4, color);
133: }
134: }
135: else
136: {
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)
141: {
142: gdImageFilledArc (im, cx, cy, width, height, (i + 2) * 90, e, color, gdChord);
143: pt[3] = gdArcClosest (width, height, e);
144: pt[3].x += cx;
145: pt[3].y += cy;
146: if (style == gdChord)
147: {
148: gdImageFilledPolygon (im, pt, 4, color);
149: gdImagePolygon (im, pt, 4, color);
150: }
151: else if (style == gdPie)
152: {
153: pt[4].x = cx;
154: pt[4].y = cy;
155: gdImageFilledPolygon (im, pt, 5, color);
156: gdImagePolygon (im, pt, 5, color);
157: }
158: }
159: else
160: {
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)
165: {
166: gdImageFilledArc (im, cx, cy, width, height, (i + 3) * 90, e, color, gdChord);
167: pt[4] = gdArcClosest (width, height, e);
168: pt[4].x += cx;
169: pt[4].y += cy;
170: if (style == gdChord)
171: {
172: gdImageFilledPolygon (im, pt, 5, color);
173: gdImagePolygon (im, pt, 5, color);
174: }
175: else if (style == gdPie)
176: {
177: pt[5].x = cx;
178: pt[5].y = cy;
179: gdImageFilledPolygon (im, pt, 6, color);
180: gdImagePolygon (im, pt, 6, color);
181: }
182: }
183: else
184: {
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;
188:
189: gdImageFilledArc (im, cx, cy, width, height, (i + 4) * 90, e, color, gdChord);
190: pt[5] = gdArcClosest (width, height, e);
191: pt[5].x += cx;
192: pt[5].y += cy;
193: if (style == gdChord)
194: {
195: gdImageFilledPolygon (im, pt, 6, color);
196: gdImagePolygon (im, pt, 6, color);
197: }
198: else if (style == gdPie)
199: {
200: pt[6].x = cx;
201: pt[6].y = cy;
202: gdImageFilledPolygon (im, pt, 7, color);
203: gdImagePolygon (im, pt, 7, color);
204: }
205: }
206: }
207: }
208: return;
209: }
210: }
211:
212: /* At this point we have only arcs that lies within a quadrant -
213: * map this to first quadrant...
214: */
215:
216: if ((s >= 90) && (e <= 180))
217: {
218: angle = s;
219: s = 180 - e;
220: e = 180 - angle;
221: flip_x = 1;
222: }
223: if ((s >= 180) && (e <= 270))
224: {
225: s = s - 180;
226: e = e - 180;
227: flip_x = 1;
228: flip_y = 1;
229: }
230: if ((s >= 270) && (e <= 360))
231: {
232: angle = s;
233: s = 360 - e;
234: e = 360 - angle;
235: flip_y = 1;
236: }
237:
238: if (s == 0)
239: {
240: s_sin = 0;
241: s_cos = (long) ((double) 32768);
242: }
243: else
244: {
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));
247: }
248: if (e == 0)
249: {
250: e_sin = (long) ((double) 32768);
251: e_cos = 0;
252: }
253: else
254: {
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));
257: }
258:
259: w = (long) width;
260: h = (long) height;
261:
262: ws = w * w;
263: hs = h * h;
264:
265: whs = 1;
266: while ((ws > 32768) || (hs > 32768))
267: {
268: ws = (ws + 1) / 2; /* Unfortunate limitations on integers makes */
269: hs = (hs + 1) / 2; /* drawing large ellipses problematic... */
270: whs *= 2;
271: }
272: while ((ws * hs) > (0x04000000L / whs))
273: {
274: ws = (ws + 1) / 2;
275: hs = (hs + 1) / 2;
276: whs *= 2;
277: }
278: whs *= ws * hs;
279:
280: pt[0].x = w / 2;
281: pt[0].y = 0;
282:
283: pt[2].x = 0;
284: pt[2].y = h / 2;
285:
286: have_s = 0;
287: have_e = 0;
288:
289: if (s == 0)
290: have_s = 1;
291: if (e == 90)
292: have_e = 1;
293:
294: x2 = w;
295: y2 = 0; /* Starting point is exactly on ellipse */
296:
297: g = x2 - 1;
298: g = g * g * hs + 4 * ws - whs;
299:
300: while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */
301: {
302: y2 += 2;
303: g += ws * 4 * (y2 + 1);
304:
305: if (g > 0) /* Need to drop */
306: {
307: x2 -= 2;
308: g -= hs * 4 * x2;
309: }
310:
311: if ((have_s == 0) && ((s_sin * x2) <= (y2 * s_cos)))
312: {
313: pt[0].x = (int) (x2 / 2);
314: pt[0].y = (int) (y2 / 2);
315: have_s = 1;
316: }
317:
318: if ((have_e == 0) && ((e_sin * x2) <= (y2 * e_cos)))
319: {
320: pt[2].x = (int) (x2 / 2);
321: pt[2].y = (int) (y2 / 2);
322: have_e = 1;
323: }
324: }
325: pt[1].x = (int) (x2 / 2);
326: pt[1].y = (int) (y2 / 2);
327:
328: x2 = 0;
329: y2 = h; /* Starting point is exactly on ellipse */
330:
331: g = y2 - 1;
332: g = g * g * ws + 4 * hs - whs;
333:
334: while ((x2 * hs) < (y2 * ws))
335: {
336: x2 += 2;
337: g += hs * 4 * (x2 + 1);
338:
339: if (g > 0) /* Need to drop */
340: {
341: y2 -= 2;
342: g -= ws * 4 * y2;
343: }
344:
345: if ((have_s == 0) && ((s_sin * x2) >= (y2 * s_cos)))
346: {
347: pt[0].x = (int) (x2 / 2);
348: pt[0].y = (int) (y2 / 2);
349: have_s = 1;
350: }
351:
352: if ((have_e == 0) && ((e_sin * x2) >= (y2 * e_cos)))
353: {
354: pt[2].x = (int) (x2 / 2);
355: pt[2].y = (int) (y2 / 2);
356: have_e = 1;
357: }
358: }
359:
360: if ((have_s == 0) || (have_e == 0))
361: return; /* Bizarre case */
362:
363: if (style == gdPie)
364: {
365: pt[3] = pt[0];
366: pt[4] = pt[1];
367: pt[5] = pt[2];
368:
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);
371: pt[1].x = cx;
372: pt[1].y = cy;
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);
377:
378: pt[0] = pt[3];
379: pt[1] = pt[4];
380: pt[2] = pt[5];
381: }
382:
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:
386: */
387: pt[3] = pt[0];
388: pt[4] = pt[1];
389: pt[5] = pt[2];
390:
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);
399:
400: pt[0] = pt[3];
401: pt[2] = pt[4];
402:
403: conquer = 1;
404: }
405:
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] */
410:
411: x2 = w;
412: y2 = 0; /* Starting point is exactly on ellipse */
413:
414: g = x2 - 1;
415: g = g * g * hs + 4 * ws - whs;
416:
417: while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */
418: {
419: if ((s_sin * x2) <= (y2 * s_cos))
420: break;
421:
422: y2 += 2;
423: g += ws * 4 * (y2 + 1);
424:
425: if (g > 0) /* Need to drop */
426: {
427: x2 -= 2;
428: g -= hs * 4 * x2;
429: }
430: }
431:
432: lx2 = x2;
433: ly2 = y2;
434:
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;
437:
438: while (y2 < (2 * pt[2].y))
439: {
440: y2 += 2;
441: g += ws * 4 * (y2 + 1);
442:
443: if (g > 0) /* Need to drop */
444: {
445: x2 -= 2;
446: g -= hs * 4 * x2;
447: }
448:
449: ly2 += 2;
450: lg -= 2 * (pt[0].x - pt[2].x);
451:
452: if (lg < 0) /* Need to drop */
453: {
454: lx2 -= 2;
455: lg -= 2 * (pt[0].y - pt[2].y);
456: }
457:
458: y = (int) (y2 / 2);
459: for (x = (int) (lx2 / 2); x <= (int) (x2 / 2); x++)
460: {
461: gdImageSetPixel (im, ((flip_x) ? (cx - x) : (cx + x)),
462: ((flip_y) ? (cy - y) : (cy + y)), color);
463: }
464: }
465: }
466: if (conquer)
467: {
468: pt[0] = pt[4];
469: pt[2] = pt[5];
470: }
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] */
475:
476: x2 = 0;
477: y2 = h; /* Starting point is exactly on ellipse */
478:
479: g = y2 - 1;
480: g = g * g * ws + 4 * hs - whs;
481:
482: while ((x2 * hs) < (y2 * ws))
483: {
484: x2 += 2;
485: g += hs * 4 * (x2 + 1);
486:
487: if (g > 0) /* Need to drop */
488: {
489: y2 -= 2;
490: g -= ws * 4 * y2;
491: }
492:
493: if ((e_sin * x2) >= (y2 * e_cos))
494: break;
495: }
496:
497: lx2 = x2;
498: ly2 = y2;
499:
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;
502:
503: while (x2 < (2 * pt[0].x))
504: {
505: x2 += 2;
506: g += hs * 4 * (x2 + 1);
507:
508: if (g > 0) /* Need to drop */
509: {
510: y2 -= 2;
511: g -= ws * 4 * y2;
512: }
513:
514: lx2 += 2;
515: lg += 2 * (pt[0].y - pt[2].y);
516:
517: if (lg < 0) /* Need to drop */
518: {
519: ly2 -= 2;
520: lg += 2 * (pt[0].x - pt[2].x);
521: }
522:
523: x = (int) (x2 / 2);
524: for (y = (int) (ly2 / 2); y <= (int) (y2 / 2); y++)
525: {
526: gdImageSetPixel (im, ((flip_x) ? (cx - x) : (cx + x)),
527: ((flip_y) ? (cy - y) : (cy + y)), color);
528: }
529: }
530: }
531: }
532:
533: static gdPoint
534: gdArcClosest (int width, int height, int angle)
535: {
536: gdPoint pt;
537:
538: int flip_x = 0;
539: int flip_y = 0;
540:
541: long a_sin = 0;
542: long a_cos = 0;
543:
544: long w; /* a * 2 */
545: long h; /* b * 2 */
546:
547: long x2; /* x * 2 */
548: long y2; /* y * 2 */
549:
550: long ws; /* (a * 2)^2 */
551: long hs; /* (b * 2)^2 */
552:
553: long whs; /* (a * 2)^2 * (b * 2)^2 */
554:
555: long g; /* decision variable */
556:
557: w = (long) ((width & 1) ? (width + 1) : (width));
558: h = (long) ((height & 1) ? (height + 1) : (height));
559:
560: while (angle < 0)
561: angle += 360;
562: while (angle >= 360)
563: angle -= 360;
564:
565: if (angle == 0)
566: {
567: pt.x = w / 2;
568: pt.y = 0;
569: return (pt);
570: }
571: if (angle == 90)
572: {
573: pt.x = 0;
574: pt.y = h / 2;
575: return (pt);
576: }
577: if (angle == 180)
578: {
579: pt.x = -w / 2;
580: pt.y = 0;
581: return (pt);
582: }
583: if (angle == 270)
584: {
585: pt.x = 0;
586: pt.y = -h / 2;
587: return (pt);
588: }
589:
590: pt.x = 0;
591: pt.y = 0;
592:
593: if ((angle > 90) && (angle < 180))
594: {
595: angle = 180 - angle;
596: flip_x = 1;
597: }
598: if ((angle > 180) && (angle < 270))
599: {
600: angle = angle - 180;
601: flip_x = 1;
602: flip_y = 1;
603: }
604: if ((angle > 270) && (angle < 360))
605: {
606: angle = 360 - angle;
607: flip_y = 1;
608: }
609:
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));
612:
613: ws = w * w;
614: hs = h * h;
615:
616: whs = 1;
617: while ((ws > 32768) || (hs > 32768))
618: {
619: ws = (ws + 1) / 2; /* Unfortunate limitations on integers makes */
620: hs = (hs + 1) / 2; /* drawing large ellipses problematic... */
621: whs *= 2;
622: }
623: while ((ws * hs) > (0x04000000L / whs))
624: {
625: ws = (ws + 1) / 2;
626: hs = (hs + 1) / 2;
627: whs *= 2;
628: }
629: whs *= ws * hs;
630:
631: if ((a_cos * hs) > (a_sin * ws))
632: {
633: x2 = w;
634: y2 = 0; /* Starting point is exactly on ellipse */
635:
636: g = x2 - 1;
637: g = g * g * hs + 4 * ws - whs;
638:
639: while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */
640: {
641: y2 += 2;
642: g += ws * 4 * (y2 + 1);
643:
644: if (g > 0) /* Need to drop */
645: {
646: x2 -= 2;
647: g -= hs * 4 * x2;
648: }
649:
650: if ((a_sin * x2) <= (y2 * a_cos))
651: {
652: pt.x = (int) (x2 / 2);
653: pt.y = (int) (y2 / 2);
654: break;
655: }
656: }
657: }
658: else
659: {
660: x2 = 0;
661: y2 = h; /* Starting point is exactly on ellipse */
662:
663: g = y2 - 1;
664: g = g * g * ws + 4 * hs - whs;
665:
666: while ((x2 * hs) < (y2 * ws))
667: {
668: x2 += 2;
669: g += hs * 4 * (x2 + 1);
670:
671: if (g > 0) /* Need to drop */
672: {
673: y2 -= 2;
674: g -= ws * 4 * y2;
675: }
676:
677: if ((a_sin * x2) >= (y2 * a_cos))
678: {
679: pt.x = (int) (x2 / 2);
680: pt.y = (int) (y2 / 2);
681: break;
682: }
683: }
684: }
685:
686: if (flip_x)
687: pt.x = -pt.x;
688: if (flip_y)
689: pt.y = -pt.y;
690:
691: return (pt);
692: }
693:
694: #include "gd.h"
695: #include <string.h>
696: #include <math.h>
697:
698: #define WIDTH 500
699: #define HEIGHT 300
700:
701: int
702: main (int argc, char *argv[])
703: {
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);
707: FILE *out;
708:
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);
712:
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);
716:
717:
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);
724:
725: /* TBB: Write img to test/arctest.png */
726: out = fopen ("test/arctest.png", "wb");
727: if (!out)
728: {
729: php_gd_error("Can't create test/arctest.png");
730: exit (1);
731: }
732: gdImagePng (im, out);
733: fclose (out);
734: php_gd_error("Test image written to test/arctest.png");
735: /* Destroy it */
736: gdImageDestroy (im);
737:
738: return 0;
739: }
740:
741: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>