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