39241fe228
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9933 a95241bf-73f2-0310-859d-f6bbb57e9c96
370 lines
12 KiB
C++
370 lines
12 KiB
C++
//----------------------------------------------------------------------------
|
|
// 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
|