+ SVG markers initial import

This commit is contained in:
Artem Pavlenko 2010-05-27 11:19:09 +00:00
parent 4584b05ff0
commit 823b7ba0fc
14 changed files with 2371 additions and 1 deletions

View file

@ -0,0 +1,76 @@
//----------------------------------------------------------------------------
// 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
//----------------------------------------------------------------------------
//
// SVG parser.
//
//----------------------------------------------------------------------------
#ifndef AGG_SVG_PARSER_INCLUDED
#define AGG_SVG_PARSER_INCLUDED
#include "agg_svg_path_renderer.h"
namespace agg
{
namespace svg
{
class parser
{
enum buf_size_e { buf_size = 256 };
public:
~parser();
parser(path_renderer& path);
void parse(const char* fname);
const char* title() const { return m_title; }
private:
// XML event handlers
static void start_element(void* data, const char* el, const char** attr);
static void end_element(void* data, const char* el);
static void content(void* data, const char* s, int len);
void parse_attr(const char** attr);
void parse_circle(const char** attr);
void parse_ellipse(const char** attr);
void parse_path(const char** attr);
void parse_poly(const char** attr, bool close_flag);
void parse_rect(const char** attr);
void parse_line(const char** attr);
void parse_style(const char* str);
bool parse_attr(const char* name, const char* value);
bool parse_name_value(const char* nv_start, const char* nv_end);
void copy_name(const char* start, const char* end);
void copy_value(const char* start, const char* end);
private:
path_renderer& m_path;
char* m_buf;
char* m_title;
unsigned m_title_len;
bool m_title_flag;
bool m_path_flag;
char* m_attr_name;
char* m_attr_value;
unsigned m_attr_name_len;
unsigned m_attr_value_len;
};
}
}
#endif

View file

@ -0,0 +1,327 @@
//----------------------------------------------------------------------------
// 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
//----------------------------------------------------------------------------
//
// SVG path renderer.
//
//----------------------------------------------------------------------------
#ifndef AGG_SVG_PATH_RENDERER_INCLUDED
#define AGG_SVG_PATH_RENDERER_INCLUDED
#include "agg_path_storage.h"
#include "agg_conv_transform.h"
#include "agg_conv_stroke.h"
#include "agg_conv_contour.h"
#include "agg_conv_curve.h"
#include "agg_color_rgba.h"
#include "agg_renderer_scanline.h"
#include "agg_bounding_rect.h"
#include "agg_rasterizer_scanline_aa.h"
namespace agg
{
namespace svg
{
template<class VertexSource> class conv_count
{
public:
conv_count(VertexSource& vs) : m_source(&vs), m_count(0) {}
void count(unsigned n) { m_count = n; }
unsigned count() const { return m_count; }
void rewind(unsigned path_id) { m_source->rewind(path_id); }
unsigned vertex(double* x, double* y)
{
++m_count;
return m_source->vertex(x, y);
}
private:
VertexSource* m_source;
unsigned m_count;
};
//============================================================================
// Basic path attributes
struct path_attributes
{
unsigned index;
rgba8 fill_color;
rgba8 stroke_color;
bool fill_flag;
bool stroke_flag;
bool even_odd_flag;
line_join_e line_join;
line_cap_e line_cap;
double miter_limit;
double stroke_width;
trans_affine transform;
// Empty constructor
path_attributes() :
index(0),
fill_color(rgba(0,0,0)),
stroke_color(rgba(0,0,0)),
fill_flag(true),
stroke_flag(false),
even_odd_flag(false),
line_join(miter_join),
line_cap(butt_cap),
miter_limit(4.0),
stroke_width(1.0),
transform()
{
}
// Copy constructor
path_attributes(const path_attributes& attr) :
index(attr.index),
fill_color(attr.fill_color),
stroke_color(attr.stroke_color),
fill_flag(attr.fill_flag),
stroke_flag(attr.stroke_flag),
even_odd_flag(attr.even_odd_flag),
line_join(attr.line_join),
line_cap(attr.line_cap),
miter_limit(attr.miter_limit),
stroke_width(attr.stroke_width),
transform(attr.transform)
{
}
// Copy constructor with new index value
path_attributes(const path_attributes& attr, unsigned idx) :
index(idx),
fill_color(attr.fill_color),
stroke_color(attr.stroke_color),
fill_flag(attr.fill_flag),
stroke_flag(attr.stroke_flag),
even_odd_flag(attr.even_odd_flag),
line_join(attr.line_join),
line_cap(attr.line_cap),
miter_limit(attr.miter_limit),
stroke_width(attr.stroke_width),
transform(attr.transform)
{
}
};
//============================================================================
// Path container and renderer.
class path_renderer
{
public:
typedef pod_bvector<path_attributes> attr_storage;
typedef conv_curve<path_storage> curved;
typedef conv_count<curved> curved_count;
typedef conv_stroke<curved_count> curved_stroked;
typedef conv_transform<curved_stroked> curved_stroked_trans;
typedef conv_transform<curved_count> curved_trans;
typedef conv_contour<curved_trans> curved_trans_contour;
path_renderer();
void remove_all();
// Use these functions as follows:
// begin_path() when the XML tag <path> comes ("start_element" handler)
// parse_path() on "d=" tag attribute
// end_path() when parsing of the entire tag is done.
void begin_path();
//void parse_path(path_tokenizer& tok);
void end_path();
// The following functions are essentially a "reflection" of
// the respective SVG path commands.
void move_to(double x, double y, bool rel=false); // M, m
void line_to(double x, double y, bool rel=false); // L, l
void hline_to(double x, bool rel=false); // H, h
void vline_to(double y, bool rel=false); // V, v
void curve3(double x1, double y1, // Q, q
double x, double y, bool rel=false);
void curve3(double x, double y, bool rel=false); // T, t
void curve4(double x1, double y1, // C, c
double x2, double y2,
double x, double y, bool rel=false);
void curve4(double x2, double y2, // S, s
double x, double y, bool rel=false);
void arc_to(double rx, double rx, // A, a
double angle,
bool large_arc_flag,
bool sweep_flag,
double x, double y,bool rel=false);
void close_subpath(); // Z, z
// template<class VertexSource>
// void add_path(VertexSource& vs,
// unsigned path_id = 0,
// bool solid_path = true)
// {
// m_storage.add_path(vs, path_id, solid_path);
// }
unsigned vertex_count() const { return m_curved_count.count(); }
// Call these functions on <g> tag (start_element, end_element respectively)
void push_attr();
void pop_attr();
// Attribute setting functions.
void fill(const rgba8& f);
void stroke(const rgba8& s);
void even_odd(bool flag);
void stroke_width(double w);
void fill_none();
void stroke_none();
void fill_opacity(double op);
void stroke_opacity(double op);
void line_join(line_join_e join);
void line_cap(line_cap_e cap);
void miter_limit(double ml);
trans_affine& transform();
// Make all polygons CCW-oriented
void arrange_orientations()
{
m_storage.arrange_orientations_all_paths(path_flags_ccw);
}
// Expand all polygons
void expand(double value)
{
m_curved_trans_contour.width(value);
}
unsigned operator [](unsigned idx)
{
m_transform = m_attr_storage[idx].transform;
return m_attr_storage[idx].index;
}
void bounding_rect(double* x1, double* y1, double* x2, double* y2)
{
agg::conv_transform<agg::path_storage> trans(m_storage, m_transform);
agg::bounding_rect(trans, *this, 0, m_attr_storage.size(), x1, y1, x2, y2);
}
// Rendering. One can specify two additional parameters:
// trans_affine and opacity. They can be used to transform the whole
// image and/or to make it translucent.
template<class Rasterizer, class Scanline, class Renderer>
void render(Rasterizer& ras,
Scanline& sl,
Renderer& ren,
const trans_affine& mtx,
const rect_i& cb,
double opacity=1.0)
{
unsigned i;
ras.clip_box(cb.x1, cb.y1, cb.x2, cb.y2);
m_curved_count.count(0);
for(i = 0; i < m_attr_storage.size(); i++)
{
const path_attributes& attr = m_attr_storage[i];
m_transform = attr.transform;
m_transform *= mtx;
double scl = m_transform.scale();
//m_curved.approximation_method(curve_inc);
m_curved.approximation_scale(scl);
m_curved.angle_tolerance(0.0);
rgba8 color;
if(attr.fill_flag)
{
ras.reset();
ras.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero);
if(fabs(m_curved_trans_contour.width()) < 0.0001)
{
ras.add_path(m_curved_trans, attr.index);
}
else
{
m_curved_trans_contour.miter_limit(attr.miter_limit);
ras.add_path(m_curved_trans_contour, attr.index);
}
color = attr.fill_color;
color.opacity(color.opacity() * opacity);
ren.color(color);
agg::render_scanlines(ras, sl, ren);
}
if(attr.stroke_flag)
{
m_curved_stroked.width(attr.stroke_width);
//m_curved_stroked.line_join((attr.line_join == miter_join) ? miter_join_round : attr.line_join);
m_curved_stroked.line_join(attr.line_join);
m_curved_stroked.line_cap(attr.line_cap);
m_curved_stroked.miter_limit(attr.miter_limit);
m_curved_stroked.inner_join(inner_round);
m_curved_stroked.approximation_scale(scl);
// If the *visual* line width is considerable we
// turn on processing of curve cusps.
//---------------------
if(attr.stroke_width * scl > 1.0)
{
m_curved.angle_tolerance(0.2);
}
ras.reset();
ras.filling_rule(fill_non_zero);
ras.add_path(m_curved_stroked_trans, attr.index);
color = attr.stroke_color;
color.opacity(color.opacity() * opacity);
ren.color(color);
agg::render_scanlines(ras, sl, ren);
}
}
}
private:
path_attributes& cur_attr();
path_storage m_storage;
attr_storage m_attr_storage;
attr_storage m_attr_stack;
trans_affine m_transform;
curved m_curved;
curved_count m_curved_count;
curved_stroked m_curved_stroked;
curved_stroked_trans m_curved_stroked_trans;
curved_trans m_curved_trans;
curved_trans_contour m_curved_trans_contour;
};
}
}
#endif

