xref: /haiku/headers/libs/agg/agg_path_storage.h (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 //          mcseemagg@yahoo.com
13 //          http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 
16 #ifndef AGG_PATH_STORAGE_INCLUDED
17 #define AGG_PATH_STORAGE_INCLUDED
18 
19 #include <string.h>
20 #include <math.h>
21 #include "agg_math.h"
22 #include "agg_array.h"
23 #include "agg_bezier_arc.h"
24 
25 namespace agg
26 {
27 
28 
29     //----------------------------------------------------vertex_block_storage
30     template<class T, unsigned BlockShift=8, unsigned BlockPool=256>
31     class vertex_block_storage
32     {
33     public:
34         // Allocation parameters
35         enum block_scale_e
36         {
37             block_shift = BlockShift,
38             block_size  = 1 << block_shift,
39             block_mask  = block_size - 1,
40             block_pool  = BlockPool
41         };
42 
43         typedef T value_type;
44         typedef vertex_block_storage<T, BlockShift, BlockPool> self_type;
45 
46         ~vertex_block_storage();
47         vertex_block_storage();
48         vertex_block_storage(const self_type& v);
49         const self_type& operator = (const self_type& ps);
50 
51         void remove_all();
52         void free_all();
53 
54         void add_vertex(double x, double y, unsigned cmd);
55         void modify_vertex(unsigned idx, double x, double y);
56         void modify_vertex(unsigned idx, double x, double y, unsigned cmd);
57         void modify_command(unsigned idx, unsigned cmd);
58         void swap_vertices(unsigned v1, unsigned v2);
59 
60         unsigned last_command() const;
61         unsigned last_vertex(double* x, double* y) const;
62         unsigned prev_vertex(double* x, double* y) const;
63 
64         double last_x() const;
65         double last_y() const;
66 
67         unsigned total_vertices() const;
68         unsigned vertex(unsigned idx, double* x, double* y) const;
69         unsigned command(unsigned idx) const;
70 
71     private:
72         void   allocate_block(unsigned nb);
73         int8u* storage_ptrs(T** xy_ptr);
74 
75     private:
76         unsigned m_total_vertices;
77         unsigned m_total_blocks;
78         unsigned m_max_blocks;
79         T**      m_coord_blocks;
80         int8u**  m_cmd_blocks;
81     };
82 
83 
84     //------------------------------------------------------------------------
85     template<class T, unsigned S, unsigned P>
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