1 //---------------------------------------------------------------------------- 2 // Anti-Grain Geometry - Version 2.4 3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 4 // Copyright (C) 2005 Tony Juricic (tonygeek@yahoo.com) 5 // 6 // Permission to copy, use, modify, sell and distribute this software 7 // is granted provided this copyright notice appears in all copies. 8 // This software is provided "as is" without express or implied 9 // warranty, and with no claim as to its suitability for any purpose. 10 // 11 //---------------------------------------------------------------------------- 12 // Contact: mcseem@antigrain.com 13 // mcseemagg@yahoo.com 14 // http://www.antigrain.com 15 //---------------------------------------------------------------------------- 16 17 #ifndef AGG_CURVES_INCLUDED 18 #define AGG_CURVES_INCLUDED 19 20 #include "agg_array.h" 21 22 namespace agg 23 { 24 25 // See Implementation agg_curves.cpp 26 27 //--------------------------------------------curve_approximation_method_e 28 enum curve_approximation_method_e 29 { 30 curve_inc, 31 curve_div 32 }; 33 34 //--------------------------------------------------------------curve3_inc 35 class curve3_inc 36 { 37 public: curve3_inc()38 curve3_inc() : 39 m_num_steps(0), m_step(0), m_scale(1.0) { } 40 curve3_inc(double x1,double y1,double x2,double y2,double x3,double y3)41 curve3_inc(double x1, double y1, 42 double x2, double y2, 43 double x3, double y3) : 44 m_num_steps(0), m_step(0), m_scale(1.0) 45 { 46 init(x1, y1, x2, y2, x3, y3); 47 } 48 reset()49 void reset() { m_num_steps = 0; m_step = -1; } 50 void init(double x1, double y1, 51 double x2, double y2, 52 double x3, double y3); 53 approximation_method(curve_approximation_method_e)54 void approximation_method(curve_approximation_method_e) {} approximation_method()55 curve_approximation_method_e approximation_method() const { return curve_inc; } 56 57 void approximation_scale(double s); 58 double approximation_scale() const; 59 angle_tolerance(double)60 void angle_tolerance(double) {} angle_tolerance()61 double angle_tolerance() const { return 0.0; } 62 cusp_limit(double)63 void cusp_limit(double) {} cusp_limit()64 double cusp_limit() const { return 0.0; } 65 66 void rewind(unsigned path_id); 67 unsigned vertex(double* x, double* y); 68 69 private: 70 int m_num_steps; 71 int m_step; 72 double m_scale; 73 double m_start_x; 74 double m_start_y; 75 double m_end_x; 76 double m_end_y; 77 double m_fx; 78 double m_fy; 79 double m_dfx; 80 double m_dfy; 81 double m_ddfx; 82 double m_ddfy; 83 double m_saved_fx; 84 double m_saved_fy; 85 double m_saved_dfx; 86 double m_saved_dfy; 87 }; 88 89 90 91 92 93 //-------------------------------------------------------------curve3_div 94 class curve3_div 95 { 96 public: curve3_div()97 curve3_div() : 98 m_approximation_scale(1.0), 99 m_angle_tolerance(0.0), 100 m_count(0) 101 {} 102 curve3_div(double x1,double y1,double x2,double y2,double x3,double y3)103 curve3_div(double x1, double y1, 104 double x2, double y2, 105 double x3, double y3) : 106 m_approximation_scale(1.0), 107 m_angle_tolerance(0.0), 108 m_count(0) 109 { 110 init(x1, y1, x2, y2, x3, y3); 111 } 112 reset()113 void reset() { m_points.remove_all(); m_count = 0; } 114 void init(double x1, double y1, 115 double x2, double y2, 116 double x3, double y3); 117 approximation_method(curve_approximation_method_e)118 void approximation_method(curve_approximation_method_e) {} approximation_method()119 curve_approximation_method_e approximation_method() const { return curve_div; } 120 approximation_scale(double s)121 void approximation_scale(double s) { m_approximation_scale = s; } approximation_scale()122 double approximation_scale() const { return m_approximation_scale; } 123 angle_tolerance(double a)124 void angle_tolerance(double a) { m_angle_tolerance = a; } angle_tolerance()125 double angle_tolerance() const { return m_angle_tolerance; } 126 cusp_limit(double)127 void cusp_limit(double) {} cusp_limit()128 double cusp_limit() const { return 0.0; } 129 rewind(unsigned)130 void rewind(unsigned) 131 { 132 m_count = 0; 133 } 134 vertex(double * x,double * y)135 unsigned vertex(double* x, double* y) 136 { 137 if(m_count >= m_points.size()) return path_cmd_stop; 138 const point_d& p = m_points[m_count++]; 139 *x = p.x; 140 *y = p.y; 141 return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to; 142 } 143 144 private: 145 void bezier(double x1, double y1, 146 double x2, double y2, 147 double x3, double y3); 148 void recursive_bezier(double x1, double y1, 149 double x2, double y2, 150 double x3, double y3, 151 unsigned level); 152 153 double m_approximation_scale; 154 double m_distance_tolerance_square; 155 double m_angle_tolerance; 156 unsigned m_count; 157 pod_bvector<point_d> m_points; 158 }; 159 160 161 162 163 164 165 166 //-------------------------------------------------------------curve4_points 167 struct curve4_points 168 { 169 double cp[8]; curve4_pointscurve4_points170 curve4_points() {} curve4_pointscurve4_points171 curve4_points(double x1, double y1, 172 double x2, double y2, 173 double x3, double y3, 174 double x4, double y4) 175 { 176 cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2; 177 cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4; 178 } initcurve4_points179 void init(double x1, double y1, 180 double x2, double y2, 181 double x3, double y3, 182 double x4, double y4) 183 { 184 cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2; 185 cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4; 186 } 187 double operator [] (unsigned i) const { return cp[i]; } 188 double& operator [] (unsigned i) { return cp[i]; } 189 }; 190 191 192 193 //-------------------------------------------------------------curve4_inc 194 class curve4_inc 195 { 196 public: curve4_inc()197 curve4_inc() : 198 m_num_steps(0), m_step(0), m_scale(1.0) { } 199 curve4_inc(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)200 curve4_inc(double x1, double y1, 201 double x2, double y2, 202 double x3, double y3, 203 double x4, double y4) : 204 m_num_steps(0), m_step(0), m_scale(1.0) 205 { 206 init(x1, y1, x2, y2, x3, y3, x4, y4); 207 } 208 curve4_inc(const curve4_points & cp)209 curve4_inc(const curve4_points& cp) : 210 m_num_steps(0), m_step(0), m_scale(1.0) 211 { 212 init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); 213 } 214 reset()215 void reset() { m_num_steps = 0; m_step = -1; } 216 void init(double x1, double y1, 217 double x2, double y2, 218 double x3, double y3, 219 double x4, double y4); 220 init(const curve4_points & cp)221 void init(const curve4_points& cp) 222 { 223 init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); 224 } 225 approximation_method(curve_approximation_method_e)226 void approximation_method(curve_approximation_method_e) {} approximation_method()227 curve_approximation_method_e approximation_method() const { return curve_inc; } 228 229 void approximation_scale(double s); 230 double approximation_scale() const; 231 angle_tolerance(double)232 void angle_tolerance(double) {} angle_tolerance()233 double angle_tolerance() const { return 0.0; } 234 cusp_limit(double)235 void cusp_limit(double) {} cusp_limit()236 double cusp_limit() const { return 0.0; } 237 238 void rewind(unsigned path_id); 239 unsigned vertex(double* x, double* y); 240 241 private: 242 int m_num_steps; 243 int m_step; 244 double m_scale; 245 double m_start_x; 246 double m_start_y; 247 double m_end_x; 248 double m_end_y; 249 double m_fx; 250 double m_fy; 251 double m_dfx; 252 double m_dfy; 253 double m_ddfx; 254 double m_ddfy; 255 double m_dddfx; 256 double m_dddfy; 257 double m_saved_fx; 258 double m_saved_fy; 259 double m_saved_dfx; 260 double m_saved_dfy; 261 double m_saved_ddfx; 262 double m_saved_ddfy; 263 }; 264 265 266 267 //-------------------------------------------------------catrom_to_bezier catrom_to_bezier(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)268 inline curve4_points catrom_to_bezier(double x1, double y1, 269 double x2, double y2, 270 double x3, double y3, 271 double x4, double y4) 272 { 273 // Trans. matrix Catmull-Rom to Bezier 274 // 275 // 0 1 0 0 276 // -1/6 1 1/6 0 277 // 0 1/6 1 -1/6 278 // 0 0 1 0 279 // 280 return curve4_points( 281 x2, 282 y2, 283 (-x1 + 6*x2 + x3) / 6, 284 (-y1 + 6*y2 + y3) / 6, 285 ( x2 + 6*x3 - x4) / 6, 286 ( y2 + 6*y3 - y4) / 6, 287 x3, 288 y3); 289 } 290 291 292 //----------------------------------------------------------------------- 293 inline curve4_points catrom_to_bezier(const curve4_points & cp)294 catrom_to_bezier(const curve4_points& cp) 295 { 296 return catrom_to_bezier(cp[0], cp[1], cp[2], cp[3], 297 cp[4], cp[5], cp[6], cp[7]); 298 } 299 300 301 302 //-----------------------------------------------------ubspline_to_bezier ubspline_to_bezier(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)303 inline curve4_points ubspline_to_bezier(double x1, double y1, 304 double x2, double y2, 305 double x3, double y3, 306 double x4, double y4) 307 { 308 // Trans. matrix Uniform BSpline to Bezier 309 // 310 // 1/6 4/6 1/6 0 311 // 0 4/6 2/6 0 312 // 0 2/6 4/6 0 313 // 0 1/6 4/6 1/6 314 // 315 return curve4_points( 316 (x1 + 4*x2 + x3) / 6, 317 (y1 + 4*y2 + y3) / 6, 318 (4*x2 + 2*x3) / 6, 319 (4*y2 + 2*y3) / 6, 320 (2*x2 + 4*x3) / 6, 321 (2*y2 + 4*y3) / 6, 322 (x2 + 4*x3 + x4) / 6, 323 (y2 + 4*y3 + y4) / 6); 324 } 325 326 327 //----------------------------------------------------------------------- 328 inline curve4_points ubspline_to_bezier(const curve4_points & cp)329 ubspline_to_bezier(const curve4_points& cp) 330 { 331 return ubspline_to_bezier(cp[0], cp[1], cp[2], cp[3], 332 cp[4], cp[5], cp[6], cp[7]); 333 } 334 335 336 337 338 //------------------------------------------------------hermite_to_bezier hermite_to_bezier(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)339 inline curve4_points hermite_to_bezier(double x1, double y1, 340 double x2, double y2, 341 double x3, double y3, 342 double x4, double y4) 343 { 344 // Trans. matrix Hermite to Bezier 345 // 346 // 1 0 0 0 347 // 1 0 1/3 0 348 // 0 1 0 -1/3 349 // 0 1 0 0 350 // 351 return curve4_points( 352 x1, 353 y1, 354 (3*x1 + x3) / 3, 355 (3*y1 + y3) / 3, 356 (3*x2 - x4) / 3, 357 (3*y2 - y4) / 3, 358 x2, 359 y2); 360 } 361 362 363 364 //----------------------------------------------------------------------- 365 inline curve4_points hermite_to_bezier(const curve4_points & cp)366 hermite_to_bezier(const curve4_points& cp) 367 { 368 return hermite_to_bezier(cp[0], cp[1], cp[2], cp[3], 369 cp[4], cp[5], cp[6], cp[7]); 370 } 371 372 373 //-------------------------------------------------------------curve4_div 374 class curve4_div 375 { 376 public: curve4_div()377 curve4_div() : 378 m_approximation_scale(1.0), 379 m_angle_tolerance(0.0), 380 m_cusp_limit(0.0), 381 m_count(0) 382 {} 383 curve4_div(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)384 curve4_div(double x1, double y1, 385 double x2, double y2, 386 double x3, double y3, 387 double x4, double y4) : 388 m_approximation_scale(1.0), 389 m_angle_tolerance(0.0), 390 m_cusp_limit(0.0), 391 m_count(0) 392 { 393 init(x1, y1, x2, y2, x3, y3, x4, y4); 394 } 395 curve4_div(const curve4_points & cp)396 curve4_div(const curve4_points& cp) : 397 m_approximation_scale(1.0), 398 m_angle_tolerance(0.0), 399 m_count(0) 400 { 401 init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); 402 } 403 reset()404 void reset() { m_points.remove_all(); m_count = 0; } 405 void init(double x1, double y1, 406 double x2, double y2, 407 double x3, double y3, 408 double x4, double y4); 409 init(const curve4_points & cp)410 void init(const curve4_points& cp) 411 { 412 init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); 413 } 414 approximation_method(curve_approximation_method_e)415 void approximation_method(curve_approximation_method_e) {} 416 approximation_method()417 curve_approximation_method_e approximation_method() const 418 { 419 return curve_div; 420 } 421 approximation_scale(double s)422 void approximation_scale(double s) { m_approximation_scale = s; } approximation_scale()423 double approximation_scale() const { return m_approximation_scale; } 424 angle_tolerance(double a)425 void angle_tolerance(double a) { m_angle_tolerance = a; } angle_tolerance()426 double angle_tolerance() const { return m_angle_tolerance; } 427 cusp_limit(double v)428 void cusp_limit(double v) 429 { 430 m_cusp_limit = (v == 0.0) ? 0.0 : pi - v; 431 } 432 cusp_limit()433 double cusp_limit() const 434 { 435 return (m_cusp_limit == 0.0) ? 0.0 : pi - m_cusp_limit; 436 } 437 rewind(unsigned)438 void rewind(unsigned) 439 { 440 m_count = 0; 441 } 442 vertex(double * x,double * y)443 unsigned vertex(double* x, double* y) 444 { 445 if(m_count >= m_points.size()) return path_cmd_stop; 446 const point_d& p = m_points[m_count++]; 447 *x = p.x; 448 *y = p.y; 449 return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to; 450 } 451 452 private: 453 void bezier(double x1, double y1, 454 double x2, double y2, 455 double x3, double y3, 456 double x4, double y4); 457 458 void recursive_bezier(double x1, double y1, 459 double x2, double y2, 460 double x3, double y3, 461 double x4, double y4, 462 unsigned level); 463 464 double m_approximation_scale; 465 double m_distance_tolerance_square; 466 double m_angle_tolerance; 467 double m_cusp_limit; 468 unsigned m_count; 469 pod_bvector<point_d> m_points; 470 }; 471 472 473 //-----------------------------------------------------------------curve3 474 class curve3 475 { 476 public: curve3()477 curve3() : m_approximation_method(curve_div) {} curve3(double x1,double y1,double x2,double y2,double x3,double y3)478 curve3(double x1, double y1, 479 double x2, double y2, 480 double x3, double y3) : 481 m_approximation_method(curve_div) 482 { 483 init(x1, y1, x2, y2, x3, y3); 484 } 485 reset()486 void reset() 487 { 488 m_curve_inc.reset(); 489 m_curve_div.reset(); 490 } 491 init(double x1,double y1,double x2,double y2,double x3,double y3)492 void init(double x1, double y1, 493 double x2, double y2, 494 double x3, double y3) 495 { 496 if(m_approximation_method == curve_inc) 497 { 498 m_curve_inc.init(x1, y1, x2, y2, x3, y3); 499 } 500 else 501 { 502 m_curve_div.init(x1, y1, x2, y2, x3, y3); 503 } 504 } 505 approximation_method(curve_approximation_method_e v)506 void approximation_method(curve_approximation_method_e v) 507 { 508 m_approximation_method = v; 509 } 510 approximation_method()511 curve_approximation_method_e approximation_method() const 512 { 513 return m_approximation_method; 514 } 515 approximation_scale(double s)516 void approximation_scale(double s) 517 { 518 m_curve_inc.approximation_scale(s); 519 m_curve_div.approximation_scale(s); 520 } 521 approximation_scale()522 double approximation_scale() const 523 { 524 return m_curve_inc.approximation_scale(); 525 } 526 angle_tolerance(double a)527 void angle_tolerance(double a) 528 { 529 m_curve_div.angle_tolerance(a); 530 } 531 angle_tolerance()532 double angle_tolerance() const 533 { 534 return m_curve_div.angle_tolerance(); 535 } 536 cusp_limit(double v)537 void cusp_limit(double v) 538 { 539 m_curve_div.cusp_limit(v); 540 } 541 cusp_limit()542 double cusp_limit() const 543 { 544 return m_curve_div.cusp_limit(); 545 } 546 rewind(unsigned path_id)547 void rewind(unsigned path_id) 548 { 549 if(m_approximation_method == curve_inc) 550 { 551 m_curve_inc.rewind(path_id); 552 } 553 else 554 { 555 m_curve_div.rewind(path_id); 556 } 557 } 558 vertex(double * x,double * y)559 unsigned vertex(double* x, double* y) 560 { 561 if(m_approximation_method == curve_inc) 562 { 563 return m_curve_inc.vertex(x, y); 564 } 565 return m_curve_div.vertex(x, y); 566 } 567 568 private: 569 curve3_inc m_curve_inc; 570 curve3_div m_curve_div; 571 curve_approximation_method_e m_approximation_method; 572 }; 573 574 575 576 577 578 //-----------------------------------------------------------------curve4 579 class curve4 580 { 581 public: curve4()582 curve4() : m_approximation_method(curve_div) {} curve4(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)583 curve4(double x1, double y1, 584 double x2, double y2, 585 double x3, double y3, 586 double x4, double y4) : 587 m_approximation_method(curve_div) 588 { 589 init(x1, y1, x2, y2, x3, y3, x4, y4); 590 } 591 curve4(const curve4_points & cp)592 curve4(const curve4_points& cp) : 593 m_approximation_method(curve_div) 594 { 595 init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); 596 } 597 reset()598 void reset() 599 { 600 m_curve_inc.reset(); 601 m_curve_div.reset(); 602 } 603 init(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)604 void init(double x1, double y1, 605 double x2, double y2, 606 double x3, double y3, 607 double x4, double y4) 608 { 609 if(m_approximation_method == curve_inc) 610 { 611 m_curve_inc.init(x1, y1, x2, y2, x3, y3, x4, y4); 612 } 613 else 614 { 615 m_curve_div.init(x1, y1, x2, y2, x3, y3, x4, y4); 616 } 617 } 618 init(const curve4_points & cp)619 void init(const curve4_points& cp) 620 { 621 init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); 622 } 623 approximation_method(curve_approximation_method_e v)624 void approximation_method(curve_approximation_method_e v) 625 { 626 m_approximation_method = v; 627 } 628 approximation_method()629 curve_approximation_method_e approximation_method() const 630 { 631 return m_approximation_method; 632 } 633 approximation_scale(double s)634 void approximation_scale(double s) 635 { 636 m_curve_inc.approximation_scale(s); 637 m_curve_div.approximation_scale(s); 638 } approximation_scale()639 double approximation_scale() const { return m_curve_inc.approximation_scale(); } 640 angle_tolerance(double v)641 void angle_tolerance(double v) 642 { 643 m_curve_div.angle_tolerance(v); 644 } 645 angle_tolerance()646 double angle_tolerance() const 647 { 648 return m_curve_div.angle_tolerance(); 649 } 650 cusp_limit(double v)651 void cusp_limit(double v) 652 { 653 m_curve_div.cusp_limit(v); 654 } 655 cusp_limit()656 double cusp_limit() const 657 { 658 return m_curve_div.cusp_limit(); 659 } 660 rewind(unsigned path_id)661 void rewind(unsigned path_id) 662 { 663 if(m_approximation_method == curve_inc) 664 { 665 m_curve_inc.rewind(path_id); 666 } 667 else 668 { 669 m_curve_div.rewind(path_id); 670 } 671 } 672 vertex(double * x,double * y)673 unsigned vertex(double* x, double* y) 674 { 675 if(m_approximation_method == curve_inc) 676 { 677 return m_curve_inc.vertex(x, y); 678 } 679 return m_curve_div.vertex(x, y); 680 } 681 682 private: 683 curve4_inc m_curve_inc; 684 curve4_div m_curve_div; 685 curve_approximation_method_e m_approximation_method; 686 }; 687 688 689 690 691 } 692 693 #endif 694