xref: /haiku/headers/libs/agg/agg_path_storage.h (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.2
3 // Copyright (C) 2002-2004 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 "agg_basics.h"
20 
21 namespace agg
22 {
23 
24     //------------------------------------------------------------path_storage
25     // A container to store vertices with their flags.
26     // A path consists of a number of contours separated with "move_to"
27     // commands. The path storage can keep and maintain more than one
28     // path.
29     // To navigate to the beginning of a particular path, use rewind(path_id);
30     // Where path_id is what start_new_path() returns. So, when you call
31     // start_new_path() you need to store its return value somewhere else
32     // to navigate to the path afterwards.
33     //
34     // See Implementation: agg_path_storage.cpp
35     // See also: vertex_source concept
36     //------------------------------------------------------------------------
37     class path_storage
38     {
39         // Allocation parameters
40         enum
41         {
42             block_shift = 8,
43             block_size  = 1 << block_shift,
44             block_mask  = block_size - 1,
45             block_pool  = 256
46         };
47 
48     public:
49 
50         //--------------------------------------------------------------------
51         class const_iterator
52         {
53             void vertex()
54             {
55                 if(m_vertex_idx < m_path->total_vertices())
56                 {
57                     m_vertex.cmd = m_path->vertex(m_vertex_idx, &m_vertex.x, &m_vertex.y);
58                 }
59                 else
60                 {
61                     m_vertex.cmd = path_cmd_stop;
62                     m_vertex.x = m_vertex.y = 0.0;
63                 }
64             }
65 
66         public:
67             const_iterator() {}
68             const_iterator(unsigned cmd) { m_vertex.cmd = cmd; }
69             const_iterator(const const_iterator& i) :
70                 m_path(i.m_path),
71                 m_vertex_idx(i.m_vertex_idx),
72                 m_vertex(i.m_vertex)
73             {
74             }
75 
76             const_iterator(const path_storage& p, unsigned id) :
77                 m_path(&p),
78                 m_vertex_idx(id)
79             {
80                 vertex();
81             }
82 
83             const_iterator& operator++()
84             {
85                 ++m_vertex_idx;
86                 vertex();
87                 return *this;
88             }
89 
90             const vertex_type& operator*() const { return m_vertex; }
91             const vertex_type* operator->() const { return &m_vertex; }
92 
93             bool operator != (const const_iterator& i)
94             {
95                 return m_vertex.cmd != i.m_vertex.cmd;
96             }
97 
98         private:
99             const path_storage* m_path;
100             unsigned            m_vertex_idx;
101             vertex_type         m_vertex;
102         };
103 
104         ~path_storage();
105         path_storage();
106         path_storage(const path_storage& ps);
107 
108         void remove_all();
109 
110         unsigned last_vertex(double* x, double* y) const;
111         unsigned prev_vertex(double* x, double* y) const;
112 
113         void rel_to_abs(double* x, double* y) const;
114 
115         void move_to(double x, double y);
116         void move_rel(double dx, double dy);
117 
118         void line_to(double x, double y);
119         void line_rel(double dx, double dy);
120 
121         void arc_to(double rx, double ry,
122                     double angle,
123                     bool large_arc_flag,
124                     bool sweep_flag,
125                     double x, double y);
126 
127         void arc_rel(double rx, double ry,
128                      double angle,
129                      bool large_arc_flag,
130                      bool sweep_flag,
131                      double dx, double dy);
132 
133         void curve3(double x_ctrl, double y_ctrl,
134                     double x_to,   double y_to);
135 
136         void curve3_rel(double dx_ctrl, double dy_ctrl,
137                         double dx_to,   double dy_to);
138 
139         void curve3(double x_to, double y_to);
140 
141         void curve3_rel(double dx_to, double dy_to);
142 
143         void curve4(double x_ctrl1, double y_ctrl1,
144                     double x_ctrl2, double y_ctrl2,
145                     double x_to,    double y_to);
146 
147         void curve4_rel(double dx_ctrl1, double dy_ctrl1,
148                         double dx_ctrl2, double dy_ctrl2,
149                         double dx_to,    double dy_to);
150 
151         void curve4(double x_ctrl2, double y_ctrl2,
152                     double x_to,    double y_to);
153 
154         void curve4_rel(double x_ctrl2, double y_ctrl2,
155                         double x_to,    double y_to);
156 
157 
158         void end_poly(unsigned flags = path_flags_close);
159 
160         void close_polygon(unsigned flags = path_flags_none)
161         {
162             end_poly(path_flags_close | flags);
163         }
164 
165         void add_poly(const double* vertices, unsigned num,
166                       bool solid_path = false,
167                       unsigned end_flags = path_flags_none);
168 
169         template<class VertexSource>
170         void add_path(VertexSource& vs,
171                       unsigned path_id = 0,
172                       bool solid_path = true)
173         {
174             double x, y;
175             unsigned cmd;
176             vs.rewind(path_id);
177             while(!is_stop(cmd = vs.vertex(&x, &y)))
178             {
179                 if(is_move_to(cmd) && solid_path && m_total_vertices)
180                 {
181                     cmd = path_cmd_line_to;
182                 }
183                 add_vertex(x, y, cmd);
184             }
185         }
186 
187         unsigned start_new_path();
188 
189         void copy_from(const path_storage& ps);
190         const path_storage& operator = (const path_storage& ps)
191         {
192             copy_from(ps);
193             return *this;
194         }
195 
196 
197         unsigned total_vertices() const { return m_total_vertices; }
198         unsigned vertex(unsigned idx, double* x, double* y) const
199         {
200             unsigned nb = idx >> block_shift;
201             const double* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1);
202             *x = *pv++;
203             *y = *pv;
204             return m_cmd_blocks[nb][idx & block_mask];
205         }
206         unsigned command(unsigned idx) const
207         {
208             return m_cmd_blocks[idx >> block_shift][idx & block_mask];
209         }
210 
211         void     rewind(unsigned path_id);
212         unsigned vertex(double* x, double* y);
213 
214         const_iterator begin(unsigned id) const { return const_iterator(*this, id); }
215         const_iterator begin()            const { return const_iterator(*this, 0); }
216         const_iterator end()              const { return const_iterator(path_cmd_stop); }
217 
218         // Arrange the orientation of all the polygons. After calling this
219         // method all the polygons will have the same orientation
220         // determined by the new_orientation flag, i.e.,
221         // path_flags_cw or path_flags_ccw
222         unsigned arrange_orientations(unsigned path_id, path_flags_e new_orientation);
223         void arrange_orientations_all_paths(path_flags_e new_orientation);
224 
225         // Flip all the vertices horizontally or vertically
226         void flip_x(double x1, double x2);
227         void flip_y(double y1, double y2);
228 
229         // This function adds a vertex with its flags directly. Since there's no
230         // checking for errors, keeping proper path integrity is the responsibility
231         // of the caller. It can be said the function is "not very public".
232         void add_vertex(double x, double y, unsigned cmd);
233 
234         // Allows you to modify vertex coordinates. The caller must know
235         // the index of the vertex.
236         void modify_vertex(unsigned idx, double x, double y)
237         {
238             double* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1);
239             *pv++ = x;
240             *pv   = y;
241         }
242 
243         // Allows you to modify vertex command. The caller must know
244         // the index of the vertex.
245         void modify_command(unsigned idx, unsigned cmd)
246         {
247             m_cmd_blocks[idx >> block_shift][idx & block_mask] = (unsigned char)cmd;
248         }
249 
250 
251     private:
252         void allocate_block(unsigned nb);
253         unsigned char* storage_ptrs(double** xy_ptr);
254         unsigned perceive_polygon_orientation(unsigned idx,
255                                               double xs, double ys,
256                                               unsigned* orientation);
257         void reverse_polygon(unsigned start, unsigned end);
258 
259     private:
260         unsigned        m_total_vertices;
261         unsigned        m_total_blocks;
262         unsigned        m_max_blocks;
263         double**        m_coord_blocks;
264         unsigned char** m_cmd_blocks;
265         unsigned        m_iterator;
266     };
267 
268 
269     //------------------------------------------------------------------------
270     inline unsigned path_storage::vertex(double* x, double* y)
271     {
272         if(m_iterator >= m_total_vertices) return path_cmd_stop;
273         return vertex(m_iterator++, x, y);
274     }
275 
276     //------------------------------------------------------------------------
277     inline unsigned path_storage::prev_vertex(double* x, double* y) const
278     {
279         if(m_total_vertices > 1)
280         {
281             return vertex(m_total_vertices - 2, x, y);
282         }
283         return path_cmd_stop;
284     }
285 
286     //------------------------------------------------------------------------
287     inline unsigned path_storage::last_vertex(double* x, double* y) const
288     {
289         if(m_total_vertices)
290         {
291             return vertex(m_total_vertices - 1, x, y);
292         }
293         return path_cmd_stop;
294     }
295 
296     //------------------------------------------------------------------------
297     inline void path_storage::rel_to_abs(double* x, double* y) const
298     {
299         if(m_total_vertices)
300         {
301             double x2;
302             double y2;
303             if(is_vertex(vertex(m_total_vertices - 1, &x2, &y2)))
304             {
305                 *x += x2;
306                 *y += y2;
307             }
308         }
309     }
310 
311     //------------------------------------------------------------------------
312     inline unsigned char* path_storage::storage_ptrs(double** xy_ptr)
313     {
314         unsigned nb = m_total_vertices >> block_shift;
315         if(nb >= m_total_blocks)
316         {
317             allocate_block(nb);
318         }
319         *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1);
320         return m_cmd_blocks[nb] + (m_total_vertices & block_mask);
321     }
322 
323 
324     //------------------------------------------------------------------------
325     inline void path_storage::add_vertex(double x, double y, unsigned cmd)
326     {
327         double* coord_ptr = 0;
328         unsigned char* cmd_ptr = storage_ptrs(&coord_ptr);
329         *cmd_ptr = (unsigned char)cmd;
330         *coord_ptr++ = x;
331         *coord_ptr   = y;
332         m_total_vertices++;
333     }
334 
335     //------------------------------------------------------------------------
336     inline void path_storage::move_to(double x, double y)
337     {
338         add_vertex(x, y, path_cmd_move_to);
339     }
340 
341     //------------------------------------------------------------------------
342     inline void path_storage::move_rel(double dx, double dy)
343     {
344         rel_to_abs(&dx, &dy);
345         add_vertex(dx, dy, path_cmd_move_to);
346     }
347 
348     //------------------------------------------------------------------------
349     inline void path_storage::line_to(double x, double y)
350     {
351         add_vertex(x, y, path_cmd_line_to);
352     }
353 
354     //------------------------------------------------------------------------
355     inline void path_storage::line_rel(double dx, double dy)
356     {
357         rel_to_abs(&dx, &dy);
358         add_vertex(dx, dy, path_cmd_line_to);
359     }
360 }
361 
362 
363 
364 #endif
365