update dev300-m58
[ooovba.git] / agg / inc / agg_path_storage.h
blob3c584d8036cfebba78065ae92e46c96c9b15e0f1
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
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 //----------------------------------------------------------------------------
16 #ifndef AGG_PATH_STORAGE_INCLUDED
17 #define AGG_PATH_STORAGE_INCLUDED
19 #include "agg_basics.h"
21 namespace agg
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.
34 // See Implementation: agg_path_storage.cpp
35 // See also: vertex_source concept
36 //------------------------------------------------------------------------
37 class path_storage
39 // Allocation parameters
40 enum
42 block_shift = 8,
43 block_size = 1 << block_shift,
44 block_mask = block_size - 1,
45 block_pool = 256
48 public:
50 //--------------------------------------------------------------------
51 class const_iterator
53 void vertex()
55 if(m_vertex_idx < m_path->total_vertices())
57 m_vertex.cmd = m_path->vertex(m_vertex_idx, &m_vertex.x, &m_vertex.y);
59 else
61 m_vertex.cmd = path_cmd_stop;
62 m_vertex.x = m_vertex.y = 0.0;
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)
76 const_iterator(const path_storage& p, unsigned id) :
77 m_path(&p),
78 m_vertex_idx(id)
80 vertex();
83 const_iterator& operator++()
85 ++m_vertex_idx;
86 vertex();
87 return *this;
90 const vertex_type& operator*() const { return m_vertex; }
91 const vertex_type* operator->() const { return &m_vertex; }
93 bool operator != (const const_iterator& i)
95 return m_vertex.cmd != i.m_vertex.cmd;
98 private:
99 const path_storage* m_path;
100 unsigned m_vertex_idx;
101 vertex_type m_vertex;
104 ~path_storage();
105 path_storage();
106 path_storage(const path_storage& ps);
108 void remove_all();
110 unsigned last_vertex(double* x, double* y) const;
111 unsigned prev_vertex(double* x, double* y) const;
113 void rel_to_abs(double* x, double* y) const;
115 void move_to(double x, double y);
116 void move_rel(double dx, double dy);
118 void line_to(double x, double y);
119 void line_rel(double dx, double dy);
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);
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);
133 void curve3(double x_ctrl, double y_ctrl,
134 double x_to, double y_to);
136 void curve3_rel(double dx_ctrl, double dy_ctrl,
137 double dx_to, double dy_to);
139 void curve3(double x_to, double y_to);
141 void curve3_rel(double dx_to, double dy_to);
143 void curve4(double x_ctrl1, double y_ctrl1,
144 double x_ctrl2, double y_ctrl2,
145 double x_to, double y_to);
147 void curve4_rel(double dx_ctrl1, double dy_ctrl1,
148 double dx_ctrl2, double dy_ctrl2,
149 double dx_to, double dy_to);
151 void curve4(double x_ctrl2, double y_ctrl2,
152 double x_to, double y_to);
154 void curve4_rel(double x_ctrl2, double y_ctrl2,
155 double x_to, double y_to);
158 void end_poly(unsigned flags = path_flags_close);
160 void close_polygon(unsigned flags = path_flags_none)
162 end_poly(path_flags_close | flags);
165 void add_poly(const double* vertices, unsigned num,
166 bool solid_path = false,
167 unsigned end_flags = path_flags_none);
169 template<class VertexSource>
170 void add_path(VertexSource& vs,
171 unsigned path_id = 0,
172 bool solid_path = true)
174 double x, y;
175 unsigned cmd;
176 vs.rewind(path_id);
177 while(!is_stop(cmd = vs.vertex(&x, &y)))
179 if(is_move_to(cmd) && solid_path && m_total_vertices)
181 cmd = path_cmd_line_to;
183 add_vertex(x, y, cmd);
187 unsigned start_new_path();
189 void copy_from(const path_storage& ps);
190 const path_storage& operator = (const path_storage& ps)
192 copy_from(ps);
193 return *this;
197 unsigned total_vertices() const { return m_total_vertices; }
198 unsigned vertex(unsigned idx, double* x, double* y) const
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];
206 unsigned command(unsigned idx) const
208 return m_cmd_blocks[idx >> block_shift][idx & block_mask];
211 void rewind(unsigned path_id);
212 unsigned vertex(double* x, double* y);
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); }
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);
225 // Flip all the vertices horizontally or vertically
226 void flip_x(double x1, double x2);
227 void flip_y(double y1, double y2);
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);
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)
238 double* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1);
239 *pv++ = x;
240 *pv = y;
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)
247 m_cmd_blocks[idx >> block_shift][idx & block_mask] = (unsigned char)cmd;
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);
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;
269 //------------------------------------------------------------------------
270 inline unsigned path_storage::vertex(double* x, double* y)
272 if(m_iterator >= m_total_vertices) return path_cmd_stop;
273 return vertex(m_iterator++, x, y);
276 //------------------------------------------------------------------------
277 inline unsigned path_storage::prev_vertex(double* x, double* y) const
279 if(m_total_vertices > 1)
281 return vertex(m_total_vertices - 2, x, y);
283 return path_cmd_stop;
286 //------------------------------------------------------------------------
287 inline unsigned path_storage::last_vertex(double* x, double* y) const
289 if(m_total_vertices)
291 return vertex(m_total_vertices - 1, x, y);
293 return path_cmd_stop;
296 //------------------------------------------------------------------------
297 inline void path_storage::rel_to_abs(double* x, double* y) const
299 if(m_total_vertices)
301 double x2;
302 double y2;
303 if(is_vertex(vertex(m_total_vertices - 1, &x2, &y2)))
305 *x += x2;
306 *y += y2;
311 //------------------------------------------------------------------------
312 inline unsigned char* path_storage::storage_ptrs(double** xy_ptr)
314 unsigned nb = m_total_vertices >> block_shift;
315 if(nb >= m_total_blocks)
317 allocate_block(nb);
319 *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1);
320 return m_cmd_blocks[nb] + (m_total_vertices & block_mask);
324 //------------------------------------------------------------------------
325 inline void path_storage::add_vertex(double x, double y, unsigned cmd)
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++;
335 //------------------------------------------------------------------------
336 inline void path_storage::move_to(double x, double y)
338 add_vertex(x, y, path_cmd_move_to);
341 //------------------------------------------------------------------------
342 inline void path_storage::move_rel(double dx, double dy)
344 rel_to_abs(&dx, &dy);
345 add_vertex(dx, dy, path_cmd_move_to);
348 //------------------------------------------------------------------------
349 inline void path_storage::line_to(double x, double y)
351 add_vertex(x, y, path_cmd_line_to);
354 //------------------------------------------------------------------------
355 inline void path_storage::line_rel(double dx, double dy)
357 rel_to_abs(&dx, &dy);
358 add_vertex(dx, dy, path_cmd_line_to);
364 #endif