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