Anti-Grain Geometry - AGG (libagg)  2.5
agg-2.5/include/agg_path_storage.h
Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 // Anti-Grain Geometry (AGG) - Version 2.5
00003 // A high quality rendering engine for C++
00004 // Copyright (C) 2002-2006 Maxim Shemanarev
00005 // Contact: mcseem@antigrain.com
00006 //          mcseemagg@yahoo.com
00007 //          http://antigrain.com
00008 // 
00009 // AGG is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU General Public License
00011 // as published by the Free Software Foundation; either version 2
00012 // of the License, or (at your option) any later version.
00013 // 
00014 // AGG is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 // 
00019 // You should have received a copy of the GNU General Public License
00020 // along with AGG; if not, write to the Free Software
00021 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
00022 // MA 02110-1301, USA.
00023 //----------------------------------------------------------------------------
00024 
00025 #ifndef AGG_PATH_STORAGE_INCLUDED
00026 #define AGG_PATH_STORAGE_INCLUDED
00027 
00028 #include <string.h>
00029 #include <math.h>
00030 #include "agg_math.h"
00031 #include "agg_array.h"
00032 #include "agg_bezier_arc.h"
00033 
00034 namespace agg
00035 {
00036 
00037 
00038     //----------------------------------------------------vertex_block_storage
00039     template<class T, unsigned BlockShift=8, unsigned BlockPool=256>
00040     class vertex_block_storage
00041     {
00042     public:
00043         // Allocation parameters
00044         enum block_scale_e
00045         {
00046             block_shift = BlockShift,
00047             block_size  = 1 << block_shift,
00048             block_mask  = block_size - 1,
00049             block_pool  = BlockPool
00050         };
00051 
00052         typedef T value_type;
00053         typedef vertex_block_storage<T, BlockShift, BlockPool> self_type;
00054 
00055         ~vertex_block_storage();
00056         vertex_block_storage();
00057         vertex_block_storage(const self_type& v);
00058         const self_type& operator = (const self_type& ps);
00059 
00060         void remove_all();
00061         void free_all();
00062 
00063         void add_vertex(double x, double y, unsigned cmd);
00064         void modify_vertex(unsigned idx, double x, double y);
00065         void modify_vertex(unsigned idx, double x, double y, unsigned cmd);
00066         void modify_command(unsigned idx, unsigned cmd);
00067         void swap_vertices(unsigned v1, unsigned v2);
00068 
00069         unsigned last_command() const;
00070         unsigned last_vertex(double* x, double* y) const;
00071         unsigned prev_vertex(double* x, double* y) const;
00072 
00073         double last_x() const;
00074         double last_y() const;
00075 
00076         unsigned total_vertices() const;
00077         unsigned vertex(unsigned idx, double* x, double* y) const;
00078         unsigned command(unsigned idx) const;
00079 
00080     private:
00081         void   allocate_block(unsigned nb);
00082         int8u* storage_ptrs(T** xy_ptr);
00083 
00084     private:
00085         unsigned m_total_vertices;
00086         unsigned m_total_blocks;
00087         unsigned m_max_blocks;
00088         T**      m_coord_blocks;
00089         int8u**  m_cmd_blocks;
00090     };
00091 
00092 
00093     //------------------------------------------------------------------------
00094     template<class T, unsigned S, unsigned P>
00095     void vertex_block_storage<T,S,P>::free_all()
00096     {
00097         if(m_total_blocks)
00098         {
00099             T** coord_blk = m_coord_blocks + m_total_blocks - 1;
00100             while(m_total_blocks--)
00101             {
00102                 pod_allocator<T>::deallocate(
00103                     *coord_blk,
00104                     block_size * 2 + 
00105                     block_size / (sizeof(T) / sizeof(unsigned char)));
00106                 --coord_blk;
00107             }
00108             pod_allocator<T*>::deallocate(m_coord_blocks, m_max_blocks * 2);
00109             m_total_blocks   = 0;
00110             m_max_blocks     = 0;
00111             m_coord_blocks   = 0;
00112             m_cmd_blocks     = 0;
00113             m_total_vertices = 0;
00114         }
00115     }
00116 
00117     //------------------------------------------------------------------------
00118     template<class T, unsigned S, unsigned P>
00119     vertex_block_storage<T,S,P>::~vertex_block_storage()
00120     {
00121         free_all();
00122     }
00123 
00124     //------------------------------------------------------------------------
00125     template<class T, unsigned S, unsigned P>
00126     vertex_block_storage<T,S,P>::vertex_block_storage() :
00127         m_total_vertices(0),
00128         m_total_blocks(0),
00129         m_max_blocks(0),
00130         m_coord_blocks(0),
00131         m_cmd_blocks(0)
00132     {
00133     }
00134 
00135     //------------------------------------------------------------------------
00136     template<class T, unsigned S, unsigned P>
00137     vertex_block_storage<T,S,P>::vertex_block_storage(const vertex_block_storage<T,S,P>& v) :
00138         m_total_vertices(0),
00139         m_total_blocks(0),
00140         m_max_blocks(0),
00141         m_coord_blocks(0),
00142         m_cmd_blocks(0)
00143     {
00144         *this = v;
00145     }
00146 
00147     //------------------------------------------------------------------------
00148     template<class T, unsigned S, unsigned P>
00149     const vertex_block_storage<T,S,P>& 
00150     vertex_block_storage<T,S,P>::operator = (const vertex_block_storage<T,S,P>& v)
00151     {
00152         remove_all();
00153         unsigned i;
00154         for(i = 0; i < v.total_vertices(); i++)
00155         {
00156             double x, y;
00157             unsigned cmd = v.vertex(i, &x, &y);
00158             add_vertex(x, y, cmd);
00159         }
00160             return *this;
00161     }
00162 
00163     //------------------------------------------------------------------------
00164     template<class T, unsigned S, unsigned P>
00165     inline void vertex_block_storage<T,S,P>::remove_all()
00166     {
00167         m_total_vertices = 0;
00168     }
00169 
00170     //------------------------------------------------------------------------
00171     template<class T, unsigned S, unsigned P>
00172     inline void vertex_block_storage<T,S,P>::add_vertex(double x, double y, 
00173                                                         unsigned cmd)
00174     {
00175         T* coord_ptr = 0;
00176         *storage_ptrs(&coord_ptr) = (int8u)cmd;
00177         coord_ptr[0] = T(x);
00178         coord_ptr[1] = T(y);
00179         m_total_vertices++;
00180     }
00181 
00182     //------------------------------------------------------------------------
00183     template<class T, unsigned S, unsigned P>
00184     inline void vertex_block_storage<T,S,P>::modify_vertex(unsigned idx, 
00185                                                            double x, double y)
00186     {
00187         T* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1);
00188         pv[0] = T(x);
00189         pv[1] = T(y);
00190     }
00191 
00192     //------------------------------------------------------------------------
00193     template<class T, unsigned S, unsigned P>
00194     inline void vertex_block_storage<T,S,P>::modify_vertex(unsigned idx, 
00195                                                            double x, double y, 
00196                                                            unsigned cmd)
00197     {
00198         unsigned block = idx >> block_shift;
00199         unsigned offset = idx & block_mask;
00200         T* pv = m_coord_blocks[block] + (offset << 1);
00201         pv[0] = T(x);
00202         pv[1] = T(y);
00203         m_cmd_blocks[block][offset] = (int8u)cmd;
00204     }
00205 
00206     //------------------------------------------------------------------------
00207     template<class T, unsigned S, unsigned P>
00208     inline void vertex_block_storage<T,S,P>::modify_command(unsigned idx, 
00209                                                             unsigned cmd)
00210     {
00211         m_cmd_blocks[idx >> block_shift][idx & block_mask] = (int8u)cmd;
00212     }
00213 
00214     //------------------------------------------------------------------------
00215     template<class T, unsigned S, unsigned P>
00216     inline void vertex_block_storage<T,S,P>::swap_vertices(unsigned v1, unsigned v2)
00217     {
00218         unsigned b1 = v1 >> block_shift;
00219         unsigned b2 = v2 >> block_shift;
00220         unsigned o1 = v1 & block_mask;
00221         unsigned o2 = v2 & block_mask;
00222         T* pv1 = m_coord_blocks[b1] + (o1 << 1);
00223         T* pv2 = m_coord_blocks[b2] + (o2 << 1);
00224         T  val;
00225         val = pv1[0]; pv1[0] = pv2[0]; pv2[0] = val;
00226         val = pv1[1]; pv1[1] = pv2[1]; pv2[1] = val;
00227         int8u cmd = m_cmd_blocks[b1][o1];
00228         m_cmd_blocks[b1][o1] = m_cmd_blocks[b2][o2];
00229         m_cmd_blocks[b2][o2] = cmd;
00230     }
00231 
00232     //------------------------------------------------------------------------
00233     template<class T, unsigned S, unsigned P>
00234     inline unsigned vertex_block_storage<T,S,P>::last_command() const
00235     {
00236         if(m_total_vertices) return command(m_total_vertices - 1);
00237         return path_cmd_stop;
00238     }
00239 
00240     //------------------------------------------------------------------------
00241     template<class T, unsigned S, unsigned P>
00242     inline unsigned vertex_block_storage<T,S,P>::last_vertex(double* x, double* y) const
00243     {
00244         if(m_total_vertices) return vertex(m_total_vertices - 1, x, y);
00245         return path_cmd_stop;
00246     }
00247 
00248     //------------------------------------------------------------------------
00249     template<class T, unsigned S, unsigned P>
00250     inline unsigned vertex_block_storage<T,S,P>::prev_vertex(double* x, double* y) const
00251     {
00252         if(m_total_vertices > 1) return vertex(m_total_vertices - 2, x, y);
00253         return path_cmd_stop;
00254     }
00255 
00256     //------------------------------------------------------------------------
00257     template<class T, unsigned S, unsigned P>
00258     inline double vertex_block_storage<T,S,P>::last_x() const
00259     {
00260         if(m_total_vertices)
00261         {
00262             unsigned idx = m_total_vertices - 1;
00263             return m_coord_blocks[idx >> block_shift][(idx & block_mask) << 1];
00264         }
00265         return 0.0;
00266     }
00267 
00268     //------------------------------------------------------------------------
00269     template<class T, unsigned S, unsigned P>
00270     inline double vertex_block_storage<T,S,P>::last_y() const
00271     {
00272         if(m_total_vertices)
00273         {
00274             unsigned idx = m_total_vertices - 1;
00275             return m_coord_blocks[idx >> block_shift][((idx & block_mask) << 1) + 1];
00276         }
00277         return 0.0;
00278     }
00279 
00280     //------------------------------------------------------------------------
00281     template<class T, unsigned S, unsigned P>
00282     inline unsigned vertex_block_storage<T,S,P>::total_vertices() const
00283     {
00284         return m_total_vertices;
00285     }
00286 
00287     //------------------------------------------------------------------------
00288     template<class T, unsigned S, unsigned P>
00289     inline unsigned vertex_block_storage<T,S,P>::vertex(unsigned idx, 
00290                                                         double* x, double* y) const
00291     {
00292         unsigned nb = idx >> block_shift;
00293         const T* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1);
00294         *x = pv[0];
00295         *y = pv[1];
00296         return m_cmd_blocks[nb][idx & block_mask];
00297     }
00298 
00299     //------------------------------------------------------------------------
00300     template<class T, unsigned S, unsigned P>
00301     inline unsigned vertex_block_storage<T,S,P>::command(unsigned idx) const
00302     {
00303         return m_cmd_blocks[idx >> block_shift][idx & block_mask];
00304     }
00305 
00306     //------------------------------------------------------------------------
00307     template<class T, unsigned S, unsigned P>
00308     void vertex_block_storage<T,S,P>::allocate_block(unsigned nb)
00309     {
00310         if(nb >= m_max_blocks) 
00311         {
00312             T** new_coords = 
00313                 pod_allocator<T*>::allocate((m_max_blocks + block_pool) * 2);
00314 
00315             unsigned char** new_cmds = 
00316                 (unsigned char**)(new_coords + m_max_blocks + block_pool);
00317 
00318             if(m_coord_blocks)
00319             {
00320                 memcpy(new_coords, 
00321                        m_coord_blocks, 
00322                        m_max_blocks * sizeof(T*));
00323 
00324                 memcpy(new_cmds, 
00325                        m_cmd_blocks, 
00326                        m_max_blocks * sizeof(unsigned char*));
00327 
00328                 pod_allocator<T*>::deallocate(m_coord_blocks, m_max_blocks * 2);
00329             }
00330             m_coord_blocks = new_coords;
00331             m_cmd_blocks   = new_cmds;
00332             m_max_blocks  += block_pool;
00333         }
00334         m_coord_blocks[nb] = 
00335             pod_allocator<T>::allocate(block_size * 2 + 
00336                    block_size / (sizeof(T) / sizeof(unsigned char)));
00337 
00338         m_cmd_blocks[nb]  = 
00339             (unsigned char*)(m_coord_blocks[nb] + block_size * 2);
00340 
00341         m_total_blocks++;
00342     }
00343 
00344     //------------------------------------------------------------------------
00345     template<class T, unsigned S, unsigned P>
00346     int8u* vertex_block_storage<T,S,P>::storage_ptrs(T** xy_ptr)
00347     {
00348         unsigned nb = m_total_vertices >> block_shift;
00349         if(nb >= m_total_blocks)
00350         {
00351             allocate_block(nb);
00352         }
00353         *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1);
00354         return m_cmd_blocks[nb] + (m_total_vertices & block_mask);
00355     }
00356 
00357 
00358 
00359 
00360     //-----------------------------------------------------poly_plain_adaptor
00361     template<class T> class poly_plain_adaptor
00362     {
00363     public:
00364         typedef T value_type;
00365 
00366         poly_plain_adaptor() : 
00367             m_data(0), 
00368             m_ptr(0),
00369             m_end(0),
00370             m_closed(false),
00371             m_stop(false)
00372         {}
00373 
00374         poly_plain_adaptor(const T* data, unsigned num_points, bool closed) :
00375             m_data(data), 
00376             m_ptr(data),
00377             m_end(data + num_points * 2),
00378             m_closed(closed),
00379             m_stop(false)
00380         {}
00381 
00382         void init(const T* data, unsigned num_points, bool closed)
00383         {
00384             m_data = data;
00385             m_ptr = data;
00386             m_end = data + num_points * 2;
00387             m_closed = closed;
00388             m_stop = false;
00389         }
00390 
00391         void rewind(unsigned)
00392         {
00393             m_ptr = m_data;
00394             m_stop = false;
00395         }
00396 
00397         unsigned vertex(double* x, double* y)
00398         {
00399             if(m_ptr < m_end)
00400             {
00401                 bool first = m_ptr == m_data;
00402                 *x = *m_ptr++;
00403                 *y = *m_ptr++;
00404                 return first ? path_cmd_move_to : path_cmd_line_to;
00405             }
00406             *x = *y = 0.0;
00407             if(m_closed && !m_stop)
00408             {
00409                 m_stop = true;
00410                 return path_cmd_end_poly | path_flags_close;
00411             }
00412             return path_cmd_stop;
00413         }
00414 
00415     private:
00416         const T* m_data;
00417         const T* m_ptr;
00418         const T* m_end;
00419         bool     m_closed;
00420         bool     m_stop;
00421     };
00422 
00423 
00424 
00425 
00426 
00427     //-------------------------------------------------poly_container_adaptor
00428     template<class Container> class poly_container_adaptor
00429     {
00430     public:
00431         typedef typename Container::value_type vertex_type;
00432 
00433         poly_container_adaptor() : 
00434             m_container(0), 
00435             m_index(0),
00436             m_closed(false),
00437             m_stop(false)
00438         {}
00439 
00440         poly_container_adaptor(const Container& data, bool closed) :
00441             m_container(&data), 
00442             m_index(0),
00443             m_closed(closed),
00444             m_stop(false)
00445         {}
00446 
00447         void init(const Container& data, bool closed)
00448         {
00449             m_container = &data;
00450             m_index = 0;
00451             m_closed = closed;
00452             m_stop = false;
00453         }
00454 
00455         void rewind(unsigned)
00456         {
00457             m_index = 0;
00458             m_stop = false;
00459         }
00460 
00461         unsigned vertex(double* x, double* y)
00462         {
00463             if(m_index < m_container->size())
00464             {
00465                 bool first = m_index == 0;
00466                 const vertex_type& v = (*m_container)[m_index++];
00467                 *x = v.x;
00468                 *y = v.y;
00469                 return first ? path_cmd_move_to : path_cmd_line_to;
00470             }
00471             *x = *y = 0.0;
00472             if(m_closed && !m_stop)
00473             {
00474                 m_stop = true;
00475                 return path_cmd_end_poly | path_flags_close;
00476             }
00477             return path_cmd_stop;
00478         }
00479 
00480     private:
00481         const Container* m_container;
00482         unsigned m_index;
00483         bool     m_closed;
00484         bool     m_stop;
00485     };
00486 
00487 
00488 
00489     //-----------------------------------------poly_container_reverse_adaptor
00490     template<class Container> class poly_container_reverse_adaptor
00491     {
00492     public:
00493         typedef typename Container::value_type vertex_type;
00494 
00495         poly_container_reverse_adaptor() : 
00496             m_container(0), 
00497             m_index(-1),
00498             m_closed(false),
00499             m_stop(false)
00500         {}
00501 
00502         poly_container_reverse_adaptor(const Container& data, bool closed) :
00503             m_container(&data), 
00504             m_index(-1),
00505             m_closed(closed),
00506             m_stop(false)
00507         {}
00508 
00509         void init(const Container& data, bool closed)
00510         {
00511             m_container = &data;
00512             m_index = m_container->size() - 1;
00513             m_closed = closed;
00514             m_stop = false;
00515         }
00516 
00517         void rewind(unsigned)
00518         {
00519             m_index = m_container->size() - 1;
00520             m_stop = false;
00521         }
00522 
00523         unsigned vertex(double* x, double* y)
00524         {
00525             if(m_index >= 0)
00526             {
00527                 bool first = m_index == int(m_container->size() - 1);
00528                 const vertex_type& v = (*m_container)[m_index--];
00529                 *x = v.x;
00530                 *y = v.y;
00531                 return first ? path_cmd_move_to : path_cmd_line_to;
00532             }
00533             *x = *y = 0.0;
00534             if(m_closed && !m_stop)
00535             {
00536                 m_stop = true;
00537                 return path_cmd_end_poly | path_flags_close;
00538             }
00539             return path_cmd_stop;
00540         }
00541 
00542     private:
00543         const Container* m_container;
00544         int  m_index;
00545         bool m_closed;
00546         bool m_stop;
00547     };
00548 
00549 
00550 
00551 
00552 
00553     //--------------------------------------------------------line_adaptor
00554     class line_adaptor
00555     {
00556     public:
00557         typedef double value_type;
00558 
00559         line_adaptor() : m_line(m_coord, 2, false) {}
00560         line_adaptor(double x1, double y1, double x2, double y2) :
00561             m_line(m_coord, 2, false)
00562         {
00563             m_coord[0] = x1;
00564             m_coord[1] = y1;
00565             m_coord[2] = x2;
00566             m_coord[3] = y2;
00567         }
00568         
00569         void init(double x1, double y1, double x2, double y2)
00570         {
00571             m_coord[0] = x1;
00572             m_coord[1] = y1;
00573             m_coord[2] = x2;
00574             m_coord[3] = y2;
00575             m_line.rewind(0);
00576         }
00577 
00578         void rewind(unsigned)
00579         {
00580             m_line.rewind(0);
00581         }
00582 
00583         unsigned vertex(double* x, double* y)
00584         {
00585             return m_line.vertex(x, y);
00586         }
00587 
00588     private:
00589         double                     m_coord[4];
00590         poly_plain_adaptor<double> m_line;
00591     };
00592 
00593 
00594 
00595 
00596 
00597 
00598 
00599 
00600 
00601 
00602 
00603 
00604 
00605     //---------------------------------------------------------------path_base
00606     // A container to store vertices with their flags. 
00607     // A path consists of a number of contours separated with "move_to" 
00608     // commands. The path storage can keep and maintain more than one
00609     // path. 
00610     // To navigate to the beginning of a particular path, use rewind(path_id);
00611     // Where path_id is what start_new_path() returns. So, when you call
00612     // start_new_path() you need to store its return value somewhere else
00613     // to navigate to the path afterwards.
00614     //
00615     // See also: vertex_source concept
00616     //------------------------------------------------------------------------
00617     template<class VertexContainer> class path_base
00618     {
00619     public:
00620         typedef VertexContainer            container_type;
00621         typedef path_base<VertexContainer> self_type;
00622 
00623         //--------------------------------------------------------------------
00624         path_base() : m_vertices(), m_iterator(0) {}
00625         void remove_all() { m_vertices.remove_all(); m_iterator = 0; }
00626         void free_all()   { m_vertices.free_all();   m_iterator = 0; }
00627 
00628         // Make path functions
00629         //--------------------------------------------------------------------
00630         unsigned start_new_path();
00631 
00632         void move_to(double x, double y);
00633         void move_rel(double dx, double dy);
00634 
00635         void line_to(double x, double y);
00636         void line_rel(double dx, double dy);
00637 
00638         void hline_to(double x);
00639         void hline_rel(double dx);
00640 
00641         void vline_to(double y);
00642         void vline_rel(double dy);
00643 
00644         void arc_to(double rx, double ry,
00645                     double angle,
00646                     bool large_arc_flag,
00647                     bool sweep_flag,
00648                     double x, double y);
00649 
00650         void arc_rel(double rx, double ry,
00651                      double angle,
00652                      bool large_arc_flag,
00653                      bool sweep_flag,
00654                      double dx, double dy);
00655 
00656         void curve3(double x_ctrl, double y_ctrl, 
00657                     double x_to,   double y_to);
00658 
00659         void curve3_rel(double dx_ctrl, double dy_ctrl, 
00660                         double dx_to,   double dy_to);
00661 
00662         void curve3(double x_to, double y_to);
00663 
00664         void curve3_rel(double dx_to, double dy_to);
00665 
00666         void curve4(double x_ctrl1, double y_ctrl1, 
00667                     double x_ctrl2, double y_ctrl2, 
00668                     double x_to,    double y_to);
00669 
00670         void curve4_rel(double dx_ctrl1, double dy_ctrl1, 
00671                         double dx_ctrl2, double dy_ctrl2, 
00672                         double dx_to,    double dy_to);
00673 
00674         void curve4(double x_ctrl2, double y_ctrl2, 
00675                     double x_to,    double y_to);
00676 
00677         void curve4_rel(double x_ctrl2, double y_ctrl2, 
00678                         double x_to,    double y_to);
00679 
00680 
00681         void end_poly(unsigned flags = path_flags_close);
00682         void close_polygon(unsigned flags = path_flags_none);
00683 
00684         // Accessors
00685         //--------------------------------------------------------------------
00686         const container_type& vertices() const { return m_vertices; } 
00687               container_type& vertices()       { return m_vertices; } 
00688 
00689         unsigned total_vertices() const;
00690 
00691         void rel_to_abs(double* x, double* y) const;
00692 
00693         unsigned last_vertex(double* x, double* y) const;
00694         unsigned prev_vertex(double* x, double* y) const;
00695 
00696         double last_x() const;
00697         double last_y() const;
00698 
00699         unsigned vertex(unsigned idx, double* x, double* y) const;
00700         unsigned command(unsigned idx) const;
00701 
00702         void modify_vertex(unsigned idx, double x, double y);
00703         void modify_vertex(unsigned idx, double x, double y, unsigned cmd);
00704         void modify_command(unsigned idx, unsigned cmd);
00705 
00706         // VertexSource interface
00707         //--------------------------------------------------------------------
00708         void     rewind(unsigned path_id);
00709         unsigned vertex(double* x, double* y);
00710 
00711         // Arrange the orientation of a polygon, all polygons in a path, 
00712         // or in all paths. After calling arrange_orientations() or 
00713         // arrange_orientations_all_paths(), all the polygons will have 
00714         // the same orientation, i.e. path_flags_cw or path_flags_ccw
00715         //--------------------------------------------------------------------
00716         unsigned arrange_polygon_orientation(unsigned start, path_flags_e orientation);
00717         unsigned arrange_orientations(unsigned path_id, path_flags_e orientation);
00718         void     arrange_orientations_all_paths(path_flags_e orientation);
00719         void     invert_polygon(unsigned start);
00720 
00721         // Flip all vertices horizontally or vertically, 
00722         // between x1 and x2, or between y1 and y2 respectively
00723         //--------------------------------------------------------------------
00724         void flip_x(double x1, double x2);
00725         void flip_y(double y1, double y2);
00726 
00727         // Concatenate path. The path is added as is.
00728         //--------------------------------------------------------------------
00729         template<class VertexSource> 
00730         void concat_path(VertexSource& vs, unsigned path_id = 0)
00731         {
00732             double x, y;
00733             unsigned cmd;
00734             vs.rewind(path_id);
00735             while(!is_stop(cmd = vs.vertex(&x, &y)))
00736             {
00737                 m_vertices.add_vertex(x, y, cmd);
00738             }
00739         }
00740 
00741         //--------------------------------------------------------------------
00742         // Join path. The path is joined with the existing one, that is, 
00743         // it behaves as if the pen of a plotter was always down (drawing)
00744         template<class VertexSource> 
00745         void join_path(VertexSource& vs, unsigned path_id = 0)
00746         {
00747             double x, y;
00748             unsigned cmd;
00749             vs.rewind(path_id);
00750             cmd = vs.vertex(&x, &y);
00751             if(!is_stop(cmd))
00752             {
00753                 if(is_vertex(cmd))
00754                 {
00755                     double x0, y0;
00756                     unsigned cmd0 = last_vertex(&x0, &y0);
00757                     if(is_vertex(cmd0))
00758                     {
00759                         if(calc_distance(x, y, x0, y0) > vertex_dist_epsilon)
00760                         {
00761                             if(is_move_to(cmd)) cmd = path_cmd_line_to;
00762                             m_vertices.add_vertex(x, y, cmd);
00763                         }
00764                     }
00765                     else
00766                     {
00767                         if(is_stop(cmd0))
00768                         {
00769                             cmd = path_cmd_move_to;
00770                         }
00771                         else
00772                         {
00773                             if(is_move_to(cmd)) cmd = path_cmd_line_to;
00774                         }
00775                         m_vertices.add_vertex(x, y, cmd);
00776                     }
00777                 }
00778                 while(!is_stop(cmd = vs.vertex(&x, &y)))
00779                 {
00780                     m_vertices.add_vertex(x, y, is_move_to(cmd) ? 
00781                                                     unsigned(path_cmd_line_to) : 
00782                                                     cmd);
00783                 }
00784             }
00785         }
00786 
00787         // Concatenate polygon/polyline. 
00788         //--------------------------------------------------------------------
00789         template<class T> void concat_poly(const T* data, 
00790                                            unsigned num_points,
00791                                            bool closed)
00792         {
00793             poly_plain_adaptor<T> poly(data, num_points, closed);
00794             concat_path(poly);
00795         }
00796 
00797         // Join polygon/polyline continuously.
00798         //--------------------------------------------------------------------
00799         template<class T> void join_poly(const T* data, 
00800                                          unsigned num_points,
00801                                          bool closed)
00802         {
00803             poly_plain_adaptor<T> poly(data, num_points, closed);
00804             join_path(poly);
00805         }
00806 
00807         //--------------------------------------------------------------------
00808         void translate(double dx, double dy, unsigned path_id=0);
00809         void translate_all_paths(double dx, double dy);
00810 
00811         //--------------------------------------------------------------------
00812         template<class Trans>
00813         void transform(const Trans& trans, unsigned path_id=0)
00814         {
00815             unsigned num_ver = m_vertices.total_vertices();
00816             for(; path_id < num_ver; path_id++)
00817             {
00818                 double x, y;
00819                 unsigned cmd = m_vertices.vertex(path_id, &x, &y);
00820                 if(is_stop(cmd)) break;
00821                 if(is_vertex(cmd))
00822                 {
00823                     trans.transform(&x, &y);
00824                     m_vertices.modify_vertex(path_id, x, y);
00825                 }
00826             }
00827         }
00828 
00829         //--------------------------------------------------------------------
00830         template<class Trans>
00831         void transform_all_paths(const Trans& trans)
00832         {
00833             unsigned idx;
00834             unsigned num_ver = m_vertices.total_vertices();
00835             for(idx = 0; idx < num_ver; idx++)
00836             {
00837                 double x, y;
00838                 if(is_vertex(m_vertices.vertex(idx, &x, &y)))
00839                 {
00840                     trans.transform(&x, &y);
00841                     m_vertices.modify_vertex(idx, x, y);
00842                 }
00843             }
00844         }
00845 
00846 
00847 
00848     private:
00849         unsigned perceive_polygon_orientation(unsigned start, unsigned end);
00850         void     invert_polygon(unsigned start, unsigned end);
00851 
00852         VertexContainer m_vertices;
00853         unsigned        m_iterator;
00854     };
00855 
00856     //------------------------------------------------------------------------
00857     template<class VC> 
00858     unsigned path_base<VC>::start_new_path()
00859     {
00860         if(!is_stop(m_vertices.last_command()))
00861         {
00862             m_vertices.add_vertex(0.0, 0.0, path_cmd_stop);
00863         }
00864         return m_vertices.total_vertices();
00865     }
00866 
00867 
00868     //------------------------------------------------------------------------
00869     template<class VC> 
00870     inline void path_base<VC>::rel_to_abs(double* x, double* y) const
00871     {
00872         if(m_vertices.total_vertices())
00873         {
00874             double x2;
00875             double y2;
00876             if(is_vertex(m_vertices.last_vertex(&x2, &y2)))
00877             {
00878                 *x += x2;
00879                 *y += y2;
00880             }
00881         }
00882     }
00883 
00884     //------------------------------------------------------------------------
00885     template<class VC> 
00886     inline void path_base<VC>::move_to(double x, double y)
00887     {
00888         m_vertices.add_vertex(x, y, path_cmd_move_to);
00889     }
00890 
00891     //------------------------------------------------------------------------
00892     template<class VC> 
00893     inline void path_base<VC>::move_rel(double dx, double dy)
00894     {
00895         rel_to_abs(&dx, &dy);
00896         m_vertices.add_vertex(dx, dy, path_cmd_move_to);
00897     }
00898 
00899     //------------------------------------------------------------------------
00900     template<class VC> 
00901     inline void path_base<VC>::line_to(double x, double y)
00902     {
00903         m_vertices.add_vertex(x, y, path_cmd_line_to);
00904     }
00905 
00906     //------------------------------------------------------------------------
00907     template<class VC> 
00908     inline void path_base<VC>::line_rel(double dx, double dy)
00909     {
00910         rel_to_abs(&dx, &dy);
00911         m_vertices.add_vertex(dx, dy, path_cmd_line_to);
00912     }
00913 
00914     //------------------------------------------------------------------------
00915     template<class VC> 
00916     inline void path_base<VC>::hline_to(double x)
00917     {
00918         m_vertices.add_vertex(x, last_y(), path_cmd_line_to);
00919     }
00920 
00921     //------------------------------------------------------------------------
00922     template<class VC> 
00923     inline void path_base<VC>::hline_rel(double dx)
00924     {
00925         double dy = 0;
00926         rel_to_abs(&dx, &dy);
00927         m_vertices.add_vertex(dx, dy, path_cmd_line_to);
00928     }
00929 
00930     //------------------------------------------------------------------------
00931     template<class VC> 
00932     inline void path_base<VC>::vline_to(double y)
00933     {
00934         m_vertices.add_vertex(last_x(), y, path_cmd_line_to);
00935     }
00936 
00937     //------------------------------------------------------------------------
00938     template<class VC> 
00939     inline void path_base<VC>::vline_rel(double dy)
00940     {
00941         double dx = 0;
00942         rel_to_abs(&dx, &dy);
00943         m_vertices.add_vertex(dx, dy, path_cmd_line_to);
00944     }
00945 
00946     //------------------------------------------------------------------------
00947     template<class VC> 
00948     void path_base<VC>::arc_to(double rx, double ry,
00949                                double angle,
00950                                bool large_arc_flag,
00951                                bool sweep_flag,
00952                                double x, double y)
00953     {
00954         if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command()))
00955         {
00956             const double epsilon = 1e-30;
00957             double x0 = 0.0;
00958             double y0 = 0.0;
00959             m_vertices.last_vertex(&x0, &y0);
00960 
00961             rx = fabs(rx);
00962             ry = fabs(ry);
00963 
00964             // Ensure radii are valid
00965             //-------------------------
00966             if(rx < epsilon || ry < epsilon) 
00967             {
00968                 line_to(x, y);
00969                 return;
00970             }
00971 
00972             if(calc_distance(x0, y0, x, y) < epsilon)
00973             {
00974                 // If the endpoints (x, y) and (x0, y0) are identical, then this
00975                 // is equivalent to omitting the elliptical arc segment entirely.
00976                 return;
00977             }
00978             bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y);
00979             if(a.radii_ok())
00980             {
00981                 join_path(a);
00982             }
00983             else
00984             {
00985                 line_to(x, y);
00986             }
00987         }
00988         else
00989         {
00990             move_to(x, y);
00991         }
00992     }
00993 
00994     //------------------------------------------------------------------------
00995     template<class VC> 
00996     void path_base<VC>::arc_rel(double rx, double ry,
00997                                 double angle,
00998                                 bool large_arc_flag,
00999                                 bool sweep_flag,
01000                                 double dx, double dy)
01001     {
01002         rel_to_abs(&dx, &dy);
01003         arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy);
01004     }
01005 
01006     //------------------------------------------------------------------------
01007     template<class VC> 
01008     void path_base<VC>::curve3(double x_ctrl, double y_ctrl, 
01009                                double x_to,   double y_to)
01010     {
01011         m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3);
01012         m_vertices.add_vertex(x_to,   y_to,   path_cmd_curve3);
01013     }
01014 
01015     //------------------------------------------------------------------------
01016     template<class VC> 
01017     void path_base<VC>::curve3_rel(double dx_ctrl, double dy_ctrl, 
01018                                    double dx_to,   double dy_to)
01019     {
01020         rel_to_abs(&dx_ctrl, &dy_ctrl);
01021         rel_to_abs(&dx_to,   &dy_to);
01022         m_vertices.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3);
01023         m_vertices.add_vertex(dx_to,   dy_to,   path_cmd_curve3);
01024     }
01025 
01026     //------------------------------------------------------------------------
01027     template<class VC> 
01028     void path_base<VC>::curve3(double x_to, double y_to)
01029     {
01030         double x0;
01031         double y0;
01032         if(is_vertex(m_vertices.last_vertex(&x0, &y0)))
01033         {
01034             double x_ctrl;
01035             double y_ctrl; 
01036             unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl);
01037             if(is_curve(cmd))
01038             {
01039                 x_ctrl = x0 + x0 - x_ctrl;
01040                 y_ctrl = y0 + y0 - y_ctrl;
01041             }
01042             else
01043             {
01044                 x_ctrl = x0;
01045                 y_ctrl = y0;
01046             }
01047             curve3(x_ctrl, y_ctrl, x_to, y_to);
01048         }
01049     }
01050 
01051     //------------------------------------------------------------------------
01052     template<class VC> 
01053     void path_base<VC>::curve3_rel(double dx_to, double dy_to)
01054     {
01055         rel_to_abs(&dx_to, &dy_to);
01056         curve3(dx_to, dy_to);
01057     }
01058 
01059     //------------------------------------------------------------------------
01060     template<class VC> 
01061     void path_base<VC>::curve4(double x_ctrl1, double y_ctrl1, 
01062                                double x_ctrl2, double y_ctrl2, 
01063                                double x_to,    double y_to)
01064     {
01065         m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4);
01066         m_vertices.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4);
01067         m_vertices.add_vertex(x_to,    y_to,    path_cmd_curve4);
01068     }
01069 
01070     //------------------------------------------------------------------------
01071     template<class VC> 
01072     void path_base<VC>::curve4_rel(double dx_ctrl1, double dy_ctrl1, 
01073                                    double dx_ctrl2, double dy_ctrl2, 
01074                                    double dx_to,    double dy_to)
01075     {
01076         rel_to_abs(&dx_ctrl1, &dy_ctrl1);
01077         rel_to_abs(&dx_ctrl2, &dy_ctrl2);
01078         rel_to_abs(&dx_to,    &dy_to);
01079         m_vertices.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4);
01080         m_vertices.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4);
01081         m_vertices.add_vertex(dx_to,    dy_to,    path_cmd_curve4);
01082     }
01083 
01084     //------------------------------------------------------------------------
01085     template<class VC> 
01086     void path_base<VC>::curve4(double x_ctrl2, double y_ctrl2, 
01087                                double x_to,    double y_to)
01088     {
01089         double x0;
01090         double y0;
01091         if(is_vertex(last_vertex(&x0, &y0)))
01092         {
01093             double x_ctrl1;
01094             double y_ctrl1; 
01095             unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1);
01096             if(is_curve(cmd))
01097             {
01098                 x_ctrl1 = x0 + x0 - x_ctrl1;
01099                 y_ctrl1 = y0 + y0 - y_ctrl1;
01100             }
01101             else
01102             {
01103                 x_ctrl1 = x0;
01104                 y_ctrl1 = y0;
01105             }
01106             curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to);
01107         }
01108     }
01109 
01110     //------------------------------------------------------------------------
01111     template<class VC> 
01112     void path_base<VC>::curve4_rel(double dx_ctrl2, double dy_ctrl2, 
01113                                    double dx_to,    double dy_to)
01114     {
01115         rel_to_abs(&dx_ctrl2, &dy_ctrl2);
01116         rel_to_abs(&dx_to,    &dy_to);
01117         curve4(dx_ctrl2, dy_ctrl2, dx_to, dy_to);
01118     }
01119 
01120     //------------------------------------------------------------------------
01121     template<class VC> 
01122     inline void path_base<VC>::end_poly(unsigned flags)
01123     {
01124         if(is_vertex(m_vertices.last_command()))
01125         {
01126             m_vertices.add_vertex(0.0, 0.0, path_cmd_end_poly | flags);
01127         }
01128     }
01129 
01130     //------------------------------------------------------------------------
01131     template<class VC> 
01132     inline void path_base<VC>::close_polygon(unsigned flags)
01133     {
01134         end_poly(path_flags_close | flags);
01135     }
01136 
01137     //------------------------------------------------------------------------
01138     template<class VC> 
01139     inline unsigned path_base<VC>::total_vertices() const
01140     {
01141         return m_vertices.total_vertices();
01142     }
01143 
01144     //------------------------------------------------------------------------
01145     template<class VC> 
01146     inline unsigned path_base<VC>::last_vertex(double* x, double* y) const
01147     {
01148         return m_vertices.last_vertex(x, y);
01149     }
01150 
01151     //------------------------------------------------------------------------
01152     template<class VC> 
01153     inline unsigned path_base<VC>::prev_vertex(double* x, double* y) const
01154     {
01155         return m_vertices.prev_vertex(x, y);
01156     }
01157 
01158     //------------------------------------------------------------------------
01159     template<class VC> 
01160     inline double path_base<VC>::last_x() const
01161     {
01162         return m_vertices.last_x();
01163     }
01164 
01165     //------------------------------------------------------------------------
01166     template<class VC> 
01167     inline double path_base<VC>::last_y() const
01168     {
01169         return m_vertices.last_y();
01170     }
01171 
01172     //------------------------------------------------------------------------
01173     template<class VC> 
01174     inline unsigned path_base<VC>::vertex(unsigned idx, double* x, double* y) const
01175     {
01176         return m_vertices.vertex(idx, x, y);
01177     }
01178  
01179     //------------------------------------------------------------------------
01180     template<class VC> 
01181     inline unsigned path_base<VC>::command(unsigned idx) const
01182     {
01183         return m_vertices.command(idx);
01184     }
01185 
01186     //------------------------------------------------------------------------
01187     template<class VC> 
01188     void path_base<VC>::modify_vertex(unsigned idx, double x, double y)
01189     {
01190         m_vertices.modify_vertex(idx, x, y);
01191     }
01192 
01193     //------------------------------------------------------------------------
01194     template<class VC> 
01195     void path_base<VC>::modify_vertex(unsigned idx, double x, double y, unsigned cmd)
01196     {
01197         m_vertices.modify_vertex(idx, x, y, cmd);
01198     }
01199 
01200     //------------------------------------------------------------------------
01201     template<class VC> 
01202     void path_base<VC>::modify_command(unsigned idx, unsigned cmd)
01203     {
01204         m_vertices.modify_command(idx, cmd);
01205     }
01206 
01207     //------------------------------------------------------------------------
01208     template<class VC> 
01209     inline void path_base<VC>::rewind(unsigned path_id)
01210     {
01211         m_iterator = path_id;
01212     }
01213 
01214     //------------------------------------------------------------------------
01215     template<class VC> 
01216     inline unsigned path_base<VC>::vertex(double* x, double* y)
01217     {
01218         if(m_iterator >= m_vertices.total_vertices()) return path_cmd_stop;
01219         return m_vertices.vertex(m_iterator++, x, y);
01220     }
01221 
01222     //------------------------------------------------------------------------
01223     template<class VC> 
01224     unsigned path_base<VC>::perceive_polygon_orientation(unsigned start,
01225                                                          unsigned end)
01226     {
01227         // Calculate signed area (double area to be exact)
01228         //---------------------
01229         unsigned np = end - start;
01230         double area = 0.0;
01231         unsigned i;
01232         for(i = 0; i < np; i++)
01233         {
01234             double x1, y1, x2, y2;
01235             m_vertices.vertex(start + i,            &x1, &y1);
01236             m_vertices.vertex(start + (i + 1) % np, &x2, &y2);
01237             area += x1 * y2 - y1 * x2;
01238         }
01239         return (area < 0.0) ? path_flags_cw : path_flags_ccw;
01240     }
01241 
01242     //------------------------------------------------------------------------
01243     template<class VC> 
01244     void path_base<VC>::invert_polygon(unsigned start, unsigned end)
01245     {
01246         unsigned i;
01247         unsigned tmp_cmd = m_vertices.command(start);
01248         
01249         --end; // Make "end" inclusive
01250 
01251         // Shift all commands to one position
01252         for(i = start; i < end; i++)
01253         {
01254             m_vertices.modify_command(i, m_vertices.command(i + 1));
01255         }
01256 
01257         // Assign starting command to the ending command
01258         m_vertices.modify_command(end, tmp_cmd);
01259 
01260         // Reverse the polygon
01261         while(end > start)
01262         {
01263             m_vertices.swap_vertices(start++, end--);
01264         }
01265     }
01266 
01267     //------------------------------------------------------------------------
01268     template<class VC> 
01269     void path_base<VC>::invert_polygon(unsigned start)
01270     {
01271         // Skip all non-vertices at the beginning
01272         while(start < m_vertices.total_vertices() && 
01273               !is_vertex(m_vertices.command(start))) ++start;
01274 
01275         // Skip all insignificant move_to
01276         while(start+1 < m_vertices.total_vertices() && 
01277               is_move_to(m_vertices.command(start)) &&
01278               is_move_to(m_vertices.command(start+1))) ++start;
01279 
01280         // Find the last vertex
01281         unsigned end = start + 1;
01282         while(end < m_vertices.total_vertices() && 
01283               !is_next_poly(m_vertices.command(end))) ++end;
01284 
01285         invert_polygon(start, end);
01286     }
01287 
01288     //------------------------------------------------------------------------
01289     template<class VC> 
01290     unsigned path_base<VC>::arrange_polygon_orientation(unsigned start, 
01291                                                         path_flags_e orientation)
01292     {
01293         if(orientation == path_flags_none) return start;
01294         
01295         // Skip all non-vertices at the beginning
01296         while(start < m_vertices.total_vertices() && 
01297               !is_vertex(m_vertices.command(start))) ++start;
01298 
01299         // Skip all insignificant move_to
01300         while(start+1 < m_vertices.total_vertices() && 
01301               is_move_to(m_vertices.command(start)) &&
01302               is_move_to(m_vertices.command(start+1))) ++start;
01303 
01304         // Find the last vertex
01305         unsigned end = start + 1;
01306         while(end < m_vertices.total_vertices() && 
01307               !is_next_poly(m_vertices.command(end))) ++end;
01308 
01309         if(end - start > 2)
01310         {
01311             if(perceive_polygon_orientation(start, end) != unsigned(orientation))
01312             {
01313                 // Invert polygon, set orientation flag, and skip all end_poly
01314                 invert_polygon(start, end);
01315                 unsigned cmd;
01316                 while(end < m_vertices.total_vertices() && 
01317                       is_end_poly(cmd = m_vertices.command(end)))
01318                 {
01319                     m_vertices.modify_command(end++, set_orientation(cmd, orientation));
01320                 }
01321             }
01322         }
01323         return end;
01324     }
01325 
01326     //------------------------------------------------------------------------
01327     template<class VC> 
01328     unsigned path_base<VC>::arrange_orientations(unsigned start, 
01329                                                  path_flags_e orientation)
01330     {
01331         if(orientation != path_flags_none)
01332         {
01333             while(start < m_vertices.total_vertices())
01334             {
01335                 start = arrange_polygon_orientation(start, orientation);
01336                 if(is_stop(m_vertices.command(start)))
01337                 {
01338                     ++start;
01339                     break;
01340                 }
01341             }
01342         }
01343         return start;
01344     }
01345 
01346     //------------------------------------------------------------------------
01347     template<class VC> 
01348     void path_base<VC>::arrange_orientations_all_paths(path_flags_e orientation)
01349     {
01350         if(orientation != path_flags_none)
01351         {
01352             unsigned start = 0;
01353             while(start < m_vertices.total_vertices())
01354             {
01355                 start = arrange_orientations(start, orientation);
01356             }
01357         }
01358     }
01359 
01360     //------------------------------------------------------------------------
01361     template<class VC> 
01362     void path_base<VC>::flip_x(double x1, double x2)
01363     {
01364         unsigned i;
01365         double x, y;
01366         for(i = 0; i < m_vertices.total_vertices(); i++)
01367         {
01368             unsigned cmd = m_vertices.vertex(i, &x, &y);
01369             if(is_vertex(cmd))
01370             {
01371                 m_vertices.modify_vertex(i, x2 - x + x1, y);
01372             }
01373         }
01374     }
01375 
01376     //------------------------------------------------------------------------
01377     template<class VC> 
01378     void path_base<VC>::flip_y(double y1, double y2)
01379     {
01380         unsigned i;
01381         double x, y;
01382         for(i = 0; i < m_vertices.total_vertices(); i++)
01383         {
01384             unsigned cmd = m_vertices.vertex(i, &x, &y);
01385             if(is_vertex(cmd))
01386             {
01387                 m_vertices.modify_vertex(i, x, y2 - y + y1);
01388             }
01389         }
01390     }
01391 
01392     //------------------------------------------------------------------------
01393     template<class VC> 
01394     void path_base<VC>::translate(double dx, double dy, unsigned path_id)
01395     {
01396         unsigned num_ver = m_vertices.total_vertices();
01397         for(; path_id < num_ver; path_id++)
01398         {
01399             double x, y;
01400             unsigned cmd = m_vertices.vertex(path_id, &x, &y);
01401             if(is_stop(cmd)) break;
01402             if(is_vertex(cmd))
01403             {
01404                 x += dx;
01405                 y += dy;
01406                 m_vertices.modify_vertex(path_id, x, y);
01407             }
01408         }
01409     }
01410 
01411     //------------------------------------------------------------------------
01412     template<class VC> 
01413     void path_base<VC>::translate_all_paths(double dx, double dy)
01414     {
01415         unsigned idx;
01416         unsigned num_ver = m_vertices.total_vertices();
01417         for(idx = 0; idx < num_ver; idx++)
01418         {
01419             double x, y;
01420             if(is_vertex(m_vertices.vertex(idx, &x, &y)))
01421             {
01422                 x += dx;
01423                 y += dy;
01424                 m_vertices.modify_vertex(idx, x, y);
01425             }
01426         }
01427     }
01428 
01429     //-----------------------------------------------------vertex_stl_storage
01430     template<class Container> class vertex_stl_storage
01431     {
01432     public:
01433         typedef typename Container::value_type vertex_type;
01434         typedef typename vertex_type::value_type value_type;
01435 
01436         void remove_all() { m_vertices.clear(); }
01437         void free_all()   { m_vertices.clear(); }
01438 
01439         void add_vertex(double x, double y, unsigned cmd)
01440         {
01441             m_vertices.push_back(vertex_type(value_type(x), 
01442                                              value_type(y), 
01443                                              int8u(cmd)));
01444         }
01445 
01446         void modify_vertex(unsigned idx, double x, double y)
01447         {
01448             vertex_type& v = m_vertices[idx];
01449             v.x = value_type(x);
01450             v.y = value_type(y);
01451         }
01452 
01453         void modify_vertex(unsigned idx, double x, double y, unsigned cmd)
01454         {
01455             vertex_type& v = m_vertices[idx];
01456             v.x   = value_type(x);
01457             v.y   = value_type(y);
01458             v.cmd = int8u(cmd);
01459         }
01460 
01461         void modify_command(unsigned idx, unsigned cmd)
01462         {
01463             m_vertices[idx].cmd = int8u(cmd);
01464         }
01465 
01466         void swap_vertices(unsigned v1, unsigned v2)
01467         {
01468             vertex_type t = m_vertices[v1];
01469             m_vertices[v1] = m_vertices[v2];
01470             m_vertices[v2] = t;
01471         }
01472 
01473         unsigned last_command() const
01474         {
01475             return m_vertices.size() ? 
01476                 m_vertices[m_vertices.size() - 1].cmd : 
01477                 path_cmd_stop;
01478         }
01479 
01480         unsigned last_vertex(double* x, double* y) const
01481         {
01482             if(m_vertices.size() == 0)
01483             {
01484                 *x = *y = 0.0;
01485                 return path_cmd_stop;
01486             }
01487             return vertex(m_vertices.size() - 1, x, y);
01488         }
01489 
01490         unsigned prev_vertex(double* x, double* y) const
01491         {
01492             if(m_vertices.size() < 2)
01493             {
01494                 *x = *y = 0.0;
01495                 return path_cmd_stop;
01496             }
01497             return vertex(m_vertices.size() - 2, x, y);
01498         }
01499 
01500         double last_x() const
01501         {
01502             return m_vertices.size() ? m_vertices[m_vertices.size() - 1].x : 0.0;
01503         }
01504 
01505         double last_y() const
01506         {
01507             return m_vertices.size() ? m_vertices[m_vertices.size() - 1].y : 0.0;
01508         }
01509 
01510         unsigned total_vertices() const
01511         {
01512             return m_vertices.size();
01513         }
01514 
01515         unsigned vertex(unsigned idx, double* x, double* y) const
01516         {
01517             const vertex_type& v = m_vertices[idx];
01518             *x = v.x;
01519             *y = v.y;
01520             return v.cmd;
01521         }
01522 
01523         unsigned command(unsigned idx) const
01524         {
01525             return m_vertices[idx].cmd;
01526         }
01527 
01528     private:
01529         Container m_vertices;
01530     };
01531 
01532     //-----------------------------------------------------------path_storage
01533     typedef path_base<vertex_block_storage<double> > path_storage;
01534 
01535     // Example of declarations path_storage with pod_bvector as a container
01536     //-----------------------------------------------------------------------
01537     //typedef path_base<vertex_stl_storage<pod_bvector<vertex_d> > > path_storage;
01538 
01539 }
01540 
01541 
01542 
01543 // Example of declarations path_storage with std::vector as a container
01544 //---------------------------------------------------------------------------
01545 //#include <vector>
01546 //namespace agg
01547 //{
01548 //    typedef path_base<vertex_stl_storage<std::vector<vertex_d> > > stl_path_storage; 
01549 //}
01550 
01551 
01552 
01553 
01554 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines