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: 38 curve3_inc() : 39 m_num_steps(0), m_step(0), m_scale(1.0) { } 40 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 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 54 void approximation_method(curve_approximation_method_e) {} 55 curve_approximation_method_e approximation_method() const { return curve_inc; } 56 57 void approximation_scale(double s); 58 double approximation_scale() const; 59 60 void angle_tolerance(double) {} 61 double angle_tolerance() const { return 0.0; } 62 63 void cusp_limit(double) {} 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: 97 curve3_div() : 98 m_approximation_scale(1.0), 99 m_angle_tolerance(0.0), 100 m_count(0) 101 {} 102 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 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 118 void approximation_method(curve_approximation_method_e) {} 119 curve_approximation_method_e approximation_method() const { return curve_div; } 120 121 void approximation_scale(double s) { m_approximation_scale = s; } 122 double approximation_scale() const { return m_approximation_scale; } 123 124 void angle_tolerance(double a) { m_angle_tolerance = a; } 125 double angle_tolerance() const { return m_angle_tolerance; } 126 127 void cusp_limit(double) {} 128 double cusp_limit() const { return 0.0; } 129 130 void rewind(unsigned) 131 { 132 m_count = 0; 133 } 134 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]; 170 curve4_points() {} 171 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 } 179 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: 197 curve4_inc() : 198 m_num_steps(0), m_step(0), m_scale(1.0) { } 199 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 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 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 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 226 void approximation_method(curve_approximation_method_e) {} 227 curve_approximation_method_e approximation_method() const { return curve_inc; } 228 229 void approximation_scale(double s); 230 double approximation_scale() const; 231 232 void angle_tolerance(double) {} 233 double angle_tolerance() const { return 0.0; } 234 235 void cusp_limit(double) {} 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 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 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 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 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 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 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: 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 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 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 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 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 415 void approximation_method(curve_approximation_method_e) {} 416 417 curve_approximation_method_e approximation_method() const 418 { 419 return curve_div; 420 } 421 422 void approximation_scale(double s) { m_approximation_scale = s; } 423 double approximation_scale() const { return m_approximation_scale; } 424 425 void angle_tolerance(double a) { m_angle_tolerance = a; } 426 double angle_tolerance() const { return m_angle_tolerance; } 427 428 void cusp_limit(double v) 429 { 430 m_cusp_limit = (v == 0.0) ? 0.0 : pi - v; 431 } 432 433 double cusp_limit() const 434 { 435 return (m_cusp_limit == 0.0) ? 0.0 : pi - m_cusp_limit; 436 } 437 438 void rewind(unsigned) 439 { 440 m_count = 0; 441 } 442 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: 477 curve3() : m_approximation_method(curve_div) {} 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 486 void reset() 487 { 488 m_curve_inc.reset(); 489 m_curve_div.reset(); 490 } 491 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 506 void approximation_method(curve_approximation_method_e v) 507 { 508 m_approximation_method = v; 509 } 510 511 curve_approximation_method_e approximation_method() const 512 { 513 return m_approximation_method; 514 } 515 516 void approximation_scale(double s) 517 { 518 m_curve_inc.approximation_scale(s); 519 m_curve_div.approximation_scale(s); 520 } 521 522 double approximation_scale() const 523 { 524 return m_curve_inc.approximation_scale(); 525 } 526 527 void angle_tolerance(double a) 528 { 529 m_curve_div.angle_tolerance(a); 530 } 531 532 double angle_tolerance() const 533 { 534 return m_curve_div.angle_tolerance(); 535 } 536 537 void cusp_limit(double v) 538 { 539 m_curve_div.cusp_limit(v); 540 } 541 542 double cusp_limit() const 543 { 544 return m_curve_div.cusp_limit(); 545 } 546 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 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: 582 curve4() : m_approximation_method(curve_div) {} 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 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 598 void reset() 599 { 600 m_curve_inc.reset(); 601 m_curve_div.reset(); 602 } 603 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 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 624 void approximation_method(curve_approximation_method_e v) 625 { 626 m_approximation_method = v; 627 } 628 629 curve_approximation_method_e approximation_method() const 630 { 631 return m_approximation_method; 632 } 633 634 void approximation_scale(double s) 635 { 636 m_curve_inc.approximation_scale(s); 637 m_curve_div.approximation_scale(s); 638 } 639 double approximation_scale() const { return m_curve_inc.approximation_scale(); } 640 641 void angle_tolerance(double v) 642 { 643 m_curve_div.angle_tolerance(v); 644 } 645 646 double angle_tolerance() const 647 { 648 return m_curve_div.angle_tolerance(); 649 } 650 651 void cusp_limit(double v) 652 { 653 m_curve_div.cusp_limit(v); 654 } 655 656 double cusp_limit() const 657 { 658 return m_curve_div.cusp_limit(); 659 } 660 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 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