View file

@ -0,0 +1,59 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2009 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
//$Id$
#ifndef MAPNIK_MARKER_CACHE_HPP
#define MAPNIK_MARKER_CACHE_HPP
// mapnik
#include <mapnik/utils.hpp>
#include <mapnik/config.hpp>
#include <mapnik/image_data.hpp>
// boost
#include <boost/utility.hpp>
#include <boost/unordered_map.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/thread/mutex.hpp>
namespace mapnik
{
typedef boost::shared_ptr<image_data_32> path_ptr;
struct MAPNIK_DECL image_cache :
public singleton <image_cache, CreateStatic>,
private boost::noncopyable
{
friend class CreateStatic<image_cache>;
static boost::mutex mutex_;
static boost::unordered_map<std::string,image_ptr> cache_;
static bool insert(std::string const& key, image_ptr);
static boost::optional<image_ptr> find(std::string const& key, bool update_cache = false);
};
}
#endif // MAPNIK_MARKER_CACHE_HPP

View file

@ -0,0 +1,255 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2010 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef SVG_COMMANDS_HPP
#define SVG_COMMANDS_HPP
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
namespace mapnik { namespace svg {
using namespace boost::fusion;
template <typename PathType>
struct move_to
{
template <typename T0, typename T1>
struct result
{
typedef void type;
};
explicit move_to(PathType & path)
: path_(path) {}
template <typename T0, typename T1>
void operator() (T0 v, T1 rel) const
{
path_.move_to(at_c<0>(v),at_c<1>(v),rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct hline_to
{
template <typename T0, typename T1>
struct result
{
typedef void type;
};
explicit hline_to(PathType & path)
: path_(path) {}
template <typename T0, typename T1>
void operator() (T0 const& x, T1 rel) const
{
path_.hline_to(x,rel);
}
PathType & path_;
};
template <typename PathType>
struct vline_to
{
template <typename T0, typename T1>
struct result
{
typedef void type;
};
explicit vline_to(PathType & path)
: path_(path) {}
template <typename T0, typename T1>
void operator() (T0 const& y, T1 rel) const
{
path_.vline_to(y,rel);
}
PathType & path_;
};
template <typename PathType>
struct line_to
{
template <typename T0, typename T1>
struct result
{
typedef void type;
};
explicit line_to(PathType & path)
: path_(path) {}
template <typename T0, typename T1>
void operator() (T0 const& v, T1 rel) const
{
path_.line_to(at_c<0>(v),at_c<1>(v),rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct curve4
{
template <typename T0, typename T1, typename T2, typename T3>
struct result
{
typedef void type;
};
explicit curve4(PathType & path)
: path_(path) {}
template <typename T0, typename T1,typename T2, typename T3>
void operator() (T0 const& v0, T1 const& v1, T2 const& v2, T3 rel) const
{
path_.curve4(at_c<0>(v0),at_c<1>(v0),
at_c<0>(v1),at_c<1>(v1),
at_c<0>(v2),at_c<1>(v2),
rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct curve4_smooth
{
template <typename T0, typename T1, typename T2>
struct result
{
typedef void type;
};
explicit curve4_smooth(PathType & path)
: path_(path) {}
template <typename T0, typename T1,typename T2>
void operator() (T0 const& v0, T1 const& v1, T2 rel) const
{
path_.curve4(at_c<0>(v0),at_c<1>(v0),
at_c<0>(v1),at_c<1>(v1),
rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct curve3
{
template <typename T0, typename T1, typename T2>
struct result
{
typedef void type;
};
explicit curve3(PathType & path)
: path_(path) {}
template <typename T0, typename T1,typename T2>
void operator() (T0 const& v0, T1 const& v1, T2 rel) const
{
path_.curve3(at_c<0>(v0),at_c<1>(v0),
at_c<0>(v1),at_c<1>(v1),
rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct curve3_smooth
{
template <typename T0, typename T1>
struct result
{
typedef void type;
};
explicit curve3_smooth(PathType & path)
: path_(path) {}
template <typename T0, typename T1>
void operator() (T0 const& v0, T1 rel) const
{
path_.curve3(at_c<0>(v0),at_c<1>(v0),
rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct arc_to
{
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
struct result
{
typedef void type;
};
explicit arc_to(PathType & path)
: path_(path) {}
template <typename T0, typename T1,typename T2, typename T3, typename T4, typename T5>
void operator() (T0 const& rv, T1 const& angle, T2 large_arc_flag, T3 sweep_flag, T4 const& v, T5 rel) const
{
path_.arc_to(at_c<0>(rv),at_c<1>(rv),
deg2rad(angle),large_arc_flag,sweep_flag,
at_c<0>(v),at_c<1>(v),
rel);
}
PathType & path_;
};
template <typename PathType>
struct close
{
typedef void result_type;
explicit close(PathType & path)
: path_(path) {}
void operator()() const
{
path_.close_subpath();
}
PathType & path_;
};
}}
#endif // SVG_COMMANDS_HPP

View file

@ -0,0 +1,159 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2010 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef SVG_PATH_GRAMMAR_HPP
#define SVG_PATH_GRAMMAR_HPP
// mapnik
#include <mapnik/svg/svg_path_commands.hpp>
// spirit
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
namespace mapnik { namespace svg {
using namespace boost::spirit;
using namespace boost::fusion;
using namespace boost::phoenix;
inline double deg2rad(double deg)
{
return (M_PI * deg)/180.0;
}
template <typename Iterator, typename SkipType, typename PathType>
struct svg_path_grammar : qi::grammar<Iterator,SkipType>
{
explicit svg_path_grammar(PathType & path)
: svg_path_grammar::base_type(start),
move_to_(move_to<PathType>(path)),
hline_to_(hline_to<PathType>(path)),
vline_to_(vline_to<PathType>(path)),
line_to_(line_to<PathType>(path)),
curve4_(curve4<PathType>(path)),
curve4_smooth_(curve4_smooth<PathType>(path)),
curve3_(curve3<PathType>(path)),
curve3_smooth_(curve3_smooth<PathType>(path)),
arc_to_(arc_to<PathType>(path)),
close_(close<PathType>(path))
{
using qi::_1;
using qi::_2;
using qi::_3;
using qi::_4;
using qi::_5;
using qi::_a;
using qi::lit;
using qi::double_;
using qi::int_;
using qi::no_case;
start = +cmd;
cmd = M | L | H | V | C | S | Q | T | A | Z;
M = (lit('M')[_a = false] | lit('m')[_a = true] )
>> coord[move_to_(_1,_a)] // move_to
>> *(-lit(',') >> coord [ line_to_(_1,_a) ] ); // *line_to
H = (lit('H')[_a = false] | lit('h')[_a = true])
>> +double_[ hline_to_(_1,_a) ] ; // +hline_to
V = (lit('V')[_a = false] | lit('v')[_a = true])
>> +double_ [ vline_to_(_1,_a) ]; // +vline_to
L = (lit('L')[_a = false] | lit('l')[_a = true])
>> +coord [ line_to_(_1,_a) ]; // +line_to
C = (lit('C')[_a = false] | lit('c')[_a = true])
>> +(coord
>> -lit(',')
>> coord
>> -lit(',')
>> coord) [ curve4_(_1,_2,_3,_a) ]; // +curve4
S = (lit('S')[_a = false] | lit('s')[_a = true])
>> +(coord
>> -lit(',')
>> coord) [ curve4_smooth_(_1,_2,_a) ]; // +curve4_smooth (smooth curveto)
Q = (lit('Q')[_a = false] | lit('q')[_a = true])
>> +(coord
>> -lit(',')
>> coord) [ curve3_(_1,_2,_a) ]; // +curve3 (quadratic-bezier-curveto)
T = (lit('T')[_a = false] | lit('t')[_a = true])
>> +(coord ) [ curve3_smooth_(_1,_a) ]; // +curve3_smooth (smooth-quadratic-bezier-curveto)
A = (lit('A')[_a = false] | lit('a')[_a = true])
>> +(coord
>> -lit(',')
>> double_
>> -lit(',')
>> int_
>> -lit(',')
>> int_
>> -lit(',')
>> coord) [arc_to_(_1,_2,_3,_4,_5,_a)]; // arc_to;
Z = no_case[lit('z')] [close_()]; // close path
coord = double_ >> -lit(',') >> double_;
}
// rules
qi::rule<Iterator,SkipType> start;
qi::rule<Iterator,SkipType> cmd;
qi::rule<Iterator,qi::locals<bool>,SkipType> M; // M,m
qi::rule<Iterator,qi::locals<bool>,SkipType> L; // L,l
qi::rule<Iterator,qi::locals<bool>,SkipType> H; // H,h
qi::rule<Iterator,qi::locals<bool>,SkipType> V; // V,v
qi::rule<Iterator,qi::locals<bool>,SkipType> C; // C,c
qi::rule<Iterator,qi::locals<bool>,SkipType> S; // S,s
qi::rule<Iterator,qi::locals<bool>,SkipType> Q; // Q,q
qi::rule<Iterator,qi::locals<bool>,SkipType> T; // T,t
qi::rule<Iterator,qi::locals<bool>,SkipType> A; // A,a
qi::rule<Iterator,SkipType> Z; // Z,z
qi::rule<Iterator,vector2<double,double>(),SkipType> coord;
// commands
function<move_to<PathType> > move_to_;
function<hline_to<PathType> > hline_to_;
function<vline_to<PathType> > vline_to_;
function<line_to<PathType> > line_to_;
function<curve4<PathType> > curve4_;
function<curve4_smooth<PathType> > curve4_smooth_;
function<curve3<PathType> > curve3_;
function<curve3_smooth<PathType> > curve3_smooth_;
function<arc_to<PathType> > arc_to_;
function<close<PathType> > close_;
};
}}
#endif // SVG_PATH_GRAMMAR_HPP

View file

@ -0,0 +1,42 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2010 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef SVG_PATH_PARSER_HPP
#define SVG_PATH_PARSER_HPP
#include <string>
namespace mapnik { namespace svg {
template <typename PathType>
bool parse_path(std::string const& wkt, PathType & p);
template <typename PathType>
bool parse_points(std::string const& wkt, PathType & p);
template <typename TransformType>
bool parse_transform(std::string const& wkt, TransformType & tr);
}}
#endif // SVG_PATH_PARSER_HPP

View file

@ -0,0 +1,72 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2010 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef SVG_POINTS_GRAMMAR_HPP
#define SVG_POINTS_GRAMMAR_HPP
// mapnik
#include <mapnik/svg/svg_path_commands.hpp>
// spirit
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
namespace mapnik { namespace svg {
using namespace boost::spirit;
using namespace boost::fusion;
using namespace boost::phoenix;
template <typename Iterator, typename SkipType, typename PathType>
struct svg_points_grammar : qi::grammar<Iterator,SkipType>
{
explicit svg_points_grammar(PathType & path)
: svg_points_grammar::base_type(start),
move_to_(move_to<PathType>(path)),
line_to_(line_to<PathType>(path)),
close_(close<PathType>(path))
{
using qi::_1;
using qi::_2;
using qi::double_;
start = coord[move_to_(_1,false)] // move_to
>> *(-lit(',') >> coord [ line_to_(_1,false) ] ); // *line_to
coord = double_ >> -lit(',') >> double_;
}
// rules
qi::rule<Iterator,SkipType> start;
qi::rule<Iterator,vector2<double,double>(),SkipType> coord;
// commands
function<move_to<PathType> > move_to_;
function<line_to<PathType> > line_to_;
function<close<PathType> > close_;
};
}}
#endif // SVG_POINTS_GRAMMAR_HPP

View file

@ -0,0 +1,260 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2010 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
//$Id$
#ifndef SVG_TRANSFORM_GRAMMAR_HPP
#define SVG_TRANSFORM_GRAMMAR_HPP
// agg
#include "agg_trans_affine.h"
// spirit
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/home/phoenix/object/construct.hpp>
namespace mapnik { namespace svg {
using namespace boost::spirit;
using namespace boost::fusion;
using namespace boost::phoenix;
inline double deg2rad(double d)
{
return M_PI * d / 180.0;
}
template <typename TransformType>
struct process_matrix
{
template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
struct result
{
typedef void type;
};
explicit process_matrix( TransformType & tr)
:tr_(tr) {}
void operator () (double a, double b, double c, double d, double e, double f) const
{
tr_ *= agg::trans_affine(a,b,c,d,e,f);
}
TransformType & tr_;
};
template <typename TransformType>
struct process_rotate
{
template <typename T0, typename T1, typename T2>
struct result
{
typedef void type;
};
explicit process_rotate( TransformType & tr)
:tr_(tr) {}
template <typename T0,typename T1,typename T2>
void operator () (T0 a, T1 cx, T2 cy) const
{
if (cx == 0.0 && cy == 0.0)
{
tr_ *= agg::trans_affine_rotation(deg2rad(a));
}
else
{
agg::trans_affine t = agg::trans_affine_translation(-cx,-cy);
t *= agg::trans_affine_rotation(deg2rad(a));
t *= agg::trans_affine_translation(cx, cy);
tr_ *= t;
}
}
TransformType & tr_;
};
template <typename TransformType>
struct process_translate
{
template <typename T0, typename T1>
struct result
{
typedef void type;
};
explicit process_translate( TransformType & tr)
:tr_(tr) {}
template <typename T0,typename T1>
void operator () (T0 tx, T1 ty) const
{
if (ty) tr_ *= agg::trans_affine_translation(tx,*ty);
else tr_ *= agg::trans_affine_translation(tx,0.0);
}
TransformType & tr_;
};
template <typename TransformType>
struct process_scale
{
template <typename T0, typename T1>
struct result
{
typedef void type;
};
explicit process_scale( TransformType & tr)
:tr_(tr) {}
template <typename T0,typename T1>
void operator () (T0 sx, T1 sy) const
{
if (sy) tr_ *= agg::trans_affine_scaling(sx,*sy);
else tr_ *= agg::trans_affine_scaling(sx,sx);
}
TransformType & tr_;
};
template <typename TransformType>
struct process_skew
{
template <typename T0, typename T1>
struct result
{
typedef void type;
};
explicit process_skew( TransformType & tr)
:tr_(tr) {}
template <typename T0,typename T1>
void operator () (T0 skew_x, T1 skew_y) const
{
tr_ *= agg::trans_affine_skewing(deg2rad(skew_x),deg2rad(skew_y));
}
TransformType & tr_;
};
struct print_action
{
template <typename T>
void operator()(T const& c, qi::unused_type, qi::unused_type) const
{
std::cerr << typeid(c).name() << std::endl;
}
};
template <typename Iterator, typename SkipType, typename TransformType>
struct svg_transform_grammar : qi::grammar<Iterator,SkipType>
{
explicit svg_transform_grammar(TransformType & tr)
: svg_transform_grammar::base_type(start),
matrix_action(process_matrix<TransformType>(tr)),
rotate_action(process_rotate<TransformType>(tr)),
translate_action(process_translate<TransformType>(tr)),
scale_action(process_scale<TransformType>(tr)),
skew_action(process_skew<TransformType>(tr))
{
using qi::_1;
using qi::_2;
using qi::_3;
using qi::_4;
using qi::_5;
using qi::_6;
using qi::_a;
using qi::_b;
using qi::_c;
using qi::_val;
using qi::double_;
using qi::no_case;
start = +transform_ ;
transform_ = matrix | rotate | translate | scale | rotate | skewX | skewY ;
matrix = no_case[lit("matrix")]
>> lit('(')
>> (
double_ >> -lit(',')
>> double_ >> -lit(',')
>> double_ >> -lit(',')
>> double_ >> -lit(',')
>> double_ >> -lit(',')
>> double_) [ matrix_action(_1,_2,_3,_4,_5,_6) ]
>> lit(')')
;
translate = no_case[lit("translate")]
>> lit('(')
>> (double_ >> -lit(',')
>> -double_) [ translate_action(_1,_2) ]
>> lit(')');
scale = no_case[lit("scale")]
>> lit('(')
>> (double_ >> -lit(',')
>> -double_ )[ scale_action(_1,_2)]
>> lit(')');
rotate = no_case[lit("rotate")]
>> lit('(')
>> double_[_a = _1] >> -lit(',')
>> -(double_ [_b = _1] >> -lit(',') >> double_[_c = _1])
>> lit(')') [ rotate_action(_a,_b,_c)];
skewX = no_case[lit("skewX")] >> lit('(') >> double_ [ skew_action(_1, 0.0)] >> lit(')');
skewY = no_case[lit("skewY")] >> lit('(') >> double_ [ skew_action(0.0, _1)] >> lit(')');
}
// rules
qi::rule<Iterator,SkipType> start;
qi::rule<Iterator,SkipType> transform_;
qi::rule<Iterator,SkipType> matrix;
qi::rule<Iterator,SkipType> translate;
qi::rule<Iterator,SkipType> scale;
qi::rule<Iterator,qi::locals<double,double,double>, SkipType> rotate;
qi::rule<Iterator,SkipType> skewX;
qi::rule<Iterator,SkipType> skewY;
// actions
function<process_matrix<TransformType> > matrix_action;
function<process_rotate<TransformType> > rotate_action;
function<process_translate<TransformType> > translate_action;
function<process_scale<TransformType> > scale_action;
function<process_skew<TransformType> > skew_action;
};
}}
#endif // SVG_TRANSFORM_GRAMMAR_HPP

View file

@ -38,6 +38,10 @@ regex = 'boost_regex%s' % env['BOOST_APPEND']
libraries = ['freetype','ltdl','png','tiff','z','jpeg','proj',env['ICU_LIB_NAME'],filesystem,regex]
### WARNING! temp solution.
libraries.append('expat')
###
if '-DHAVE_CAIRO' in env['CXXFLAGS']:
# add cairo and cairomm-1.0 to libs
libraries.append([lib for lib in env['LIBS'] if lib.startswith('cairo')])
@ -110,9 +114,21 @@ source = Split(
arrow.cpp
unicode.cpp
glyph_symbolizer.cpp
"""
"""
)
if True :
source += Split(
"""
agg_svg_parser.cpp
agg_svg_path_renderer.cpp
svg_path_parser.cpp
svg_points_parser.cpp
svg_transform_parser.cpp
"""
)
if 'cairo' in env['LIBS']:
source += Split(
"""

663
src/agg_svg_parser.cpp Normal file
View file

@ -0,0 +1,663 @@
//----------------------------------------------------------------------------
// 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
//----------------------------------------------------------------------------
//
// SVG parser.
//
//----------------------------------------------------------------------------
#include <cmath>
#include <cstdlib>
#include <limits.h>
#include <expat.h>
#include <mapnik/svg/agg_svg_parser.h>
#include <mapnik/svg/svg_path_parser.hpp>
#include <mapnik/color_factory.hpp>
#include <boost/tokenizer.hpp>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
namespace agg
{
namespace svg
{
//------------------------------------------------------------------------
parser::~parser()
{
delete [] m_attr_value;
delete [] m_attr_name;
delete [] m_buf;
delete [] m_title;
}
//------------------------------------------------------------------------
parser::parser(path_renderer& path) :
m_path(path),
m_buf(new char[buf_size]),
m_title(new char[256]),
m_title_len(0),
m_title_flag(false),
m_path_flag(false),
m_attr_name(new char[128]),
m_attr_value(new char[1024]),
m_attr_name_len(127),
m_attr_value_len(1023)
{
m_title[0] = 0;
}
//------------------------------------------------------------------------
void parser::parse(const char* fname)
{
char msg[1024];
XML_Parser p = XML_ParserCreate(NULL);
if(p == 0)
{
throw std::runtime_error("Couldn't allocate memory for parser");
}
XML_SetUserData(p, this);
XML_SetElementHandler(p, start_element, end_element);
XML_SetCharacterDataHandler(p, content);
FILE* fd = fopen(fname, "r");
if(fd == 0)
{
sprintf(msg, "Couldn't open file %s", fname);
throw std::runtime_error(msg);
}
bool done = false;
do
{
size_t len = fread(m_buf, 1, buf_size, fd);
done = len < buf_size;
if(!XML_Parse(p, m_buf, len, done))
{
sprintf(msg,
"%s at line %d\n",
XML_ErrorString(XML_GetErrorCode(p)),
XML_GetCurrentLineNumber(p));
throw std::runtime_error(msg);
}
}
while(!done);
fclose(fd);
XML_ParserFree(p);
char* ts = m_title;
while(*ts)
{
if(*ts < ' ') *ts = ' ';
++ts;
}
}
//------------------------------------------------------------------------
void parser::start_element(void* data, const char* el, const char** attr)
{
parser& self = *(parser*)data;
if(strcmp(el, "title") == 0)
{
self.m_title_flag = true;
}
else
if(strcmp(el, "g") == 0)
{
self.m_path.push_attr();
self.parse_attr(attr);
}
else
if(strcmp(el, "path") == 0)
{
if(self.m_path_flag)
{
throw std::runtime_error("start_element: Nested path");
}
self.m_path.begin_path();
self.parse_path(attr);
self.m_path.end_path();
self.m_path_flag = true;
}
else
if(strcmp(el, "rect") == 0)
{
self.parse_rect(attr);
}
else
if(strcmp(el, "line") == 0)
{
self.parse_line(attr);
}
else
if(strcmp(el, "polyline") == 0)
{
self.parse_poly(attr, false);
}
else
if(strcmp(el, "polygon") == 0)
{
self.parse_poly(attr, true);
}
else
if(strcmp(el, "circle") == 0)
{
self.parse_circle(attr);
}
else
if(strcmp(el, "ellipse") == 0)
{
self.parse_ellipse(attr);
}
//else
//if(strcmp(el, "<OTHER_ELEMENTS>") == 0)
//{
//}
// . . .
}
//------------------------------------------------------------------------
void parser::end_element(void* data, const char* el)
{
parser& self = *(parser*)data;
if(strcmp(el, "title") == 0)
{
self.m_title_flag = false;
}
else
if(strcmp(el, "g") == 0)
{
self.m_path.pop_attr();
}
else
if(strcmp(el, "path") == 0)
{
self.m_path_flag = false;
}
//else
//if(strcmp(el, "<OTHER_ELEMENTS>") == 0)
//{
//}
// . . .
}
//------------------------------------------------------------------------
void parser::content(void* data, const char* s, int len)
{
parser& self = *(parser*)data;
// m_title_flag signals that the <title> tag is being parsed now.
// The following code concatenates the pieces of content of the <title> tag.
if(self.m_title_flag)
{
if(len + self.m_title_len > 255) len = 255 - self.m_title_len;
if(len > 0)
{
memcpy(self.m_title + self.m_title_len, s, len);
self.m_title_len += len;
self.m_title[self.m_title_len] = 0;
}
}
}
//------------------------------------------------------------------------
void parser::parse_attr(const char** attr)
{
int i;
for(i = 0; attr[i]; i += 2)
{
if(strcmp(attr[i], "style") == 0)
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
boost::char_separator<char> sep(";");
std::string str(attr[i+1]);
std::cerr << str << std::endl;
tokenizer tok(str,sep);
for (tokenizer::iterator tok_iter = tok.begin();
tok_iter != tok.end(); ++tok_iter)
{
parse_style(tok_iter->c_str());
}
//parse_style(attr[i+1]);
}
else
{
parse_attr(attr[i], attr[i + 1]);
}
}
}
//-------------------------------------------------------------
void parser::parse_path(const char** attr)
{
int i;
for(i = 0; attr[i]; i += 2)
{
// The <path> tag can consist of the path itself ("d=")
// as well as of other parameters like "style=", "transform=", etc.
// In the last case we simply rely on the function of parsing
// attributes (see 'else' branch).
if(strcmp(attr[i], "d") == 0)
{
std::string wkt(attr[i+1]);
if (!mapnik::svg::parse_path(wkt, m_path))
{
std::runtime_error("can't parse PATH\n");
}
}
else
{
// Create a temporary single pair "name-value" in order
// to avoid multiple calls for the same attribute.
const char* tmp[4];
tmp[0] = attr[i];
tmp[1] = attr[i + 1];
tmp[2] = 0;
tmp[3] = 0;
parse_attr(tmp);
}
}
}
//-------------------------------------------------------------
rgba8 parse_color(const char* str)
{
mapnik::color c(100,100,100);
try
{
mapnik::color_factory::init_from_string(c,str);
}
catch (mapnik::config_error & ex)
{
std::cerr << ex.what() << std::endl;
}
return rgba8(c.red(), c.green(), c.blue(), c.alpha());
}
double parse_double(const char* str)
{
while(*str == ' ') ++str;
return atof(str);
}
//-------------------------------------------------------------
bool parser::parse_attr(const char* name, const char* value)
{
if(strcmp(name, "style") == 0)
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
boost::char_separator<char> sep(";");
std::string str(value);
std::cerr << str << std::endl;
tokenizer tok(str,sep);
for (tokenizer::iterator tok_iter = tok.begin();
tok_iter != tok.end(); ++tok_iter)
{
parse_style(tok_iter->c_str());
}
}
else if(strcmp(name, "fill") == 0)
{
if(strcmp(value, "none") == 0)
{
m_path.fill_none();
}
else
{
m_path.fill(parse_color(value));
}
}
else if(strcmp(name, "fill-opacity") == 0)
{
m_path.fill_opacity(parse_double(value));
}
else if(strcmp(name, "stroke") == 0)
{
if(strcmp(value, "none") == 0)
{
m_path.stroke_none();
}
else
{
m_path.stroke(parse_color(value));
}
}
else if(strcmp(name, "fill-rule") == 0)
{
if (strcmp(value, "evenodd") == 0)
{
m_path.even_odd(true);
}
}
else if(strcmp(name, "stroke-width") == 0)
{
m_path.stroke_width(parse_double(value));
}
else if(strcmp(name, "stroke-linecap") == 0)
{
if(strcmp(value, "butt") == 0) m_path.line_cap(butt_cap);
else if(strcmp(value, "round") == 0) m_path.line_cap(round_cap);
else if(strcmp(value, "square") == 0) m_path.line_cap(square_cap);
}
else
if(strcmp(name, "stroke-linejoin") == 0)
{
if(strcmp(value, "miter") == 0) m_path.line_join(miter_join);
else if(strcmp(value, "round") == 0) m_path.line_join(round_join);
else if(strcmp(value, "bevel") == 0) m_path.line_join(bevel_join);
}
else if(strcmp(name, "stroke-miterlimit") == 0)
{
m_path.miter_limit(parse_double(value));
}
else if(strcmp(name, "stroke-opacity") == 0)
{
m_path.stroke_opacity(parse_double(value));
}
else if(strcmp(name, "transform") == 0)
{
agg::trans_affine tr;
mapnik::svg::parse_transform(value,tr);
m_path.transform().premultiply(tr);
}
else if(strcmp(name,"opacity") == 0)
{
double opacity = parse_double(value);
m_path.stroke_opacity(opacity);
m_path.fill_opacity(opacity);
}
//else
//if(strcmp(el, "<OTHER_ATTRIBUTES>") == 0)
//{
//}
// . . .
else
{
return false;
}
return true;
}
//-------------------------------------------------------------
void parser::copy_name(const char* start, const char* end)
{
unsigned len = unsigned(end - start);
if(m_attr_name_len == 0 || len > m_attr_name_len)
{
delete [] m_attr_name;
m_attr_name = new char[len + 1];
m_attr_name_len = len;
}
if(len) memcpy(m_attr_name, start, len);
m_attr_name[len] = 0;
}
//-------------------------------------------------------------
void parser::copy_value(const char* start, const char* end)
{
unsigned len = unsigned(end - start);
if(m_attr_value_len == 0 || len > m_attr_value_len)
{
delete [] m_attr_value;
m_attr_value = new char[len + 1];
m_attr_value_len = len;
}
if(len) memcpy(m_attr_value, start, len);
m_attr_value[len] = 0;
}
//-------------------------------------------------------------
bool parser::parse_name_value(const char* nv_start, const char* nv_end)
{
const char* str = nv_start;
while(str < nv_end && *str != ':') ++str;
const char* val = str;
// Right Trim
while(str > nv_start &&
(*str == ':' || isspace(*str))) --str;
++str;
copy_name(nv_start, str);
while(val < nv_end && (*val == ':' || isspace(*val))) ++val;
copy_value(val, nv_end);
return parse_attr(m_attr_name, m_attr_value);
}
//-------------------------------------------------------------
void parser::parse_style(const char* str)
{
while(*str)
{
// Left Trim
while(*str && isspace(*str)) ++str;
const char* nv_start = str;
while(*str && *str != ';') ++str;
const char* nv_end = str;
// Right Trim
while(nv_end > nv_start &&
(*nv_end == ';' || isspace(*nv_end))) --nv_end;
++nv_end;
parse_name_value(nv_start, nv_end);
if(*str) ++str;
}
}
//-------------------------------------------------------------
void parser::parse_rect(const char** attr)
{
int i;
double x = 0.0;
double y = 0.0;
double w = 0.0;
double h = 0.0;
double rx = 0.0;
double ry = 0.0;
m_path.begin_path();
for(i = 0; attr[i]; i += 2)
{
if(!parse_attr(attr[i], attr[i + 1]))
{
if(strcmp(attr[i], "x") == 0) x = parse_double(attr[i + 1]);
if(strcmp(attr[i], "y") == 0) y = parse_double(attr[i + 1]);
if(strcmp(attr[i], "width") == 0) w = parse_double(attr[i + 1]);
if(strcmp(attr[i], "height") == 0) h = parse_double(attr[i + 1]);
if(strcmp(attr[i], "rx") == 0) rx = parse_double(attr[i + 1]);
if(strcmp(attr[i], "ry") == 0) ry = parse_double(attr[i + 1]);
}
}
if(w != 0.0 && h != 0.0)
{
if(w < 0.0) throw std::runtime_error("parse_rect: Invalid width: %f");//, w);
if(h < 0.0) throw std::runtime_error("parse_rect: Invalid height: %f");//, h);
if(rx < 0.0) throw std::runtime_error("parse_rect: Invalid rx: %f");//, rx);
if(ry < 0.0) throw std::runtime_error("parse_rect: Invalid ry: %f");// ry);
if(rx > 0.0 && ry > 0.0)
{
m_path.move_to(x + rx,y);
m_path.line_to(x + w -rx,y);
m_path.arc_to (rx,ry,0,0,1,x + w, y + ry);
m_path.line_to(x + w, y + h - ry);
m_path.arc_to (rx,ry,0,0,1,x + w - rx, y + h);
m_path.line_to(x + rx, y + h);
m_path.arc_to(rx,ry,0,0,1,x,y + h - ry);
m_path.line_to(x,y+ry);
m_path.arc_to(rx,ry,0,0,1,x + rx,y);
}
else
{
m_path.move_to(x, y);
m_path.line_to(x + w, y);
m_path.line_to(x + w, y + h);
m_path.line_to(x, y + h);
m_path.close_subpath();
}
}
m_path.end_path();
}
//-------------------------------------------------------------
void parser::parse_circle(const char** attr)
{
int i;
double cx = 0.0;
double cy = 0.0;
double r = 0.0;
m_path.begin_path();
for(i = 0; attr[i]; i += 2)
{
if(!parse_attr(attr[i], attr[i + 1]))
{
if(strcmp(attr[i], "cx") == 0) cx = parse_double(attr[i + 1]);
if(strcmp(attr[i], "cy") == 0) cy = parse_double(attr[i + 1]);
if(strcmp(attr[i], "r") == 0) r = parse_double(attr[i + 1]);
}
}
if(r != 0.0)
{
if(r < 0.0) throw std::runtime_error("parse_cirle: Invalid radius: %f");// r);
m_path.move_to(cx+r,cy);
m_path.arc_to(r,r,0,1,0,cx-r,cy);
m_path.arc_to(r,r,0,1,0,cx+r,cy);
}
m_path.end_path();
}
//-------------------------------------------------------------
void parser::parse_ellipse(const char** attr)
{
double cx = 0.0;
double cy = 0.0;
double rx = 0.0;
double ry = 0.0;
m_path.begin_path();
for(int i = 0; attr[i]; i += 2)
{
if(!parse_attr(attr[i], attr[i + 1]))
{
if(strcmp(attr[i], "cx") == 0) cx = parse_double(attr[i + 1]);
if(strcmp(attr[i], "cy") == 0) cy = parse_double(attr[i + 1]);
if(strcmp(attr[i], "rx") == 0) rx = parse_double(attr[i + 1]);
if(strcmp(attr[i], "ry") == 0) ry = parse_double(attr[i + 1]);
}
}
if(rx != 0.0 && ry != 0.0)
{
if(rx < 0.0) throw std::runtime_error("parse_cirle: Invalid rx: %f");
if(ry < 0.0) throw std::runtime_error("parse_cirle: Invalid ry: %f");
m_path.move_to(cx+rx,cy);
m_path.arc_to(rx,ry,0,1,0,cx-rx,cy);
m_path.arc_to(rx,ry,0,1,0,cx+rx,cy);
}
m_path.end_path();
}
//-------------------------------------------------------------
void parser::parse_line(const char** attr)
{
int i;
double x1 = 0.0;
double y1 = 0.0;
double x2 = 0.0;
double y2 = 0.0;
m_path.begin_path();
for(i = 0; attr[i]; i += 2)
{
if(!parse_attr(attr[i], attr[i + 1]))
{
if(strcmp(attr[i], "x1") == 0) x1 = parse_double(attr[i + 1]);
if(strcmp(attr[i], "y1") == 0) y1 = parse_double(attr[i + 1]);
if(strcmp(attr[i], "x2") == 0) x2 = parse_double(attr[i + 1]);
if(strcmp(attr[i], "y2") == 0) y2 = parse_double(attr[i + 1]);
}
}
m_path.move_to(x1, y1);
m_path.line_to(x2, y2);
m_path.end_path();
}
//-------------------------------------------------------------
void parser::parse_poly(const char** attr, bool close_flag)
{
m_path.begin_path();
for(int i = 0; attr[i]; i += 2)
{
if(!parse_attr(attr[i], attr[i + 1]))
{
if(strcmp(attr[i], "points") == 0)
{
if (!mapnik::svg::parse_points(attr[i+1], m_path))
{
throw std::runtime_error("can't parse POINTS\n");
}
}
}
}
if(close_flag)
{
m_path.close_subpath();
}
m_path.end_path();
}
}
}

View file

@ -0,0 +1,300 @@
//----------------------------------------------------------------------------
// 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
//----------------------------------------------------------------------------
//
// SVG path renderer.
//
//----------------------------------------------------------------------------
#include <stdio.h>
#include <stdexcept>
#include <mapnik/svg/agg_svg_path_renderer.h>
namespace agg
{
namespace svg
{
//------------------------------------------------------------------------
path_renderer::path_renderer() :
m_curved(m_storage),
m_curved_count(m_curved),
m_curved_stroked(m_curved_count),
m_curved_stroked_trans(m_curved_stroked, m_transform),
m_curved_trans(m_curved_count, m_transform),
m_curved_trans_contour(m_curved_trans)
{
m_curved_trans_contour.auto_detect_orientation(false);
}
//------------------------------------------------------------------------
void path_renderer::remove_all()
{
m_storage.remove_all();
m_attr_storage.remove_all();
m_attr_stack.remove_all();
m_transform.reset();
}
//------------------------------------------------------------------------
void path_renderer::begin_path()
{
push_attr();
unsigned idx = m_storage.start_new_path();
m_attr_storage.add(path_attributes(cur_attr(), idx));
}
//------------------------------------------------------------------------
void path_renderer::end_path()
{
if(m_attr_storage.size() == 0)
{
throw std::runtime_error("end_path : The path was not begun");
}
path_attributes attr = cur_attr();
unsigned idx = m_attr_storage[m_attr_storage.size() - 1].index;
attr.index = idx;
m_attr_storage[m_attr_storage.size() - 1] = attr;
pop_attr();
}
//------------------------------------------------------------------------
void path_renderer::move_to(double x, double y, bool rel) // M, m
{
if(rel) m_storage.rel_to_abs(&x, &y);
m_storage.move_to(x, y);
}
//------------------------------------------------------------------------
void path_renderer::line_to(double x, double y, bool rel) // L, l
{
if(rel) m_storage.rel_to_abs(&x, &y);
m_storage.line_to(x, y);
}
//------------------------------------------------------------------------
void path_renderer::hline_to(double x, bool rel) // H, h
{
double x2 = 0.0;
double y2 = 0.0;
if(m_storage.total_vertices())
{
m_storage.vertex(m_storage.total_vertices() - 1, &x2, &y2);
if(rel) x += x2;
m_storage.line_to(x, y2);
}
}
//------------------------------------------------------------------------
void path_renderer::vline_to(double y, bool rel) // V, v
{
double x2 = 0.0;
double y2 = 0.0;
if(m_storage.total_vertices())
{
m_storage.vertex(m_storage.total_vertices() - 1, &x2, &y2);
if(rel) y += y2;
m_storage.line_to(x2, y);
}
}
//------------------------------------------------------------------------
void path_renderer::curve3(double x1, double y1, // Q, q
double x, double y, bool rel)
{
if(rel)
{
m_storage.rel_to_abs(&x1, &y1);
m_storage.rel_to_abs(&x, &y);
}
m_storage.curve3(x1, y1, x, y);
}
//------------------------------------------------------------------------
void path_renderer::curve3(double x, double y, bool rel) // T, t
{
// throw std::runtime_error("curve3(x, y) : NOT IMPLEMENTED YET");
if(rel)
{
m_storage.curve3_rel(x, y);
} else
{
m_storage.curve3(x, y);
}
}
//------------------------------------------------------------------------
void path_renderer::curve4(double x1, double y1, // C, c
double x2, double y2,
double x, double y, bool rel)
{
if(rel)
{
m_storage.rel_to_abs(&x1, &y1);
m_storage.rel_to_abs(&x2, &y2);
m_storage.rel_to_abs(&x, &y);
}
m_storage.curve4(x1, y1, x2, y2, x, y);
}
//------------------------------------------------------------------------
void path_renderer::curve4(double x2, double y2, // S, s
double x, double y, bool rel)
{
//throw std::runtime_error("curve4(x2, y2, x, y) : NOT IMPLEMENTED YET");
if(rel)
{
m_storage.curve4_rel(x2, y2, x, y);
} else
{
m_storage.curve4(x2, y2, x, y);
}
}
//------------------------------------------------------------------------
void path_renderer::arc_to(double rx, double ry, // A, a
double angle,
bool large_arc_flag,
bool sweep_flag,
double x, double y,
bool rel)
{
if(rel)
{
m_storage.arc_rel(rx, ry, angle, large_arc_flag, sweep_flag, x, y);
}
else
{
m_storage.arc_to(rx, ry, angle, large_arc_flag, sweep_flag, x, y);
}
}
//------------------------------------------------------------------------
void path_renderer::close_subpath()
{
m_storage.end_poly(path_flags_close);
}
//------------------------------------------------------------------------
path_attributes& path_renderer::cur_attr()
{
if(m_attr_stack.size() == 0)
{
throw std::runtime_error("cur_attr : Attribute stack is empty");
}
return m_attr_stack[m_attr_stack.size() - 1];
}
//------------------------------------------------------------------------
void path_renderer::push_attr()
{
m_attr_stack.add(m_attr_stack.size() ?
m_attr_stack[m_attr_stack.size() - 1] :
path_attributes());
}
//------------------------------------------------------------------------
void path_renderer::pop_attr()
{
if(m_attr_stack.size() == 0)
{
throw std::runtime_error("pop_attr : Attribute stack is empty");
}
m_attr_stack.remove_last();
}
//------------------------------------------------------------------------
void path_renderer::fill(const rgba8& f)
{
path_attributes& attr = cur_attr();
attr.fill_color = f;
attr.fill_flag = true;
}
//------------------------------------------------------------------------
void path_renderer::stroke(const rgba8& s)
{
path_attributes& attr = cur_attr();
attr.stroke_color = s;
attr.stroke_flag = true;
}
//------------------------------------------------------------------------
void path_renderer::even_odd(bool flag)
{
cur_attr().even_odd_flag = flag;
}
//------------------------------------------------------------------------
void path_renderer::stroke_width(double w)
{
cur_attr().stroke_width = w;
}
//------------------------------------------------------------------------
void path_renderer::fill_none()
{
cur_attr().fill_flag = false;
}
//------------------------------------------------------------------------
void path_renderer::stroke_none()
{
cur_attr().stroke_flag = false;
}
//------------------------------------------------------------------------
void path_renderer::fill_opacity(double op)
{
cur_attr().fill_color.opacity(op);
}
//------------------------------------------------------------------------
void path_renderer::stroke_opacity(double op)
{
cur_attr().stroke_color.opacity(op);
}
//------------------------------------------------------------------------
void path_renderer::line_join(line_join_e join)
{
cur_attr().line_join = join;
}
//------------------------------------------------------------------------
void path_renderer::line_cap(line_cap_e cap)
{
cur_attr().line_cap = cap;
}
//------------------------------------------------------------------------
void path_renderer::miter_limit(double ml)
{
cur_attr().miter_limit = ml;
}
//------------------------------------------------------------------------
trans_affine& path_renderer::transform()
{
return cur_attr().transform;
}
}
}

47
src/svg_path_parser.cpp Normal file
View file

@ -0,0 +1,47 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2010 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
// mapnik
#include <mapnik/svg/svg_path_parser.hpp>
#include <mapnik/svg/svg_path_grammar.hpp>
// agg
#include <mapnik/svg/agg_svg_path_renderer.h>
// stl
#include <string>
namespace mapnik { namespace svg {
template <typename PathType>
bool parse_path(std::string const& wkt, PathType & p)
{
using namespace boost::spirit;
typedef std::string::const_iterator iterator_type;
typedef ascii::space_type skip_type;
svg_path_grammar<iterator_type,skip_type,PathType> g(p);
iterator_type first = wkt.begin();
iterator_type last = wkt.end();
return qi::phrase_parse(first, last, g, skip_type());
}
template bool parse_path<agg::svg::path_renderer>(std::string const&, agg::svg::path_renderer&) ;
}}

47
src/svg_points_parser.cpp Normal file
View file

@ -0,0 +1,47 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2010 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
// mapnik
#include <mapnik/svg/svg_path_parser.hpp>
#include <mapnik/svg/svg_points_grammar.hpp>
// agg
#include <mapnik/svg/agg_svg_path_renderer.h>
// stl
#include <string>
namespace mapnik { namespace svg {
template <typename PathType>
bool parse_points(std::string const& wkt, PathType & p)
{
using namespace boost::spirit;
typedef std::string::const_iterator iterator_type;
typedef ascii::space_type skip_type;
svg_points_grammar<iterator_type,skip_type,PathType> g(p);
iterator_type first = wkt.begin();
iterator_type last = wkt.end();
return qi::phrase_parse(first, last, g, skip_type());
}
template bool parse_points<agg::svg::path_renderer>(std::string const&, agg::svg::path_renderer&);
}}

View file

@ -0,0 +1,47 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2010 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
// mapnik
#include <mapnik/svg/svg_path_parser.hpp>
#include <mapnik/svg/svg_transform_grammar.hpp>
// agg
#include "agg_trans_affine.h"
// stl
#include <string>
namespace mapnik { namespace svg {
template <typename TransformType>
bool parse_transform(std::string const& wkt, TransformType & p)
{
using namespace boost::spirit;
typedef std::string::const_iterator iterator_type;
typedef ascii::space_type skip_type;
svg_transform_grammar<iterator_type,skip_type,TransformType> g(p);
iterator_type first = wkt.begin();
iterator_type last = wkt.end();
return qi::phrase_parse(first, last, g, skip_type());
}
template bool parse_transform<agg::trans_affine>(std::string const&, agg::trans_affine&);
}}