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 //----------------------------------------------------------------------------
18 //----------------------------------------------------------------------------
21 #include "agg_path_storage.h"
23 #include "agg_bezier_arc.h"
29 //------------------------------------------------------------------------
30 path_storage::~path_storage()
34 double** coord_blk
= m_coord_blocks
+ m_total_blocks
- 1;
35 while(m_total_blocks
--)
40 delete [] m_coord_blocks
;
45 //------------------------------------------------------------------------
46 path_storage::path_storage() :
57 //------------------------------------------------------------------------
58 path_storage::path_storage(const path_storage
& ps
) :
70 //------------------------------------------------------------------------
71 void path_storage::remove_all()
78 //------------------------------------------------------------------------
79 void path_storage::copy_from(const path_storage
& ps
)
83 for(i
= 0; i
< ps
.total_vertices(); i
++)
86 unsigned cmd
= ps
.vertex(i
, &x
, &y
);
87 add_vertex(x
, y
, cmd
);
92 //------------------------------------------------------------------------
93 void path_storage::allocate_block(unsigned nb
)
95 if(nb
>= m_max_blocks
)
98 new double* [(m_max_blocks
+ block_pool
) * 2];
100 unsigned char** new_cmds
=
101 (unsigned char**)(new_coords
+ m_max_blocks
+ block_pool
);
107 m_max_blocks
* sizeof(double*));
111 m_max_blocks
* sizeof(unsigned char*));
113 delete [] m_coord_blocks
;
115 m_coord_blocks
= new_coords
;
116 m_cmd_blocks
= new_cmds
;
117 m_max_blocks
+= block_pool
;
120 new double [block_size
* 2 +
122 (sizeof(double) / sizeof(unsigned char))];
125 (unsigned char*)(m_coord_blocks
[nb
] + block_size
* 2);
131 //------------------------------------------------------------------------
132 void path_storage::rewind(unsigned path_id
)
134 m_iterator
= path_id
;
139 //------------------------------------------------------------------------
140 void path_storage::arc_to(double rx
, double ry
,
146 if(m_total_vertices
&& is_vertex(command(m_total_vertices
- 1)))
148 const double epsilon
= 1e-30;
151 last_vertex(&x0
, &y0
);
156 // Ensure radii are valid
157 //-------------------------
158 if(rx
< epsilon
|| ry
< epsilon
)
164 if(calc_distance(x0
, y0
, x
, y
) < epsilon
)
166 // If the endpoints (x, y) and (x0, y0) are identical, then this
167 // is equivalent to omitting the elliptical arc segment entirely.
170 bezier_arc_svg
a(x0
, y0
, rx
, ry
, angle
, large_arc_flag
, sweep_flag
, x
, y
);
173 add_path(a
, 0, true);
187 //------------------------------------------------------------------------
188 void path_storage::arc_rel(double rx
, double ry
,
192 double dx
, double dy
)
194 rel_to_abs(&dx
, &dy
);
195 arc_to(rx
, ry
, angle
, large_arc_flag
, sweep_flag
, dx
, dy
);
199 //------------------------------------------------------------------------
200 void path_storage::curve3(double x_ctrl
, double y_ctrl
,
201 double x_to
, double y_to
)
203 add_vertex(x_ctrl
, y_ctrl
, path_cmd_curve3
);
204 add_vertex(x_to
, y_to
, path_cmd_curve3
);
207 //------------------------------------------------------------------------
208 void path_storage::curve3_rel(double dx_ctrl
, double dy_ctrl
,
209 double dx_to
, double dy_to
)
211 rel_to_abs(&dx_ctrl
, &dy_ctrl
);
212 rel_to_abs(&dx_to
, &dy_to
);
213 add_vertex(dx_ctrl
, dy_ctrl
, path_cmd_curve3
);
214 add_vertex(dx_to
, dy_to
, path_cmd_curve3
);
217 //------------------------------------------------------------------------
218 void path_storage::curve3(double x_to
, double y_to
)
222 if(is_vertex(last_vertex(&x0
, &y0
)))
226 unsigned cmd
= prev_vertex(&x_ctrl
, &y_ctrl
);
229 x_ctrl
= x0
+ x0
- x_ctrl
;
230 y_ctrl
= y0
+ y0
- y_ctrl
;
237 curve3(x_ctrl
, y_ctrl
, x_to
, y_to
);
242 //------------------------------------------------------------------------
243 void path_storage::curve3_rel(double dx_to
, double dy_to
)
245 rel_to_abs(&dx_to
, &dy_to
);
246 curve3(dx_to
, dy_to
);
250 //------------------------------------------------------------------------
251 void path_storage::curve4(double x_ctrl1
, double y_ctrl1
,
252 double x_ctrl2
, double y_ctrl2
,
253 double x_to
, double y_to
)
255 add_vertex(x_ctrl1
, y_ctrl1
, path_cmd_curve4
);
256 add_vertex(x_ctrl2
, y_ctrl2
, path_cmd_curve4
);
257 add_vertex(x_to
, y_to
, path_cmd_curve4
);
260 //------------------------------------------------------------------------
261 void path_storage::curve4_rel(double dx_ctrl1
, double dy_ctrl1
,
262 double dx_ctrl2
, double dy_ctrl2
,
263 double dx_to
, double dy_to
)
265 rel_to_abs(&dx_ctrl1
, &dy_ctrl1
);
266 rel_to_abs(&dx_ctrl2
, &dy_ctrl2
);
267 rel_to_abs(&dx_to
, &dy_to
);
268 add_vertex(dx_ctrl1
, dy_ctrl1
, path_cmd_curve4
);
269 add_vertex(dx_ctrl2
, dy_ctrl2
, path_cmd_curve4
);
270 add_vertex(dx_to
, dy_to
, path_cmd_curve4
);
274 //------------------------------------------------------------------------
275 void path_storage::curve4(double x_ctrl2
, double y_ctrl2
,
276 double x_to
, double y_to
)
280 if(is_vertex(last_vertex(&x0
, &y0
)))
284 unsigned cmd
= prev_vertex(&x_ctrl1
, &y_ctrl1
);
287 x_ctrl1
= x0
+ x0
- x_ctrl1
;
288 y_ctrl1
= y0
+ y0
- y_ctrl1
;
295 curve4(x_ctrl1
, y_ctrl1
, x_ctrl2
, y_ctrl2
, x_to
, y_to
);
300 //------------------------------------------------------------------------
301 void path_storage::curve4_rel(double dx_ctrl2
, double dy_ctrl2
,
302 double dx_to
, double dy_to
)
304 rel_to_abs(&dx_ctrl2
, &dy_ctrl2
);
305 rel_to_abs(&dx_to
, &dy_to
);
306 curve4(dx_ctrl2
, dy_ctrl2
, dx_to
, dy_to
);
310 //------------------------------------------------------------------------
311 void path_storage::end_poly(unsigned flags
)
315 if(is_vertex(command(m_total_vertices
- 1)))
317 add_vertex(0.0, 0.0, path_cmd_end_poly
| flags
);
323 //------------------------------------------------------------------------
324 unsigned path_storage::start_new_path()
328 if(!is_stop(command(m_total_vertices
- 1)))
330 add_vertex(0.0, 0.0, path_cmd_stop
);
333 return m_total_vertices
;
337 //------------------------------------------------------------------------
338 void path_storage::add_poly(const double* vertices
, unsigned num
,
339 bool solid_path
, unsigned end_flags
)
345 move_to(vertices
[0], vertices
[1]);
351 line_to(vertices
[0], vertices
[1]);
354 if(end_flags
) end_poly(end_flags
);
359 //------------------------------------------------------------------------
360 unsigned path_storage::perceive_polygon_orientation(unsigned idx
,
361 double xs
, double ys
,
362 unsigned* orientation
)
370 for(i
= idx
; i
< m_total_vertices
; ++i
)
372 if(is_next_poly(vertex(i
, &xn
, &yn
))) break;
373 sum
+= x
* yn
- y
* xn
;
377 if(i
> idx
) sum
+= x
* ys
- y
* xs
;
378 *orientation
= path_flags_none
;
381 *orientation
= (sum
< 0.0) ? path_flags_cw
: path_flags_ccw
;
387 //------------------------------------------------------------------------
388 void path_storage::reverse_polygon(unsigned _start
, unsigned _end
)
391 unsigned tmp_cmd
= command(_start
);
393 // Shift all commands to one position
394 for(i
= _start
; i
< _end
; i
++)
396 modify_command(i
, command(i
+ 1));
399 // Assign starting command to the ending command
400 modify_command(_end
, tmp_cmd
);
402 // Reverse the polygon
405 unsigned start_nb
= _start
>> block_shift
;
406 unsigned end_nb
= _end
>> block_shift
;
407 double* start_ptr
= m_coord_blocks
[start_nb
] + ((_start
& block_mask
) << 1);
408 double* end_ptr
= m_coord_blocks
[end_nb
] + ((_end
& block_mask
) << 1);
412 *start_ptr
++ = *end_ptr
;
416 *start_ptr
= *end_ptr
;
419 tmp_cmd
= m_cmd_blocks
[start_nb
][_start
& block_mask
];
420 m_cmd_blocks
[start_nb
][_start
& block_mask
] = m_cmd_blocks
[end_nb
][_end
& block_mask
];
421 m_cmd_blocks
[end_nb
][_end
& block_mask
] = (unsigned char)tmp_cmd
;
429 //------------------------------------------------------------------------
430 unsigned path_storage::arrange_orientations(unsigned path_id
,
431 path_flags_e new_orientation
)
433 unsigned _end
= m_total_vertices
;
434 if(m_total_vertices
&& new_orientation
!= path_flags_none
)
436 unsigned start
= path_id
;
439 unsigned cmd
= vertex(start
, &xs
, &ys
);
443 unsigned orientation
;
444 _end
= perceive_polygon_orientation(start
+ 1, xs
, ys
,
446 if(_end
> start
+ 2 &&
448 orientation
!= unsigned(new_orientation
))
450 reverse_polygon(start
+ inc
, _end
- 1);
452 if(_end
>= m_total_vertices
) break;
462 modify_command(_end
, set_orientation(cmd
, new_orientation
));
466 cmd
= vertex(++_end
, &xs
, &ys
);
477 //------------------------------------------------------------------------
478 void path_storage::arrange_orientations_all_paths(path_flags_e new_orientation
)
480 if(new_orientation
!= path_flags_none
)
483 while(start
< m_total_vertices
)
485 start
= arrange_orientations(start
, new_orientation
);
492 //------------------------------------------------------------------------
493 void path_storage::flip_x(double x1
, double x2
)
497 for(i
= 0; i
< m_total_vertices
; i
++)
499 unsigned cmd
= vertex(i
, &x
, &y
);
502 modify_vertex(i
, x2
- x
+ x1
, y
);
508 //------------------------------------------------------------------------
509 void path_storage::flip_y(double y1
, double y2
)
513 for(i
= 0; i
< m_total_vertices
; i
++)
515 unsigned cmd
= vertex(i
, &x
, &y
);
518 modify_vertex(i
, x
, y2
- y
+ y1
);