2008-02-23 01:17:53 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* This file is part of Mapnik (c++ mapping toolkit)
|
|
|
|
*
|
2011-10-23 15:04:25 +02:00
|
|
|
* Copyright (C) 2011 Artem Pavlenko
|
2008-02-23 01:17:53 +01:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2009-06-08 21:43:49 +02:00
|
|
|
#if defined(HAVE_CAIRO)
|
|
|
|
|
2008-02-23 01:17:53 +01:00
|
|
|
// mapnik
|
2012-04-08 02:20:56 +02:00
|
|
|
#include <mapnik/debug.hpp>
|
2008-02-23 01:17:53 +01:00
|
|
|
#include <mapnik/cairo_renderer.hpp>
|
|
|
|
#include <mapnik/image_util.hpp>
|
|
|
|
#include <mapnik/unicode.hpp>
|
2010-05-30 05:16:51 +02:00
|
|
|
#include <mapnik/markers_placement.hpp>
|
2008-02-23 01:17:53 +01:00
|
|
|
#include <mapnik/arrow.hpp>
|
2010-06-18 17:39:32 +02:00
|
|
|
#include <mapnik/parse_path.hpp>
|
2012-03-08 17:37:58 +01:00
|
|
|
#include <mapnik/marker.hpp>
|
2011-01-26 02:18:40 +01:00
|
|
|
#include <mapnik/marker_cache.hpp>
|
|
|
|
#include <mapnik/svg/svg_path_adapter.hpp>
|
|
|
|
#include <mapnik/svg/svg_path_attributes.hpp>
|
2011-03-22 01:02:50 +01:00
|
|
|
#include <mapnik/segment.hpp>
|
2012-01-26 14:04:08 +01:00
|
|
|
#include <mapnik/symbolizer_helpers.hpp>
|
2011-09-01 03:18:10 +02:00
|
|
|
#include <mapnik/expression_evaluator.hpp>
|
2011-09-16 16:34:14 +02:00
|
|
|
#include <mapnik/warp.hpp>
|
2011-09-16 16:35:47 +02:00
|
|
|
#include <mapnik/config.hpp>
|
2012-03-04 23:25:13 +01:00
|
|
|
#include <mapnik/text_path.hpp>
|
2012-05-09 16:45:44 +02:00
|
|
|
#include <mapnik/vertex_converters.hpp>
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2008-02-23 01:17:53 +01:00
|
|
|
// cairo
|
|
|
|
#include <cairomm/context.h>
|
|
|
|
#include <cairomm/surface.h>
|
|
|
|
#include <cairo-ft.h>
|
2012-05-30 01:57:58 +02:00
|
|
|
#include <cairo-version.h>
|
2008-02-23 01:17:53 +01:00
|
|
|
|
|
|
|
// boost
|
|
|
|
#include <boost/utility.hpp>
|
2011-05-10 23:09:54 +02:00
|
|
|
#include <boost/make_shared.hpp>
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-03-08 12:07:13 +01:00
|
|
|
// agg
|
2012-05-09 16:45:44 +02:00
|
|
|
|
2012-03-08 12:07:13 +01:00
|
|
|
#include "agg_conv_clip_polyline.h"
|
|
|
|
#include "agg_conv_clip_polygon.h"
|
2012-03-14 18:38:27 +01:00
|
|
|
#include "agg_conv_smooth_poly1.h"
|
2012-03-08 12:07:13 +01:00
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
// markers
|
|
|
|
#include "agg_path_storage.h"
|
|
|
|
#include "agg_ellipse.h"
|
|
|
|
|
2008-02-23 01:17:53 +01:00
|
|
|
namespace mapnik
|
|
|
|
{
|
2009-12-16 21:02:06 +01:00
|
|
|
class cairo_pattern : private boost::noncopyable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
cairo_pattern(image_data_32 const& data)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
int pixels = data.width() * data.height();
|
|
|
|
const unsigned int *in_ptr = data.getData();
|
|
|
|
const unsigned int *in_end = in_ptr + pixels;
|
|
|
|
unsigned int *out_ptr;
|
|
|
|
|
2010-10-01 13:22:39 +02:00
|
|
|
surface_ = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, data.width(), data.height());
|
|
|
|
|
|
|
|
out_ptr = reinterpret_cast<unsigned int *>(surface_->get_data());
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
while (in_ptr < in_end)
|
|
|
|
{
|
|
|
|
unsigned int in = *in_ptr++;
|
|
|
|
unsigned int r = (in >> 0) & 0xff;
|
|
|
|
unsigned int g = (in >> 8) & 0xff;
|
|
|
|
unsigned int b = (in >> 16) & 0xff;
|
|
|
|
unsigned int a = (in >> 24) & 0xff;
|
|
|
|
|
|
|
|
r = r * a / 255;
|
|
|
|
g = g * a / 255;
|
|
|
|
b = b * a / 255;
|
|
|
|
|
|
|
|
*out_ptr++ = (a << 24) | (r << 16) | (g << 8) | b;
|
|
|
|
}
|
2010-10-01 13:22:39 +02:00
|
|
|
// mark the surface as dirty as we've modified it behind cairo's back
|
|
|
|
surface_->mark_dirty();
|
2010-06-02 13:03:30 +02:00
|
|
|
pattern_ = Cairo::SurfacePattern::create(surface_);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
~cairo_pattern(void)
|
|
|
|
{
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void set_matrix(Cairo::Matrix const& matrix)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
pattern_->set_matrix(matrix);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_origin(double x, double y)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
Cairo::Matrix matrix;
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
pattern_->get_matrix(matrix);
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
matrix.x0 = -x;
|
|
|
|
matrix.y0 = -y;
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
pattern_->set_matrix(matrix);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void set_extend(Cairo::Extend extend)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
pattern_->set_extend(extend);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void set_filter(Cairo::Filter filter)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
pattern_->set_filter(filter);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
Cairo::RefPtr<Cairo::SurfacePattern> const& pattern(void) const
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
return pattern_;
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
private:
|
|
|
|
Cairo::RefPtr<Cairo::ImageSurface> surface_;
|
|
|
|
Cairo::RefPtr<Cairo::SurfacePattern> pattern_;
|
|
|
|
};
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2011-01-26 02:18:40 +01:00
|
|
|
class cairo_gradient : private boost::noncopyable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
cairo_gradient(const mapnik::gradient &grad, double opacity=1.0)
|
|
|
|
{
|
|
|
|
double x1,x2,y1,y2,r;
|
|
|
|
grad.get_control_points(x1,y1,x2,y2,r);
|
|
|
|
if (grad.get_gradient_type() == LINEAR)
|
|
|
|
{
|
|
|
|
pattern_ = Cairo::LinearGradient::create(x1, y1, x2, y2);
|
|
|
|
}
|
|
|
|
else if (grad.get_gradient_type() == RADIAL)
|
|
|
|
{
|
|
|
|
pattern_ = Cairo::RadialGradient::create(x1, y1, 0, x2, y2, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
units_ = grad.get_units();
|
|
|
|
|
|
|
|
BOOST_FOREACH ( mapnik::stop_pair const& st, grad.get_stop_array() )
|
|
|
|
{
|
|
|
|
mapnik::color const& stop_color = st.second;
|
|
|
|
double r= static_cast<double> (stop_color.red())/255.0;
|
|
|
|
double g= static_cast<double> (stop_color.green())/255.0;
|
|
|
|
double b= static_cast<double> (stop_color.blue())/255.0;
|
|
|
|
double a= static_cast<double> (stop_color.alpha())/255.0;
|
|
|
|
pattern_->add_color_stop_rgba(st.first, r, g, b, a*opacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
double m[6];
|
|
|
|
agg::trans_affine tr = grad.get_transform();
|
|
|
|
tr.invert();
|
|
|
|
tr.store_to(m);
|
|
|
|
pattern_->set_matrix(Cairo::Matrix(m[0],m[1],m[2],m[3],m[4],m[5]));
|
|
|
|
}
|
|
|
|
|
|
|
|
~cairo_gradient(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Cairo::RefPtr<Cairo::Gradient> const& gradient(void) const
|
|
|
|
{
|
|
|
|
return pattern_;
|
|
|
|
}
|
|
|
|
|
|
|
|
gradient_unit_e units() const
|
|
|
|
{
|
|
|
|
return units_;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Cairo::RefPtr<Cairo::Gradient> pattern_;
|
|
|
|
gradient_unit_e units_;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
class cairo_face : private boost::noncopyable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
cairo_face(boost::shared_ptr<freetype_engine> const& engine, face_ptr const& face)
|
2010-06-02 13:03:30 +02:00
|
|
|
: face_(face)
|
2009-12-16 21:02:06 +01:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
static cairo_user_data_key_t key;
|
|
|
|
cairo_font_face_t *c_face;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
c_face = cairo_ft_font_face_create_for_ft_face(face->get_face(), FT_LOAD_NO_HINTING);
|
|
|
|
cairo_font_face_set_user_data(c_face, &key, new handle(engine, face), destroy);
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
cairo_face_ = Cairo::RefPtr<Cairo::FontFace>(new Cairo::FontFace(c_face));
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Cairo::RefPtr<Cairo::FontFace> const& face(void) const
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
return cairo_face_;
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
class handle
|
|
|
|
{
|
|
|
|
public:
|
2010-06-02 13:03:30 +02:00
|
|
|
handle(boost::shared_ptr<freetype_engine> const& engine, face_ptr const& face)
|
|
|
|
: engine_(engine), face_(face) {}
|
2009-12-16 21:02:06 +01:00
|
|
|
|
|
|
|
private:
|
2010-06-02 13:03:30 +02:00
|
|
|
boost::shared_ptr<freetype_engine> engine_;
|
|
|
|
face_ptr face_;
|
2009-12-16 21:02:06 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static void destroy(void *data)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
handle *h = static_cast<handle *>(data);
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
delete h;
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
face_ptr face_;
|
|
|
|
Cairo::RefPtr<Cairo::FontFace> cairo_face_;
|
|
|
|
};
|
|
|
|
|
|
|
|
cairo_face_manager::cairo_face_manager(boost::shared_ptr<freetype_engine> engine,
|
2010-06-02 13:03:30 +02:00
|
|
|
face_manager<freetype_engine> & manager)
|
2009-12-16 21:02:06 +01:00
|
|
|
: font_engine_(engine),
|
|
|
|
font_manager_(manager)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_face_ptr cairo_face_manager::get_face(face_ptr face)
|
|
|
|
{
|
|
|
|
cairo_face_cache::iterator itr = cache_.find(face);
|
|
|
|
cairo_face_ptr entry;
|
|
|
|
|
|
|
|
if (itr != cache_.end())
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
entry = itr->second;
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-12 14:07:36 +01:00
|
|
|
entry = boost::make_shared<cairo_face>(font_engine_, face);
|
2010-06-02 13:03:30 +02:00
|
|
|
cache_.insert(std::make_pair(face, entry));
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2012-03-13 15:56:11 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
class cairo_context : private boost::noncopyable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
cairo_context(Cairo::RefPtr<Cairo::Context> const& context)
|
2010-06-02 13:03:30 +02:00
|
|
|
: context_(context)
|
2009-12-16 21:02:06 +01:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->save();
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
~cairo_context(void)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->restore();
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_color(color const &color, double opacity = 1.0)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_color(color.red(), color.green(), color.blue(), color.alpha() * opacity / 255.0);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_color(int r, int g, int b, double opacity = 1.0)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->set_source_rgba(r / 255.0, g / 255.0, b / 255.0, opacity);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-05-03 15:34:17 +02:00
|
|
|
void set_operator(composite_mode_e comp_op)
|
|
|
|
{
|
|
|
|
switch (comp_op)
|
|
|
|
{
|
|
|
|
case clear:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_CLEAR);
|
|
|
|
break;
|
|
|
|
case src:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_SOURCE);
|
|
|
|
break;
|
|
|
|
case dst:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_DEST);
|
|
|
|
break;
|
|
|
|
case src_over:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_OVER);
|
|
|
|
break;
|
|
|
|
case dst_over:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_DEST_OVER);
|
2012-05-10 13:10:37 +02:00
|
|
|
break;
|
2012-05-03 15:34:17 +02:00
|
|
|
case src_in:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_IN);
|
|
|
|
break;
|
|
|
|
case dst_in:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_DEST_IN);
|
2012-05-10 13:10:37 +02:00
|
|
|
break;
|
2012-05-03 15:34:17 +02:00
|
|
|
case src_out:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_OUT);
|
|
|
|
break;
|
|
|
|
case dst_out:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_DEST_OUT);
|
2012-05-10 13:10:37 +02:00
|
|
|
break;
|
2012-05-03 15:34:17 +02:00
|
|
|
case src_atop:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_ATOP);
|
|
|
|
break;
|
|
|
|
case dst_atop:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_DEST_ATOP);
|
2012-05-10 13:10:37 +02:00
|
|
|
break;
|
2012-05-03 15:34:17 +02:00
|
|
|
case _xor:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_XOR);
|
|
|
|
break;
|
|
|
|
case plus:
|
|
|
|
context_->set_operator(Cairo::OPERATOR_ADD);
|
2012-05-10 13:10:37 +02:00
|
|
|
break;
|
2012-05-18 20:31:08 +02:00
|
|
|
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)
|
2012-05-03 15:34:17 +02:00
|
|
|
case multiply:
|
|
|
|
context_->set_operator(static_cast<Cairo::Operator>(CAIRO_OPERATOR_MULTIPLY));
|
2012-05-10 13:10:37 +02:00
|
|
|
break;
|
2012-05-03 15:34:17 +02:00
|
|
|
case screen:
|
|
|
|
context_->set_operator(static_cast<Cairo::Operator>(CAIRO_OPERATOR_SCREEN));
|
2012-05-10 13:10:37 +02:00
|
|
|
break;
|
2012-05-03 15:34:17 +02:00
|
|
|
case overlay:
|
|
|
|
context_->set_operator(static_cast<Cairo::Operator>(CAIRO_OPERATOR_OVERLAY));
|
|
|
|
break;
|
|
|
|
case darken:
|
|
|
|
context_->set_operator(static_cast<Cairo::Operator>(CAIRO_OPERATOR_DARKEN));
|
|
|
|
break;
|
|
|
|
case lighten:
|
|
|
|
context_->set_operator(static_cast<Cairo::Operator>(CAIRO_OPERATOR_LIGHTEN));
|
|
|
|
break;
|
|
|
|
case color_dodge:
|
|
|
|
context_->set_operator(static_cast<Cairo::Operator>(CAIRO_OPERATOR_COLOR_DODGE));
|
|
|
|
break;
|
|
|
|
case color_burn:
|
|
|
|
context_->set_operator(static_cast<Cairo::Operator>(CAIRO_OPERATOR_COLOR_BURN));
|
|
|
|
break;
|
|
|
|
case hard_light:
|
|
|
|
context_->set_operator(static_cast<Cairo::Operator>(CAIRO_OPERATOR_HARD_LIGHT));
|
|
|
|
break;
|
|
|
|
case soft_light:
|
|
|
|
context_->set_operator(static_cast<Cairo::Operator>(CAIRO_OPERATOR_SOFT_LIGHT));
|
|
|
|
break;
|
|
|
|
case difference:
|
|
|
|
context_->set_operator(static_cast<Cairo::Operator>(CAIRO_OPERATOR_DIFFERENCE));
|
|
|
|
break;
|
|
|
|
case exclusion:
|
|
|
|
context_->set_operator(static_cast<Cairo::Operator>(CAIRO_OPERATOR_EXCLUSION));
|
|
|
|
break;
|
2012-05-18 20:31:08 +02:00
|
|
|
#else
|
|
|
|
#warning building against cairo older that 1.10.0, some compositing options are disabled
|
|
|
|
case multiply:
|
|
|
|
case screen:
|
|
|
|
case overlay:
|
|
|
|
case darken:
|
|
|
|
case lighten:
|
|
|
|
case color_dodge:
|
|
|
|
case color_burn:
|
|
|
|
case hard_light:
|
|
|
|
case soft_light:
|
|
|
|
case difference:
|
|
|
|
case exclusion:
|
|
|
|
break;
|
|
|
|
#endif
|
2012-05-03 15:34:17 +02:00
|
|
|
case contrast:
|
|
|
|
case minus:
|
|
|
|
case invert:
|
|
|
|
case invert_rgb:
|
2012-05-25 11:35:43 +02:00
|
|
|
case grain_merge:
|
2012-05-29 16:09:33 +02:00
|
|
|
case grain_extract:
|
2012-06-17 21:19:29 +02:00
|
|
|
case hue:
|
|
|
|
case saturation:
|
|
|
|
case _color:
|
2012-06-18 20:30:01 +02:00
|
|
|
case _value:
|
2012-06-18 17:10:04 +02:00
|
|
|
case color_spin:
|
2012-05-10 13:10:37 +02:00
|
|
|
break;
|
|
|
|
}
|
2012-05-03 15:34:17 +02:00
|
|
|
}
|
2012-06-17 21:19:29 +02:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void set_line_join(line_join_e join)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
if (join == MITER_JOIN)
|
|
|
|
context_->set_line_join(Cairo::LINE_JOIN_MITER);
|
|
|
|
else if (join == MITER_REVERT_JOIN)
|
|
|
|
context_->set_line_join(Cairo::LINE_JOIN_MITER);
|
|
|
|
else if (join == ROUND_JOIN)
|
|
|
|
context_->set_line_join(Cairo::LINE_JOIN_ROUND);
|
|
|
|
else
|
|
|
|
context_->set_line_join(Cairo::LINE_JOIN_BEVEL);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_line_cap(line_cap_e cap)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
if (cap == BUTT_CAP)
|
|
|
|
context_->set_line_cap(Cairo::LINE_CAP_BUTT);
|
|
|
|
else if (cap == SQUARE_CAP)
|
|
|
|
context_->set_line_cap(Cairo::LINE_CAP_SQUARE);
|
|
|
|
else
|
|
|
|
context_->set_line_cap(Cairo::LINE_CAP_ROUND);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_miter_limit(double limit)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->set_miter_limit(limit);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_line_width(double width)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->set_line_width(width);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_dash(dash_array const &dashes)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
std::valarray<double> d(dashes.size() * 2);
|
|
|
|
dash_array::const_iterator itr = dashes.begin();
|
|
|
|
dash_array::const_iterator end = dashes.end();
|
|
|
|
int index = 0;
|
|
|
|
|
|
|
|
for (; itr != end; ++itr)
|
|
|
|
{
|
|
|
|
d[index++] = itr->first;
|
|
|
|
d[index++] = itr->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
context_->set_dash(d, 0.0);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
2011-01-26 02:18:40 +01:00
|
|
|
void set_fill_rule(Cairo::FillRule fill_rule)
|
|
|
|
{
|
|
|
|
context_->set_fill_rule(fill_rule);
|
|
|
|
}
|
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void move_to(double x, double y)
|
|
|
|
{
|
2008-04-20 13:30:10 +02:00
|
|
|
#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 6, 0)
|
2010-06-02 13:03:30 +02:00
|
|
|
if (x < -32767.0) x = -32767.0;
|
|
|
|
else if (x > 32767.0) x = 32767.0;
|
|
|
|
if (y < -32767.0) y = -32767.0;
|
|
|
|
else if (y > 32767.0) y = 32767.0;
|
2008-04-20 13:30:10 +02:00
|
|
|
#endif
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->move_to(x, y);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
2011-01-26 02:18:40 +01:00
|
|
|
void curve_to(double ct1_x, double ct1_y, double ct2_x, double ct2_y, double end_x, double end_y)
|
|
|
|
{
|
|
|
|
context_->curve_to(ct1_x,ct1_y,ct2_x,ct2_y,end_x,end_y);
|
|
|
|
}
|
|
|
|
|
|
|
|
void close_path()
|
|
|
|
{
|
|
|
|
context_->close_path();
|
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void line_to(double x, double y)
|
|
|
|
{
|
|
|
|
#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 6, 0)
|
2010-06-02 13:03:30 +02:00
|
|
|
if (x < -32767.0) x = -32767.0;
|
|
|
|
else if (x > 32767.0) x = 32767.0;
|
|
|
|
if (y < -32767.0) y = -32767.0;
|
|
|
|
else if (y > 32767.0) y = 32767.0;
|
2009-12-16 21:02:06 +01:00
|
|
|
#endif
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->line_to(x, y);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
template <typename T>
|
2011-01-26 02:18:40 +01:00
|
|
|
void add_path(T& path, unsigned start_index = 0)
|
2009-12-16 21:02:06 +01:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
double x, y;
|
|
|
|
|
2011-01-26 02:18:40 +01:00
|
|
|
path.rewind(start_index);
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
for (unsigned cm = path.vertex(&x, &y); cm != SEG_END; cm = path.vertex(&x, &y))
|
|
|
|
{
|
|
|
|
if (cm == SEG_MOVETO)
|
|
|
|
{
|
|
|
|
move_to(x, y);
|
|
|
|
}
|
|
|
|
else if (cm == SEG_LINETO)
|
|
|
|
{
|
|
|
|
line_to(x, y);
|
|
|
|
}
|
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2011-01-26 02:18:40 +01:00
|
|
|
template <typename T>
|
|
|
|
void add_agg_path(T& path, unsigned start_index = 0)
|
|
|
|
{
|
2011-02-28 19:30:38 +01:00
|
|
|
double x=0;
|
|
|
|
double y=0;
|
2011-01-26 02:18:40 +01:00
|
|
|
|
|
|
|
path.rewind(start_index);
|
|
|
|
|
|
|
|
for (unsigned cm = path.vertex(&x, &y); !agg::is_stop(cm); cm = path.vertex(&x, &y))
|
|
|
|
{
|
|
|
|
if (agg::is_move_to(cm))
|
|
|
|
{
|
|
|
|
move_to(x, y);
|
|
|
|
}
|
|
|
|
else if (agg::is_drawing(cm))
|
|
|
|
{
|
|
|
|
if (agg::is_curve3(cm))
|
|
|
|
{
|
2011-02-28 19:30:38 +01:00
|
|
|
double end_x=0;
|
|
|
|
double end_y=0;
|
2012-04-10 00:51:04 +02:00
|
|
|
|
|
|
|
MAPNIK_LOG_WARN(cairo_renderer) << "Curve 3 not implemented";
|
|
|
|
|
2011-01-26 02:18:40 +01:00
|
|
|
path.vertex(&end_x, &end_y);
|
|
|
|
|
|
|
|
curve_to(x,y,x,y,end_x,end_y);
|
|
|
|
}
|
|
|
|
else if (agg::is_curve4(cm))
|
|
|
|
{
|
2011-02-28 19:30:38 +01:00
|
|
|
double ct2_x=0;
|
|
|
|
double ct2_y=0;
|
|
|
|
double end_x=0;
|
|
|
|
double end_y=0;
|
2011-01-26 02:18:40 +01:00
|
|
|
|
|
|
|
path.vertex(&ct2_x, &ct2_y);
|
|
|
|
path.vertex(&end_x, &end_y);
|
|
|
|
|
|
|
|
curve_to(x,y,ct2_x,ct2_y,end_x,end_y);
|
|
|
|
}
|
|
|
|
else if (agg::is_line_to(cm))
|
|
|
|
{
|
|
|
|
line_to(x, y);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-04-10 00:51:04 +02:00
|
|
|
MAPNIK_LOG_WARN(cairo_renderer) << "Unimplemented drawing command: " << cm;
|
2011-01-26 02:18:40 +01:00
|
|
|
move_to(x, y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (agg::is_close(cm))
|
|
|
|
{
|
|
|
|
close_path();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-04-10 00:51:04 +02:00
|
|
|
MAPNIK_LOG_WARN(cairo_renderer) << "Unimplemented path command: " << cm;
|
2011-01-26 02:18:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void rectangle(double x, double y, double w, double h)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->rectangle(x, y, w, h);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void stroke(void)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->stroke();
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void fill(void)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->fill();
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void paint(void)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->paint();
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void set_pattern(cairo_pattern const& pattern)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->set_source(pattern.pattern());
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2011-01-26 02:18:40 +01:00
|
|
|
void set_gradient(cairo_gradient const& pattern, const box2d<double> &bbox)
|
|
|
|
{
|
|
|
|
Cairo::RefPtr<Cairo::Gradient> p = pattern.gradient();
|
|
|
|
|
|
|
|
double bx1=bbox.minx();
|
|
|
|
double by1=bbox.miny();
|
|
|
|
double bx2=bbox.maxx();
|
|
|
|
double by2=bbox.maxy();
|
|
|
|
if (pattern.units() != USER_SPACE_ON_USE)
|
|
|
|
{
|
|
|
|
if (pattern.units() == OBJECT_BOUNDING_BOX)
|
|
|
|
{
|
|
|
|
context_->get_path_extents (bx1, by1, bx2, by2);
|
|
|
|
}
|
|
|
|
Cairo::Matrix m = p->get_matrix();
|
|
|
|
m.scale(1.0/(bx2-bx1),1.0/(by2-by1));
|
|
|
|
m.translate(-bx1,-by1);
|
|
|
|
p->set_matrix(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
context_->set_source(p);
|
|
|
|
}
|
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void add_image(double x, double y, image_data_32 & data, double opacity = 1.0)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
cairo_pattern pattern(data);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
pattern.set_origin(x, y);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->save();
|
|
|
|
context_->set_source(pattern.pattern());
|
|
|
|
context_->paint_with_alpha(opacity);
|
|
|
|
context_->restore();
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void set_font_face(cairo_face_manager & manager, face_ptr face)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->set_font_face(manager.get_face(face)->face());
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void set_font_matrix(Cairo::Matrix const& matrix)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->set_font_matrix(matrix);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-05-30 05:16:51 +02:00
|
|
|
void set_matrix(Cairo::Matrix const& matrix)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->set_matrix(matrix);
|
2010-05-30 05:16:51 +02:00
|
|
|
}
|
|
|
|
|
2011-01-26 02:18:40 +01:00
|
|
|
void transform(Cairo::Matrix const& matrix)
|
|
|
|
{
|
|
|
|
context_->transform(matrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
void translate(double x, double y)
|
|
|
|
{
|
|
|
|
context_->translate(x,y);
|
|
|
|
}
|
|
|
|
|
|
|
|
void save()
|
|
|
|
{
|
|
|
|
context_->save();
|
|
|
|
}
|
|
|
|
|
|
|
|
void restore()
|
|
|
|
{
|
|
|
|
context_->restore();
|
|
|
|
}
|
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void show_glyph(unsigned long index, double x, double y)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
Cairo::Glyph glyph;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
glyph.index = index;
|
|
|
|
glyph.x = x;
|
|
|
|
glyph.y = y;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
std::vector<Cairo::Glyph> glyphs;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
glyphs.push_back(glyph);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->show_glyphs(glyphs);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
void glyph_path(unsigned long index, double x, double y)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
Cairo::Glyph glyph;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
glyph.index = index;
|
|
|
|
glyph.x = x;
|
|
|
|
glyph.y = y;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
std::vector<Cairo::Glyph> glyphs;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
glyphs.push_back(glyph);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
context_->glyph_path(glyphs);
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-03-19 10:33:57 +01:00
|
|
|
void add_text(text_path & path,
|
2010-06-02 13:03:30 +02:00
|
|
|
cairo_face_manager & manager,
|
2012-01-26 14:04:08 +01:00
|
|
|
face_manager<freetype_engine> &font_manager)
|
2009-12-16 21:02:06 +01:00
|
|
|
{
|
2012-02-18 13:07:23 +01:00
|
|
|
double sx = path.center.x;
|
|
|
|
double sy = path.center.y;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
path.rewind();
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
for (int iii = 0; iii < path.num_nodes(); iii++)
|
|
|
|
{
|
2012-03-04 03:53:39 +01:00
|
|
|
char_info_ptr c;
|
2010-06-02 13:03:30 +02:00
|
|
|
double x, y, angle;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-03-04 03:53:39 +01:00
|
|
|
path.vertex(&c, &x, &y, &angle);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-03-04 03:53:39 +01:00
|
|
|
face_set_ptr faces = font_manager.get_face_set(c->format->face_name, c->format->fontset);
|
|
|
|
float text_size = c->format->text_size;
|
2012-01-26 14:04:08 +01:00
|
|
|
faces->set_character_sizes(text_size);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-03-04 03:53:39 +01:00
|
|
|
glyph_ptr glyph = faces->get_glyph(c->c);
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
if (glyph)
|
|
|
|
{
|
|
|
|
Cairo::Matrix matrix;
|
2008-07-26 01:26:02 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
matrix.xx = text_size * cos(angle);
|
|
|
|
matrix.xy = text_size * sin(angle);
|
|
|
|
matrix.yx = text_size * -sin(angle);
|
|
|
|
matrix.yy = text_size * cos(angle);
|
|
|
|
matrix.x0 = 0;
|
|
|
|
matrix.y0 = 0;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
set_font_matrix(matrix);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
set_font_face(manager, glyph->get_face());
|
2008-07-26 01:26:02 +02:00
|
|
|
|
2012-01-26 14:04:08 +01:00
|
|
|
glyph_path(glyph->get_index(), sx + x, sy - y);
|
2012-03-04 03:53:39 +01:00
|
|
|
set_line_width(c->format->halo_radius);
|
2012-01-26 14:04:08 +01:00
|
|
|
set_line_join(ROUND_JOIN);
|
2012-03-04 03:53:39 +01:00
|
|
|
set_color(c->format->halo_fill);
|
2012-01-26 14:04:08 +01:00
|
|
|
stroke();
|
2012-03-04 03:53:39 +01:00
|
|
|
set_color(c->format->fill);
|
2010-06-02 13:03:30 +02:00
|
|
|
show_glyph(glyph->get_index(), sx + x, sy - y);
|
|
|
|
}
|
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
Cairo::RefPtr<Cairo::Context> context_;
|
|
|
|
};
|
|
|
|
|
|
|
|
cairo_renderer_base::cairo_renderer_base(Map const& m, Cairo::RefPtr<Cairo::Context> const& context, unsigned offset_x, unsigned offset_y)
|
|
|
|
: m_(m),
|
|
|
|
context_(context),
|
2010-06-25 17:23:35 +02:00
|
|
|
t_(m.width(),m.height(),m.get_current_extent(),offset_x,offset_y),
|
2012-03-10 01:20:50 +01:00
|
|
|
font_engine_(boost::make_shared<freetype_engine>()),
|
2009-12-16 21:02:06 +01:00
|
|
|
font_manager_(*font_engine_),
|
|
|
|
face_manager_(font_engine_,font_manager_),
|
2010-06-25 17:23:35 +02:00
|
|
|
detector_(box2d<double>(-m.buffer_size() ,-m.buffer_size() , m.width() + m.buffer_size() ,m.height() + m.buffer_size()))
|
2009-12-16 21:02:06 +01:00
|
|
|
{
|
2012-04-09 21:41:56 +02:00
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: Scale=" << m.scale();
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
cairo_renderer<Cairo::Context>::cairo_renderer(Map const& m, Cairo::RefPtr<Cairo::Context> const& context, unsigned offset_x, unsigned offset_y)
|
|
|
|
: feature_style_processor<cairo_renderer>(m),
|
|
|
|
cairo_renderer_base(m,context,offset_x,offset_y)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
cairo_renderer<Cairo::Surface>::cairo_renderer(Map const& m, Cairo::RefPtr<Cairo::Surface> const& surface, unsigned offset_x, unsigned offset_y)
|
|
|
|
: feature_style_processor<cairo_renderer>(m),
|
|
|
|
cairo_renderer_base(m,Cairo::Context::create(surface),offset_x,offset_y)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_renderer_base::~cairo_renderer_base() {}
|
|
|
|
|
|
|
|
void cairo_renderer_base::start_map_processing(Map const& map)
|
|
|
|
{
|
2012-04-09 21:41:56 +02:00
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: Start map processing bbox=" << map.get_current_extent();
|
2008-04-20 01:22:03 +02:00
|
|
|
|
2008-04-20 13:30:10 +02:00
|
|
|
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0)
|
2012-02-02 02:53:35 +01:00
|
|
|
box2d<double> bounds = t_.forward(t_.extent());
|
|
|
|
context_->rectangle(bounds.minx(), bounds.miny(), bounds.maxx(), bounds.maxy());
|
|
|
|
context_->clip();
|
2012-05-18 20:31:08 +02:00
|
|
|
#else
|
|
|
|
#warning building against cairo older that 1.6.0, map clipping is disabled
|
2008-04-20 13:30:10 +02:00
|
|
|
#endif
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
boost::optional<color> bg = m_.background();
|
|
|
|
if (bg)
|
|
|
|
{
|
|
|
|
cairo_context context(context_);
|
|
|
|
context.set_color(*bg);
|
|
|
|
context.paint();
|
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
template <>
|
|
|
|
void cairo_renderer<Cairo::Context>::end_map_processing(Map const& )
|
|
|
|
{
|
2012-04-09 21:41:56 +02:00
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: End map processing";
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2009-02-06 01:46:29 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
template <>
|
|
|
|
void cairo_renderer<Cairo::Surface>::end_map_processing(Map const& )
|
|
|
|
{
|
2012-04-09 21:41:56 +02:00
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: End map processing";
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
context_->show_page();
|
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-03-06 14:07:04 +01:00
|
|
|
void cairo_renderer_base::start_layer_processing(layer const& lay, box2d<double> const& query_extent)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2012-04-09 21:41:56 +02:00
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: Start processing layer=" << lay.name() ;
|
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: -- datasource=" << lay.datasource().get();
|
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: -- query_extent=" << query_extent;
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
if (lay.clear_label_cache())
|
|
|
|
{
|
|
|
|
detector_.clear();
|
|
|
|
}
|
2012-03-08 12:07:13 +01:00
|
|
|
query_extent_ = query_extent;
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2012-03-13 15:56:11 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
void cairo_renderer_base::end_layer_processing(layer const&)
|
|
|
|
{
|
2012-04-09 21:41:56 +02:00
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: End layer processing";
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-04-18 16:09:12 +02:00
|
|
|
void cairo_renderer_base::start_style_processing(feature_type_style const& st)
|
|
|
|
{
|
2012-05-03 13:17:37 +02:00
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer:start style processing";
|
2012-04-18 16:09:12 +02:00
|
|
|
}
|
2012-05-03 13:17:37 +02:00
|
|
|
|
2012-04-18 16:09:12 +02:00
|
|
|
void cairo_renderer_base::end_style_processing(feature_type_style const& st)
|
|
|
|
{
|
2012-05-03 13:17:37 +02:00
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer:end style processing";
|
2012-04-18 16:09:12 +02:00
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
void cairo_renderer_base::process(polygon_symbolizer const& sym,
|
2012-06-16 04:17:26 +02:00
|
|
|
mapnik::feature_impl & feature,
|
2012-02-02 02:53:35 +01:00
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
|
|
|
cairo_context context(context_);
|
2012-05-10 13:10:37 +02:00
|
|
|
context.set_operator(sym.comp_op());
|
2012-02-02 02:53:35 +01:00
|
|
|
context.set_color(sym.get_fill(), sym.get_opacity());
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-05-27 23:50:09 +02:00
|
|
|
agg::trans_affine tr;
|
2012-06-16 04:17:26 +02:00
|
|
|
evaluate_transform(tr, feature, sym.get_transform());
|
2012-05-27 23:50:09 +02:00
|
|
|
|
2012-05-09 16:45:44 +02:00
|
|
|
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
|
2012-05-27 23:50:09 +02:00
|
|
|
vertex_converter<box2d<double>, cairo_context, polygon_symbolizer,
|
|
|
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
|
|
|
converter(query_extent_,context,sym,t_,prj_trans,tr,1.0);
|
2012-05-10 13:10:37 +02:00
|
|
|
|
|
|
|
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
|
|
|
|
converter.set<transform_tag>(); //always transform
|
2012-05-09 16:45:44 +02:00
|
|
|
converter.set<affine_transform_tag>();
|
|
|
|
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-06-16 04:17:26 +02:00
|
|
|
BOOST_FOREACH( geometry_type & geom, feature.paths())
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
if (geom.num_points() > 2)
|
2012-05-10 13:10:37 +02:00
|
|
|
{
|
2012-05-09 16:45:44 +02:00
|
|
|
converter.apply(geom);
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2012-03-15 12:29:57 +01:00
|
|
|
// fill polygon
|
|
|
|
context.fill();
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2012-03-13 15:56:11 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
void cairo_renderer_base::process(building_symbolizer const& sym,
|
2012-06-16 04:17:26 +02:00
|
|
|
mapnik::feature_impl & feature,
|
2012-02-02 02:53:35 +01:00
|
|
|
proj_transform const& prj_trans)
|
2011-12-13 15:28:18 +01:00
|
|
|
{
|
2012-05-31 13:13:09 +02:00
|
|
|
typedef coord_transform<CoordTransform,geometry_type> path_type;
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
cairo_context context(context_);
|
2012-05-10 13:10:37 +02:00
|
|
|
context.set_operator(sym.comp_op());
|
2012-02-02 02:53:35 +01:00
|
|
|
color const& fill = sym.get_fill();
|
|
|
|
double height = 0.0;
|
|
|
|
expression_ptr height_expr = sym.height();
|
|
|
|
if (height_expr)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-06-16 04:17:26 +02:00
|
|
|
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(feature), *height_expr);
|
2012-05-30 17:27:55 +02:00
|
|
|
height = result.to_double(); //scale_factor is always 1.0 atm
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2012-01-09 13:41:38 +01:00
|
|
|
|
2012-06-16 04:17:26 +02:00
|
|
|
for (unsigned i = 0; i < feature.num_geometries(); ++i)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2012-06-16 04:17:26 +02:00
|
|
|
geometry_type const& geom = feature.get_geometry(i);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
if (geom.num_points() > 2)
|
2008-02-23 01:17:53 +01:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
boost::scoped_ptr<geometry_type> frame(new geometry_type(LineString));
|
|
|
|
boost::scoped_ptr<geometry_type> roof(new geometry_type(Polygon));
|
|
|
|
std::deque<segment_t> face_segments;
|
|
|
|
double x0(0);
|
|
|
|
double y0(0);
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
geom.rewind(0);
|
|
|
|
unsigned cm = geom.vertex(&x0, &y0);
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
for (unsigned j = 1; j < geom.num_points(); ++j)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
double x=0;
|
|
|
|
double y=0;
|
|
|
|
|
|
|
|
cm = geom.vertex(&x,&y);
|
|
|
|
|
|
|
|
if (cm == SEG_MOVETO)
|
|
|
|
{
|
|
|
|
frame->move_to(x,y);
|
|
|
|
}
|
|
|
|
else if (cm == SEG_LINETO)
|
|
|
|
{
|
|
|
|
frame->line_to(x,y);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j != 0)
|
|
|
|
{
|
|
|
|
face_segments.push_back(segment_t(x0, y0, x, y));
|
|
|
|
}
|
|
|
|
|
|
|
|
x0 = x;
|
|
|
|
y0 = y;
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
std::sort(face_segments.begin(), face_segments.end(), y_order);
|
|
|
|
std::deque<segment_t>::const_iterator itr = face_segments.begin();
|
|
|
|
for (; itr != face_segments.end(); ++itr)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
boost::scoped_ptr<geometry_type> faces(new geometry_type(Polygon));
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
faces->move_to(itr->get<0>(), itr->get<1>());
|
|
|
|
faces->line_to(itr->get<2>(), itr->get<3>());
|
|
|
|
faces->line_to(itr->get<2>(), itr->get<3>() + height);
|
|
|
|
faces->line_to(itr->get<0>(), itr->get<1>() + height);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
path_type faces_path(t_, *faces, prj_trans);
|
|
|
|
context.set_color(int(fill.red() * 0.8), int(fill.green() * 0.8),
|
|
|
|
int(fill.blue() * 0.8), fill.alpha() * sym.get_opacity() / 255.0);
|
|
|
|
context.add_path(faces_path);
|
|
|
|
context.fill();
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
frame->move_to(itr->get<0>(), itr->get<1>());
|
|
|
|
frame->line_to(itr->get<0>(), itr->get<1>() + height);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
|
|
|
geom.rewind(0);
|
|
|
|
for (unsigned j = 0; j < geom.num_points(); ++j)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
double x, y;
|
|
|
|
unsigned cm = geom.vertex(&x, &y);
|
|
|
|
|
|
|
|
if (cm == SEG_MOVETO)
|
|
|
|
{
|
|
|
|
frame->move_to(x, y + height);
|
|
|
|
roof->move_to(x, y + height);
|
|
|
|
}
|
|
|
|
else if (cm == SEG_LINETO)
|
|
|
|
{
|
|
|
|
frame->line_to(x, y + height);
|
|
|
|
roof->line_to(x, y + height);
|
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-05-30 17:29:39 +02:00
|
|
|
//path_type path(t_, *frame, prj_trans);
|
|
|
|
//context.set_color(128, 128, 128, sym.get_opacity());
|
|
|
|
//context.add_path(path);
|
|
|
|
//context.stroke();
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
path_type roof_path(t_, *roof, prj_trans);
|
|
|
|
context.set_color(sym.get_fill(), sym.get_opacity());
|
|
|
|
context.add_path(roof_path);
|
|
|
|
context.fill();
|
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
void cairo_renderer_base::process(line_symbolizer const& sym,
|
2012-06-16 04:17:26 +02:00
|
|
|
mapnik::feature_impl & feature,
|
2012-02-02 02:53:35 +01:00
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
2012-03-15 12:29:57 +01:00
|
|
|
cairo_context context(context_);
|
2012-05-10 13:10:37 +02:00
|
|
|
mapnik::stroke const& stroke_ = sym.get_stroke();
|
|
|
|
context.set_operator(sym.comp_op());
|
2012-05-03 15:34:17 +02:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
context.set_color(stroke_.get_color(), stroke_.get_opacity());
|
2012-03-15 12:29:57 +01:00
|
|
|
context.set_line_join(stroke_.get_line_join());
|
|
|
|
context.set_line_cap(stroke_.get_line_cap());
|
|
|
|
context.set_miter_limit(4.0);
|
|
|
|
context.set_line_width(stroke_.get_width());
|
|
|
|
if (stroke_.has_dash())
|
|
|
|
{
|
|
|
|
context.set_dash(stroke_.get_dash_array());
|
|
|
|
}
|
2012-03-23 00:37:24 +01:00
|
|
|
|
2012-05-27 23:50:09 +02:00
|
|
|
agg::trans_affine tr;
|
2012-06-16 04:17:26 +02:00
|
|
|
evaluate_transform(tr, feature, sym.get_transform());
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-05-09 16:45:44 +02:00
|
|
|
typedef boost::mpl::vector<clip_line_tag,transform_tag, offset_transform_tag, affine_transform_tag, smooth_tag> conv_types;
|
2012-05-27 23:50:09 +02:00
|
|
|
vertex_converter<box2d<double>, cairo_context, line_symbolizer,
|
|
|
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
|
|
|
converter(query_extent_,context,sym,t_,prj_trans,tr,1.0);
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-05-09 16:45:44 +02:00
|
|
|
if (sym.clip()) converter.set<clip_line_tag>(); // optional clip (default: true)
|
|
|
|
converter.set<transform_tag>(); // always transform
|
|
|
|
|
|
|
|
if (fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
|
|
|
|
converter.set<affine_transform_tag>(); // optional affine transform
|
|
|
|
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-06-16 04:17:26 +02:00
|
|
|
BOOST_FOREACH( geometry_type & geom, feature.paths())
|
2012-05-09 16:45:44 +02:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
if (geom.num_points() > 1)
|
2008-02-23 01:17:53 +01:00
|
|
|
{
|
2012-05-09 16:45:44 +02:00
|
|
|
converter.apply(geom);
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2012-05-09 16:45:44 +02:00
|
|
|
// stroke
|
2012-03-15 12:29:57 +01:00
|
|
|
context.stroke();
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& marker, const agg::trans_affine & tr, double opacity, bool recenter)
|
2011-01-26 02:18:40 +01:00
|
|
|
|
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
cairo_context context(context_);
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
if (marker.is_vector())
|
2011-01-26 02:18:40 +01:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
box2d<double> bbox;
|
|
|
|
bbox = (*marker.get_vector_data())->bounding_box();
|
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
agg::trans_affine mtx = tr;
|
|
|
|
|
|
|
|
if (recenter)
|
|
|
|
{
|
|
|
|
coord<double,2> c = bbox.center();
|
|
|
|
// center the svg marker on '0,0'
|
|
|
|
mtx = agg::trans_affine_translation(-c.x,-c.y);
|
|
|
|
// apply symbol transformation to get to map space
|
|
|
|
mtx *= tr;
|
|
|
|
// render the marker at the center of the marker box
|
|
|
|
mtx.translate(pos.x+0.5 * marker.width(), pos.y+0.5 * marker.height());
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-05-31 13:13:09 +02:00
|
|
|
typedef coord_transform<CoordTransform,geometry_type> path_type;
|
2012-03-28 01:21:11 +02:00
|
|
|
agg::trans_affine transform;
|
2012-02-02 02:53:35 +01:00
|
|
|
mapnik::path_ptr vmarker = *marker.get_vector_data();
|
2012-03-08 17:37:58 +01:00
|
|
|
using namespace mapnik::svg;
|
2012-02-02 02:53:35 +01:00
|
|
|
agg::pod_bvector<path_attributes> const & attributes_ = vmarker->attributes();
|
|
|
|
for(unsigned i = 0; i < attributes_.size(); ++i)
|
2011-01-26 02:18:40 +01:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
mapnik::svg::path_attributes const& attr = attributes_[i];
|
|
|
|
if (!attr.visibility_flag)
|
|
|
|
continue;
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
context.save();
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
transform = attr.transform;
|
2012-02-02 02:53:35 +01:00
|
|
|
transform *= mtx;
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
// TODO - this 'is_valid' check is not used in the AGG renderer and also
|
|
|
|
// appears to lead to bogus results with
|
|
|
|
// tests/data/good_maps/markers_symbolizer_lines_file.xml
|
|
|
|
if (/*transform.is_valid() && */ !transform.is_identity())
|
2011-01-26 02:18:40 +01:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
double m[6];
|
|
|
|
transform.store_to(m);
|
|
|
|
context.transform(Cairo::Matrix(m[0],m[1],m[2],m[3],m[4],m[5]));
|
2011-01-26 02:18:40 +01:00
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
vertex_stl_adapter<svg_path_storage> stl_storage(vmarker->source());
|
|
|
|
svg_path_adapter svg_path(stl_storage);
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT)
|
2011-01-26 02:18:40 +01:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
context.add_agg_path(svg_path,attr.index);
|
|
|
|
if (attr.even_odd_flag)
|
|
|
|
{
|
|
|
|
context.set_fill_rule(Cairo::FILL_RULE_EVEN_ODD);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
context.set_fill_rule(Cairo::FILL_RULE_WINDING);
|
|
|
|
}
|
|
|
|
if(attr.fill_gradient.get_gradient_type() != NO_GRADIENT)
|
|
|
|
{
|
|
|
|
cairo_gradient g(attr.fill_gradient,attr.opacity*opacity);
|
|
|
|
|
|
|
|
context.set_gradient(g,bbox);
|
|
|
|
context.fill();
|
|
|
|
}
|
|
|
|
else if(attr.fill_flag)
|
|
|
|
{
|
2012-05-30 17:26:34 +02:00
|
|
|
double fill_opacity = attr.opacity * opacity * attr.fill_color.opacity();
|
|
|
|
context.set_color(attr.fill_color.r,attr.fill_color.g,attr.fill_color.b, fill_opacity);
|
2012-02-02 02:53:35 +01:00
|
|
|
context.fill();
|
|
|
|
}
|
2011-01-26 02:18:40 +01:00
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-05-30 17:26:34 +02:00
|
|
|
if (attr.stroke_gradient.get_gradient_type() != NO_GRADIENT || attr.stroke_flag)
|
2011-01-26 02:18:40 +01:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
context.add_agg_path(svg_path,attr.index);
|
|
|
|
if(attr.stroke_gradient.get_gradient_type() != NO_GRADIENT)
|
|
|
|
{
|
|
|
|
context.set_line_width(attr.stroke_width);
|
|
|
|
context.set_line_cap(line_cap_enum(attr.line_cap));
|
|
|
|
context.set_line_join(line_join_enum(attr.line_join));
|
|
|
|
context.set_miter_limit(attr.miter_limit);
|
|
|
|
cairo_gradient g(attr.stroke_gradient,attr.opacity*opacity);
|
|
|
|
context.set_gradient(g,bbox);
|
|
|
|
context.stroke();
|
|
|
|
}
|
2012-05-30 17:26:34 +02:00
|
|
|
else if (attr.stroke_flag)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2012-05-30 17:26:34 +02:00
|
|
|
double stroke_opacity = attr.opacity * opacity * attr.stroke_color.opacity();
|
|
|
|
context.set_color(attr.stroke_color.r,attr.stroke_color.g,attr.stroke_color.b, stroke_opacity);
|
2012-02-02 02:53:35 +01:00
|
|
|
context.set_line_width(attr.stroke_width);
|
|
|
|
context.set_line_cap(line_cap_enum(attr.line_cap));
|
|
|
|
context.set_line_join(line_join_enum(attr.line_join));
|
|
|
|
context.set_miter_limit(attr.miter_limit);
|
|
|
|
context.stroke();
|
|
|
|
}
|
2011-01-26 02:18:40 +01:00
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
context.restore();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (marker.is_bitmap())
|
|
|
|
{
|
2012-02-20 19:32:34 +01:00
|
|
|
context.add_image(pos.x, pos.y, **marker.get_bitmap_data(), opacity);
|
2011-01-26 02:18:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
void cairo_renderer_base::process(point_symbolizer const& sym,
|
2012-06-16 04:17:26 +02:00
|
|
|
mapnik::feature_impl & feature,
|
2012-02-02 02:53:35 +01:00
|
|
|
proj_transform const& prj_trans)
|
2010-03-03 04:26:12 +01:00
|
|
|
{
|
2012-06-16 04:17:26 +02:00
|
|
|
std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
boost::optional<marker_ptr> marker;
|
|
|
|
if ( !filename.empty() )
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
marker = marker_cache::instance()->find(filename, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
marker.reset(boost::make_shared<mapnik::marker>());
|
|
|
|
}
|
2011-02-01 09:16:32 +01:00
|
|
|
|
2012-05-27 23:50:09 +02:00
|
|
|
agg::trans_affine mtx;
|
2012-06-16 04:17:26 +02:00
|
|
|
evaluate_transform(mtx, feature, sym.get_image_transform());
|
2012-05-27 23:50:09 +02:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
if (marker)
|
|
|
|
{
|
2012-06-16 04:17:26 +02:00
|
|
|
for (unsigned i = 0; i < feature.num_geometries(); ++i)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2012-06-16 04:17:26 +02:00
|
|
|
geometry_type const& geom = feature.get_geometry(i);
|
2012-02-02 02:53:35 +01:00
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
double z = 0;
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT)
|
|
|
|
geom.label_position(&x, &y);
|
|
|
|
else
|
|
|
|
geom.label_interior_position(&x, &y);
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
prj_trans.backward(x, y, z);
|
|
|
|
t_.forward(&x, &y);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
int w = (*marker)->width();
|
|
|
|
int h = (*marker)->height();
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
int px = int(floor(x - 0.5 * w));
|
|
|
|
int py = int(floor(y - 0.5 * h));
|
|
|
|
box2d<double> label_ext (px, py, px + w, py + h);
|
|
|
|
if (sym.get_allow_overlap() ||
|
|
|
|
detector_.has_placement(label_ext))
|
2010-07-06 02:37:05 +02:00
|
|
|
{
|
2012-02-20 19:32:34 +01:00
|
|
|
render_marker(pixel_position(px,py),**marker, mtx, sym.get_opacity());
|
2012-02-02 02:53:35 +01:00
|
|
|
|
|
|
|
if (!sym.get_ignore_placement())
|
|
|
|
detector_.insert(label_ext);
|
|
|
|
metawriter_with_properties writer = sym.get_metawriter();
|
|
|
|
if (writer.first)
|
|
|
|
{
|
2012-06-16 04:17:26 +02:00
|
|
|
writer.first->add_box(label_ext, feature, t_, writer.second);
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2010-07-06 02:37:05 +02:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
void cairo_renderer_base::process(shield_symbolizer const& sym,
|
2012-06-16 04:17:26 +02:00
|
|
|
mapnik::feature_impl & feature,
|
2012-02-02 02:53:35 +01:00
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
|
|
|
shield_symbolizer_helper<face_manager<freetype_engine>,
|
2012-01-29 05:03:38 +01:00
|
|
|
label_collision_detector4> helper(
|
2012-06-16 04:17:26 +02:00
|
|
|
sym, feature, prj_trans,
|
2012-01-29 05:03:38 +01:00
|
|
|
detector_.extent().width(), detector_.extent().height(),
|
|
|
|
1.0 /*scale_factor*/,
|
2012-03-08 12:07:13 +01:00
|
|
|
t_, font_manager_, detector_, query_extent_);
|
2012-02-02 02:53:35 +01:00
|
|
|
cairo_context context(context_);
|
2012-05-10 13:10:37 +02:00
|
|
|
context.set_operator(sym.comp_op());
|
|
|
|
|
|
|
|
while (helper.next())
|
2012-05-09 16:45:44 +02:00
|
|
|
{
|
2012-03-03 20:15:24 +01:00
|
|
|
placements_type &placements = helper.placements();
|
|
|
|
for (unsigned int ii = 0; ii < placements.size(); ++ii)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2012-03-03 20:15:24 +01:00
|
|
|
pixel_position marker_pos = helper.get_marker_position(placements[ii]);
|
2012-02-20 19:32:34 +01:00
|
|
|
render_marker(marker_pos,
|
2012-05-01 17:47:33 +02:00
|
|
|
helper.get_marker(), helper.get_image_transform(),
|
2012-02-02 02:53:35 +01:00
|
|
|
sym.get_opacity());
|
2012-03-03 20:15:24 +01:00
|
|
|
context.add_text(placements[ii], face_manager_, font_manager_);
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
void cairo_renderer_base::process(line_pattern_symbolizer const& sym,
|
2012-06-16 04:17:26 +02:00
|
|
|
mapnik::feature_impl & feature,
|
2012-02-02 02:53:35 +01:00
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
2012-03-08 12:07:13 +01:00
|
|
|
typedef agg::conv_clip_polyline<geometry_type> clipped_geometry_type;
|
2012-05-31 13:13:09 +02:00
|
|
|
typedef coord_transform<CoordTransform,clipped_geometry_type> path_type;
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-06-16 04:17:26 +02:00
|
|
|
std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
|
2012-02-02 02:53:35 +01:00
|
|
|
boost::optional<mapnik::marker_ptr> marker = mapnik::marker_cache::instance()->find(filename,true);
|
|
|
|
if (!marker && !(*marker)->is_bitmap()) return;
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
unsigned width((*marker)->width());
|
|
|
|
unsigned height((*marker)->height());
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
cairo_context context(context_);
|
2012-05-10 13:10:37 +02:00
|
|
|
context.set_operator(sym.comp_op());
|
2012-02-02 02:53:35 +01:00
|
|
|
cairo_pattern pattern(**((*marker)->get_bitmap_data()));
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
pattern.set_extend(Cairo::EXTEND_REPEAT);
|
|
|
|
pattern.set_filter(Cairo::FILTER_BILINEAR);
|
|
|
|
context.set_line_width(height);
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-06-16 04:17:26 +02:00
|
|
|
for (unsigned i = 0; i < feature.num_geometries(); ++i)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-06-16 04:17:26 +02:00
|
|
|
geometry_type & geom = feature.get_geometry(i);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
if (geom.num_points() > 1)
|
2008-02-23 01:17:53 +01:00
|
|
|
{
|
2012-03-08 12:07:13 +01:00
|
|
|
clipped_geometry_type clipped(geom);
|
|
|
|
clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy());
|
|
|
|
path_type path(t_,clipped,prj_trans);
|
2012-03-13 15:56:11 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
double length(0);
|
|
|
|
double x0(0), y0(0);
|
|
|
|
double x, y;
|
|
|
|
|
|
|
|
for (unsigned cm = path.vertex(&x, &y); cm != SEG_END; cm = path.vertex(&x, &y))
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
if (cm == SEG_MOVETO)
|
|
|
|
{
|
|
|
|
length = 0.0;
|
|
|
|
}
|
|
|
|
else if (cm == SEG_LINETO)
|
|
|
|
{
|
|
|
|
double dx = x - x0;
|
|
|
|
double dy = y - y0;
|
|
|
|
double angle = atan2(dy, dx);
|
|
|
|
double offset = fmod(length, width);
|
|
|
|
|
|
|
|
Cairo::Matrix matrix;
|
|
|
|
cairo_matrix_init_identity(&matrix);
|
|
|
|
cairo_matrix_translate(&matrix,x0,y0);
|
|
|
|
cairo_matrix_rotate(&matrix,angle);
|
|
|
|
cairo_matrix_translate(&matrix,-offset,0.5*height);
|
|
|
|
cairo_matrix_invert(&matrix);
|
|
|
|
|
|
|
|
pattern.set_matrix(matrix);
|
|
|
|
|
|
|
|
context.set_pattern(pattern);
|
|
|
|
|
|
|
|
context.move_to(x0, y0);
|
|
|
|
context.line_to(x, y);
|
|
|
|
context.stroke();
|
|
|
|
|
|
|
|
length = length + hypot(x - x0, y - y0);
|
|
|
|
}
|
|
|
|
|
|
|
|
x0 = x;
|
|
|
|
y0 = y;
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
void cairo_renderer_base::process(polygon_pattern_symbolizer const& sym,
|
2012-06-16 04:17:26 +02:00
|
|
|
mapnik::feature_impl & feature,
|
2012-02-02 02:53:35 +01:00
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
|
|
|
cairo_context context(context_);
|
2012-05-10 13:10:37 +02:00
|
|
|
context.set_operator(sym.comp_op());
|
|
|
|
|
2012-06-16 04:17:26 +02:00
|
|
|
std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
|
2012-02-02 02:53:35 +01:00
|
|
|
boost::optional<mapnik::marker_ptr> marker = mapnik::marker_cache::instance()->find(filename,true);
|
|
|
|
if (!marker && !(*marker)->is_bitmap()) return;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
cairo_pattern pattern(**((*marker)->get_bitmap_data()));
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
pattern.set_extend(Cairo::EXTEND_REPEAT);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
context.set_pattern(pattern);
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-05-27 23:50:09 +02:00
|
|
|
agg::trans_affine tr;
|
2012-06-16 04:17:26 +02:00
|
|
|
evaluate_transform(tr, feature, sym.get_transform());
|
2012-05-27 23:50:09 +02:00
|
|
|
|
2012-05-09 16:45:44 +02:00
|
|
|
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
|
2012-05-27 23:50:09 +02:00
|
|
|
vertex_converter<box2d<double>, cairo_context, polygon_pattern_symbolizer,
|
|
|
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
|
|
|
converter(query_extent_,context,sym,t_,prj_trans,tr,1.0);
|
2012-05-10 13:10:37 +02:00
|
|
|
|
|
|
|
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
|
|
|
|
converter.set<transform_tag>(); //always transform
|
2012-05-09 16:45:44 +02:00
|
|
|
converter.set<affine_transform_tag>();
|
|
|
|
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-06-16 04:17:26 +02:00
|
|
|
BOOST_FOREACH( geometry_type & geom, feature.paths())
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
if (geom.num_points() > 2)
|
2012-05-10 13:10:37 +02:00
|
|
|
{
|
2012-05-09 16:45:44 +02:00
|
|
|
converter.apply(geom);
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2012-05-10 13:10:37 +02:00
|
|
|
|
|
|
|
// fill polygon
|
2012-05-03 16:28:57 +02:00
|
|
|
context.fill();
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
void cairo_renderer_base::process(raster_symbolizer const& sym,
|
2012-06-16 04:17:26 +02:00
|
|
|
mapnik::feature_impl & feature,
|
2012-02-02 02:53:35 +01:00
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
2012-06-16 04:17:26 +02:00
|
|
|
raster_ptr const& source = feature.get_raster();
|
2012-02-02 02:53:35 +01:00
|
|
|
if (source)
|
2010-03-03 04:23:53 +01:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
// If there's a colorizer defined, use it to color the raster in-place
|
|
|
|
raster_colorizer_ptr colorizer = sym.get_colorizer();
|
|
|
|
if (colorizer)
|
2012-06-16 04:17:26 +02:00
|
|
|
colorizer->colorize(source,feature);
|
2012-02-02 02:53:35 +01:00
|
|
|
|
|
|
|
box2d<double> target_ext = box2d<double>(source->ext_);
|
|
|
|
prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS);
|
|
|
|
|
|
|
|
box2d<double> ext=t_.forward(target_ext);
|
|
|
|
int start_x = (int)ext.minx();
|
|
|
|
int start_y = (int)ext.miny();
|
|
|
|
int end_x = (int)ceil(ext.maxx());
|
|
|
|
int end_y = (int)ceil(ext.maxy());
|
|
|
|
int raster_width = end_x - start_x;
|
|
|
|
int raster_height = end_y - start_y;
|
|
|
|
double err_offs_x = ext.minx() - start_x;
|
|
|
|
double err_offs_y = ext.miny() - start_y;
|
|
|
|
|
|
|
|
if (raster_width > 0 && raster_height > 0)
|
|
|
|
{
|
|
|
|
double scale_factor = ext.width() / source->data_.width();
|
|
|
|
image_data_32 target_data(raster_width,raster_height);
|
|
|
|
raster target(target_ext, target_data);
|
|
|
|
|
|
|
|
reproject_raster(target, *source, prj_trans, err_offs_x, err_offs_y,
|
|
|
|
sym.get_mesh_size(),
|
|
|
|
sym.calculate_filter_factor(),
|
|
|
|
scale_factor,
|
|
|
|
sym.get_scaling());
|
|
|
|
|
|
|
|
cairo_context context(context_);
|
2012-05-10 13:10:37 +02:00
|
|
|
context.set_operator(sym.comp_op());
|
2012-02-02 02:53:35 +01:00
|
|
|
//TODO -- support for advanced image merging
|
|
|
|
context.add_image(start_x, start_y, target.data_, sym.get_opacity());
|
|
|
|
}
|
2010-03-03 04:23:53 +01:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
void cairo_renderer_base::process(markers_symbolizer const& sym,
|
2012-06-16 04:17:26 +02:00
|
|
|
mapnik::feature_impl & feature,
|
2012-02-02 02:53:35 +01:00
|
|
|
proj_transform const& prj_trans)
|
2010-05-30 05:16:51 +02:00
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
cairo_context context(context_);
|
2012-05-10 13:10:37 +02:00
|
|
|
context.set_operator(sym.comp_op());
|
|
|
|
double scale_factor_ = 1;
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
typedef agg::conv_clip_polyline<geometry_type> clipped_geometry_type;
|
2012-05-31 13:13:09 +02:00
|
|
|
typedef coord_transform<CoordTransform,clipped_geometry_type> path_type;
|
2012-03-28 01:21:11 +02:00
|
|
|
|
|
|
|
agg::trans_affine tr;
|
2012-06-16 04:17:26 +02:00
|
|
|
evaluate_transform(tr, feature, sym.get_image_transform());
|
2012-05-27 23:50:09 +02:00
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
// TODO - use this?
|
|
|
|
//tr = agg::trans_affine_scaling(scale_factor_) * tr;
|
2012-06-16 04:17:26 +02:00
|
|
|
std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature);
|
2012-03-28 01:21:11 +02:00
|
|
|
marker_placement_e placement_method = sym.get_marker_placement();
|
|
|
|
marker_type_e marker_type = sym.get_marker_type();
|
|
|
|
metawriter_with_properties writer = sym.get_metawriter();
|
|
|
|
|
|
|
|
if (!filename.empty())
|
2010-05-30 05:16:51 +02:00
|
|
|
{
|
2012-03-28 01:21:11 +02:00
|
|
|
boost::optional<marker_ptr> mark = mapnik::marker_cache::instance()->find(filename, true);
|
|
|
|
if (mark && *mark)
|
|
|
|
{
|
2012-04-08 02:20:56 +02:00
|
|
|
if (!(*mark)->is_vector())
|
|
|
|
{
|
2012-06-04 20:11:29 +02:00
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: markers_symbolizer does not yet support non-SVG markers";
|
2010-05-30 05:16:51 +02:00
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
boost::optional<path_ptr> marker = (*mark)->get_vector_data();
|
|
|
|
box2d<double> const& bbox = (*marker)->bounding_box();
|
|
|
|
double x1 = bbox.minx();
|
|
|
|
double y1 = bbox.miny();
|
|
|
|
double x2 = bbox.maxx();
|
|
|
|
double y2 = bbox.maxy();
|
|
|
|
double w = (*mark)->width();
|
|
|
|
double h = (*mark)->height();
|
|
|
|
|
|
|
|
agg::trans_affine recenter = agg::trans_affine_translation(-0.5*(x1+x2),-0.5*(y1+y2));
|
|
|
|
tr.transform(&x1,&y1);
|
|
|
|
tr.transform(&x2,&y2);
|
|
|
|
box2d<double> extent(x1,y1,x2,y2);
|
|
|
|
using namespace mapnik::svg;
|
|
|
|
|
2012-06-16 04:17:26 +02:00
|
|
|
for (unsigned i=0; i<feature.num_geometries(); ++i)
|
2012-03-28 01:21:11 +02:00
|
|
|
{
|
2012-06-16 04:17:26 +02:00
|
|
|
geometry_type & geom = feature.get_geometry(i);
|
2012-03-28 01:21:11 +02:00
|
|
|
// TODO - merge this code with point_symbolizer rendering
|
|
|
|
if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1)
|
|
|
|
{
|
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
double z=0;
|
|
|
|
geom.label_interior_position(&x, &y);
|
|
|
|
prj_trans.backward(x,y,z);
|
|
|
|
t_.forward(&x,&y);
|
|
|
|
extent.re_center(x,y);
|
|
|
|
|
|
|
|
if (sym.get_allow_overlap() ||
|
|
|
|
detector_.has_placement(extent))
|
|
|
|
{
|
|
|
|
render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**mark, tr, sym.get_opacity());
|
|
|
|
|
|
|
|
// TODO - impl this for markers?
|
|
|
|
//if (!sym.get_ignore_placement())
|
|
|
|
// detector_.insert(label_ext);
|
|
|
|
metawriter_with_properties writer = sym.get_metawriter();
|
2012-06-16 04:17:26 +02:00
|
|
|
if (writer.first) writer.first->add_box(extent, feature, t_, writer.second);
|
2012-03-28 01:21:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
clipped_geometry_type clipped(geom);
|
|
|
|
clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy());
|
|
|
|
path_type path(t_,clipped,prj_trans);
|
|
|
|
markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_,
|
|
|
|
sym.get_spacing() * scale_factor_,
|
|
|
|
sym.get_max_error(),
|
|
|
|
sym.get_allow_overlap());
|
|
|
|
double x, y, angle;
|
|
|
|
|
|
|
|
while (placement.get_point(&x, &y, &angle))
|
|
|
|
{
|
|
|
|
agg::trans_affine matrix = recenter * tr * agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y);
|
|
|
|
render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h), **mark, matrix, sym.get_opacity(),false);
|
|
|
|
|
|
|
|
if (writer.first)
|
2012-04-08 02:20:56 +02:00
|
|
|
{
|
2012-03-28 01:21:11 +02:00
|
|
|
//writer.first->add_box(label_ext, feature, t_, writer.second);
|
2012-04-10 00:51:04 +02:00
|
|
|
MAPNIK_LOG_WARN(cairo_renderer) << "metawriter not yet supported for LINE placement";
|
2012-04-08 02:20:56 +02:00
|
|
|
}
|
2012-03-28 01:21:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
context.fill();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
color const& fill_ = sym.get_fill();
|
|
|
|
stroke const& stroke_ = sym.get_stroke();
|
|
|
|
color const& col = stroke_.get_color();
|
|
|
|
double strk_width = stroke_.get_width();
|
|
|
|
double w = sym.get_width();
|
|
|
|
double h = sym.get_height();
|
|
|
|
double rx = w/2.0;
|
|
|
|
double ry = h/2.0;
|
|
|
|
|
|
|
|
arrow arrow_;
|
|
|
|
box2d<double> extent;
|
|
|
|
|
|
|
|
double dx = w + (2*strk_width);
|
|
|
|
double dy = h + (2*strk_width);
|
|
|
|
|
2012-06-04 22:42:51 +02:00
|
|
|
if (marker_type == MARKER_ARROW)
|
2012-03-28 01:21:11 +02:00
|
|
|
{
|
|
|
|
extent = arrow_.extent();
|
|
|
|
double x1 = extent.minx();
|
|
|
|
double y1 = extent.miny();
|
|
|
|
double x2 = extent.maxx();
|
|
|
|
double y2 = extent.maxy();
|
|
|
|
tr.transform(&x1,&y1);
|
|
|
|
tr.transform(&x2,&y2);
|
|
|
|
extent.init(x1,y1,x2,y2);
|
|
|
|
}
|
|
|
|
else
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2012-03-28 01:21:11 +02:00
|
|
|
double x1 = -1 *(dx);
|
|
|
|
double y1 = -1 *(dy);
|
|
|
|
double x2 = dx;
|
|
|
|
double y2 = dy;
|
|
|
|
tr.transform(&x1,&y1);
|
|
|
|
tr.transform(&x2,&y2);
|
|
|
|
extent.init(x1,y1,x2,y2);
|
|
|
|
}
|
2012-03-13 15:56:11 +01:00
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
double z=0;
|
2012-03-13 15:56:11 +01:00
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
agg::path_storage marker;
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-06-16 04:17:26 +02:00
|
|
|
for (unsigned i=0; i<feature.num_geometries(); ++i)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2012-06-16 04:17:26 +02:00
|
|
|
geometry_type & geom = feature.get_geometry(i);
|
2012-03-28 01:21:11 +02:00
|
|
|
if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1)
|
|
|
|
{
|
|
|
|
geom.label_position(&x,&y);
|
|
|
|
prj_trans.backward(x,y,z);
|
|
|
|
t_.forward(&x,&y);
|
|
|
|
int px = int(floor(x - 0.5 * dx));
|
|
|
|
int py = int(floor(y - 0.5 * dy));
|
|
|
|
box2d<double> label_ext (px, py, px + dx +1, py + dy +1);
|
|
|
|
if (sym.get_allow_overlap() ||
|
|
|
|
detector_.has_placement(label_ext))
|
|
|
|
{
|
|
|
|
agg::ellipse c(x, y, rx, ry);
|
|
|
|
marker.concat_path(c);
|
|
|
|
context.set_color(fill_,sym.get_opacity());
|
|
|
|
context.add_agg_path(marker);
|
|
|
|
context.fill();
|
|
|
|
|
|
|
|
if (strk_width)
|
|
|
|
{
|
|
|
|
//context.restore();
|
|
|
|
context.set_color(col,stroke_.get_opacity());
|
|
|
|
context.set_line_width(stroke_.get_width());
|
|
|
|
if (stroke_.has_dash())
|
|
|
|
{
|
|
|
|
context.set_dash(stroke_.get_dash_array());
|
|
|
|
}
|
|
|
|
context.add_agg_path(marker);
|
|
|
|
context.stroke();
|
|
|
|
}
|
|
|
|
if (!sym.get_ignore_placement())
|
|
|
|
detector_.insert(label_ext);
|
2012-06-16 04:17:26 +02:00
|
|
|
if (writer.first) writer.first->add_box(label_ext, feature, t_, writer.second);
|
2012-03-28 01:21:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-06-04 22:42:51 +02:00
|
|
|
if (marker_type == MARKER_ARROW)
|
2012-03-28 01:21:11 +02:00
|
|
|
marker.concat_path(arrow_);
|
2012-03-13 15:56:11 +01:00
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
clipped_geometry_type clipped(geom);
|
|
|
|
clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy());
|
|
|
|
path_type path(t_,clipped,prj_trans);
|
|
|
|
markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_,
|
|
|
|
sym.get_spacing() * scale_factor_,
|
|
|
|
sym.get_max_error(),
|
|
|
|
sym.get_allow_overlap());
|
|
|
|
double x_t, y_t, angle;
|
2012-03-13 15:56:11 +01:00
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
while (placement.get_point(&x_t, &y_t, &angle))
|
|
|
|
{
|
|
|
|
agg::trans_affine matrix;
|
|
|
|
|
2012-06-04 22:42:51 +02:00
|
|
|
if (marker_type == MARKER_ELLIPSE)
|
2012-03-28 01:21:11 +02:00
|
|
|
{
|
|
|
|
agg::ellipse c(x_t, y_t, rx, ry);
|
|
|
|
marker.concat_path(c);
|
|
|
|
agg::trans_affine matrix;
|
|
|
|
matrix *= agg::trans_affine_translation(-x_t,-y_t);
|
|
|
|
matrix *= agg::trans_affine_rotation(angle);
|
|
|
|
matrix *= agg::trans_affine_translation(x_t,y_t);
|
|
|
|
marker.transform(matrix);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
matrix = tr * agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x_t, y_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
if (writer.first)
|
2012-04-08 02:20:56 +02:00
|
|
|
{
|
2012-03-28 01:21:11 +02:00
|
|
|
//writer.first->add_box(label_ext, feature, t_, writer.second);
|
2012-04-10 00:51:04 +02:00
|
|
|
MAPNIK_LOG_WARN(cairo_renderer) << "metawriter not yet supported for LINE placement";
|
2012-04-08 02:20:56 +02:00
|
|
|
}
|
2012-03-28 01:21:11 +02:00
|
|
|
|
|
|
|
agg::conv_transform<agg::path_storage, agg::trans_affine> trans(marker, matrix);
|
|
|
|
context.set_color(fill_,sym.get_opacity());
|
|
|
|
context.add_agg_path(trans);
|
|
|
|
context.fill();
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-03-28 01:21:11 +02:00
|
|
|
if (strk_width)
|
|
|
|
{
|
|
|
|
context.set_color(col,stroke_.get_opacity());
|
|
|
|
context.set_line_width(stroke_.get_width());
|
|
|
|
if (stroke_.has_dash())
|
|
|
|
{
|
|
|
|
context.set_dash(stroke_.get_dash_array());
|
|
|
|
}
|
|
|
|
context.add_agg_path(trans);
|
|
|
|
context.stroke();
|
|
|
|
}
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2010-05-30 05:16:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
void cairo_renderer_base::process(text_symbolizer const& sym,
|
2012-06-16 04:17:26 +02:00
|
|
|
mapnik::feature_impl & feature,
|
2012-02-02 02:53:35 +01:00
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
2012-06-16 04:17:26 +02:00
|
|
|
text_symbolizer_helper<face_manager<freetype_engine>, label_collision_detector4> helper(sym, feature, prj_trans, detector_.extent().width(), detector_.extent().height(), 1.0 /*scale_factor*/, t_, font_manager_, detector_, query_extent_);
|
2010-08-11 13:45:56 +02:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
cairo_context context(context_);
|
2012-05-10 13:10:37 +02:00
|
|
|
context.set_operator(sym.comp_op());
|
|
|
|
|
2012-03-03 20:15:24 +01:00
|
|
|
while (helper.next()) {
|
|
|
|
placements_type &placements = helper.placements();
|
|
|
|
for (unsigned int ii = 0; ii < placements.size(); ++ii)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2012-03-03 20:15:24 +01:00
|
|
|
context.add_text(placements[ii], face_manager_, font_manager_);
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2012-01-26 19:58:47 +01:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2009-02-06 01:46:29 +01:00
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
template class cairo_renderer<Cairo::Surface>;
|
|
|
|
template class cairo_renderer<Cairo::Context>;
|
2008-02-23 01:17:53 +01:00
|
|
|
}
|
2009-06-08 21:43:49 +02:00
|
|
|
|
|
|
|
#endif
|