comparison src/shape_path.c @ 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
comparison
equal deleted inserted replaced
96:ca94493b75bb 97:9453e68092b5
102 old = p; 102 old = p;
103 SKIP_NUM(p); 103 SKIP_NUM(p);
104 if(p == old) 104 if(p == old)
105 return ERR; 105 return ERR;
106 arg_cnt++; 106 arg_cnt++;
107
108 cmd_cnt++;
107 } 109 }
108 break; 110 break;
109 case 's': 111 case 's':
110 case 'S': 112 case 'S':
111 case 'q': 113 case 'q':
137 old = p; 139 old = p;
138 SKIP_NUM(p); 140 SKIP_NUM(p);
139 if(p == old) 141 if(p == old)
140 return ERR; 142 return ERR;
141 arg_cnt++; 143 arg_cnt++;
144
145 cmd_cnt++;
142 } 146 }
143 break; 147 break;
144 case 'm': 148 case 'm':
145 case 'M': 149 case 'M':
146 case 'l': 150 case 'l':
160 old = p; 164 old = p;
161 SKIP_NUM(p); 165 SKIP_NUM(p);
162 if(p == old) 166 if(p == old)
163 return ERR; 167 return ERR;
164 arg_cnt++; 168 arg_cnt++;
169
170 cmd_cnt++;
165 } 171 }
166 break; 172 break;
167 case 'h': 173 case 'h':
168 case 'H': 174 case 'H':
169 case 'v': 175 case 'v':
173 old = p; 179 old = p;
174 SKIP_NUM(p); 180 SKIP_NUM(p);
175 if(p == old) 181 if(p == old)
176 break; 182 break;
177 arg_cnt += 2; 183 arg_cnt += 2;
184
185 cmd_cnt++;
178 } 186 }
179 break; 187 break;
180 case 'A': 188 case 'A':
181 case 'a': 189 case 'a':
182 while(*p) { 190 while(*p) {
193 if(p == old) 201 if(p == old)
194 return ERR; 202 return ERR;
195 } 203 }
196 204
197 arg_cnt += 6; 205 arg_cnt += 6;
206
207 cmd_cnt++;
198 } 208 }
199 break; 209 break;
200 case 'z': 210 case 'z':
201 case 'Z': 211 case 'Z':
212 cmd_cnt++;
202 break; 213 break;
203 default: 214 default:
204 return ERR; 215 return ERR;
205 } 216 }
206 /*! \todo cmd_cnt should be increased for each implicit repeating. */ 217 /*! \todo cmd_cnt should be increased for each implicit repeating. */
207 cmd_cnt++;
208 SKIP_SPACE(p); 218 SKIP_SPACE(p);
209 } 219 }
210 220
211 *cmd_cntp = cmd_cnt; 221 *cmd_cntp = cmd_cnt;
212 *arg_cntp = arg_cnt; 222 *arg_cntp = arg_cnt;
213 return OK; 223 return OK;
214 } 224 }
215 225
226 #include <math.h>
227 /*! \brief Calculate center of the ellipse of an arc.
228 *
229 * - ux0 = x0 / rx
230 * - uy0 = y0 / ry
231 * - ux = x / rx
232 * - uy = y / rx
233 * ux0, uy0, ux, yu are got by transforming (x0, y0) and (x, y) into points
234 * on the unit circle. The center of unit circle are (ucx, ucy):
235 * - umx = (ux0 + ux) / 2
236 * - umy = (uy0 + uy) / 2
237 * - udcx = ucx - umx
238 * - udcy = ucy - umy
239 * - udx = ux - umx
240 * - udy = uy - umy
241 * - udcx * udx + udcy * udy = 0
242 * - udcy = - udcx * udx / udy
243 * - udcx ** 2 + udcy ** 2 + udx ** 2 + udy ** 2 = 1
244 * - udcx ** 2 + (udcx * udx / udy) ** 2 = 1 - udx ** 2 - udy ** 2
245 * - udcx ** 2 = (1 - udx ** 2 - udy ** 2) / (1 + (udx/udy) ** 2)
246 *
247 * - cx = rx * ucx
248 * - cx = rx * (udcx + umx)
249 * - cy = ry * ucy
250 * - cy = ry * (udcy + umy)
251 */
216 static int calc_center_and_x_aix(co_aix x0, co_aix y0, 252 static int calc_center_and_x_aix(co_aix x0, co_aix y0,
217 co_aix x, co_aix y, 253 co_aix x, co_aix y,
254 co_aix rx, co_aix ry,
218 co_aix x_rotate, 255 co_aix x_rotate,
219 int large, int sweep, 256 int large, int sweep,
220 co_aix *cx, co_aix *cy, 257 co_aix *cx, co_aix *cy,
221 co_aix *xx, co_aix *xy) { 258 co_aix *xx, co_aix *xy) {
259 co_aix nrx, nry, nrx0, nry0;
260 co_aix udx, udy, udx2, udy2;
261 co_aix umx, umy;
262 co_aix udcx, udcy;
263 co_aix nrcx, nrcy;
264 float _sin = sinf(x_rotate);
265 float _cos = cosf(x_rotate);
222 266
223 } 267 nrx = x * _cos + y * _sin;
224 268 nry = x * -_sin + y * _cos;
225 269 nrx0 = x0 * _cos + y0 * _sin;
226 static int sh_path_arc_cmd_arg_fill(char cmd, const char *data, 270 nry0 = x0 * -_sin + y0 * _cos;
227 co_aix **args_p, const char **old_p) { 271
272 udx = (nrx - nrx0) / 2 / rx;
273 udy = (nry - nry0) / 2 / ry;
274 umx = (nrx + nrx0) / 2 / rx;
275 umy = (nry + nry0) / 2 / ry;
276 udx2 = udx * udx;
277 udy2 = udy * udy;
278 udcx = sqrtf((1 - udx2 - udy2) / (1 + udx2 / udy2));
279 udcy = - udcx * udx / udy;
280 nrcx = rx * (udcx + umx);
281 nrcy = ry * (udcy + umy);
282
283 *cx = nrcx * _cos - nrcy * _sin;
284 *cy = nrcx * _sin + nrcy * _cos;
285
286 *xx = rx * _cos + *cx;
287 *xy = rx * _sin + *cy;
288
289 return OK;
290 }
291
292
293 static int sh_path_arc_cmd_arg_fill(char cmd, char **cmds_p,
294 const char **data_p, co_aix **args_p) {
228 co_aix rx, ry; 295 co_aix rx, ry;
229 co_aix x_rotate; 296 co_aix x_rotate;
230 int large, sweep; 297 int large, sweep;
231 co_aix x, y, x0, y0, cx, cy, xx, xy; 298 co_aix x, y, x0, y0, cx, cy, xx, xy;
232 co_aix *args = *args_p; 299 co_aix *args = *args_p;
233 const char *old = *old_p; 300 const char *old;
234 const char *p; 301 const char *p;
235 302 char *cmds;
236 p = data; 303
304 p = *data_p;
305 cmds = *cmds_p;
237 while(*p) { 306 while(*p) {
238 SKIP_SPACE(p); 307 SKIP_SPACE(p);
239 old = p; 308 old = p;
240 SKIP_NUM(p); 309 SKIP_NUM(p);
241 if(p == old) 310 if(p == old)
291 x += x0; 360 x += x0;
292 y += y0; 361 y += y0;
293 } 362 }
294 363
295 calc_center_and_x_aix(x0, y0, x, y, 364 calc_center_and_x_aix(x0, y0, x, y,
365 rx, ry,
296 x_rotate, large, sweep, 366 x_rotate, large, sweep,
297 &cx, &cy, &xx, &xy); 367 &cx, &cy, &xx, &xy);
298 368
299 *(args++) = cx; 369 *(args++) = cx;
300 *(args++) = cy; 370 *(args++) = cy;
301 *(args++) = xx; 371 *(args++) = xx;
302 *(args++) = xy; 372 *(args++) = xy;
303 *(args++) = x; 373 *(args++) = x;
304 *(args++) = y; 374 *(args++) = y;
305 } 375
306 376 *cmds++ = toupper(cmd);
307 *old_p = old; 377 }
378
379 *data_p = p;
380 *args_p = args;
381 *cmds_p = cmds;
308 382
309 return OK; 383 return OK;
310 } 384 }
311 385
312 #define TO_ABS islower(cmd)? *(args - 2) + atof(old): atof(old) 386 void sh_path_arc_path(cairo_t *cr, const co_aix **args) {
387
388 }
389
390 #define TO_ABSX islower(cmd)? x + atof(old): atof(old)
391 #define TO_ABSY islower(cmd)? y + atof(old): atof(old)
313 392
314 static int sh_path_cmd_arg_fill(char *data, sh_path_t *path) { 393 static int sh_path_cmd_arg_fill(char *data, sh_path_t *path) {
315 char *p, *old; 394 char *p, *old;
316 char *cmds; 395 char *cmds;
317 char cmd; 396 char cmd;
318 co_aix *args; 397 co_aix *args;
398 co_aix x, y;
399 int r;
319 400
320 cmds = path->user_data; 401 cmds = path->user_data;
321 args = (co_aix *)(cmds + path->cmd_len); 402 args = (co_aix *)(cmds + path->cmd_len);
322 p = data; 403 p = data;
323 SKIP_SPACE(p); 404 SKIP_SPACE(p);
324 while(*p) { 405 while(*p) {
325 /* Transform all relative to absolute, */ 406 /* Transform all relative to absolute, */
326 *cmds++ = toupper(*p); 407 x = *(args - 2);
408 y = *(args - 1);
409
327 switch((cmd = *p++)) { 410 switch((cmd = *p++)) {
328 case 'c': 411 case 'c':
329 case 'C': 412 case 'C':
330 while(*p) { 413 while(*p) {
331 old = p; 414 old = p;
332 SKIP_SPACE(p); 415 SKIP_SPACE(p);
333 old = p; 416 old = p;
334 SKIP_NUM(p); 417 SKIP_NUM(p);
335 if(p == old) 418 if(p == old)
336 break; 419 break;
337 *args = TO_ABS; 420 *args = TO_ABSX;
338 args++; 421 args++;
339 422
340 SKIP_SPACE(p); 423 SKIP_SPACE(p);
341 old = p; 424 old = p;
342 SKIP_NUM(p); 425 SKIP_NUM(p);
343 if(p == old) 426 if(p == old)
344 return ERR; 427 return ERR;
345 *args = TO_ABS; 428 *args = TO_ABSY;
346 args++; 429 args++;
347 430
348 SKIP_SPACE(p); 431 SKIP_SPACE(p);
349 old = p; 432 old = p;
350 SKIP_NUM(p); 433 SKIP_NUM(p);
351 if(p == old) 434 if(p == old)
352 return ERR; 435 return ERR;
353 *args = TO_ABS; 436 *args = TO_ABSX;
354 args++; 437 args++;
355 438
356 SKIP_SPACE(p); 439 SKIP_SPACE(p);
357 old = p; 440 old = p;
358 SKIP_NUM(p); 441 SKIP_NUM(p);
359 if(p == old) 442 if(p == old)
360 return ERR; 443 return ERR;
361 *args = TO_ABS; 444 *args = TO_ABSY;
362 args++; 445 args++;
363 SKIP_SPACE(p); 446 SKIP_SPACE(p);
364 old = p; 447 old = p;
365 SKIP_NUM(p); 448 SKIP_NUM(p);
366 if(p == old) 449 if(p == old)
367 return ERR; 450 return ERR;
368 *args = TO_ABS; 451 *args = TO_ABSX;
369 args++; 452 args++;
370 453
371 SKIP_SPACE(p); 454 SKIP_SPACE(p);
372 old = p; 455 old = p;
373 SKIP_NUM(p); 456 SKIP_NUM(p);
374 if(p == old) 457 if(p == old)
375 return ERR; 458 return ERR;
376 *args = TO_ABS; 459 *args = TO_ABSY;
377 args++; 460 args++;
461
462 *cmds++ = toupper(cmd);
378 } 463 }
379 break; 464 break;
380 case 's': 465 case 's':
381 case 'S': 466 case 'S':
382 case 'q': 467 case 'q':
386 SKIP_SPACE(p); 471 SKIP_SPACE(p);
387 old = p; 472 old = p;
388 SKIP_NUM(p); 473 SKIP_NUM(p);
389 if(p == old) 474 if(p == old)
390 break; 475 break;
391 *args = TO_ABS; 476 *args = TO_ABSX;
392 args++; 477 args++;
393 478
394 SKIP_SPACE(p); 479 SKIP_SPACE(p);
395 old = p; 480 old = p;
396 SKIP_NUM(p); 481 SKIP_NUM(p);
397 if(p == old) 482 if(p == old)
398 return ERR; 483 return ERR;
399 *args = TO_ABS; 484 *args = TO_ABSY;
400 args++; 485 args++;
401 486
402 SKIP_SPACE(p); 487 SKIP_SPACE(p);
403 old = p; 488 old = p;
404 SKIP_NUM(p); 489 SKIP_NUM(p);
405 if(p == old) 490 if(p == old)
406 return ERR; 491 return ERR;
407 *args = TO_ABS; 492 *args = TO_ABSX;
408 args++; 493 args++;
409 494
410 SKIP_SPACE(p); 495 SKIP_SPACE(p);
411 old = p; 496 old = p;
412 SKIP_NUM(p); 497 SKIP_NUM(p);
413 if(p == old) 498 if(p == old)
414 return ERR; 499 return ERR;
415 *args = TO_ABS; 500 *args = TO_ABSY;
416 args++; 501 args++;
502
503 *cmds++ = toupper(cmd);
417 } 504 }
418 break; 505 break;
419 case 'm': 506 case 'm':
420 case 'M': 507 case 'M':
421 case 'l': 508 case 'l':
427 SKIP_SPACE(p); 514 SKIP_SPACE(p);
428 old = p; 515 old = p;
429 SKIP_NUM(p); 516 SKIP_NUM(p);
430 if(p == old) 517 if(p == old)
431 break; 518 break;
432 *args = TO_ABS; 519 *args = TO_ABSX;
433 args++; 520 args++;
434 521
435 SKIP_SPACE(p); 522 SKIP_SPACE(p);
436 old = p; 523 old = p;
437 SKIP_NUM(p); 524 SKIP_NUM(p);
438 if(p == old) 525 if(p == old)
439 return ERR; 526 return ERR;
440 *args = TO_ABS; 527 *args = TO_ABSY;
441 args++; 528 args++;
529
530 *cmds++ = toupper(cmd);
442 } 531 }
443 break; 532 break;
444 case 'h': 533 case 'h':
445 case 'H': 534 case 'H':
446 case 'v': 535 case 'v':
448 /*! \todo implement h, H, v, V comamnds for path. */ 537 /*! \todo implement h, H, v, V comamnds for path. */
449 return ERR; 538 return ERR;
450 539
451 case 'A': 540 case 'A':
452 case 'a': 541 case 'a':
453 542 r = sh_path_arc_cmd_arg_fill(cmd, &cmds, (const char **)&p, &args);
543 if(r != OK)
544 return ERR;
454 break; 545 break;
455 546
456 case 'z': 547 case 'z':
457 case 'Z': 548 case 'Z':
549 *cmds++ = toupper(cmd);
458 break; 550 break;
459 default: 551 default:
460 return ERR; 552 return ERR;
461 } 553 }
462 SKIP_SPACE(p); 554 SKIP_SPACE(p);
555 647
556 static void sh_path_path(shape_t *shape, cairo_t *cr) { 648 static void sh_path_path(shape_t *shape, cairo_t *cr) {
557 sh_path_t *path; 649 sh_path_t *path;
558 int cmd_len; 650 int cmd_len;
559 char *cmds, cmd; 651 char *cmds, cmd;
560 co_aix *args; 652 const co_aix *args;
561 co_aix x, y, x1, y1, x2, y2; 653 co_aix x, y, x1, y1, x2, y2;
562 int i; 654 int i;
563 655
564 ASSERT(shape->type == SHT_PATH); 656 ASSERT(shape->type == SHT_PATH);
565 657
567 cmd_len = path->cmd_len; 659 cmd_len = path->cmd_len;
568 cmds = path->dev_data; 660 cmds = path->dev_data;
569 args = (co_aix *)(cmds + cmd_len); 661 args = (co_aix *)(cmds + cmd_len);
570 x = y = x1 = y1 = x2 = y2 = 0; 662 x = y = x1 = y1 = x2 = y2 = 0;
571 for(i = 0; i < cmd_len; i++) { 663 for(i = 0; i < cmd_len; i++) {
664 /* All path commands and arguments are transformed
665 * to absoluted form.
666 */
572 cmd = *cmds++; 667 cmd = *cmds++;
573 switch(cmd) { 668 switch(cmd) {
574 case 'm':
575 x = x + *args++;
576 y = y + *args++;
577 cairo_move_to(cr, x, y);
578 break;
579 case 'M': 669 case 'M':
580 x = *args++; 670 x = *args++;
581 y = *args++; 671 y = *args++;
582 cairo_move_to(cr, x, y); 672 cairo_move_to(cr, x, y);
583 break; 673 break;
584 case 'l':
585 x = x + *args++;
586 y = y + *args++;
587 cairo_line_to(cr, x, y);
588 break;
589 case 'L': 674 case 'L':
590 x = *args++; 675 x = *args++;
591 y = *args++; 676 y = *args++;
592 cairo_line_to(cr, x, y); 677 cairo_line_to(cr, x, y);
593 break;
594 case 'c':
595 x1 = x + *args++;
596 y1 = y + *args++;
597 x2 = x + *args++;
598 y2 = y + *args++;
599 x = x + *args++;
600 y = y + *args++;
601 cairo_curve_to(cr, x1, y1, x2, y2, x, y);
602 break; 678 break;
603 case 'C': 679 case 'C':
604 x1 = *args++; 680 x1 = *args++;
605 y1 = *args++; 681 y1 = *args++;
606 x2 = *args++; 682 x2 = *args++;
607 y2 = *args++; 683 y2 = *args++;
608 x = *args++; 684 x = *args++;
609 y = *args++; 685 y = *args++;
610 cairo_curve_to(cr, x1, y1, x2, y2, x, y); 686 cairo_curve_to(cr, x1, y1, x2, y2, x, y);
611 break; 687 break;
612 case 's':
613 x1 = x + x - x2;
614 y1 = y + y - y2;
615 x2 = x + *args++;
616 y2 = y + *args++;
617 x = x + *args++;
618 y = y + *args++;
619 cairo_curve_to(cr, x1, y1, x2, y2, x, y);
620 break;
621 case 'S': 688 case 'S':
622 x1 = x + x - x2; 689 x1 = x + x - x2;
623 y1 = y + y - y2; 690 y1 = y + y - y2;
624 x2 = *args++; 691 x2 = *args++;
625 y2 = *args++; 692 y2 = *args++;
626 x = *args++; 693 x = *args++;
627 y = *args++; 694 y = *args++;
628 cairo_curve_to(cr, x1, y1, x2, y2, x, y); 695 cairo_curve_to(cr, x1, y1, x2, y2, x, y);
629 break; 696 break;
630 case 'q':
631 x1 = x + *args++;
632 y1 = y + *args++;
633 x2 = x1;
634 y2 = y1;
635 x = x + *args++;
636 y = y + *args++;
637 cairo_curve_to(cr, x1, y1, x2, y2, x, y);
638 break;
639 case 'Q': 697 case 'Q':
640 x1 = *args++; 698 x1 = *args++;
641 y1 = *args++; 699 y1 = *args++;
642 x2 = x1; 700 x2 = x1;
643 y2 = y1; 701 y2 = y1;
644 x = *args++; 702 x = *args++;
645 y = *args++; 703 y = *args++;
646 cairo_curve_to(cr, x1, y1, x2, y2, x, y); 704 cairo_curve_to(cr, x1, y1, x2, y2, x, y);
647 break; 705 break;
648 case 't':
649 x1 = x + x - x2;
650 y1 = y + y - y2;
651 x2 = x1;
652 y2 = y1;
653 x = x + *args++;
654 y = y + *args++;
655 cairo_curve_to(cr, x1, y1, x2, y2, x, y);
656 break;
657 case 'T': 706 case 'T':
658 x1 = x + x - x2; 707 x1 = x + x - x2;
659 y1 = y + y - y2; 708 y1 = y + y - y2;
660 x2 = x1; 709 x2 = x1;
661 y2 = y1; 710 y2 = y1;
662 x = *args++; 711 x = *args++;
663 y = *args++; 712 y = *args++;
664 cairo_curve_to(cr, x1, y1, x2, y2, x, y); 713 cairo_curve_to(cr, x1, y1, x2, y2, x, y);
665 break; 714 break;
715 case 'A':
716 sh_path_arc_path(cr, &args);
717 break;
666 case 'Z': 718 case 'Z':
667 case 'z':
668 cairo_close_path(cr); 719 cairo_close_path(cr);
669 break; 720 break;
670 case '\x0': 721 case '\x0':
671 i = cmd_len; /* padding! Skip remain ones. */ 722 i = cmd_len; /* padding! Skip remain ones. */
672 break; 723 break;
684 735
685 void test_sh_path_new(void) { 736 void test_sh_path_new(void) {
686 sh_path_t *path; 737 sh_path_t *path;
687 co_aix *args; 738 co_aix *args;
688 739
689 path = (sh_path_t *)sh_path_new("M 33 25l33 55C 33 87 44 22 55 99L33 77z"); 740 path = (sh_path_t *)sh_path_new("M 33 25l33 55c 33 87 44 22 55 99L33 77z");
690 CU_ASSERT(path != NULL); 741 CU_ASSERT(path != NULL);
691 CU_ASSERT(path->cmd_len == ((5 + RESERVED_AIXS + 3) & ~0x3)); 742 CU_ASSERT(path->cmd_len == ((5 + RESERVED_AIXS + 3) & ~0x3));
692 CU_ASSERT(path->arg_len == 12); 743 CU_ASSERT(path->arg_len == 12);
693 CU_ASSERT(strcmp(path->user_data, "MLCLZ") == 0); 744 CU_ASSERT(strcmp(path->user_data, "MLCLZ") == 0);
694 CU_ASSERT(strcmp(path->dev_data, "MLCLZ") == 0); 745 CU_ASSERT(strcmp(path->dev_data, "MLCLZ") == 0);
696 args = (co_aix *)(path->user_data + path->cmd_len); 747 args = (co_aix *)(path->user_data + path->cmd_len);
697 CU_ASSERT(args[0] == 33); 748 CU_ASSERT(args[0] == 33);
698 CU_ASSERT(args[1] == 25); 749 CU_ASSERT(args[1] == 25);
699 CU_ASSERT(args[2] == 66); 750 CU_ASSERT(args[2] == 66);
700 CU_ASSERT(args[3] == 80); 751 CU_ASSERT(args[3] == 80);
701 CU_ASSERT(args[4] == 33); 752 CU_ASSERT(args[4] == 99);
702 CU_ASSERT(args[5] == 87); 753 CU_ASSERT(args[5] == 167);
703 CU_ASSERT(args[6] == 44); 754 CU_ASSERT(args[6] == 110);
704 CU_ASSERT(args[7] == 22); 755 CU_ASSERT(args[7] == 102);
705 CU_ASSERT(args[8] == 55); 756 CU_ASSERT(args[8] == 121);
706 CU_ASSERT(args[9] == 99); 757 CU_ASSERT(args[9] == 179);
707 CU_ASSERT(args[10] == 33); 758 CU_ASSERT(args[10] == 33);
708 CU_ASSERT(args[11] == 77); 759 CU_ASSERT(args[11] == 77);
709 sh_path_free((shape_t *)path); 760 sh_path_free((shape_t *)path);
710 } 761 }
711 762