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