16 #ifndef AGG_PATH_STORAGE_INCLUDED 17 #define AGG_PATH_STORAGE_INCLUDED 21 #include "agg_array.h" 22 #include "agg_bezier_arc.h" 29 template<
class T,
unsigned BlockShift=8,
unsigned BlockPool=256>
36 block_shift = BlockShift,
37 block_size = 1 << block_shift,
38 block_mask = block_size - 1,
39 block_pool = BlockPool
48 const self_type& operator = (
const self_type& ps);
53 void add_vertex(
double x,
double y,
unsigned cmd);
54 void modify_vertex(
unsigned idx,
double x,
double y);
55 void modify_vertex(
unsigned idx,
double x,
double y,
unsigned cmd);
56 void modify_command(
unsigned idx,
unsigned cmd);
57 void swap_vertices(
unsigned v1,
unsigned v2);
59 unsigned last_command()
const;
60 unsigned last_vertex(
double* x,
double* y)
const;
61 unsigned prev_vertex(
double* x,
double* y)
const;
63 double last_x()
const;
64 double last_y()
const;
66 unsigned total_vertices()
const;
67 unsigned vertex(
unsigned idx,
double* x,
double* y)
const;
68 unsigned command(
unsigned idx)
const;
71 void allocate_block(
unsigned nb);
72 int8u* storage_ptrs(T** xy_ptr);
75 unsigned m_total_vertices;
76 unsigned m_total_blocks;
77 unsigned m_max_blocks;
84 template<
class T,
unsigned S,
unsigned P>
89 T** coord_blk = m_coord_blocks + m_total_blocks - 1;
90 while(m_total_blocks--)
95 block_size / (
sizeof(T) /
sizeof(
unsigned char)));
103 m_total_vertices = 0;
108 template<
class T,
unsigned S,
unsigned P>
115 template<
class T,
unsigned S,
unsigned P>
126 template<
class T,
unsigned S,
unsigned P>
138 template<
class T,
unsigned S,
unsigned P>
144 for(i = 0; i < v.total_vertices(); i++)
147 unsigned cmd = v.vertex(i, &x, &y);
148 add_vertex(x, y, cmd);
154 template<
class T,
unsigned S,
unsigned P>
157 m_total_vertices = 0;
161 template<
class T,
unsigned S,
unsigned P>
166 *storage_ptrs(&coord_ptr) = (int8u)cmd;
173 template<
class T,
unsigned S,
unsigned P>
177 T* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1);
183 template<
class T,
unsigned S,
unsigned P>
188 unsigned block = idx >> block_shift;
189 unsigned offset = idx & block_mask;
190 T* pv = m_coord_blocks[block] + (offset << 1);
193 m_cmd_blocks[block][offset] = (int8u)cmd;
197 template<
class T,
unsigned S,
unsigned P>
201 m_cmd_blocks[idx >> block_shift][idx & block_mask] = (int8u)cmd;
205 template<
class T,
unsigned S,
unsigned P>
208 unsigned b1 = v1 >> block_shift;
209 unsigned b2 = v2 >> block_shift;
210 unsigned o1 = v1 & block_mask;
211 unsigned o2 = v2 & block_mask;
212 T* pv1 = m_coord_blocks[b1] + (o1 << 1);
213 T* pv2 = m_coord_blocks[b2] + (o2 << 1);
215 val = pv1[0]; pv1[0] = pv2[0]; pv2[0] = val;
216 val = pv1[1]; pv1[1] = pv2[1]; pv2[1] = val;
217 int8u cmd = m_cmd_blocks[b1][o1];
218 m_cmd_blocks[b1][o1] = m_cmd_blocks[b2][o2];
219 m_cmd_blocks[b2][o2] = cmd;
223 template<
class T,
unsigned S,
unsigned P>
226 if(m_total_vertices)
return command(m_total_vertices - 1);
227 return path_cmd_stop;
231 template<
class T,
unsigned S,
unsigned P>
234 if(m_total_vertices)
return vertex(m_total_vertices - 1, x, y);
235 return path_cmd_stop;
239 template<
class T,
unsigned S,
unsigned P>
242 if(m_total_vertices > 1)
return vertex(m_total_vertices - 2, x, y);
243 return path_cmd_stop;
247 template<
class T,
unsigned S,
unsigned P>
252 unsigned idx = m_total_vertices - 1;
253 return m_coord_blocks[idx >> block_shift][(idx & block_mask) << 1];
259 template<
class T,
unsigned S,
unsigned P>
264 unsigned idx = m_total_vertices - 1;
265 return m_coord_blocks[idx >> block_shift][((idx & block_mask) << 1) + 1];
271 template<
class T,
unsigned S,
unsigned P>
274 return m_total_vertices;
278 template<
class T,
unsigned S,
unsigned P>
280 double* x,
double* y)
const 282 unsigned nb = idx >> block_shift;
283 const T* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1);
286 return m_cmd_blocks[nb][idx & block_mask];
290 template<
class T,
unsigned S,
unsigned P>
293 return m_cmd_blocks[idx >> block_shift][idx & block_mask];
297 template<
class T,
unsigned S,
unsigned P>
300 if(nb >= m_max_blocks)
305 unsigned char** new_cmds =
306 (
unsigned char**)(new_coords + m_max_blocks + block_pool);
310 std::memcpy(new_coords,
312 m_max_blocks *
sizeof(T*));
314 std::memcpy(new_cmds,
316 m_max_blocks *
sizeof(
unsigned char*));
320 m_coord_blocks = new_coords;
321 m_cmd_blocks = new_cmds;
322 m_max_blocks += block_pool;
326 block_size / (
sizeof(T) /
sizeof(
unsigned char)));
329 (
unsigned char*)(m_coord_blocks[nb] + block_size * 2);
335 template<
class T,
unsigned S,
unsigned P>
338 unsigned nb = m_total_vertices >> block_shift;
339 if(nb >= m_total_blocks)
343 *xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1);
344 return m_cmd_blocks[nb] + (m_total_vertices & block_mask);
354 typedef T value_type;
367 m_end(data + num_points * 2),
372 void init(
const T* data,
unsigned num_points,
bool closed)
376 m_end = data + num_points * 2;
381 void rewind(
unsigned)
387 unsigned vertex(
double* x,
double* y)
391 bool first = m_ptr == m_data;
394 return first ? path_cmd_move_to : path_cmd_line_to;
397 if(m_closed && !m_stop)
400 return path_cmd_end_poly | path_flags_close;
402 return path_cmd_stop;
421 typedef typename Container::value_type vertex_type;
437 void init(
const Container& data,
bool closed)
445 void rewind(
unsigned)
451 unsigned vertex(
double* x,
double* y)
453 if(m_index < m_container->size())
455 bool first = m_index == 0;
456 const vertex_type& v = (*m_container)[m_index++];
459 return first ? path_cmd_move_to : path_cmd_line_to;
462 if(m_closed && !m_stop)
465 return path_cmd_end_poly | path_flags_close;
467 return path_cmd_stop;
471 const Container* m_container;
483 typedef typename Container::value_type vertex_type;
499 void init(Container& data,
bool closed)
502 m_index = m_container->size() - 1;
507 void rewind(
unsigned)
509 m_index = m_container->size() - 1;
513 unsigned vertex(
double* x,
double* y)
517 bool first = m_index == int(m_container->size() - 1);
518 const vertex_type& v = (*m_container)[m_index--];
521 return first ? path_cmd_move_to : path_cmd_line_to;
524 if(m_closed && !m_stop)
527 return path_cmd_end_poly | path_flags_close;
529 return path_cmd_stop;
533 Container* m_container;
547 typedef double value_type;
550 line_adaptor(
double x1,
double y1,
double x2,
double y2) :
551 m_line(m_coord, 2,
false)
559 void init(
double x1,
double y1,
double x2,
double y2)
568 void rewind(
unsigned)
573 unsigned vertex(
double* x,
double* y)
575 return m_line.vertex(x, y);
610 typedef VertexContainer container_type;
614 path_base() : m_vertices(), m_iterator(0) {}
615 void remove_all() { m_vertices.remove_all(); m_iterator = 0; }
616 void free_all() { m_vertices.free_all(); m_iterator = 0; }
620 unsigned start_new_path();
622 void move_to(
double x,
double y);
623 void move_rel(
double dx,
double dy);
625 void line_to(
double x,
double y);
626 void line_rel(
double dx,
double dy);
628 void hline_to(
double x);
629 void hline_rel(
double dx);
631 void vline_to(
double y);
632 void vline_rel(
double dy);
634 void arc_to(
double rx,
double ry,
640 void arc_rel(
double rx,
double ry,
644 double dx,
double dy);
646 void curve3(
double x_ctrl,
double y_ctrl,
647 double x_to,
double y_to);
649 void curve3_rel(
double dx_ctrl,
double dy_ctrl,
650 double dx_to,
double dy_to);
652 void curve3(
double x_to,
double y_to);
654 void curve3_rel(
double dx_to,
double dy_to);
656 void curve4(
double x_ctrl1,
double y_ctrl1,
657 double x_ctrl2,
double y_ctrl2,
658 double x_to,
double y_to);
660 void curve4_rel(
double dx_ctrl1,
double dy_ctrl1,
661 double dx_ctrl2,
double dy_ctrl2,
662 double dx_to,
double dy_to);
664 void curve4(
double x_ctrl2,
double y_ctrl2,
665 double x_to,
double y_to);
667 void curve4_rel(
double x_ctrl2,
double y_ctrl2,
668 double x_to,
double y_to);
671 void end_poly(
unsigned flags = path_flags_close);
672 void close_polygon(
unsigned flags = path_flags_none);
676 const container_type& vertices()
const {
return m_vertices; }
677 container_type& vertices() {
return m_vertices; }
679 unsigned total_vertices()
const;
681 void rel_to_abs(
double* x,
double* y)
const;
683 unsigned last_vertex(
double* x,
double* y)
const;
684 unsigned prev_vertex(
double* x,
double* y)
const;
686 double last_x()
const;
687 double last_y()
const;
689 unsigned vertex(
unsigned idx,
double* x,
double* y)
const;
690 unsigned command(
unsigned idx)
const;
692 void modify_vertex(
unsigned idx,
double x,
double y);
693 void modify_vertex(
unsigned idx,
double x,
double y,
unsigned cmd);
694 void modify_command(
unsigned idx,
unsigned cmd);
698 void rewind(
unsigned path_id);
699 unsigned vertex(
double* x,
double* y);
706 unsigned arrange_polygon_orientation(
unsigned start, path_flags_e orientation);
707 unsigned arrange_orientations(
unsigned path_id, path_flags_e orientation);
708 void arrange_orientations_all_paths(path_flags_e orientation);
709 void invert_polygon(
unsigned start);
714 void flip_x(
double x1,
double x2);
715 void flip_y(
double y1,
double y2);
719 template<
class VertexSource>
720 void concat_path(VertexSource& vs,
unsigned path_id = 0)
725 while(!is_stop(cmd = vs.vertex(&x, &y)))
727 m_vertices.add_vertex(x, y, cmd);
734 template<
class VertexSource>
735 void join_path(VertexSource& vs,
unsigned path_id = 0)
740 cmd = vs.vertex(&x, &y);
746 unsigned cmd0 = last_vertex(&x0, &y0);
749 if(calc_distance(x, y, x0, y0) > vertex_dist_epsilon)
751 if(is_move_to(cmd)) cmd = path_cmd_line_to;
752 m_vertices.add_vertex(x, y, cmd);
759 cmd = path_cmd_move_to;
763 if(is_move_to(cmd)) cmd = path_cmd_line_to;
765 m_vertices.add_vertex(x, y, cmd);
768 while(!is_stop(cmd = vs.vertex(&x, &y)))
770 m_vertices.add_vertex(x, y, is_move_to(cmd) ?
771 unsigned(path_cmd_line_to) :
779 template<
class T>
void concat_poly(
const T* data,
789 template<
class T>
void join_poly(
const T* data,
798 void translate(
double dx,
double dy,
unsigned path_id=0);
799 void translate_all_paths(
double dx,
double dy);
802 template<
class Trans>
803 void transform(
const Trans& trans,
unsigned path_id=0)
805 unsigned num_ver = m_vertices.total_vertices();
806 for(; path_id < num_ver; path_id++)
809 unsigned cmd = m_vertices.vertex(path_id, &x, &y);
810 if(is_stop(cmd))
break;
813 trans.transform(&x, &y);
814 m_vertices.modify_vertex(path_id, x, y);
820 template<
class Trans>
821 void transform_all_paths(
const Trans& trans)
824 unsigned num_ver = m_vertices.total_vertices();
825 for(idx = 0; idx < num_ver; idx++)
828 if(is_vertex(m_vertices.vertex(idx, &x, &y)))
830 trans.transform(&x, &y);
831 m_vertices.modify_vertex(idx, x, y);
841 unsigned align_path(
unsigned idx = 0)
843 if (idx >= total_vertices() || !is_move_to(command(idx)))
845 return total_vertices();
848 double start_x, start_y;
849 for (; idx < total_vertices() && is_move_to(command(idx)); ++idx)
851 vertex(idx, &start_x, &start_y);
853 while (idx < total_vertices() && is_drawing(command(idx)))
857 if (is_drawing(vertex(idx - 1, &x, &y)) &&
858 is_equal_eps(x, start_x, 1e-8) &&
859 is_equal_eps(y, start_y, 1e-8))
861 modify_vertex(idx - 1, start_x, start_y);
864 while (idx < total_vertices() && !is_move_to(command(idx)))
869 void align_all_paths()
871 for (
unsigned i = 0; i < total_vertices(); i = align_path(i));
876 unsigned perceive_polygon_orientation(
unsigned start,
unsigned end);
877 void invert_polygon(
unsigned start,
unsigned end);
879 VertexContainer m_vertices;
887 if(!is_stop(m_vertices.last_command()))
889 m_vertices.add_vertex(0.0, 0.0, path_cmd_stop);
891 return m_vertices.total_vertices();
899 if(m_vertices.total_vertices())
903 if(is_vertex(m_vertices.last_vertex(&x2, &y2)))
915 m_vertices.add_vertex(x, y, path_cmd_move_to);
922 rel_to_abs(&dx, &dy);
923 m_vertices.add_vertex(dx, dy, path_cmd_move_to);
930 m_vertices.add_vertex(x, y, path_cmd_line_to);
937 rel_to_abs(&dx, &dy);
938 m_vertices.add_vertex(dx, dy, path_cmd_line_to);
945 m_vertices.add_vertex(x, last_y(), path_cmd_line_to);
953 rel_to_abs(&dx, &dy);
954 m_vertices.add_vertex(dx, dy, path_cmd_line_to);
961 m_vertices.add_vertex(last_x(), y, path_cmd_line_to);
969 rel_to_abs(&dx, &dy);
970 m_vertices.add_vertex(dx, dy, path_cmd_line_to);
981 if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command()))
983 const double epsilon = 1e-30;
986 m_vertices.last_vertex(&x0, &y0);
993 if(rx < epsilon || ry < epsilon)
999 if(calc_distance(x0, y0, x, y) < epsilon)
1005 bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y);
1025 bool large_arc_flag,
1027 double dx,
double dy)
1029 rel_to_abs(&dx, &dy);
1030 arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy);
1036 double x_to,
double y_to)
1038 m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3);
1039 m_vertices.add_vertex(x_to, y_to, path_cmd_curve3);
1045 double dx_to,
double dy_to)
1047 rel_to_abs(&dx_ctrl, &dy_ctrl);
1048 rel_to_abs(&dx_to, &dy_to);
1049 m_vertices.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3);
1050 m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve3);
1059 if(is_vertex(m_vertices.last_vertex(&x0, &y0)))
1063 unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl);
1066 x_ctrl = x0 + x0 - x_ctrl;
1067 y_ctrl = y0 + y0 - y_ctrl;
1074 curve3(x_ctrl, y_ctrl, x_to, y_to);
1082 rel_to_abs(&dx_to, &dy_to);
1089 double x_ctrl2,
double y_ctrl2,
1090 double x_to,
double y_to)
1092 m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4);
1093 m_vertices.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4);
1094 m_vertices.add_vertex(x_to, y_to, path_cmd_curve4);
1100 double dx_ctrl2,
double dy_ctrl2,
1101 double dx_to,
double dy_to)
1103 rel_to_abs(&dx_ctrl1, &dy_ctrl1);
1104 rel_to_abs(&dx_ctrl2, &dy_ctrl2);
1105 rel_to_abs(&dx_to, &dy_to);
1106 m_vertices.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4);
1107 m_vertices.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4);
1108 m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve4);
1114 double x_to,
double y_to)
1118 if(is_vertex(last_vertex(&x0, &y0)))
1122 unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1);
1125 x_ctrl1 = x0 + x0 - x_ctrl1;
1126 y_ctrl1 = y0 + y0 - y_ctrl1;
1133 curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to);
1140 double dx_to,
double dy_to)
1142 rel_to_abs(&dx_ctrl2, &dy_ctrl2);
1143 rel_to_abs(&dx_to, &dy_to);
1144 curve4(dx_ctrl2, dy_ctrl2, dx_to, dy_to);
1151 if(is_vertex(m_vertices.last_command()))
1153 m_vertices.add_vertex(0.0, 0.0, path_cmd_end_poly | flags);
1161 end_poly(path_flags_close | flags);
1168 return m_vertices.total_vertices();
1175 return m_vertices.last_vertex(x, y);
1182 return m_vertices.prev_vertex(x, y);
1189 return m_vertices.last_x();
1196 return m_vertices.last_y();
1203 return m_vertices.vertex(idx, x, y);
1210 return m_vertices.command(idx);
1217 m_vertices.modify_vertex(idx, x, y);
1224 m_vertices.modify_vertex(idx, x, y, cmd);
1231 m_vertices.modify_command(idx, cmd);
1238 m_iterator = path_id;
1245 if(m_iterator >= m_vertices.total_vertices())
return path_cmd_stop;
1246 return m_vertices.vertex(m_iterator++, x, y);
1256 unsigned np = end - start;
1259 for(i = 0; i < np; i++)
1261 double x1, y1, x2, y2;
1262 m_vertices.vertex(start + i, &x1, &y1);
1263 m_vertices.vertex(start + (i + 1) % np, &x2, &y2);
1264 area += x1 * y2 - y1 * x2;
1266 return (area < 0.0) ? path_flags_cw : path_flags_ccw;
1274 unsigned tmp_cmd = m_vertices.command(start);
1279 for(i = start; i < end; i++)
1281 m_vertices.modify_command(i, m_vertices.command(i + 1));
1285 m_vertices.modify_command(end, tmp_cmd);
1290 m_vertices.swap_vertices(start++, end--);
1299 while(start < m_vertices.total_vertices() &&
1300 !is_vertex(m_vertices.command(start))) ++start;
1303 while(start+1 < m_vertices.total_vertices() &&
1304 is_move_to(m_vertices.command(start)) &&
1305 is_move_to(m_vertices.command(start+1))) ++start;
1308 unsigned end = start + 1;
1309 while(end < m_vertices.total_vertices() &&
1310 !is_next_poly(m_vertices.command(end))) ++end;
1312 invert_polygon(start, end);
1318 path_flags_e orientation)
1320 if(orientation == path_flags_none)
return start;
1323 while(start < m_vertices.total_vertices() &&
1324 !is_vertex(m_vertices.command(start))) ++start;
1327 while(start+1 < m_vertices.total_vertices() &&
1328 is_move_to(m_vertices.command(start)) &&
1329 is_move_to(m_vertices.command(start+1))) ++start;
1332 unsigned end = start + 1;
1333 while(end < m_vertices.total_vertices() &&
1334 !is_next_poly(m_vertices.command(end))) ++end;
1338 if(perceive_polygon_orientation(start, end) != unsigned(orientation))
1341 invert_polygon(start, end);
1343 while(end < m_vertices.total_vertices() &&
1344 is_end_poly(cmd = m_vertices.command(end)))
1346 m_vertices.modify_command(end++, set_orientation(cmd, orientation));
1356 path_flags_e orientation)
1358 if(orientation != path_flags_none)
1360 while(start < m_vertices.total_vertices())
1362 start = arrange_polygon_orientation(start, orientation);
1363 if(is_stop(m_vertices.command(start)))
1377 if(orientation != path_flags_none)
1380 while(start < m_vertices.total_vertices())
1382 start = arrange_orientations(start, orientation);
1393 for(i = 0; i < m_vertices.total_vertices(); i++)
1395 unsigned cmd = m_vertices.vertex(i, &x, &y);
1398 m_vertices.modify_vertex(i, x2 - x + x1, y);
1409 for(i = 0; i < m_vertices.total_vertices(); i++)
1411 unsigned cmd = m_vertices.vertex(i, &x, &y);
1414 m_vertices.modify_vertex(i, x, y2 - y + y1);
1423 unsigned num_ver = m_vertices.total_vertices();
1424 for(; path_id < num_ver; path_id++)
1427 unsigned cmd = m_vertices.vertex(path_id, &x, &y);
1428 if(is_stop(cmd))
break;
1433 m_vertices.modify_vertex(path_id, x, y);
1443 unsigned num_ver = m_vertices.total_vertices();
1444 for(idx = 0; idx < num_ver; idx++)
1447 if(is_vertex(m_vertices.vertex(idx, &x, &y)))
1451 m_vertices.modify_vertex(idx, x, y);
1460 typedef typename Container::value_type vertex_type;
1461 typedef typename vertex_type::value_type value_type;
1463 void remove_all() { m_vertices.clear(); }
1464 void free_all() { m_vertices.clear(); }
1466 void add_vertex(
double x,
double y,
unsigned cmd)
1468 m_vertices.push_back(vertex_type(value_type(x),
1473 void modify_vertex(
unsigned idx,
double x,
double y)
1475 vertex_type& v = m_vertices[idx];
1476 v.x = value_type(x);
1477 v.y = value_type(y);
1480 void modify_vertex(
unsigned idx,
double x,
double y,
unsigned cmd)
1482 vertex_type& v = m_vertices[idx];
1483 v.x = value_type(x);
1484 v.y = value_type(y);
1488 void modify_command(
unsigned idx,
unsigned cmd)
1490 m_vertices[idx].cmd = int8u(cmd);
1493 void swap_vertices(
unsigned v1,
unsigned v2)
1495 vertex_type t = m_vertices[v1];
1496 m_vertices[v1] = m_vertices[v2];
1500 unsigned last_command()
const 1502 return m_vertices.size() ?
1503 m_vertices[m_vertices.size() - 1].cmd :
1507 unsigned last_vertex(
double* x,
double* y)
const 1509 if(m_vertices.size() == 0)
1512 return path_cmd_stop;
1514 return vertex(m_vertices.size() - 1, x, y);
1517 unsigned prev_vertex(
double* x,
double* y)
const 1519 if(m_vertices.size() < 2)
1522 return path_cmd_stop;
1524 return vertex(m_vertices.size() - 2, x, y);
1527 double last_x()
const 1529 return m_vertices.size() ? m_vertices[m_vertices.size() - 1].x : 0.0;
1532 double last_y()
const 1534 return m_vertices.size() ? m_vertices[m_vertices.size() - 1].y : 0.0;
1537 unsigned total_vertices()
const 1539 return m_vertices.size();
1542 unsigned vertex(
unsigned idx,
double* x,
double* y)
const 1544 const vertex_type& v = m_vertices[idx];
1550 unsigned command(
unsigned idx)
const 1552 return m_vertices[idx].cmd;
1556 Container m_vertices;