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