1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
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.
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"
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
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 //------------------------------------------------------------------------
39 // Allocation parameters
43 block_size
= 1 << block_shift
,
44 block_mask
= block_size
- 1,
50 //--------------------------------------------------------------------
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
);
61 m_vertex
.cmd
= path_cmd_stop
;
62 m_vertex
.x
= m_vertex
.y
= 0.0;
68 const_iterator(unsigned cmd
) { m_vertex
.cmd
= cmd
; }
69 const_iterator(const const_iterator
& i
) :
71 m_vertex_idx(i
.m_vertex_idx
),
76 const_iterator(const path_storage
& p
, unsigned id
) :
83 const_iterator
& operator++()
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
;
99 const path_storage
* m_path
;
100 unsigned m_vertex_idx
;
101 vertex_type m_vertex
;
106 path_storage(const path_storage
& ps
);
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
,
127 void arc_rel(double rx
, double ry
,
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)
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
)
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);
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);
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
;
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
);
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
;
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
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
303 if(is_vertex(vertex(m_total_vertices
- 1, &x2
, &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
)
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
;
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
);