Mercurial > MadButterfly
changeset 97:9453e68092b5
Fix bug of translation relative to absolute points
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Thu, 04 Sep 2008 08:21:39 +0800 |
parents | ca94493b75bb |
children | 688f76b8e71c |
files | src/shape_path.c |
diffstat | 1 files changed, 127 insertions(+), 76 deletions(-) [+] |
line wrap: on
line diff
--- a/src/shape_path.c Sat Aug 30 00:32:05 2008 +0800 +++ b/src/shape_path.c Thu Sep 04 08:21:39 2008 +0800 @@ -104,6 +104,8 @@ if(p == old) return ERR; arg_cnt++; + + cmd_cnt++; } break; case 's': @@ -139,6 +141,8 @@ if(p == old) return ERR; arg_cnt++; + + cmd_cnt++; } break; case 'm': @@ -162,6 +166,8 @@ if(p == old) return ERR; arg_cnt++; + + cmd_cnt++; } break; case 'h': @@ -175,6 +181,8 @@ if(p == old) break; arg_cnt += 2; + + cmd_cnt++; } break; case 'A': @@ -195,16 +203,18 @@ } arg_cnt += 6; + + cmd_cnt++; } break; case 'z': case 'Z': + cmd_cnt++; break; default: return ERR; } /*! \todo cmd_cnt should be increased for each implicit repeating. */ - cmd_cnt++; SKIP_SPACE(p); } @@ -213,27 +223,86 @@ return OK; } +#include <math.h> +/*! \brief Calculate center of the ellipse of an arc. + * + * - ux0 = x0 / rx + * - uy0 = y0 / ry + * - ux = x / rx + * - uy = y / rx + * ux0, uy0, ux, yu are got by transforming (x0, y0) and (x, y) into points + * on the unit circle. The center of unit circle are (ucx, ucy): + * - umx = (ux0 + ux) / 2 + * - umy = (uy0 + uy) / 2 + * - udcx = ucx - umx + * - udcy = ucy - umy + * - udx = ux - umx + * - udy = uy - umy + * - udcx * udx + udcy * udy = 0 + * - udcy = - udcx * udx / udy + * - udcx ** 2 + udcy ** 2 + udx ** 2 + udy ** 2 = 1 + * - udcx ** 2 + (udcx * udx / udy) ** 2 = 1 - udx ** 2 - udy ** 2 + * - udcx ** 2 = (1 - udx ** 2 - udy ** 2) / (1 + (udx/udy) ** 2) + * + * - cx = rx * ucx + * - cx = rx * (udcx + umx) + * - cy = ry * ucy + * - cy = ry * (udcy + umy) + */ static int calc_center_and_x_aix(co_aix x0, co_aix y0, co_aix x, co_aix y, + co_aix rx, co_aix ry, co_aix x_rotate, int large, int sweep, co_aix *cx, co_aix *cy, co_aix *xx, co_aix *xy) { + co_aix nrx, nry, nrx0, nry0; + co_aix udx, udy, udx2, udy2; + co_aix umx, umy; + co_aix udcx, udcy; + co_aix nrcx, nrcy; + float _sin = sinf(x_rotate); + float _cos = cosf(x_rotate); + nrx = x * _cos + y * _sin; + nry = x * -_sin + y * _cos; + nrx0 = x0 * _cos + y0 * _sin; + nry0 = x0 * -_sin + y0 * _cos; + + udx = (nrx - nrx0) / 2 / rx; + udy = (nry - nry0) / 2 / ry; + umx = (nrx + nrx0) / 2 / rx; + umy = (nry + nry0) / 2 / ry; + udx2 = udx * udx; + udy2 = udy * udy; + udcx = sqrtf((1 - udx2 - udy2) / (1 + udx2 / udy2)); + udcy = - udcx * udx / udy; + nrcx = rx * (udcx + umx); + nrcy = ry * (udcy + umy); + + *cx = nrcx * _cos - nrcy * _sin; + *cy = nrcx * _sin + nrcy * _cos; + + *xx = rx * _cos + *cx; + *xy = rx * _sin + *cy; + + return OK; } -static int sh_path_arc_cmd_arg_fill(char cmd, const char *data, - co_aix **args_p, const char **old_p) { +static int sh_path_arc_cmd_arg_fill(char cmd, char **cmds_p, + const char **data_p, co_aix **args_p) { co_aix rx, ry; co_aix x_rotate; int large, sweep; co_aix x, y, x0, y0, cx, cy, xx, xy; co_aix *args = *args_p; - const char *old = *old_p; + const char *old; const char *p; + char *cmds; - p = data; + p = *data_p; + cmds = *cmds_p; while(*p) { SKIP_SPACE(p); old = p; @@ -293,6 +362,7 @@ } calc_center_and_x_aix(x0, y0, x, y, + rx, ry, x_rotate, large, sweep, &cx, &cy, &xx, &xy); @@ -302,20 +372,31 @@ *(args++) = xy; *(args++) = x; *(args++) = y; + + *cmds++ = toupper(cmd); } - *old_p = old; + *data_p = p; + *args_p = args; + *cmds_p = cmds; return OK; } -#define TO_ABS islower(cmd)? *(args - 2) + atof(old): atof(old) +void sh_path_arc_path(cairo_t *cr, const co_aix **args) { + +} + +#define TO_ABSX islower(cmd)? x + atof(old): atof(old) +#define TO_ABSY islower(cmd)? y + atof(old): atof(old) static int sh_path_cmd_arg_fill(char *data, sh_path_t *path) { char *p, *old; char *cmds; char cmd; co_aix *args; + co_aix x, y; + int r; cmds = path->user_data; args = (co_aix *)(cmds + path->cmd_len); @@ -323,7 +404,9 @@ SKIP_SPACE(p); while(*p) { /* Transform all relative to absolute, */ - *cmds++ = toupper(*p); + x = *(args - 2); + y = *(args - 1); + switch((cmd = *p++)) { case 'c': case 'C': @@ -334,7 +417,7 @@ SKIP_NUM(p); if(p == old) break; - *args = TO_ABS; + *args = TO_ABSX; args++; SKIP_SPACE(p); @@ -342,7 +425,7 @@ SKIP_NUM(p); if(p == old) return ERR; - *args = TO_ABS; + *args = TO_ABSY; args++; SKIP_SPACE(p); @@ -350,7 +433,7 @@ SKIP_NUM(p); if(p == old) return ERR; - *args = TO_ABS; + *args = TO_ABSX; args++; SKIP_SPACE(p); @@ -358,14 +441,14 @@ SKIP_NUM(p); if(p == old) return ERR; - *args = TO_ABS; + *args = TO_ABSY; args++; SKIP_SPACE(p); old = p; SKIP_NUM(p); if(p == old) return ERR; - *args = TO_ABS; + *args = TO_ABSX; args++; SKIP_SPACE(p); @@ -373,8 +456,10 @@ SKIP_NUM(p); if(p == old) return ERR; - *args = TO_ABS; + *args = TO_ABSY; args++; + + *cmds++ = toupper(cmd); } break; case 's': @@ -388,7 +473,7 @@ SKIP_NUM(p); if(p == old) break; - *args = TO_ABS; + *args = TO_ABSX; args++; SKIP_SPACE(p); @@ -396,7 +481,7 @@ SKIP_NUM(p); if(p == old) return ERR; - *args = TO_ABS; + *args = TO_ABSY; args++; SKIP_SPACE(p); @@ -404,7 +489,7 @@ SKIP_NUM(p); if(p == old) return ERR; - *args = TO_ABS; + *args = TO_ABSX; args++; SKIP_SPACE(p); @@ -412,8 +497,10 @@ SKIP_NUM(p); if(p == old) return ERR; - *args = TO_ABS; + *args = TO_ABSY; args++; + + *cmds++ = toupper(cmd); } break; case 'm': @@ -429,7 +516,7 @@ SKIP_NUM(p); if(p == old) break; - *args = TO_ABS; + *args = TO_ABSX; args++; SKIP_SPACE(p); @@ -437,8 +524,10 @@ SKIP_NUM(p); if(p == old) return ERR; - *args = TO_ABS; + *args = TO_ABSY; args++; + + *cmds++ = toupper(cmd); } break; case 'h': @@ -450,11 +539,14 @@ case 'A': case 'a': - + r = sh_path_arc_cmd_arg_fill(cmd, &cmds, (const char **)&p, &args); + if(r != OK) + return ERR; break; case 'z': case 'Z': + *cmds++ = toupper(cmd); break; default: return ERR; @@ -557,7 +649,7 @@ sh_path_t *path; int cmd_len; char *cmds, cmd; - co_aix *args; + const co_aix *args; co_aix x, y, x1, y1, x2, y2; int i; @@ -569,37 +661,21 @@ args = (co_aix *)(cmds + cmd_len); x = y = x1 = y1 = x2 = y2 = 0; for(i = 0; i < cmd_len; i++) { + /* All path commands and arguments are transformed + * to absoluted form. + */ cmd = *cmds++; switch(cmd) { - case 'm': - x = x + *args++; - y = y + *args++; - cairo_move_to(cr, x, y); - break; case 'M': x = *args++; y = *args++; cairo_move_to(cr, x, y); break; - case 'l': - x = x + *args++; - y = y + *args++; - cairo_line_to(cr, x, y); - break; case 'L': x = *args++; y = *args++; cairo_line_to(cr, x, y); break; - case 'c': - x1 = x + *args++; - y1 = y + *args++; - x2 = x + *args++; - y2 = y + *args++; - x = x + *args++; - y = y + *args++; - cairo_curve_to(cr, x1, y1, x2, y2, x, y); - break; case 'C': x1 = *args++; y1 = *args++; @@ -609,15 +685,6 @@ y = *args++; cairo_curve_to(cr, x1, y1, x2, y2, x, y); break; - case 's': - x1 = x + x - x2; - y1 = y + y - y2; - x2 = x + *args++; - y2 = y + *args++; - x = x + *args++; - y = y + *args++; - cairo_curve_to(cr, x1, y1, x2, y2, x, y); - break; case 'S': x1 = x + x - x2; y1 = y + y - y2; @@ -627,15 +694,6 @@ y = *args++; cairo_curve_to(cr, x1, y1, x2, y2, x, y); break; - case 'q': - x1 = x + *args++; - y1 = y + *args++; - x2 = x1; - y2 = y1; - x = x + *args++; - y = y + *args++; - cairo_curve_to(cr, x1, y1, x2, y2, x, y); - break; case 'Q': x1 = *args++; y1 = *args++; @@ -645,15 +703,6 @@ y = *args++; cairo_curve_to(cr, x1, y1, x2, y2, x, y); break; - case 't': - x1 = x + x - x2; - y1 = y + y - y2; - x2 = x1; - y2 = y1; - x = x + *args++; - y = y + *args++; - cairo_curve_to(cr, x1, y1, x2, y2, x, y); - break; case 'T': x1 = x + x - x2; y1 = y + y - y2; @@ -663,8 +712,10 @@ y = *args++; cairo_curve_to(cr, x1, y1, x2, y2, x, y); break; + case 'A': + sh_path_arc_path(cr, &args); + break; case 'Z': - case 'z': cairo_close_path(cr); break; case '\x0': @@ -686,7 +737,7 @@ sh_path_t *path; co_aix *args; - path = (sh_path_t *)sh_path_new("M 33 25l33 55C 33 87 44 22 55 99L33 77z"); + path = (sh_path_t *)sh_path_new("M 33 25l33 55c 33 87 44 22 55 99L33 77z"); CU_ASSERT(path != NULL); CU_ASSERT(path->cmd_len == ((5 + RESERVED_AIXS + 3) & ~0x3)); CU_ASSERT(path->arg_len == 12); @@ -698,12 +749,12 @@ CU_ASSERT(args[1] == 25); CU_ASSERT(args[2] == 66); CU_ASSERT(args[3] == 80); - CU_ASSERT(args[4] == 33); - CU_ASSERT(args[5] == 87); - CU_ASSERT(args[6] == 44); - CU_ASSERT(args[7] == 22); - CU_ASSERT(args[8] == 55); - CU_ASSERT(args[9] == 99); + CU_ASSERT(args[4] == 99); + CU_ASSERT(args[5] == 167); + CU_ASSERT(args[6] == 110); + CU_ASSERT(args[7] == 102); + CU_ASSERT(args[8] == 121); + CU_ASSERT(args[9] == 179); CU_ASSERT(args[10] == 33); CU_ASSERT(args[11] == 77); sh_path_free((shape_t *)path);