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
25namespace 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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
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
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
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
382        void rewind(unsigned)
383        {
384            m_ptr = m_data;
385            m_stop = false;
386        }
387
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
424        poly_container_adaptor() :
425            m_container(0),
426            m_index(0),
427            m_closed(false),
428            m_stop(false)
429        {}
430
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
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
446        void rewind(unsigned)
447        {
448            m_index = 0;
449            m_stop = false;
450        }
451
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
486        poly_container_reverse_adaptor() :
487            m_container(0),
488            m_index(-1),
489            m_closed(false),
490            m_stop(false)
491        {}
492
493        poly_container_reverse_adaptor(const Container& data, bool closed) :
494            m_container(&data),
495            m_index(-1),
496            m_closed(closed),
497            m_stop(false)
498        {}
499
500        void init(const 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
508        void rewind(unsigned)
509        {
510            m_index = m_container->size() - 1;
511            m_stop = false;
512        }
513
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        const 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
550        line_adaptor() : m_line(m_coord, 2, false) {}
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
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
569        void rewind(unsigned)
570        {
571            m_line.rewind(0);
572        }
573
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        //--------------------------------------------------------------------
615        path_base() : m_vertices(), m_iterator(0) {}
616        void remove_all() { m_vertices.remove_all(); m_iterator = 0; }
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        //--------------------------------------------------------------------
677        const container_type& vertices() const { return m_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                                                    path_cmd_line_to :
773                                                    cmd);
774                }
775            }
776        }
777
778        // Concatenate polygon/polyline.
779        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
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    private:
800        unsigned perceive_polygon_orientation(unsigned start, unsigned end);
801        void     invert_polygon(unsigned start, unsigned end);
802
803        VertexContainer m_vertices;
804        unsigned        m_iterator;
805    };
806
807    //------------------------------------------------------------------------
808    template<class VC>
809    unsigned path_base<VC>::start_new_path()
810    {
811        if(!is_stop(m_vertices.last_command()))
812        {
813            m_vertices.add_vertex(0.0, 0.0, path_cmd_stop);
814        }
815        return m_vertices.total_vertices();
816    }
817
818
819    //------------------------------------------------------------------------
820    template<class VC>
821    inline void path_base<VC>::rel_to_abs(double* x, double* y) const
822    {
823        if(m_vertices.total_vertices())
824        {
825            double x2;
826            double y2;
827            if(is_vertex(m_vertices.last_vertex(&x2, &y2)))
828            {
829                *x += x2;
830                *y += y2;
831            }
832        }
833    }
834
835    //------------------------------------------------------------------------
836    template<class VC>
837    inline void path_base<VC>::move_to(double x, double y)
838    {
839        m_vertices.add_vertex(x, y, path_cmd_move_to);
840    }
841
842    //------------------------------------------------------------------------
843    template<class VC>
844    inline void path_base<VC>::move_rel(double dx, double dy)
845    {
846        rel_to_abs(&dx, &dy);
847        m_vertices.add_vertex(dx, dy, path_cmd_move_to);
848    }
849
850    //------------------------------------------------------------------------
851    template<class VC>
852    inline void path_base<VC>::line_to(double x, double y)
853    {
854        m_vertices.add_vertex(x, y, path_cmd_line_to);
855    }
856
857    //------------------------------------------------------------------------
858    template<class VC>
859    inline void path_base<VC>::line_rel(double dx, double dy)
860    {
861        rel_to_abs(&dx, &dy);
862        m_vertices.add_vertex(dx, dy, path_cmd_line_to);
863    }
864
865    //------------------------------------------------------------------------
866    template<class VC>
867    inline void path_base<VC>::hline_to(double x)
868    {
869        m_vertices.add_vertex(x, last_y(), path_cmd_line_to);
870    }
871
872    //------------------------------------------------------------------------
873    template<class VC>
874    inline void path_base<VC>::hline_rel(double dx)
875    {
876        double dy = 0;
877        rel_to_abs(&dx, &dy);
878        m_vertices.add_vertex(dx, dy, path_cmd_line_to);
879    }
880
881    //------------------------------------------------------------------------
882    template<class VC>
883    inline void path_base<VC>::vline_to(double y)
884    {
885        m_vertices.add_vertex(last_x(), y, path_cmd_line_to);
886    }
887
888    //------------------------------------------------------------------------
889    template<class VC>
890    inline void path_base<VC>::vline_rel(double dy)
891    {
892        double dx = 0;
893        rel_to_abs(&dx, &dy);
894        m_vertices.add_vertex(dx, dy, path_cmd_line_to);
895    }
896
897    //------------------------------------------------------------------------
898    template<class VC>
899    void path_base<VC>::arc_to(double rx, double ry,
900                               double angle,
901                               bool large_arc_flag,
902                               bool sweep_flag,
903                               double x, double y)
904    {
905        if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command()))
906        {
907            const double epsilon = 1e-30;
908            double x0 = 0.0;
909            double y0 = 0.0;
910            m_vertices.last_vertex(&x0, &y0);
911
912            rx = fabs(rx);
913            ry = fabs(ry);
914
915            // Ensure radii are valid
916            //-------------------------
917            if(rx < epsilon || ry < epsilon)
918            {
919                line_to(x, y);
920                return;
921            }
922
923            if(calc_distance(x0, y0, x, y) < epsilon)
924            {
925                // If the endpoints (x, y) and (x0, y0) are identical, then this
926                // is equivalent to omitting the elliptical arc segment entirely.
927                return;
928            }
929            bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y);
930            if(a.radii_ok())
931            {
932                join_path(a);
933            }
934            else
935            {
936                line_to(x, y);
937            }
938        }
939        else
940        {
941            move_to(x, y);
942        }
943    }
944
945    //------------------------------------------------------------------------
946    template<class VC>
947    void path_base<VC>::arc_rel(double rx, double ry,
948                                double angle,
949                                bool large_arc_flag,
950                                bool sweep_flag,
951                                double dx, double dy)
952    {
953        rel_to_abs(&dx, &dy);
954        arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy);
955    }
956
957    //------------------------------------------------------------------------
958    template<class VC>
959    void path_base<VC>::curve3(double x_ctrl, double y_ctrl,
960                               double x_to,   double y_to)
961    {
962        m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3);
963        m_vertices.add_vertex(x_to,   y_to,   path_cmd_curve3);
964    }
965
966    //------------------------------------------------------------------------
967    template<class VC>
968    void path_base<VC>::curve3_rel(double dx_ctrl, double dy_ctrl,
969                                   double dx_to,   double dy_to)
970    {
971        rel_to_abs(&dx_ctrl, &dy_ctrl);
972        rel_to_abs(&dx_to,   &dy_to);
973        m_vertices.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3);
974        m_vertices.add_vertex(dx_to,   dy_to,   path_cmd_curve3);
975    }
976
977    //------------------------------------------------------------------------
978    template<class VC>
979    void path_base<VC>::curve3(double x_to, double y_to)
980    {
981        double x0;
982        double y0;
983        if(is_vertex(m_vertices.last_vertex(&x0, &y0)))
984        {
985            double x_ctrl;
986            double y_ctrl;
987            unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl);
988            if(is_curve(cmd))
989            {
990                x_ctrl = x0 + x0 - x_ctrl;
991                y_ctrl = y0 + y0 - y_ctrl;
992            }
993            else
994            {
995                x_ctrl = x0;
996                y_ctrl = y0;
997            }
998            curve3(x_ctrl, y_ctrl, x_to, y_to);
999        }
1000    }
1001
1002    //------------------------------------------------------------------------
1003    template<class VC>
1004    void path_base<VC>::curve3_rel(double dx_to, double dy_to)
1005    {
1006        rel_to_abs(&dx_to, &dy_to);
1007        curve3(dx_to, dy_to);
1008    }
1009
1010    //------------------------------------------------------------------------
1011    template<class VC>
1012    void path_base<VC>::curve4(double x_ctrl1, double y_ctrl1,
1013                               double x_ctrl2, double y_ctrl2,
1014                               double x_to,    double y_to)
1015    {
1016        m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4);
1017        m_vertices.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4);
1018        m_vertices.add_vertex(x_to,    y_to,    path_cmd_curve4);
1019    }
1020
1021    //------------------------------------------------------------------------
1022    template<class VC>
1023    void path_base<VC>::curve4_rel(double dx_ctrl1, double dy_ctrl1,
1024                                   double dx_ctrl2, double dy_ctrl2,
1025                                   double dx_to,    double dy_to)
1026    {
1027        rel_to_abs(&dx_ctrl1, &dy_ctrl1);
1028        rel_to_abs(&dx_ctrl2, &dy_ctrl2);
1029        rel_to_abs(&dx_to,    &dy_to);
1030        m_vertices.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4);
1031        m_vertices.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4);
1032        m_vertices.add_vertex(dx_to,    dy_to,    path_cmd_curve4);
1033    }
1034
1035    //------------------------------------------------------------------------
1036    template<class VC>
1037    void path_base<VC>::curve4(double x_ctrl2, double y_ctrl2,
1038                               double x_to,    double y_to)
1039    {
1040        double x0;
1041        double y0;
1042        if(is_vertex(last_vertex(&x0, &y0)))
1043        {
1044            double x_ctrl1;
1045            double y_ctrl1;
1046            unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1);
1047            if(is_curve(cmd))
1048            {
1049                x_ctrl1 = x0 + x0 - x_ctrl1;
1050                y_ctrl1 = y0 + y0 - y_ctrl1;
1051            }
1052            else
1053            {
1054                x_ctrl1 = x0;
1055                y_ctrl1 = y0;
1056            }
1057            curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to);
1058        }
1059    }
1060
1061    //------------------------------------------------------------------------
1062    template<class VC>
1063    void path_base<VC>::curve4_rel(double dx_ctrl2, double dy_ctrl2,
1064                                   double dx_to,    double dy_to)
1065    {
1066        rel_to_abs(&dx_ctrl2, &dy_ctrl2);
1067        rel_to_abs(&dx_to,    &dy_to);
1068        curve4(dx_ctrl2, dy_ctrl2, dx_to, dy_to);
1069    }
1070
1071    //------------------------------------------------------------------------
1072    template<class VC>
1073    inline void path_base<VC>::end_poly(unsigned flags)
1074    {
1075        if(is_vertex(m_vertices.last_command()))
1076        {
1077            m_vertices.add_vertex(0.0, 0.0, path_cmd_end_poly | flags);
1078        }
1079    }
1080
1081    //------------------------------------------------------------------------
1082    template<class VC>
1083    inline void path_base<VC>::close_polygon(unsigned flags)
1084    {
1085        end_poly(path_flags_close | flags);
1086    }
1087
1088    //------------------------------------------------------------------------
1089    template<class VC>
1090    inline unsigned path_base<VC>::total_vertices() const
1091    {
1092        return m_vertices.total_vertices();
1093    }
1094
1095    //------------------------------------------------------------------------
1096    template<class VC>
1097    inline unsigned path_base<VC>::last_vertex(double* x, double* y) const
1098    {
1099        return m_vertices.last_vertex(x, y);
1100    }
1101
1102    //------------------------------------------------------------------------
1103    template<class VC>
1104    inline unsigned path_base<VC>::prev_vertex(double* x, double* y) const
1105    {
1106        return m_vertices.prev_vertex(x, y);
1107    }
1108
1109    //------------------------------------------------------------------------
1110    template<class VC>
1111    inline double path_base<VC>::last_x() const
1112    {
1113        return m_vertices.last_x();
1114    }
1115
1116    //------------------------------------------------------------------------
1117    template<class VC>
1118    inline double path_base<VC>::last_y() const
1119    {
1120        return m_vertices.last_y();
1121    }
1122
1123    //------------------------------------------------------------------------
1124    template<class VC>
1125    inline unsigned path_base<VC>::vertex(unsigned idx, double* x, double* y) const
1126    {
1127        return m_vertices.vertex(idx, x, y);
1128    }
1129
1130    //------------------------------------------------------------------------
1131    template<class VC>
1132    inline unsigned path_base<VC>::command(unsigned idx) const
1133    {
1134        return m_vertices.command(idx);
1135    }
1136
1137    //------------------------------------------------------------------------
1138    template<class VC>
1139    void path_base<VC>::modify_vertex(unsigned idx, double x, double y)
1140    {
1141        m_vertices.modify_vertex(idx, x, y);
1142    }
1143
1144    //------------------------------------------------------------------------
1145    template<class VC>
1146    void path_base<VC>::modify_vertex(unsigned idx, double x, double y, unsigned cmd)
1147    {
1148        m_vertices.modify_vertex(idx, x, y, cmd);
1149    }
1150
1151    //------------------------------------------------------------------------
1152    template<class VC>
1153    void path_base<VC>::modify_command(unsigned idx, unsigned cmd)
1154    {
1155        m_vertices.modify_command(idx, cmd);
1156    }
1157
1158    //------------------------------------------------------------------------
1159    template<class VC>
1160    inline void path_base<VC>::rewind(unsigned path_id)
1161    {
1162        m_iterator = path_id;
1163    }
1164
1165    //------------------------------------------------------------------------
1166    template<class VC>
1167    inline unsigned path_base<VC>::vertex(double* x, double* y)
1168    {
1169        if(m_iterator >= m_vertices.total_vertices()) return path_cmd_stop;
1170        return m_vertices.vertex(m_iterator++, x, y);
1171    }
1172
1173
1174    //------------------------------------------------------------------------
1175    template<class VC>
1176    unsigned path_base<VC>::perceive_polygon_orientation(unsigned start,
1177                                                         unsigned end)
1178    {
1179        // Calculate signed area (double area to be exact)
1180        //---------------------
1181        unsigned np = end - start;
1182        double area = 0.0;
1183        unsigned i;
1184        for(i = 0; i < np; i++)
1185        {
1186            double x1, y1, x2, y2;
1187            m_vertices.vertex(start + i,            &x1, &y1);
1188            m_vertices.vertex(start + (i + 1) % np, &x2, &y2);
1189            area += x1 * y2 - y1 * x2;
1190        }
1191        return (area < 0.0) ? path_flags_cw : path_flags_ccw;
1192    }
1193
1194
1195    //------------------------------------------------------------------------
1196    template<class VC>
1197    void path_base<VC>::invert_polygon(unsigned start, unsigned end)
1198    {
1199        unsigned i;
1200        unsigned tmp_cmd = m_vertices.command(start);
1201
1202        --end; // Make "end" inclusive
1203
1204        // Shift all commands to one position
1205        for(i = start; i < end; i++)
1206        {
1207            m_vertices.modify_command(i, m_vertices.command(i + 1));
1208        }
1209
1210        // Assign starting command to the ending command
1211        m_vertices.modify_command(end, tmp_cmd);
1212
1213        // Reverse the polygon
1214        while(end > start)
1215        {
1216            m_vertices.swap_vertices(start++, end--);
1217        }
1218    }
1219
1220    //------------------------------------------------------------------------
1221    template<class VC>
1222    void path_base<VC>::invert_polygon(unsigned start)
1223    {
1224        // Skip all non-vertices at the beginning
1225        while(start < m_vertices.total_vertices() &&
1226              !is_vertex(m_vertices.command(start))) ++start;
1227
1228        // Skip all insignificant move_to
1229        while(start+1 < m_vertices.total_vertices() &&
1230              is_move_to(m_vertices.command(start)) &&
1231              is_move_to(m_vertices.command(start+1))) ++start;
1232
1233        // Find the last vertex
1234        unsigned end = start + 1;
1235        while(end < m_vertices.total_vertices() &&
1236              !is_next_poly(m_vertices.command(end))) ++end;
1237
1238        invert_polygon(start, end);
1239    }
1240
1241    //------------------------------------------------------------------------
1242    template<class VC>
1243    unsigned path_base<VC>::arrange_polygon_orientation(unsigned start,
1244                                                        path_flags_e orientation)
1245    {
1246        if(orientation == path_flags_none) return start;
1247
1248        // Skip all non-vertices at the beginning
1249        while(start < m_vertices.total_vertices() &&
1250              !is_vertex(m_vertices.command(start))) ++start;
1251
1252        // Skip all insignificant move_to
1253        while(start+1 < m_vertices.total_vertices() &&
1254              is_move_to(m_vertices.command(start)) &&
1255              is_move_to(m_vertices.command(start+1))) ++start;
1256
1257        // Find the last vertex
1258        unsigned end = start + 1;
1259        while(end < m_vertices.total_vertices() &&
1260              !is_next_poly(m_vertices.command(end))) ++end;
1261
1262        if(end - start > 2)
1263        {
1264            if(perceive_polygon_orientation(start, end) != unsigned(orientation))
1265            {
1266                // Invert polygon, set orientation flag, and skip all end_poly
1267                invert_polygon(start, end);
1268                unsigned cmd;
1269                while(end < m_vertices.total_vertices() &&
1270                      is_end_poly(cmd = m_vertices.command(end)))
1271                {
1272                    m_vertices.modify_command(end++, set_orientation(cmd, orientation));
1273                }
1274            }
1275        }
1276        return end;
1277    }
1278
1279
1280    //------------------------------------------------------------------------
1281    template<class VC>
1282    unsigned path_base<VC>::arrange_orientations(unsigned start,
1283                                                 path_flags_e orientation)
1284    {
1285        if(orientation != path_flags_none)
1286        {
1287            while(start < m_vertices.total_vertices())
1288            {
1289                start = arrange_polygon_orientation(start, orientation);
1290                if(is_stop(m_vertices.command(start)))
1291                {
1292                    ++start;
1293                    break;
1294                }
1295            }
1296        }
1297        return start;
1298    }
1299
1300
1301    //------------------------------------------------------------------------
1302    template<class VC>
1303    void path_base<VC>::arrange_orientations_all_paths(path_flags_e orientation)
1304    {
1305        if(orientation != path_flags_none)
1306        {
1307            unsigned start = 0;
1308            while(start < m_vertices.total_vertices())
1309            {
1310                start = arrange_orientations(start, orientation);
1311            }
1312        }
1313    }
1314
1315
1316    //------------------------------------------------------------------------
1317    template<class VC>
1318    void path_base<VC>::flip_x(double x1, double x2)
1319    {
1320        unsigned i;
1321        double x, y;
1322        for(i = 0; i < m_vertices.total_vertices(); i++)
1323        {
1324            unsigned cmd = m_vertices.vertex(i, &x, &y);
1325            if(is_vertex(cmd))
1326            {
1327                m_vertices.modify_vertex(i, x2 - x + x1, y);
1328            }
1329        }
1330    }
1331
1332
1333    //------------------------------------------------------------------------
1334    template<class VC>
1335    void path_base<VC>::flip_y(double y1, double y2)
1336    {
1337        unsigned i;
1338        double x, y;
1339        for(i = 0; i < m_vertices.total_vertices(); i++)
1340        {
1341            unsigned cmd = m_vertices.vertex(i, &x, &y);
1342            if(is_vertex(cmd))
1343            {
1344                m_vertices.modify_vertex(i, x, y2 - y + y1);
1345            }
1346        }
1347    }
1348
1349
1350
1351
1352
1353    //-----------------------------------------------------vertex_stl_storage
1354    template<class Container> class vertex_stl_storage
1355    {
1356    public:
1357        typedef typename Container::value_type vertex_type;
1358        typedef typename vertex_type::value_type value_type;
1359
1360        void remove_all() { m_vertices.clear(); }
1361        void free_all()   { m_vertices.clear(); }
1362
1363        void add_vertex(double x, double y, unsigned cmd)
1364        {
1365            m_vertices.push_back(vertex_type(value_type(x),
1366                                             value_type(y),
1367                                             int8u(cmd)));
1368        }
1369
1370        void modify_vertex(unsigned idx, double x, double y)
1371        {
1372            vertex_type& v = m_vertices[idx];
1373            v.x = value_type(x);
1374            v.y = value_type(y);
1375        }
1376
1377        void modify_vertex(unsigned idx, double x, double y, unsigned cmd)
1378        {
1379            vertex_type& v = m_vertices[idx];
1380            v.x   = value_type(x);
1381            v.y   = value_type(y);
1382            v.cmd = int8u(cmd);
1383        }
1384
1385        void modify_command(unsigned idx, unsigned cmd)
1386        {
1387            m_vertices[idx].cmd = int8u(cmd);
1388        }
1389
1390        void swap_vertices(unsigned v1, unsigned v2)
1391        {
1392            vertex_type t = m_vertices[v1];
1393            m_vertices[v1] = m_vertices[v2];
1394            m_vertices[v2] = t;
1395        }
1396
1397        unsigned last_command() const
1398        {
1399            return m_vertices.size() ?
1400                m_vertices[m_vertices.size() - 1].cmd :
1401                path_cmd_stop;
1402        }
1403
1404        unsigned last_vertex(double* x, double* y) const
1405        {
1406            if(m_vertices.size() == 0)
1407            {
1408                *x = *y = 0.0;
1409                return path_cmd_stop;
1410            }
1411            return vertex(m_vertices.size() - 1, x, y);
1412        }
1413
1414        unsigned prev_vertex(double* x, double* y) const
1415        {
1416            if(m_vertices.size() < 2)
1417            {
1418                *x = *y = 0.0;
1419                return path_cmd_stop;
1420            }
1421            return vertex(m_vertices.size() - 2, x, y);
1422        }
1423
1424        double last_x() const
1425        {
1426            return m_vertices.size() ? m_vertices[m_vertices.size() - 1].x : 0.0;
1427        }
1428
1429        double last_y() const
1430        {
1431            return m_vertices.size() ? m_vertices[m_vertices.size() - 1].y : 0.0;
1432        }
1433
1434        unsigned total_vertices() const
1435        {
1436            return m_vertices.size();
1437        }
1438
1439        unsigned vertex(unsigned idx, double* x, double* y) const
1440        {
1441            const vertex_type& v = m_vertices[idx];
1442            *x = v.x;
1443            *y = v.y;
1444            return v.cmd;
1445        }
1446
1447        unsigned command(unsigned idx) const
1448        {
1449            return m_vertices[idx].cmd;
1450        }
1451
1452    private:
1453        Container m_vertices;
1454    };
1455
1456    //-----------------------------------------------------------path_storage
1457    typedef path_base<vertex_block_storage<double> > path_storage;
1458
1459    // Example of declarations path_storage with pod_bvector as a container
1460    //-----------------------------------------------------------------------
1461    //typedef path_base<vertex_stl_storage<pod_bvector<vertex_d> > > path_storage;
1462
1463}
1464
1465
1466
1467// Example of declarations path_storage with std::vector as a container
1468//---------------------------------------------------------------------------
1469//#include <vector>
1470//namespace agg
1471//{
1472//    typedef path_base<vertex_stl_storage<std::vector<vertex_d> > > stl_path_storage;
1473//}
1474
1475
1476
1477
1478#endif
1479