diff options
Diffstat (limited to 'agg/source/agg_path_storage.cpp')
-rwxr-xr-x | agg/source/agg_path_storage.cpp | 525 |
1 files changed, 525 insertions, 0 deletions
diff --git a/agg/source/agg_path_storage.cpp b/agg/source/agg_path_storage.cpp new file mode 100755 index 000000000000..60eafffff14f --- /dev/null +++ b/agg/source/agg_path_storage.cpp @@ -0,0 +1,525 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.3 +// Copyright (C) 2002-2005 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 +//---------------------------------------------------------------------------- +// +// Class path_storage +// +//---------------------------------------------------------------------------- +#include <string.h> +#include <math.h> +#include "agg_path_storage.h" +#include "agg_math.h" +#include "agg_bezier_arc.h" + + +namespace agg +{ + + //------------------------------------------------------------------------ + path_storage::~path_storage() + { + if(m_total_blocks) + { + double** coord_blk = m_coord_blocks + m_total_blocks - 1; + while(m_total_blocks--) + { + delete [] *coord_blk; + --coord_blk; + } + delete [] m_coord_blocks; + } + } + + + //------------------------------------------------------------------------ + path_storage::path_storage() : + m_total_vertices(0), + m_total_blocks(0), + m_max_blocks(0), + m_coord_blocks(0), + m_cmd_blocks(0), + m_iterator(0) + { + } + + + //------------------------------------------------------------------------ + path_storage::path_storage(const path_storage& ps) : + m_total_vertices(0), + m_total_blocks(0), + m_max_blocks(0), + m_coord_blocks(0), + m_cmd_blocks(0), + m_iterator(0) + { + copy_from(ps); + } + + + //------------------------------------------------------------------------ + void path_storage::remove_all() + { + m_total_vertices = 0; + m_iterator = 0; + } + + + //------------------------------------------------------------------------ + void path_storage::copy_from(const path_storage& ps) + { + remove_all(); + unsigned i; + for(i = 0; i < ps.total_vertices(); i++) + { + double x, y; + unsigned cmd = ps.vertex(i, &x, &y); + add_vertex(x, y, cmd); + } + } + + + //------------------------------------------------------------------------ + void path_storage::allocate_block(unsigned nb) + { + if(nb >= m_max_blocks) + { + double** new_coords = + new double* [(m_max_blocks + block_pool) * 2]; + + unsigned char** new_cmds = + (unsigned char**)(new_coords + m_max_blocks + block_pool); + + if(m_coord_blocks) + { + memcpy(new_coords, + m_coord_blocks, + m_max_blocks * sizeof(double*)); + + memcpy(new_cmds, + m_cmd_blocks, + m_max_blocks * sizeof(unsigned char*)); + + delete [] m_coord_blocks; + } + m_coord_blocks = new_coords; + m_cmd_blocks = new_cmds; + m_max_blocks += block_pool; + } + m_coord_blocks[nb] = + new double [block_size * 2 + + block_size / + (sizeof(double) / sizeof(unsigned char))]; + + m_cmd_blocks[nb] = + (unsigned char*)(m_coord_blocks[nb] + block_size * 2); + + m_total_blocks++; + } + + + //------------------------------------------------------------------------ + void path_storage::rewind(unsigned path_id) + { + m_iterator = path_id; + } + + + + //------------------------------------------------------------------------ + void path_storage::arc_to(double rx, double ry, + double angle, + bool large_arc_flag, + bool sweep_flag, + double x, double y) + { + if(m_total_vertices && is_vertex(command(m_total_vertices - 1))) + { + const double epsilon = 1e-30; + double x0 = 0.0; + double y0 = 0.0; + last_vertex(&x0, &y0); + + rx = fabs(rx); + ry = fabs(ry); + + // Ensure radii are valid + //------------------------- + if(rx < epsilon || ry < epsilon) + { + line_to(x, y); + return; + } + + if(calc_distance(x0, y0, x, y) < epsilon) + { + // If the endpoints (x, y) and (x0, y0) are identical, then this + // is equivalent to omitting the elliptical arc segment entirely. + return; + } + bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y); + if(a.radii_ok()) + { + add_path(a, 0, true); + } + else + { + line_to(x, y); + } + } + else + { + move_to(x, y); + } + } + + + //------------------------------------------------------------------------ + void path_storage::arc_rel(double rx, double ry, + double angle, + bool large_arc_flag, + bool sweep_flag, + double dx, double dy) + { + rel_to_abs(&dx, &dy); + arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy); + } + + + //------------------------------------------------------------------------ + void path_storage::curve3(double x_ctrl, double y_ctrl, + double x_to, double y_to) + { + add_vertex(x_ctrl, y_ctrl, path_cmd_curve3); + add_vertex(x_to, y_to, path_cmd_curve3); + } + + //------------------------------------------------------------------------ + void path_storage::curve3_rel(double dx_ctrl, double dy_ctrl, + double dx_to, double dy_to) + { + rel_to_abs(&dx_ctrl, &dy_ctrl); + rel_to_abs(&dx_to, &dy_to); + add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3); + add_vertex(dx_to, dy_to, path_cmd_curve3); + } + + //------------------------------------------------------------------------ + void path_storage::curve3(double x_to, double y_to) + { + double x0 = 0; + double y0 = 0; + if(is_vertex(last_vertex(&x0, &y0))) + { + double x_ctrl = 0; + double y_ctrl = 0; + unsigned cmd = prev_vertex(&x_ctrl, &y_ctrl); + if(is_curve(cmd)) + { + x_ctrl = x0 + x0 - x_ctrl; + y_ctrl = y0 + y0 - y_ctrl; + } + else + { + x_ctrl = x0; + y_ctrl = y0; + } + curve3(x_ctrl, y_ctrl, x_to, y_to); + } + } + + + //------------------------------------------------------------------------ + void path_storage::curve3_rel(double dx_to, double dy_to) + { + rel_to_abs(&dx_to, &dy_to); + curve3(dx_to, dy_to); + } + + + //------------------------------------------------------------------------ + void path_storage::curve4(double x_ctrl1, double y_ctrl1, + double x_ctrl2, double y_ctrl2, + double x_to, double y_to) + { + add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4); + add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4); + add_vertex(x_to, y_to, path_cmd_curve4); + } + + //------------------------------------------------------------------------ + void path_storage::curve4_rel(double dx_ctrl1, double dy_ctrl1, + double dx_ctrl2, double dy_ctrl2, + double dx_to, double dy_to) + { + rel_to_abs(&dx_ctrl1, &dy_ctrl1); + rel_to_abs(&dx_ctrl2, &dy_ctrl2); + rel_to_abs(&dx_to, &dy_to); + add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4); + add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4); + add_vertex(dx_to, dy_to, path_cmd_curve4); + } + + + //------------------------------------------------------------------------ + void path_storage::curve4(double x_ctrl2, double y_ctrl2, + double x_to, double y_to) + { + double x0 = 0; + double y0 = 0; + if(is_vertex(last_vertex(&x0, &y0))) + { + double x_ctrl1 = 0; + double y_ctrl1 = 0; + unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1); + if(is_curve(cmd)) + { + x_ctrl1 = x0 + x0 - x_ctrl1; + y_ctrl1 = y0 + y0 - y_ctrl1; + } + else + { + x_ctrl1 = x0; + y_ctrl1 = y0; + } + curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to); + } + } + + + //------------------------------------------------------------------------ + void path_storage::curve4_rel(double dx_ctrl2, double dy_ctrl2, + double dx_to, double dy_to) + { + rel_to_abs(&dx_ctrl2, &dy_ctrl2); + rel_to_abs(&dx_to, &dy_to); + curve4(dx_ctrl2, dy_ctrl2, dx_to, dy_to); + } + + + //------------------------------------------------------------------------ + void path_storage::end_poly(unsigned flags) + { + if(m_total_vertices) + { + if(is_vertex(command(m_total_vertices - 1))) + { + add_vertex(0.0, 0.0, path_cmd_end_poly | flags); + } + } + } + + + //------------------------------------------------------------------------ + unsigned path_storage::start_new_path() + { + if(m_total_vertices) + { + if(!is_stop(command(m_total_vertices - 1))) + { + add_vertex(0.0, 0.0, path_cmd_stop); + } + } + return m_total_vertices; + } + + + //------------------------------------------------------------------------ + void path_storage::add_poly(const double* vertices, unsigned num, + bool solid_path, unsigned end_flags) + { + if(num) + { + if(!solid_path) + { + move_to(vertices[0], vertices[1]); + vertices += 2; + --num; + } + while(num--) + { + line_to(vertices[0], vertices[1]); + vertices += 2; + } + if(end_flags) end_poly(end_flags); + } + } + + + //------------------------------------------------------------------------ + unsigned path_storage::perceive_polygon_orientation(unsigned idx, + double xs, double ys, + unsigned* orientation) + { + unsigned i; + double sum = 0.0; + double x, y, xn, yn; + + x = xs; + y = ys; + for(i = idx; i < m_total_vertices; ++i) + { + if(is_next_poly(vertex(i, &xn, &yn))) break; + sum += x * yn - y * xn; + x = xn; + y = yn; + } + if(i > idx) sum += x * ys - y * xs; + *orientation = path_flags_none; + if(sum != 0.0) + { + *orientation = (sum < 0.0) ? path_flags_cw : path_flags_ccw; + } + return i; + } + + + //------------------------------------------------------------------------ + void path_storage::reverse_polygon(unsigned _start, unsigned _end) + { + unsigned i; + unsigned tmp_cmd = command(_start); + + // Shift all commands to one position + for(i = _start; i < _end; i++) + { + modify_command(i, command(i + 1)); + } + + // Assign starting command to the ending command + modify_command(_end, tmp_cmd); + + // Reverse the polygon + while(_end > _start) + { + unsigned start_nb = _start >> block_shift; + unsigned end_nb = _end >> block_shift; + double* start_ptr = m_coord_blocks[start_nb] + ((_start & block_mask) << 1); + double* end_ptr = m_coord_blocks[end_nb] + ((_end & block_mask) << 1); + double tmp_xy; + + tmp_xy = *start_ptr; + *start_ptr++ = *end_ptr; + *end_ptr++ = tmp_xy; + + tmp_xy = *start_ptr; + *start_ptr = *end_ptr; + *end_ptr = tmp_xy; + + tmp_cmd = m_cmd_blocks[start_nb][_start & block_mask]; + m_cmd_blocks[start_nb][_start & block_mask] = m_cmd_blocks[end_nb][_end & block_mask]; + m_cmd_blocks[end_nb][_end & block_mask] = (unsigned char)tmp_cmd; + + ++_start; + --_end; + } + } + + + //------------------------------------------------------------------------ + unsigned path_storage::arrange_orientations(unsigned path_id, + path_flags_e new_orientation) + { + unsigned _end = m_total_vertices; + if(m_total_vertices && new_orientation != path_flags_none) + { + unsigned start = path_id; + + double xs, ys; + unsigned cmd = vertex(start, &xs, &ys); + unsigned inc = 0; + for(;;) + { + unsigned orientation; + _end = perceive_polygon_orientation(start + 1, xs, ys, + &orientation); + if(_end > start + 2 && + orientation && + orientation != unsigned(new_orientation)) + { + reverse_polygon(start + inc, _end - 1); + } + if(_end >= m_total_vertices) break; + cmd = command(_end); + if(is_stop(cmd)) + { + ++_end; + break; + } + if(is_end_poly(cmd)) + { + inc = 1; + modify_command(_end, set_orientation(cmd, new_orientation)); + } + else + { + cmd = vertex(++_end, &xs, &ys); + inc = 0; + } + start = _end; + } + } + return _end; + } + + + + //------------------------------------------------------------------------ + void path_storage::arrange_orientations_all_paths(path_flags_e new_orientation) + { + if(new_orientation != path_flags_none) + { + unsigned start = 0; + while(start < m_total_vertices) + { + start = arrange_orientations(start, new_orientation); + } + } + } + + + + //------------------------------------------------------------------------ + void path_storage::flip_x(double x1, double x2) + { + unsigned i; + double x, y; + for(i = 0; i < m_total_vertices; i++) + { + unsigned cmd = vertex(i, &x, &y); + if(is_vertex(cmd)) + { + modify_vertex(i, x2 - x + x1, y); + } + } + } + + + //------------------------------------------------------------------------ + void path_storage::flip_y(double y1, double y2) + { + unsigned i; + double x, y; + for(i = 0; i < m_total_vertices; i++) + { + unsigned cmd = vertex(i, &x, &y); + if(is_vertex(cmd)) + { + modify_vertex(i, x, y2 - y + y1); + } + } + } + + +} + |