diff options
Diffstat (limited to 'ext/gd/libgd/gd_arc_f_buggy.c')
-rw-r--r-- | ext/gd/libgd/gd_arc_f_buggy.c | 741 |
1 files changed, 741 insertions, 0 deletions
diff --git a/ext/gd/libgd/gd_arc_f_buggy.c b/ext/gd/libgd/gd_arc_f_buggy.c new file mode 100644 index 0000000..c26e421 --- /dev/null +++ b/ext/gd/libgd/gd_arc_f_buggy.c @@ -0,0 +1,741 @@ +/* This is potentially great stuff, but fails against the test + program at the end. This would probably be much more + efficent than the implementation currently in gd.c if the + errors in the output were corrected. TBB */ + +#if 0 + +#include "gd.h" +#include <math.h> + +/* Courtesy of F J Franklin. */ + +static gdPoint gdArcClosest (int width, int height, int angle); + +void +gdImageFilledEllipse (gdImagePtr im, int cx, int cy, int width, int height, int color) +{ + gdImageFilledArc (im, cx, cy, width, height, 0, 360, color, gdChord); +} + +void +gdImageFilledArc (gdImagePtr im, int cx, int cy, int width, int height, int s, int e, int color, int style) +{ + gdPoint pt[7]; + gdPoint axis_pt[4]; + + int angle; + + int have_s = 0; + int have_e = 0; + + int flip_x = 0; + int flip_y = 0; + + int conquer = 0; + + int i; + + int a; + int b; + + int x; + int y; + + long s_sin = 0; + long s_cos = 0; + long e_sin = 0; + long e_cos = 0; + + long w; /* a * 2 */ + long h; /* b * 2 */ + + long x2; /* x * 2 */ + long y2; /* y * 2 */ + long lx2; /* x * 2 (line) */ + long ly2; /* y * 2 (line) */ + + long ws; /* (a * 2)^2 */ + long hs; /* (b * 2)^2 */ + + long whs; /* (a * 2)^2 * (b * 2)^2 */ + + long g; /* decision variable */ + long lg; /* decision variable (line) */ + + width = (width & 1) ? (width + 1) : (width); + height = (height & 1) ? (height + 1) : (height); + + a = width / 2; + b = height / 2; + + axis_pt[0].x = a; + axis_pt[0].y = 0; + axis_pt[1].x = 0; + axis_pt[1].y = b; + axis_pt[2].x = -a; + axis_pt[2].y = 0; + axis_pt[3].x = 0; + axis_pt[3].y = -b; + + if (s == e) + return; + + if ((e - s) >= 360) + { + s = 0; + e = 0; + } + + while (s < 0) + s += 360; + while (s >= 360) + s -= 360; + while (e < 0) + e += 360; + while (e >= 360) + e -= 360; + + if (e <= s) + e += 360; + + /* I'm assuming a chord-rule at the moment. Need to add origin to get a + * pie-rule, but will need to set chord-rule before recursion... + */ + + for (i = 0; i < 4; i++) + { + if ((s < (i + 1) * 90) && (e > (i + 1) * 90)) + { + gdImageFilledArc (im, cx, cy, width, height, s, (i + 1) * 90, color, gdChord); + pt[0] = gdArcClosest (width, height, s); + pt[0].x += cx; + pt[0].y += cy; + pt[1].x = cx + axis_pt[(i + 1) & 3].x; + pt[1].y = cy + axis_pt[(i + 1) & 3].y; + if (e <= (i + 2) * 90) + { + gdImageFilledArc (im, cx, cy, width, height, (i + 1) * 90, e, color, gdChord); + pt[2] = gdArcClosest (width, height, e); + pt[2].x += cx; + pt[2].y += cy; + if (style == gdChord) + { + gdImageFilledPolygon (im, pt, 3, color); + gdImagePolygon (im, pt, 3, color); + } + else if (style == gdPie) + { + pt[3].x = cx; + pt[3].y = cy; + gdImageFilledPolygon (im, pt, 4, color); + gdImagePolygon (im, pt, 4, color); + } + } + else + { + gdImageFilledArc (im, cx, cy, width, height, (i + 1) * 90, (i + 2) * 90, color, gdChord); + pt[2].x = cx + axis_pt[(i + 2) & 3].x; + pt[2].y = cy + axis_pt[(i + 2) & 3].y; + if (e <= (i + 3) * 90) + { + gdImageFilledArc (im, cx, cy, width, height, (i + 2) * 90, e, color, gdChord); + pt[3] = gdArcClosest (width, height, e); + pt[3].x += cx; + pt[3].y += cy; + if (style == gdChord) + { + gdImageFilledPolygon (im, pt, 4, color); + gdImagePolygon (im, pt, 4, color); + } + else if (style == gdPie) + { + pt[4].x = cx; + pt[4].y = cy; + gdImageFilledPolygon (im, pt, 5, color); + gdImagePolygon (im, pt, 5, color); + } + } + else + { + gdImageFilledArc (im, cx, cy, width, height, (i + 2) * 90, (i + 3) * 90, color, gdChord); + pt[3].x = cx + axis_pt[(i + 3) & 3].x; + pt[3].y = cy + axis_pt[(i + 3) & 3].y; + if (e <= (i + 4) * 90) + { + gdImageFilledArc (im, cx, cy, width, height, (i + 3) * 90, e, color, gdChord); + pt[4] = gdArcClosest (width, height, e); + pt[4].x += cx; + pt[4].y += cy; + if (style == gdChord) + { + gdImageFilledPolygon (im, pt, 5, color); + gdImagePolygon (im, pt, 5, color); + } + else if (style == gdPie) + { + pt[5].x = cx; + pt[5].y = cy; + gdImageFilledPolygon (im, pt, 6, color); + gdImagePolygon (im, pt, 6, color); + } + } + else + { + gdImageFilledArc (im, cx, cy, width, height, (i + 3) * 90, (i + 4) * 90, color, gdChord); + pt[4].x = cx + axis_pt[(i + 4) & 3].x; + pt[4].y = cy + axis_pt[(i + 4) & 3].y; + + gdImageFilledArc (im, cx, cy, width, height, (i + 4) * 90, e, color, gdChord); + pt[5] = gdArcClosest (width, height, e); + pt[5].x += cx; + pt[5].y += cy; + if (style == gdChord) + { + gdImageFilledPolygon (im, pt, 6, color); + gdImagePolygon (im, pt, 6, color); + } + else if (style == gdPie) + { + pt[6].x = cx; + pt[6].y = cy; + gdImageFilledPolygon (im, pt, 7, color); + gdImagePolygon (im, pt, 7, color); + } + } + } + } + return; + } + } + + /* At this point we have only arcs that lies within a quadrant - + * map this to first quadrant... + */ + + if ((s >= 90) && (e <= 180)) + { + angle = s; + s = 180 - e; + e = 180 - angle; + flip_x = 1; + } + if ((s >= 180) && (e <= 270)) + { + s = s - 180; + e = e - 180; + flip_x = 1; + flip_y = 1; + } + if ((s >= 270) && (e <= 360)) + { + angle = s; + s = 360 - e; + e = 360 - angle; + flip_y = 1; + } + + if (s == 0) + { + s_sin = 0; + s_cos = (long) ((double) 32768); + } + else + { + s_sin = (long) ((double) 32768 * sin ((double) s * M_PI / (double) 180)); + s_cos = (long) ((double) 32768 * cos ((double) s * M_PI / (double) 180)); + } + if (e == 0) + { + e_sin = (long) ((double) 32768); + e_cos = 0; + } + else + { + e_sin = (long) ((double) 32768 * sin ((double) e * M_PI / (double) 180)); + e_cos = (long) ((double) 32768 * cos ((double) e * M_PI / (double) 180)); + } + + w = (long) width; + h = (long) height; + + ws = w * w; + hs = h * h; + + whs = 1; + while ((ws > 32768) || (hs > 32768)) + { + ws = (ws + 1) / 2; /* Unfortunate limitations on integers makes */ + hs = (hs + 1) / 2; /* drawing large ellipses problematic... */ + whs *= 2; + } + while ((ws * hs) > (0x04000000L / whs)) + { + ws = (ws + 1) / 2; + hs = (hs + 1) / 2; + whs *= 2; + } + whs *= ws * hs; + + pt[0].x = w / 2; + pt[0].y = 0; + + pt[2].x = 0; + pt[2].y = h / 2; + + have_s = 0; + have_e = 0; + + if (s == 0) + have_s = 1; + if (e == 90) + have_e = 1; + + x2 = w; + y2 = 0; /* Starting point is exactly on ellipse */ + + g = x2 - 1; + g = g * g * hs + 4 * ws - whs; + + while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */ + { + y2 += 2; + g += ws * 4 * (y2 + 1); + + if (g > 0) /* Need to drop */ + { + x2 -= 2; + g -= hs * 4 * x2; + } + + if ((have_s == 0) && ((s_sin * x2) <= (y2 * s_cos))) + { + pt[0].x = (int) (x2 / 2); + pt[0].y = (int) (y2 / 2); + have_s = 1; + } + + if ((have_e == 0) && ((e_sin * x2) <= (y2 * e_cos))) + { + pt[2].x = (int) (x2 / 2); + pt[2].y = (int) (y2 / 2); + have_e = 1; + } + } + pt[1].x = (int) (x2 / 2); + pt[1].y = (int) (y2 / 2); + + x2 = 0; + y2 = h; /* Starting point is exactly on ellipse */ + + g = y2 - 1; + g = g * g * ws + 4 * hs - whs; + + while ((x2 * hs) < (y2 * ws)) + { + x2 += 2; + g += hs * 4 * (x2 + 1); + + if (g > 0) /* Need to drop */ + { + y2 -= 2; + g -= ws * 4 * y2; + } + + if ((have_s == 0) && ((s_sin * x2) >= (y2 * s_cos))) + { + pt[0].x = (int) (x2 / 2); + pt[0].y = (int) (y2 / 2); + have_s = 1; + } + + if ((have_e == 0) && ((e_sin * x2) >= (y2 * e_cos))) + { + pt[2].x = (int) (x2 / 2); + pt[2].y = (int) (y2 / 2); + have_e = 1; + } + } + + if ((have_s == 0) || (have_e == 0)) + return; /* Bizarre case */ + + if (style == gdPie) + { + pt[3] = pt[0]; + pt[4] = pt[1]; + pt[5] = pt[2]; + + pt[0].x = cx + (flip_x ? (-pt[0].x) : pt[0].x); + pt[0].y = cy + (flip_y ? (-pt[0].y) : pt[0].y); + pt[1].x = cx; + pt[1].y = cy; + pt[2].x = cx + (flip_x ? (-pt[2].x) : pt[2].x); + pt[2].y = cy + (flip_y ? (-pt[2].y) : pt[2].y); + gdImageFilledPolygon (im, pt, 3, color); + gdImagePolygon (im, pt, 3, color); + + pt[0] = pt[3]; + pt[1] = pt[4]; + pt[2] = pt[5]; + } + + if (((s_cos * hs) > (s_sin * ws)) && ((e_cos * hs) < (e_sin * ws))) + { /* the points are on different parts of the curve... + * this is too tricky to try to handle, so divide and conquer: + */ + pt[3] = pt[0]; + pt[4] = pt[1]; + pt[5] = pt[2]; + + pt[0].x = cx + (flip_x ? (-pt[0].x) : pt[0].x); + pt[0].y = cy + (flip_y ? (-pt[0].y) : pt[0].y); + pt[1].x = cx + (flip_x ? (-pt[1].x) : pt[1].x); + pt[1].y = cy + (flip_y ? (-pt[1].y) : pt[1].y); + pt[2].x = cx + (flip_x ? (-pt[2].x) : pt[2].x); + pt[2].y = cy + (flip_y ? (-pt[2].y) : pt[2].y); + gdImageFilledPolygon (im, pt, 3, color); + gdImagePolygon (im, pt, 3, color); + + pt[0] = pt[3]; + pt[2] = pt[4]; + + conquer = 1; + } + + if (conquer || (((s_cos * hs) > (s_sin * ws)) && ((e_cos * hs) > (e_sin * ws)))) + { /* This is the best bit... */ + /* steep line + ellipse */ + /* go up & left from pt[0] to pt[2] */ + + x2 = w; + y2 = 0; /* Starting point is exactly on ellipse */ + + g = x2 - 1; + g = g * g * hs + 4 * ws - whs; + + while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */ + { + if ((s_sin * x2) <= (y2 * s_cos)) + break; + + y2 += 2; + g += ws * 4 * (y2 + 1); + + if (g > 0) /* Need to drop */ + { + x2 -= 2; + g -= hs * 4 * x2; + } + } + + lx2 = x2; + ly2 = y2; + + lg = lx2 * (pt[0].y - pt[2].y) - ly2 * (pt[0].x - pt[2].x); + lg = (lx2 - 1) * (pt[0].y - pt[2].y) - (ly2 + 2) * (pt[0].x - pt[2].x) - lg; + + while (y2 < (2 * pt[2].y)) + { + y2 += 2; + g += ws * 4 * (y2 + 1); + + if (g > 0) /* Need to drop */ + { + x2 -= 2; + g -= hs * 4 * x2; + } + + ly2 += 2; + lg -= 2 * (pt[0].x - pt[2].x); + + if (lg < 0) /* Need to drop */ + { + lx2 -= 2; + lg -= 2 * (pt[0].y - pt[2].y); + } + + y = (int) (y2 / 2); + for (x = (int) (lx2 / 2); x <= (int) (x2 / 2); x++) + { + gdImageSetPixel (im, ((flip_x) ? (cx - x) : (cx + x)), + ((flip_y) ? (cy - y) : (cy + y)), color); + } + } + } + if (conquer) + { + pt[0] = pt[4]; + pt[2] = pt[5]; + } + if (conquer || (((s_cos * hs) < (s_sin * ws)) && ((e_cos * hs) < (e_sin * ws)))) + { /* This is the best bit... */ + /* gradual line + ellipse */ + /* go down & right from pt[2] to pt[0] */ + + x2 = 0; + y2 = h; /* Starting point is exactly on ellipse */ + + g = y2 - 1; + g = g * g * ws + 4 * hs - whs; + + while ((x2 * hs) < (y2 * ws)) + { + x2 += 2; + g += hs * 4 * (x2 + 1); + + if (g > 0) /* Need to drop */ + { + y2 -= 2; + g -= ws * 4 * y2; + } + + if ((e_sin * x2) >= (y2 * e_cos)) + break; + } + + lx2 = x2; + ly2 = y2; + + lg = lx2 * (pt[0].y - pt[2].y) - ly2 * (pt[0].x - pt[2].x); + lg = (lx2 + 2) * (pt[0].y - pt[2].y) - (ly2 - 1) * (pt[0].x - pt[2].x) - lg; + + while (x2 < (2 * pt[0].x)) + { + x2 += 2; + g += hs * 4 * (x2 + 1); + + if (g > 0) /* Need to drop */ + { + y2 -= 2; + g -= ws * 4 * y2; + } + + lx2 += 2; + lg += 2 * (pt[0].y - pt[2].y); + + if (lg < 0) /* Need to drop */ + { + ly2 -= 2; + lg += 2 * (pt[0].x - pt[2].x); + } + + x = (int) (x2 / 2); + for (y = (int) (ly2 / 2); y <= (int) (y2 / 2); y++) + { + gdImageSetPixel (im, ((flip_x) ? (cx - x) : (cx + x)), + ((flip_y) ? (cy - y) : (cy + y)), color); + } + } + } +} + +static gdPoint +gdArcClosest (int width, int height, int angle) +{ + gdPoint pt; + + int flip_x = 0; + int flip_y = 0; + + long a_sin = 0; + long a_cos = 0; + + long w; /* a * 2 */ + long h; /* b * 2 */ + + long x2; /* x * 2 */ + long y2; /* y * 2 */ + + long ws; /* (a * 2)^2 */ + long hs; /* (b * 2)^2 */ + + long whs; /* (a * 2)^2 * (b * 2)^2 */ + + long g; /* decision variable */ + + w = (long) ((width & 1) ? (width + 1) : (width)); + h = (long) ((height & 1) ? (height + 1) : (height)); + + while (angle < 0) + angle += 360; + while (angle >= 360) + angle -= 360; + + if (angle == 0) + { + pt.x = w / 2; + pt.y = 0; + return (pt); + } + if (angle == 90) + { + pt.x = 0; + pt.y = h / 2; + return (pt); + } + if (angle == 180) + { + pt.x = -w / 2; + pt.y = 0; + return (pt); + } + if (angle == 270) + { + pt.x = 0; + pt.y = -h / 2; + return (pt); + } + + pt.x = 0; + pt.y = 0; + + if ((angle > 90) && (angle < 180)) + { + angle = 180 - angle; + flip_x = 1; + } + if ((angle > 180) && (angle < 270)) + { + angle = angle - 180; + flip_x = 1; + flip_y = 1; + } + if ((angle > 270) && (angle < 360)) + { + angle = 360 - angle; + flip_y = 1; + } + + a_sin = (long) ((double) 32768 * sin ((double) angle * M_PI / (double) 180)); + a_cos = (long) ((double) 32768 * cos ((double) angle * M_PI / (double) 180)); + + ws = w * w; + hs = h * h; + + whs = 1; + while ((ws > 32768) || (hs > 32768)) + { + ws = (ws + 1) / 2; /* Unfortunate limitations on integers makes */ + hs = (hs + 1) / 2; /* drawing large ellipses problematic... */ + whs *= 2; + } + while ((ws * hs) > (0x04000000L / whs)) + { + ws = (ws + 1) / 2; + hs = (hs + 1) / 2; + whs *= 2; + } + whs *= ws * hs; + + if ((a_cos * hs) > (a_sin * ws)) + { + x2 = w; + y2 = 0; /* Starting point is exactly on ellipse */ + + g = x2 - 1; + g = g * g * hs + 4 * ws - whs; + + while ((x2 * hs) > (y2 * ws)) /* Keep |tangent| > 1 */ + { + y2 += 2; + g += ws * 4 * (y2 + 1); + + if (g > 0) /* Need to drop */ + { + x2 -= 2; + g -= hs * 4 * x2; + } + + if ((a_sin * x2) <= (y2 * a_cos)) + { + pt.x = (int) (x2 / 2); + pt.y = (int) (y2 / 2); + break; + } + } + } + else + { + x2 = 0; + y2 = h; /* Starting point is exactly on ellipse */ + + g = y2 - 1; + g = g * g * ws + 4 * hs - whs; + + while ((x2 * hs) < (y2 * ws)) + { + x2 += 2; + g += hs * 4 * (x2 + 1); + + if (g > 0) /* Need to drop */ + { + y2 -= 2; + g -= ws * 4 * y2; + } + + if ((a_sin * x2) >= (y2 * a_cos)) + { + pt.x = (int) (x2 / 2); + pt.y = (int) (y2 / 2); + break; + } + } + } + + if (flip_x) + pt.x = -pt.x; + if (flip_y) + pt.y = -pt.y; + + return (pt); +} + +#include "gd.h" +#include <string.h> +#include <math.h> + +#define WIDTH 500 +#define HEIGHT 300 + +int +main (int argc, char *argv[]) +{ + gdImagePtr im = gdImageCreate (WIDTH, HEIGHT); + int white = gdImageColorResolve (im, 0xFF, 0xFF, 0xFF), black = gdImageColorResolve (im, 0, 0, 0), + red = gdImageColorResolve (im, 0xFF, 0xA0, 0xA0); + FILE *out; + + /* filled arc - circle */ + gdImageFilledArc (im, WIDTH / 5, HEIGHT / 4, 200, 200, 45, 90, red, gdPie); + gdImageArc (im, WIDTH / 5, HEIGHT / 4, 200, 200, 45, 90, black); + + /* filled arc - ellipse */ + gdImageFilledArc (im, WIDTH / 2, HEIGHT / 4, 200, 150, 45, 90, red, gdPie); + gdImageArc (im, WIDTH / 2, HEIGHT / 4, 200, 150, 45, 90, black); + + + /* reference lines */ + gdImageLine (im, 0, HEIGHT / 4, WIDTH, HEIGHT / 4, black); + gdImageLine (im, WIDTH / 5, 0, WIDTH / 5, HEIGHT, black); + gdImageLine (im, WIDTH / 2, 0, WIDTH / 2, HEIGHT, black); + gdImageLine (im, WIDTH / 2, HEIGHT / 4, WIDTH / 2 + 300, HEIGHT / 4 + 300, black); + gdImageLine (im, WIDTH / 5, HEIGHT / 4, WIDTH / 5 + 300, HEIGHT / 4 + 300, black); + + /* TBB: Write img to test/arctest.png */ + out = fopen ("test/arctest.png", "wb"); + if (!out) + { + php_gd_error("Can't create test/arctest.png"); + exit (1); + } + gdImagePng (im, out); + fclose (out); + php_gd_error("Test image written to test/arctest.png"); + /* Destroy it */ + gdImageDestroy (im); + + return 0; +} + +#endif |