1 //---------------------------------------------------------------------------- 2 // Anti-Grain Geometry - Version 2.4 3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 4 // 5 // Permission to copy, use, modify, sell and distribute this software 6 // is granted provided this copyright notice appears in all copies. 7 // This software is provided "as is" without express or implied 8 // warranty, and with no claim as to its suitability for any purpose. 9 // 10 //---------------------------------------------------------------------------- 11 // Contact: mcseem@antigrain.com 12 // mcseemagg@yahoo.com 13 // http://www.antigrain.com 14 //---------------------------------------------------------------------------- 15 16 #ifndef AGG_PATH_STORAGE_INCLUDED 17 #define AGG_PATH_STORAGE_INCLUDED 18 19 #include <string.h> 20 #include <math.h> 21 #include "agg_math.h" 22 #include "agg_array.h" 23 #include "agg_bezier_arc.h" 24 25 namespace agg 26 { 27 28 29 //----------------------------------------------------vertex_block_storage 30 template<class T, unsigned BlockShift=8, unsigned BlockPool=256> 31 class vertex_block_storage 32 { 33 public: 34 // Allocation parameters 35 enum block_scale_e 36 { 37 block_shift = BlockShift, 38 block_size = 1 << block_shift, 39 block_mask = block_size - 1, 40 block_pool = BlockPool 41 }; 42 43 typedef T value_type; 44 typedef vertex_block_storage<T, BlockShift, BlockPool> self_type; 45 46 ~vertex_block_storage(); 47 vertex_block_storage(); 48 vertex_block_storage(const self_type& v); 49 const self_type& operator = (const self_type& ps); 50 51 void remove_all(); 52 void free_all(); 53 54 void add_vertex(double x, double y, unsigned cmd); 55 void modify_vertex(unsigned idx, double x, double y); 56 void modify_vertex(unsigned idx, double x, double y, unsigned cmd); 57 void modify_command(unsigned idx, unsigned cmd); 58 void swap_vertices(unsigned v1, unsigned v2); 59 60 unsigned last_command() const; 61 unsigned last_vertex(double* x, double* y) const; 62 unsigned prev_vertex(double* x, double* y) const; 63 64 double last_x() const; 65 double last_y() const; 66 67 unsigned total_vertices() const; 68 unsigned vertex(unsigned idx, double* x, double* y) const; 69 unsigned command(unsigned idx) const; 70 71 private: 72 void allocate_block(unsigned nb); 73 int8u* storage_ptrs(T** xy_ptr); 74 75 private: 76 unsigned m_total_vertices; 77 unsigned m_total_blocks; 78 unsigned m_max_blocks; 79 T** m_coord_blocks; 80 int8u** m_cmd_blocks; 81 }; 82 83 84 //------------------------------------------------------------------------ 85 template<class T, unsigned S, unsigned P> free_all()86 void vertex_block_storage<T,S,P>::free_all() 87 { 88 if(m_total_blocks) 89 { 90 T** coord_blk = m_coord_blocks + m_total_blocks - 1; 91 while(m_total_blocks--) 92 { 93 pod_allocator<T>::deallocate( 94 *coord_blk, 95 block_size * 2 + 96 block_size / (sizeof(T) / sizeof(unsigned char))); 97 --coord_blk; 98 } 99 pod_allocator<T*>::deallocate(m_coord_blocks, m_max_blocks * 2); 100 m_total_blocks = 0; 101 m_max_blocks = 0; 102 m_coord_blocks = 0; 103 m_cmd_blocks = 0; 104 m_total_vertices = 0; 105 } 106 } 107 108 //------------------------------------------------------------------------ 109 template<class T, unsigned S, unsigned P> ~vertex_block_storage()110 vertex_block_storage<T,S,P>::~vertex_block_storage() 111 { 112 free_all(); 113 } 114 115 //------------------------------------------------------------------------ 116 template<class T, unsigned S, unsigned P> vertex_block_storage()117 vertex_block_storage<T,S,P>::vertex_block_storage() : 118 m_total_vertices(0), 119 m_total_blocks(0), 120 m_max_blocks(0), 121 m_coord_blocks(0), 122 m_cmd_blocks(0) 123 { 124 } 125 126 //------------------------------------------------------------------------ 127 template<class T, unsigned S, unsigned P> vertex_block_storage(const vertex_block_storage<T,S,P> & v)128 vertex_block_storage<T,S,P>::vertex_block_storage(const vertex_block_storage<T,S,P>& v) : 129 m_total_vertices(0), 130 m_total_blocks(0), 131 m_max_blocks(0), 132 m_coord_blocks(0), 133 m_cmd_blocks(0) 134 { 135 *this = v; 136 } 137 138 //------------------------------------------------------------------------ 139 template<class T, unsigned S, unsigned P> 140 const vertex_block_storage<T,S,P>& 141 vertex_block_storage<T,S,P>::operator = (const vertex_block_storage<T,S,P>& v) 142 { 143 remove_all(); 144 unsigned i; 145 for(i = 0; i < v.total_vertices(); i++) 146 { 147 double x, y; 148 unsigned cmd = v.vertex(i, &x, &y); 149 add_vertex(x, y, cmd); 150 } 151 return *this; 152 } 153 154 //------------------------------------------------------------------------ 155 template<class T, unsigned S, unsigned P> remove_all()156 inline void vertex_block_storage<T,S,P>::remove_all() 157 { 158 m_total_vertices = 0; 159 } 160 161 //------------------------------------------------------------------------ 162 template<class T, unsigned S, unsigned P> add_vertex(double x,double y,unsigned cmd)163 inline void vertex_block_storage<T,S,P>::add_vertex(double x, double y, 164 unsigned cmd) 165 { 166 T* coord_ptr = 0; 167 *storage_ptrs(&coord_ptr) = (int8u)cmd; 168 coord_ptr[0] = T(x); 169 coord_ptr[1] = T(y); 170 m_total_vertices++; 171 } 172 173 //------------------------------------------------------------------------ 174 template<class T, unsigned S, unsigned P> modify_vertex(unsigned idx,double x,double y)175 inline void vertex_block_storage<T,S,P>::modify_vertex(unsigned idx, 176 double x, double y) 177 { 178 T* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1); 179 pv[0] = T(x); 180 pv[1] = T(y); 181 } 182 183 //------------------------------------------------------------------------ 184 template<class T, unsigned S, unsigned P> modify_vertex(unsigned idx,double x,double y,unsigned cmd)185 inline void vertex_block_storage<T,S,P>::modify_vertex(unsigned idx, 186 double x, double y, 187 unsigned cmd) 188 { 189 unsigned block = idx >> block_shift; 190 unsigned offset = idx & block_mask; 191 T* pv = m_coord_blocks[block] + (offset << 1); 192 pv[0] = T(x); 193 pv[1] = T(y); 194 m_cmd_blocks[block][offset] = (int8u)cmd; 195 } 196 197 //------------------------------------------------------------------------ 198 template<class T, unsigned S, unsigned P> modify_command(unsigned idx,unsigned cmd)199 inline void vertex_block_storage<T,S,P>::modify_command(unsigned idx, 200 unsigned cmd) 201 { 202 m_cmd_blocks[idx >> block_shift][idx & block_mask] = (int8u)cmd; 203 } 204 205 //------------------------------------------------------------------------ 206 template<class T, unsigned S, unsigned P> swap_vertices(unsigned v1,unsigned v2)207 inline void vertex_block_storage<T,S,P>::swap_vertices(unsigned v1, unsigned v2) 208 { 209 unsigned b1 = v1 >> block_shift; 210 unsigned b2 = v2 >> block_shift; 211 unsigned o1 = v1 & block_mask; 212 unsigned o2 = v2 & block_mask; 213 T* pv1 = m_coord_blocks[b1] + (o1 << 1); 214 T* pv2 = m_coord_blocks[b2] + (o2 << 1); 215 T val; 216 val = pv1[0]; pv1[0] = pv2[0]; pv2[0] = val; 217 val = pv1[1]; pv1[1] = pv2[1]; pv2[1] = val; 218 int8u cmd = m_cmd_blocks[b1][o1]; 219 m_cmd_blocks[b1][o1] = m_cmd_blocks[b2][o2]; 220 m_cmd_blocks[b2][o2] = cmd; 221 } 222 223 //------------------------------------------------------------------------ 224 template<class T, unsigned S, unsigned P> last_command()225 inline unsigned vertex_block_storage<T,S,P>::last_command() const 226 { 227 if(m_total_vertices) return command(m_total_vertices - 1); 228 return path_cmd_stop; 229 } 230 231 //------------------------------------------------------------------------ 232 template<class T, unsigned S, unsigned P> last_vertex(double * x,double * y)233 inline unsigned vertex_block_storage<T,S,P>::last_vertex(double* x, double* y) const 234 { 235 if(m_total_vertices) return vertex(m_total_vertices - 1, x, y); 236 return path_cmd_stop; 237 } 238 239 //------------------------------------------------------------------------ 240 template<class T, unsigned S, unsigned P> prev_vertex(double * x,double * y)241 inline unsigned vertex_block_storage<T,S,P>::prev_vertex(double* x, double* y) const 242 { 243 if(m_total_vertices > 1) return vertex(m_total_vertices - 2, x, y); 244 return path_cmd_stop; 245 } 246 247 //------------------------------------------------------------------------ 248 template<class T, unsigned S, unsigned P> last_x()249 inline double vertex_block_storage<T,S,P>::last_x() const 250 { 251 if(m_total_vertices) 252 { 253 unsigned idx = m_total_vertices - 1; 254 return m_coord_blocks[idx >> block_shift][(idx & block_mask) << 1]; 255 } 256 return 0.0; 257 } 258 259 //------------------------------------------------------------------------ 260 template<class T, unsigned S, unsigned P> last_y()261 inline double vertex_block_storage<T,S,P>::last_y() const 262 { 263 if(m_total_vertices) 264 { 265 unsigned idx = m_total_vertices - 1; 266 return m_coord_blocks[idx >> block_shift][((idx & block_mask) << 1) + 1]; 267 } 268 return 0.0; 269 } 270 271 //------------------------------------------------------------------------ 272 template<class T, unsigned S, unsigned P> total_vertices()273 inline unsigned vertex_block_storage<T,S,P>::total_vertices() const 274 { 275 return m_total_vertices; 276 } 277 278 //------------------------------------------------------------------------ 279 template<class T, unsigned S, unsigned P> vertex(unsigned idx,double * x,double * y)280 inline unsigned vertex_block_storage<T,S,P>::vertex(unsigned idx, 281 double* x, double* y) const 282 { 283 unsigned nb = idx >> block_shift; 284 const T* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1); 285 *x = pv[0]; 286 *y = pv[1]; 287 return m_cmd_blocks[nb][idx & block_mask]; 288 } 289 290 //------------------------------------------------------------------------ 291 template<class T, unsigned S, unsigned P> command(unsigned idx)292 inline unsigned vertex_block_storage<T,S,P>::command(unsigned idx) const 293 { 294 return m_cmd_blocks[idx >> block_shift][idx & block_mask]; 295 } 296 297 //------------------------------------------------------------------------ 298 template<class T, unsigned S, unsigned P> allocate_block(unsigned nb)299 void vertex_block_storage<T,S,P>::allocate_block(unsigned nb) 300 { 301 if(nb >= m_max_blocks) 302 { 303 T** new_coords = 304 pod_allocator<T*>::allocate((m_max_blocks + block_pool) * 2); 305 306 unsigned char** new_cmds = 307 (unsigned char**)(new_coords + m_max_blocks + block_pool); 308 309 if(m_coord_blocks) 310 { 311 memcpy(new_coords, 312 m_coord_blocks, 313 m_max_blocks * sizeof(T*)); 314 315 memcpy(new_cmds, 316 m_cmd_blocks, 317 m_max_blocks * sizeof(unsigned char*)); 318 319 pod_allocator<T*>::deallocate(m_coord_blocks, m_max_blocks * 2); 320 } 321 m_coord_blocks = new_coords; 322 m_cmd_blocks = new_cmds; 323 m_max_blocks += block_pool; 324 } 325 m_coord_blocks[nb] = 326 pod_allocator<T>::allocate(block_size * 2 + 327 block_size / (sizeof(T) / sizeof(unsigned char))); 328 329 m_cmd_blocks[nb] = 330 (unsigned char*)(m_coord_blocks[nb] + block_size * 2); 331 332 m_total_blocks++; 333 } 334 335 //------------------------------------------------------------------------ 336 template<class T, unsigned S, unsigned P> storage_ptrs(T ** xy_ptr)337 int8u* vertex_block_storage<T,S,P>::storage_ptrs(T** xy_ptr) 338 { 339 unsigned nb = m_total_vertices >> block_shift; 340 if(nb >= m_total_blocks) 341 { 342 allocate_block(nb); 343 } 344 *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1); 345 return m_cmd_blocks[nb] + (m_total_vertices & block_mask); 346 } 347 348 349 350 351 //-----------------------------------------------------poly_plain_adaptor 352 template<class T> class poly_plain_adaptor 353 { 354 public: 355 typedef T value_type; 356 poly_plain_adaptor()357 poly_plain_adaptor() : 358 m_data(0), 359 m_ptr(0), 360 m_end(0), 361 m_closed(false), 362 m_stop(false) 363 {} 364 poly_plain_adaptor(const T * data,unsigned num_points,bool closed)365 poly_plain_adaptor(const T* data, unsigned num_points, bool closed) : 366 m_data(data), 367 m_ptr(data), 368 m_end(data + num_points * 2), 369 m_closed(closed), 370 m_stop(false) 371 {} 372 init(const T * data,unsigned num_points,bool closed)373 void init(const T* data, unsigned num_points, bool closed) 374 { 375 m_data = data; 376 m_ptr = data; 377 m_end = data + num_points * 2; 378 m_closed = closed; 379 m_stop = false; 380 } 381 rewind(unsigned)382 void rewind(unsigned) 383 { 384 m_ptr = m_data; 385 m_stop = false; 386 } 387 vertex(double * x,double * y)388 unsigned vertex(double* x, double* y) 389 { 390 if(m_ptr < m_end) 391 { 392 bool first = m_ptr == m_data; 393 *x = *m_ptr++; 394 *y = *m_ptr++; 395 return first ? path_cmd_move_to : path_cmd_line_to; 396 } 397 *x = *y = 0.0; 398 if(m_closed && !m_stop) 399 { 400 m_stop = true; 401 return path_cmd_end_poly | path_flags_close; 402 } 403 return path_cmd_stop; 404 } 405 406 private: 407 const T* m_data; 408 const T* m_ptr; 409 const T* m_end; 410 bool m_closed; 411 bool m_stop; 412 }; 413 414 415 416 417 418 //-------------------------------------------------poly_container_adaptor 419 template<class Container> class poly_container_adaptor 420 { 421 public: 422 typedef typename Container::value_type vertex_type; 423 poly_container_adaptor()424 poly_container_adaptor() : 425 m_container(0), 426 m_index(0), 427 m_closed(false), 428 m_stop(false) 429 {} 430 poly_container_adaptor(const Container & data,bool closed)431 poly_container_adaptor(const Container& data, bool closed) : 432 m_container(&data), 433 m_index(0), 434 m_closed(closed), 435 m_stop(false) 436 {} 437 init(const Container & data,bool closed)438 void init(const Container& data, bool closed) 439 { 440 m_container = &data; 441 m_index = 0; 442 m_closed = closed; 443 m_stop = false; 444 } 445 rewind(unsigned)446 void rewind(unsigned) 447 { 448 m_index = 0; 449 m_stop = false; 450 } 451 vertex(double * x,double * y)452 unsigned vertex(double* x, double* y) 453 { 454 if(m_index < m_container->size()) 455 { 456 bool first = m_index == 0; 457 const vertex_type& v = (*m_container)[m_index++]; 458 *x = v.x; 459 *y = v.y; 460 return first ? path_cmd_move_to : path_cmd_line_to; 461 } 462 *x = *y = 0.0; 463 if(m_closed && !m_stop) 464 { 465 m_stop = true; 466 return path_cmd_end_poly | path_flags_close; 467 } 468 return path_cmd_stop; 469 } 470 471 private: 472 const Container* m_container; 473 unsigned m_index; 474 bool m_closed; 475 bool m_stop; 476 }; 477 478 479 480 //-----------------------------------------poly_container_reverse_adaptor 481 template<class Container> class poly_container_reverse_adaptor 482 { 483 public: 484 typedef typename Container::value_type vertex_type; 485 poly_container_reverse_adaptor()486 poly_container_reverse_adaptor() : 487 m_container(0), 488 m_index(-1), 489 m_closed(false), 490 m_stop(false) 491 {} 492 poly_container_reverse_adaptor(Container & data,bool closed)493 poly_container_reverse_adaptor(Container& data, bool closed) : 494 m_container(&data), 495 m_index(-1), 496 m_closed(closed), 497 m_stop(false) 498 {} 499 init(Container & data,bool closed)500 void init(Container& data, bool closed) 501 { 502 m_container = &data; 503 m_index = m_container->size() - 1; 504 m_closed = closed; 505 m_stop = false; 506 } 507 rewind(unsigned)508 void rewind(unsigned) 509 { 510 m_index = m_container->size() - 1; 511 m_stop = false; 512 } 513 vertex(double * x,double * y)514 unsigned vertex(double* x, double* y) 515 { 516 if(m_index >= 0) 517 { 518 bool first = m_index == int(m_container->size() - 1); 519 const vertex_type& v = (*m_container)[m_index--]; 520 *x = v.x; 521 *y = v.y; 522 return first ? path_cmd_move_to : path_cmd_line_to; 523 } 524 *x = *y = 0.0; 525 if(m_closed && !m_stop) 526 { 527 m_stop = true; 528 return path_cmd_end_poly | path_flags_close; 529 } 530 return path_cmd_stop; 531 } 532 533 private: 534 Container* m_container; 535 int m_index; 536 bool m_closed; 537 bool m_stop; 538 }; 539 540 541 542 543 544 //--------------------------------------------------------line_adaptor 545 class line_adaptor 546 { 547 public: 548 typedef double value_type; 549 line_adaptor()550 line_adaptor() : m_line(m_coord, 2, false) {} line_adaptor(double x1,double y1,double x2,double y2)551 line_adaptor(double x1, double y1, double x2, double y2) : 552 m_line(m_coord, 2, false) 553 { 554 m_coord[0] = x1; 555 m_coord[1] = y1; 556 m_coord[2] = x2; 557 m_coord[3] = y2; 558 } 559 init(double x1,double y1,double x2,double y2)560 void init(double x1, double y1, double x2, double y2) 561 { 562 m_coord[0] = x1; 563 m_coord[1] = y1; 564 m_coord[2] = x2; 565 m_coord[3] = y2; 566 m_line.rewind(0); 567 } 568 rewind(unsigned)569 void rewind(unsigned) 570 { 571 m_line.rewind(0); 572 } 573 vertex(double * x,double * y)574 unsigned vertex(double* x, double* y) 575 { 576 return m_line.vertex(x, y); 577 } 578 579 private: 580 double m_coord[4]; 581 poly_plain_adaptor<double> m_line; 582 }; 583 584 585 586 587 588 589 590 591 592 593 594 595 596 //---------------------------------------------------------------path_base 597 // A container to store vertices with their flags. 598 // A path consists of a number of contours separated with "move_to" 599 // commands. The path storage can keep and maintain more than one 600 // path. 601 // To navigate to the beginning of a particular path, use rewind(path_id); 602 // Where path_id is what start_new_path() returns. So, when you call 603 // start_new_path() you need to store its return value somewhere else 604 // to navigate to the path afterwards. 605 // 606 // See also: vertex_source concept 607 //------------------------------------------------------------------------ 608 template<class VertexContainer> class path_base 609 { 610 public: 611 typedef VertexContainer container_type; 612 typedef path_base<VertexContainer> self_type; 613 614 //-------------------------------------------------------------------- path_base()615 path_base() : m_vertices(), m_iterator(0) {} remove_all()616 void remove_all() { m_vertices.remove_all(); m_iterator = 0; } free_all()617 void free_all() { m_vertices.free_all(); m_iterator = 0; } 618 619 // Make path functions 620 //-------------------------------------------------------------------- 621 unsigned start_new_path(); 622 623 void move_to(double x, double y); 624 void move_rel(double dx, double dy); 625 626 void line_to(double x, double y); 627 void line_rel(double dx, double dy); 628 629 void hline_to(double x); 630 void hline_rel(double dx); 631 632 void vline_to(double y); 633 void vline_rel(double dy); 634 635 void arc_to(double rx, double ry, 636 double angle, 637 bool large_arc_flag, 638 bool sweep_flag, 639 double x, double y); 640 641 void arc_rel(double rx, double ry, 642 double angle, 643 bool large_arc_flag, 644 bool sweep_flag, 645 double dx, double dy); 646 647 void curve3(double x_ctrl, double y_ctrl, 648 double x_to, double y_to); 649 650 void curve3_rel(double dx_ctrl, double dy_ctrl, 651 double dx_to, double dy_to); 652 653 void curve3(double x_to, double y_to); 654 655 void curve3_rel(double dx_to, double dy_to); 656 657 void curve4(double x_ctrl1, double y_ctrl1, 658 double x_ctrl2, double y_ctrl2, 659 double x_to, double y_to); 660 661 void curve4_rel(double dx_ctrl1, double dy_ctrl1, 662 double dx_ctrl2, double dy_ctrl2, 663 double dx_to, double dy_to); 664 665 void curve4(double x_ctrl2, double y_ctrl2, 666 double x_to, double y_to); 667 668 void curve4_rel(double x_ctrl2, double y_ctrl2, 669 double x_to, double y_to); 670 671 672 void end_poly(unsigned flags = path_flags_close); 673 void close_polygon(unsigned flags = path_flags_none); 674 675 // Accessors 676 //-------------------------------------------------------------------- vertices()677 const container_type& vertices() const { return m_vertices; } vertices()678 container_type& vertices() { return m_vertices; } 679 680 unsigned total_vertices() const; 681 682 void rel_to_abs(double* x, double* y) const; 683 684 unsigned last_vertex(double* x, double* y) const; 685 unsigned prev_vertex(double* x, double* y) const; 686 687 double last_x() const; 688 double last_y() const; 689 690 unsigned vertex(unsigned idx, double* x, double* y) const; 691 unsigned command(unsigned idx) const; 692 693 void modify_vertex(unsigned idx, double x, double y); 694 void modify_vertex(unsigned idx, double x, double y, unsigned cmd); 695 void modify_command(unsigned idx, unsigned cmd); 696 697 // VertexSource interface 698 //-------------------------------------------------------------------- 699 void rewind(unsigned path_id); 700 unsigned vertex(double* x, double* y); 701 702 // Arrange the orientation of a polygon, all polygons in a path, 703 // or in all paths. After calling arrange_orientations() or 704 // arrange_orientations_all_paths(), all the polygons will have 705 // the same orientation, i.e. path_flags_cw or path_flags_ccw 706 //-------------------------------------------------------------------- 707 unsigned arrange_polygon_orientation(unsigned start, path_flags_e orientation); 708 unsigned arrange_orientations(unsigned path_id, path_flags_e orientation); 709 void arrange_orientations_all_paths(path_flags_e orientation); 710 void invert_polygon(unsigned start); 711 712 // Flip all vertices horizontally or vertically, 713 // between x1 and x2, or between y1 and y2 respectively 714 //-------------------------------------------------------------------- 715 void flip_x(double x1, double x2); 716 void flip_y(double y1, double y2); 717 718 // Concatenate path. The path is added as is. 719 //-------------------------------------------------------------------- 720 template<class VertexSource> 721 void concat_path(VertexSource& vs, unsigned path_id = 0) 722 { 723 double x, y; 724 unsigned cmd; 725 vs.rewind(path_id); 726 while(!is_stop(cmd = vs.vertex(&x, &y))) 727 { 728 m_vertices.add_vertex(x, y, cmd); 729 } 730 } 731 732 //-------------------------------------------------------------------- 733 // Join path. The path is joined with the existing one, that is, 734 // it behaves as if the pen of a plotter was always down (drawing) 735 template<class VertexSource> 736 void join_path(VertexSource& vs, unsigned path_id = 0) 737 { 738 double x, y; 739 unsigned cmd; 740 vs.rewind(path_id); 741 cmd = vs.vertex(&x, &y); 742 if(!is_stop(cmd)) 743 { 744 if(is_vertex(cmd)) 745 { 746 double x0, y0; 747 unsigned cmd0 = last_vertex(&x0, &y0); 748 if(is_vertex(cmd0)) 749 { 750 if(calc_distance(x, y, x0, y0) > vertex_dist_epsilon) 751 { 752 if(is_move_to(cmd)) cmd = path_cmd_line_to; 753 m_vertices.add_vertex(x, y, cmd); 754 } 755 } 756 else 757 { 758 if(is_stop(cmd0)) 759 { 760 cmd = path_cmd_move_to; 761 } 762 else 763 { 764 if(is_move_to(cmd)) cmd = path_cmd_line_to; 765 } 766 m_vertices.add_vertex(x, y, cmd); 767 } 768 } 769 while(!is_stop(cmd = vs.vertex(&x, &y))) 770 { 771 m_vertices.add_vertex(x, y, is_move_to(cmd) ? 772 unsigned(path_cmd_line_to) : 773 cmd); 774 } 775 } 776 } 777 778 // Concatenate polygon/polyline. 779 //-------------------------------------------------------------------- concat_poly(const T * data,unsigned num_points,bool closed)780 template<class T> void concat_poly(const T* data, 781 unsigned num_points, 782 bool closed) 783 { 784 poly_plain_adaptor<T> poly(data, num_points, closed); 785 concat_path(poly); 786 } 787 788 // Join polygon/polyline continuously. 789 //-------------------------------------------------------------------- join_poly(const T * data,unsigned num_points,bool closed)790 template<class T> void join_poly(const T* data, 791 unsigned num_points, 792 bool closed) 793 { 794 poly_plain_adaptor<T> poly(data, num_points, closed); 795 join_path(poly); 796 } 797 798 //-------------------------------------------------------------------- 799 void translate(double dx, double dy, unsigned path_id=0); 800 void translate_all_paths(double dx, double dy); 801 802 //-------------------------------------------------------------------- 803 template<class Trans> 804 void transform(const Trans& trans, unsigned path_id=0) 805 { 806 unsigned num_ver = m_vertices.total_vertices(); 807 for(; path_id < num_ver; path_id++) 808 { 809 double x, y; 810 unsigned cmd = m_vertices.vertex(path_id, &x, &y); 811 if(is_stop(cmd)) break; 812 if(is_vertex(cmd)) 813 { 814 trans.transform(&x, &y); 815 m_vertices.modify_vertex(path_id, x, y); 816 } 817 } 818 } 819 820 //-------------------------------------------------------------------- 821 template<class Trans> transform_all_paths(const Trans & trans)822 void transform_all_paths(const Trans& trans) 823 { 824 unsigned idx; 825 unsigned num_ver = m_vertices.total_vertices(); 826 for(idx = 0; idx < num_ver; idx++) 827 { 828 double x, y; 829 if(is_vertex(m_vertices.vertex(idx, &x, &y))) 830 { 831 trans.transform(&x, &y); 832 m_vertices.modify_vertex(idx, x, y); 833 } 834 } 835 } 836 837 838 839 private: 840 unsigned perceive_polygon_orientation(unsigned start, unsigned end); 841 void invert_polygon(unsigned start, unsigned end); 842 843 VertexContainer m_vertices; 844 unsigned m_iterator; 845 }; 846 847 //------------------------------------------------------------------------ 848 template<class VC> start_new_path()849 unsigned path_base<VC>::start_new_path() 850 { 851 if(!is_stop(m_vertices.last_command())) 852 { 853 m_vertices.add_vertex(0.0, 0.0, path_cmd_stop); 854 } 855 return m_vertices.total_vertices(); 856 } 857 858 859 //------------------------------------------------------------------------ 860 template<class VC> rel_to_abs(double * x,double * y)861 inline void path_base<VC>::rel_to_abs(double* x, double* y) const 862 { 863 if(m_vertices.total_vertices()) 864 { 865 double x2; 866 double y2; 867 if(is_vertex(m_vertices.last_vertex(&x2, &y2))) 868 { 869 *x += x2; 870 *y += y2; 871 } 872 } 873 } 874 875 //------------------------------------------------------------------------ 876 template<class VC> move_to(double x,double y)877 inline void path_base<VC>::move_to(double x, double y) 878 { 879 m_vertices.add_vertex(x, y, path_cmd_move_to); 880 } 881 882 //------------------------------------------------------------------------ 883 template<class VC> move_rel(double dx,double dy)884 inline void path_base<VC>::move_rel(double dx, double dy) 885 { 886 rel_to_abs(&dx, &dy); 887 m_vertices.add_vertex(dx, dy, path_cmd_move_to); 888 } 889 890 //------------------------------------------------------------------------ 891 template<class VC> line_to(double x,double y)892 inline void path_base<VC>::line_to(double x, double y) 893 { 894 m_vertices.add_vertex(x, y, path_cmd_line_to); 895 } 896 897 //------------------------------------------------------------------------ 898 template<class VC> line_rel(double dx,double dy)899 inline void path_base<VC>::line_rel(double dx, double dy) 900 { 901 rel_to_abs(&dx, &dy); 902 m_vertices.add_vertex(dx, dy, path_cmd_line_to); 903 } 904 905 //------------------------------------------------------------------------ 906 template<class VC> hline_to(double x)907 inline void path_base<VC>::hline_to(double x) 908 { 909 m_vertices.add_vertex(x, last_y(), path_cmd_line_to); 910 } 911 912 //------------------------------------------------------------------------ 913 template<class VC> hline_rel(double dx)914 inline void path_base<VC>::hline_rel(double dx) 915 { 916 double dy = 0; 917 rel_to_abs(&dx, &dy); 918 m_vertices.add_vertex(dx, dy, path_cmd_line_to); 919 } 920 921 //------------------------------------------------------------------------ 922 template<class VC> vline_to(double y)923 inline void path_base<VC>::vline_to(double y) 924 { 925 m_vertices.add_vertex(last_x(), y, path_cmd_line_to); 926 } 927 928 //------------------------------------------------------------------------ 929 template<class VC> vline_rel(double dy)930 inline void path_base<VC>::vline_rel(double dy) 931 { 932 double dx = 0; 933 rel_to_abs(&dx, &dy); 934 m_vertices.add_vertex(dx, dy, path_cmd_line_to); 935 } 936 937 //------------------------------------------------------------------------ 938 template<class VC> arc_to(double rx,double ry,double angle,bool large_arc_flag,bool sweep_flag,double x,double y)939 void path_base<VC>::arc_to(double rx, double ry, 940 double angle, 941 bool large_arc_flag, 942 bool sweep_flag, 943 double x, double y) 944 { 945 if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command())) 946 { 947 const double epsilon = 1e-30; 948 double x0 = 0.0; 949 double y0 = 0.0; 950 m_vertices.last_vertex(&x0, &y0); 951 952 rx = fabs(rx); 953 ry = fabs(ry); 954 955 // Ensure radii are valid 956 //------------------------- 957 if(rx < epsilon || ry < epsilon) 958 { 959 line_to(x, y); 960 return; 961 } 962 963 if(calc_distance(x0, y0, x, y) < epsilon) 964 { 965 // If the endpoints (x, y) and (x0, y0) are identical, then this 966 // is equivalent to omitting the elliptical arc segment entirely. 967 return; 968 } 969 bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y); 970 if(a.radii_ok()) 971 { 972 join_path(a); 973 } 974 else 975 { 976 line_to(x, y); 977 } 978 } 979 else 980 { 981 move_to(x, y); 982 } 983 } 984 985 //------------------------------------------------------------------------ 986 template<class VC> arc_rel(double rx,double ry,double angle,bool large_arc_flag,bool sweep_flag,double dx,double dy)987 void path_base<VC>::arc_rel(double rx, double ry, 988 double angle, 989 bool large_arc_flag, 990 bool sweep_flag, 991 double dx, double dy) 992 { 993 rel_to_abs(&dx, &dy); 994 arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy); 995 } 996 997 //------------------------------------------------------------------------ 998 template<class VC> curve3(double x_ctrl,double y_ctrl,double x_to,double y_to)999 void path_base<VC>::curve3(double x_ctrl, double y_ctrl, 1000 double x_to, double y_to) 1001 { 1002 m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3); 1003 m_vertices.add_vertex(x_to, y_to, path_cmd_curve3); 1004 } 1005 1006 //------------------------------------------------------------------------ 1007 template<class VC> curve3_rel(double dx_ctrl,double dy_ctrl,double dx_to,double dy_to)1008 void path_base<VC>::curve3_rel(double dx_ctrl, double dy_ctrl, 1009 double dx_to, double dy_to) 1010 { 1011 rel_to_abs(&dx_ctrl, &dy_ctrl); 1012 rel_to_abs(&dx_to, &dy_to); 1013 m_vertices.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3); 1014 m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve3); 1015 } 1016 1017 //------------------------------------------------------------------------ 1018 template<class VC> curve3(double x_to,double y_to)1019 void path_base<VC>::curve3(double x_to, double y_to) 1020 { 1021 double x0; 1022 double y0; 1023 if(is_vertex(m_vertices.last_vertex(&x0, &y0))) 1024 { 1025 double x_ctrl; 1026 double y_ctrl; 1027 unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl); 1028 if(is_curve(cmd)) 1029 { 1030 x_ctrl = x0 + x0 - x_ctrl; 1031 y_ctrl = y0 + y0 - y_ctrl; 1032 } 1033 else 1034 { 1035 x_ctrl = x0; 1036 y_ctrl = y0; 1037 } 1038 curve3(x_ctrl, y_ctrl, x_to, y_to); 1039 } 1040 } 1041 1042 //------------------------------------------------------------------------ 1043 template<class VC> curve3_rel(double dx_to,double dy_to)1044 void path_base<VC>::curve3_rel(double dx_to, double dy_to) 1045 { 1046 rel_to_abs(&dx_to, &dy_to); 1047 curve3(dx_to, dy_to); 1048 } 1049 1050 //------------------------------------------------------------------------ 1051 template<class VC> curve4(double x_ctrl1,double y_ctrl1,double x_ctrl2,double y_ctrl2,double x_to,double y_to)1052 void path_base<VC>::curve4(double x_ctrl1, double y_ctrl1, 1053 double x_ctrl2, double y_ctrl2, 1054 double x_to, double y_to) 1055 { 1056 m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4); 1057 m_vertices.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4); 1058 m_vertices.add_vertex(x_to, y_to, path_cmd_curve4); 1059 } 1060 1061 //------------------------------------------------------------------------ 1062 template<class VC> curve4_rel(double dx_ctrl1,double dy_ctrl1,double dx_ctrl2,double dy_ctrl2,double dx_to,double dy_to)1063 void path_base<VC>::curve4_rel(double dx_ctrl1, double dy_ctrl1, 1064 double dx_ctrl2, double dy_ctrl2, 1065 double dx_to, double dy_to) 1066 { 1067 rel_to_abs(&dx_ctrl1, &dy_ctrl1); 1068 rel_to_abs(&dx_ctrl2, &dy_ctrl2); 1069 rel_to_abs(&dx_to, &dy_to); 1070 m_vertices.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4); 1071 m_vertices.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4); 1072 m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve4); 1073 } 1074 1075 //------------------------------------------------------------------------ 1076 template<class VC> curve4(double x_ctrl2,double y_ctrl2,double x_to,double y_to)1077 void path_base<VC>::curve4(double x_ctrl2, double y_ctrl2, 1078 double x_to, double y_to) 1079 { 1080 double x0; 1081 double y0; 1082 if(is_vertex(last_vertex(&x0, &y0))) 1083 { 1084 double x_ctrl1; 1085 double y_ctrl1; 1086 unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1); 1087 if(is_curve(cmd)) 1088 { 1089 x_ctrl1 = x0 + x0 - x_ctrl1; 1090 y_ctrl1 = y0 + y0 - y_ctrl1; 1091 } 1092 else 1093 { 1094 x_ctrl1 = x0; 1095 y_ctrl1 = y0; 1096 } 1097 curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to); 1098 } 1099 } 1100 1101 //------------------------------------------------------------------------ 1102 template<class VC> curve4_rel(double dx_ctrl2,double dy_ctrl2,double dx_to,double dy_to)1103 void path_base<VC>::curve4_rel(double dx_ctrl2, double dy_ctrl2, 1104 double dx_to, double dy_to) 1105 { 1106 rel_to_abs(&dx_ctrl2, &dy_ctrl2); 1107 rel_to_abs(&dx_to, &dy_to); 1108 curve4(dx_ctrl2, dy_ctrl2, dx_to, dy_to); 1109 } 1110 1111 //------------------------------------------------------------------------ 1112 template<class VC> end_poly(unsigned flags)1113 inline void path_base<VC>::end_poly(unsigned flags) 1114 { 1115 if(is_vertex(m_vertices.last_command())) 1116 { 1117 m_vertices.add_vertex(0.0, 0.0, path_cmd_end_poly | flags); 1118 } 1119 } 1120 1121 //------------------------------------------------------------------------ 1122 template<class VC> close_polygon(unsigned flags)1123 inline void path_base<VC>::close_polygon(unsigned flags) 1124 { 1125 end_poly(path_flags_close | flags); 1126 } 1127 1128 //------------------------------------------------------------------------ 1129 template<class VC> total_vertices()1130 inline unsigned path_base<VC>::total_vertices() const 1131 { 1132 return m_vertices.total_vertices(); 1133 } 1134 1135 //------------------------------------------------------------------------ 1136 template<class VC> last_vertex(double * x,double * y)1137 inline unsigned path_base<VC>::last_vertex(double* x, double* y) const 1138 { 1139 return m_vertices.last_vertex(x, y); 1140 } 1141 1142 //------------------------------------------------------------------------ 1143 template<class VC> prev_vertex(double * x,double * y)1144 inline unsigned path_base<VC>::prev_vertex(double* x, double* y) const 1145 { 1146 return m_vertices.prev_vertex(x, y); 1147 } 1148 1149 //------------------------------------------------------------------------ 1150 template<class VC> last_x()1151 inline double path_base<VC>::last_x() const 1152 { 1153 return m_vertices.last_x(); 1154 } 1155 1156 //------------------------------------------------------------------------ 1157 template<class VC> last_y()1158 inline double path_base<VC>::last_y() const 1159 { 1160 return m_vertices.last_y(); 1161 } 1162 1163 //------------------------------------------------------------------------ 1164 template<class VC> vertex(unsigned idx,double * x,double * y)1165 inline unsigned path_base<VC>::vertex(unsigned idx, double* x, double* y) const 1166 { 1167 return m_vertices.vertex(idx, x, y); 1168 } 1169 1170 //------------------------------------------------------------------------ 1171 template<class VC> command(unsigned idx)1172 inline unsigned path_base<VC>::command(unsigned idx) const 1173 { 1174 return m_vertices.command(idx); 1175 } 1176 1177 //------------------------------------------------------------------------ 1178 template<class VC> modify_vertex(unsigned idx,double x,double y)1179 void path_base<VC>::modify_vertex(unsigned idx, double x, double y) 1180 { 1181 m_vertices.modify_vertex(idx, x, y); 1182 } 1183 1184 //------------------------------------------------------------------------ 1185 template<class VC> modify_vertex(unsigned idx,double x,double y,unsigned cmd)1186 void path_base<VC>::modify_vertex(unsigned idx, double x, double y, unsigned cmd) 1187 { 1188 m_vertices.modify_vertex(idx, x, y, cmd); 1189 } 1190 1191 //------------------------------------------------------------------------ 1192 template<class VC> modify_command(unsigned idx,unsigned cmd)1193 void path_base<VC>::modify_command(unsigned idx, unsigned cmd) 1194 { 1195 m_vertices.modify_command(idx, cmd); 1196 } 1197 1198 //------------------------------------------------------------------------ 1199 template<class VC> rewind(unsigned path_id)1200 inline void path_base<VC>::rewind(unsigned path_id) 1201 { 1202 m_iterator = path_id; 1203 } 1204 1205 //------------------------------------------------------------------------ 1206 template<class VC> vertex(double * x,double * y)1207 inline unsigned path_base<VC>::vertex(double* x, double* y) 1208 { 1209 if(m_iterator >= m_vertices.total_vertices()) return path_cmd_stop; 1210 return m_vertices.vertex(m_iterator++, x, y); 1211 } 1212 1213 //------------------------------------------------------------------------ 1214 template<class VC> perceive_polygon_orientation(unsigned start,unsigned end)1215 unsigned path_base<VC>::perceive_polygon_orientation(unsigned start, 1216 unsigned end) 1217 { 1218 // Calculate signed area (double area to be exact) 1219 //--------------------- 1220 unsigned np = end - start; 1221 double area = 0.0; 1222 unsigned i; 1223 for(i = 0; i < np; i++) 1224 { 1225 double x1, y1, x2, y2; 1226 m_vertices.vertex(start + i, &x1, &y1); 1227 m_vertices.vertex(start + (i + 1) % np, &x2, &y2); 1228 area += x1 * y2 - y1 * x2; 1229 } 1230 return (area < 0.0) ? path_flags_cw : path_flags_ccw; 1231 } 1232 1233 //------------------------------------------------------------------------ 1234 template<class VC> invert_polygon(unsigned start,unsigned end)1235 void path_base<VC>::invert_polygon(unsigned start, unsigned end) 1236 { 1237 unsigned i; 1238 unsigned tmp_cmd = m_vertices.command(start); 1239 1240 --end; // Make "end" inclusive 1241 1242 // Shift all commands to one position 1243 for(i = start; i < end; i++) 1244 { 1245 m_vertices.modify_command(i, m_vertices.command(i + 1)); 1246 } 1247 1248 // Assign starting command to the ending command 1249 m_vertices.modify_command(end, tmp_cmd); 1250 1251 // Reverse the polygon 1252 while(end > start) 1253 { 1254 m_vertices.swap_vertices(start++, end--); 1255 } 1256 } 1257 1258 //------------------------------------------------------------------------ 1259 template<class VC> invert_polygon(unsigned start)1260 void path_base<VC>::invert_polygon(unsigned start) 1261 { 1262 // Skip all non-vertices at the beginning 1263 while(start < m_vertices.total_vertices() && 1264 !is_vertex(m_vertices.command(start))) ++start; 1265 1266 // Skip all insignificant move_to 1267 while(start+1 < m_vertices.total_vertices() && 1268 is_move_to(m_vertices.command(start)) && 1269 is_move_to(m_vertices.command(start+1))) ++start; 1270 1271 // Find the last vertex 1272 unsigned end = start + 1; 1273 while(end < m_vertices.total_vertices() && 1274 !is_next_poly(m_vertices.command(end))) ++end; 1275 1276 invert_polygon(start, end); 1277 } 1278 1279 //------------------------------------------------------------------------ 1280 template<class VC> arrange_polygon_orientation(unsigned start,path_flags_e orientation)1281 unsigned path_base<VC>::arrange_polygon_orientation(unsigned start, 1282 path_flags_e orientation) 1283 { 1284 if(orientation == path_flags_none) return start; 1285 1286 // Skip all non-vertices at the beginning 1287 while(start < m_vertices.total_vertices() && 1288 !is_vertex(m_vertices.command(start))) ++start; 1289 1290 // Skip all insignificant move_to 1291 while(start+1 < m_vertices.total_vertices() && 1292 is_move_to(m_vertices.command(start)) && 1293 is_move_to(m_vertices.command(start+1))) ++start; 1294 1295 // Find the last vertex 1296 unsigned end = start + 1; 1297 while(end < m_vertices.total_vertices() && 1298 !is_next_poly(m_vertices.command(end))) ++end; 1299 1300 if(end - start > 2) 1301 { 1302 if(perceive_polygon_orientation(start, end) != unsigned(orientation)) 1303 { 1304 // Invert polygon, set orientation flag, and skip all end_poly 1305 invert_polygon(start, end); 1306 unsigned cmd; 1307 while(end < m_vertices.total_vertices() && 1308 is_end_poly(cmd = m_vertices.command(end))) 1309 { 1310 m_vertices.modify_command(end++, set_orientation(cmd, orientation)); 1311 } 1312 } 1313 } 1314 return end; 1315 } 1316 1317 //------------------------------------------------------------------------ 1318 template<class VC> arrange_orientations(unsigned start,path_flags_e orientation)1319 unsigned path_base<VC>::arrange_orientations(unsigned start, 1320 path_flags_e orientation) 1321 { 1322 if(orientation != path_flags_none) 1323 { 1324 while(start < m_vertices.total_vertices()) 1325 { 1326 start = arrange_polygon_orientation(start, orientation); 1327 if(is_stop(m_vertices.command(start))) 1328 { 1329 ++start; 1330 break; 1331 } 1332 } 1333 } 1334 return start; 1335 } 1336 1337 //------------------------------------------------------------------------ 1338 template<class VC> arrange_orientations_all_paths(path_flags_e orientation)1339 void path_base<VC>::arrange_orientations_all_paths(path_flags_e orientation) 1340 { 1341 if(orientation != path_flags_none) 1342 { 1343 unsigned start = 0; 1344 while(start < m_vertices.total_vertices()) 1345 { 1346 start = arrange_orientations(start, orientation); 1347 } 1348 } 1349 } 1350 1351 //------------------------------------------------------------------------ 1352 template<class VC> flip_x(double x1,double x2)1353 void path_base<VC>::flip_x(double x1, double x2) 1354 { 1355 unsigned i; 1356 double x, y; 1357 for(i = 0; i < m_vertices.total_vertices(); i++) 1358 { 1359 unsigned cmd = m_vertices.vertex(i, &x, &y); 1360 if(is_vertex(cmd)) 1361 { 1362 m_vertices.modify_vertex(i, x2 - x + x1, y); 1363 } 1364 } 1365 } 1366 1367 //------------------------------------------------------------------------ 1368 template<class VC> flip_y(double y1,double y2)1369 void path_base<VC>::flip_y(double y1, double y2) 1370 { 1371 unsigned i; 1372 double x, y; 1373 for(i = 0; i < m_vertices.total_vertices(); i++) 1374 { 1375 unsigned cmd = m_vertices.vertex(i, &x, &y); 1376 if(is_vertex(cmd)) 1377 { 1378 m_vertices.modify_vertex(i, x, y2 - y + y1); 1379 } 1380 } 1381 } 1382 1383 //------------------------------------------------------------------------ 1384 template<class VC> translate(double dx,double dy,unsigned path_id)1385 void path_base<VC>::translate(double dx, double dy, unsigned path_id) 1386 { 1387 unsigned num_ver = m_vertices.total_vertices(); 1388 for(; path_id < num_ver; path_id++) 1389 { 1390 double x, y; 1391 unsigned cmd = m_vertices.vertex(path_id, &x, &y); 1392 if(is_stop(cmd)) break; 1393 if(is_vertex(cmd)) 1394 { 1395 x += dx; 1396 y += dy; 1397 m_vertices.modify_vertex(path_id, x, y); 1398 } 1399 } 1400 } 1401 1402 //------------------------------------------------------------------------ 1403 template<class VC> translate_all_paths(double dx,double dy)1404 void path_base<VC>::translate_all_paths(double dx, double dy) 1405 { 1406 unsigned idx; 1407 unsigned num_ver = m_vertices.total_vertices(); 1408 for(idx = 0; idx < num_ver; idx++) 1409 { 1410 double x, y; 1411 if(is_vertex(m_vertices.vertex(idx, &x, &y))) 1412 { 1413 x += dx; 1414 y += dy; 1415 m_vertices.modify_vertex(idx, x, y); 1416 } 1417 } 1418 } 1419 1420 //-----------------------------------------------------vertex_stl_storage 1421 template<class Container> class vertex_stl_storage 1422 { 1423 public: 1424 typedef typename Container::value_type vertex_type; 1425 typedef typename vertex_type::value_type value_type; 1426 remove_all()1427 void remove_all() { m_vertices.clear(); } free_all()1428 void free_all() { m_vertices.clear(); } 1429 add_vertex(double x,double y,unsigned cmd)1430 void add_vertex(double x, double y, unsigned cmd) 1431 { 1432 m_vertices.push_back(vertex_type(value_type(x), 1433 value_type(y), 1434 int8u(cmd))); 1435 } 1436 modify_vertex(unsigned idx,double x,double y)1437 void modify_vertex(unsigned idx, double x, double y) 1438 { 1439 vertex_type& v = m_vertices[idx]; 1440 v.x = value_type(x); 1441 v.y = value_type(y); 1442 } 1443 modify_vertex(unsigned idx,double x,double y,unsigned cmd)1444 void modify_vertex(unsigned idx, double x, double y, unsigned cmd) 1445 { 1446 vertex_type& v = m_vertices[idx]; 1447 v.x = value_type(x); 1448 v.y = value_type(y); 1449 v.cmd = int8u(cmd); 1450 } 1451 modify_command(unsigned idx,unsigned cmd)1452 void modify_command(unsigned idx, unsigned cmd) 1453 { 1454 m_vertices[idx].cmd = int8u(cmd); 1455 } 1456 swap_vertices(unsigned v1,unsigned v2)1457 void swap_vertices(unsigned v1, unsigned v2) 1458 { 1459 vertex_type t = m_vertices[v1]; 1460 m_vertices[v1] = m_vertices[v2]; 1461 m_vertices[v2] = t; 1462 } 1463 last_command()1464 unsigned last_command() const 1465 { 1466 return m_vertices.size() ? 1467 m_vertices[m_vertices.size() - 1].cmd : 1468 path_cmd_stop; 1469 } 1470 last_vertex(double * x,double * y)1471 unsigned last_vertex(double* x, double* y) const 1472 { 1473 if(m_vertices.size() == 0) 1474 { 1475 *x = *y = 0.0; 1476 return path_cmd_stop; 1477 } 1478 return vertex(m_vertices.size() - 1, x, y); 1479 } 1480 prev_vertex(double * x,double * y)1481 unsigned prev_vertex(double* x, double* y) const 1482 { 1483 if(m_vertices.size() < 2) 1484 { 1485 *x = *y = 0.0; 1486 return path_cmd_stop; 1487 } 1488 return vertex(m_vertices.size() - 2, x, y); 1489 } 1490 last_x()1491 double last_x() const 1492 { 1493 return m_vertices.size() ? m_vertices[m_vertices.size() - 1].x : 0.0; 1494 } 1495 last_y()1496 double last_y() const 1497 { 1498 return m_vertices.size() ? m_vertices[m_vertices.size() - 1].y : 0.0; 1499 } 1500 total_vertices()1501 unsigned total_vertices() const 1502 { 1503 return m_vertices.size(); 1504 } 1505 vertex(unsigned idx,double * x,double * y)1506 unsigned vertex(unsigned idx, double* x, double* y) const 1507 { 1508 const vertex_type& v = m_vertices[idx]; 1509 *x = v.x; 1510 *y = v.y; 1511 return v.cmd; 1512 } 1513 command(unsigned idx)1514 unsigned command(unsigned idx) const 1515 { 1516 return m_vertices[idx].cmd; 1517 } 1518 1519 private: 1520 Container m_vertices; 1521 }; 1522 1523 //-----------------------------------------------------------path_storage 1524 typedef path_base<vertex_block_storage<double> > path_storage; 1525 1526 // Example of declarations path_storage with pod_bvector as a container 1527 //----------------------------------------------------------------------- 1528 //typedef path_base<vertex_stl_storage<pod_bvector<vertex_d> > > path_storage; 1529 1530 } 1531 1532 1533 1534 // Example of declarations path_storage with std::vector as a container 1535 //--------------------------------------------------------------------------- 1536 //#include <vector> 1537 //namespace agg 1538 //{ 1539 // typedef path_base<vertex_stl_storage<std::vector<vertex_d> > > stl_path_storage; 1540 //} 1541 1542 1543 1544 1545 #endif 1546