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
|
2013-01-06 20:56:35 +01:00
|
|
|
#include <mapnik/rule.hpp>
|
|
|
|
#include <mapnik/debug.hpp>
|
2012-07-25 03:35:41 +02:00
|
|
|
#include <mapnik/layer.hpp>
|
2013-01-28 05:54:31 +01:00
|
|
|
#include <mapnik/raster.hpp>
|
2013-01-04 08:20:30 +01:00
|
|
|
#include <mapnik/feature.hpp>
|
2013-01-28 05:54:31 +01:00
|
|
|
#include <mapnik/proj_transform.hpp>
|
2012-07-25 03:35:41 +02:00
|
|
|
#include <mapnik/feature_type_style.hpp>
|
2008-02-23 01:17:53 +01:00
|
|
|
#include <mapnik/cairo_renderer.hpp>
|
2013-01-09 18:00:30 +01:00
|
|
|
#include <mapnik/cairo_context.hpp>
|
2008-02-23 01:17:53 +01:00
|
|
|
#include <mapnik/image_util.hpp>
|
|
|
|
#include <mapnik/unicode.hpp>
|
2010-05-30 05:16:51 +02:00
|
|
|
#include <mapnik/markers_placement.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>
|
2013-01-06 20:56:35 +01:00
|
|
|
#include <mapnik/font_set.hpp>
|
|
|
|
#include <mapnik/parse_path.hpp>
|
|
|
|
#include <mapnik/map.hpp>
|
2011-01-26 02:18:40 +01:00
|
|
|
#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>
|
2012-10-02 00:01:12 +02:00
|
|
|
#include <mapnik/raster_colorizer.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>
|
2012-08-09 18:46:55 +02:00
|
|
|
#include <mapnik/marker_helpers.hpp>
|
2012-12-17 03:19:52 +01:00
|
|
|
#include <mapnik/noncopyable.hpp>
|
2013-03-13 00:56:47 +01:00
|
|
|
#include <mapnik/pixel_position.hpp>
|
2012-10-04 21:03:40 +02:00
|
|
|
|
2008-02-23 01:17:53 +01:00
|
|
|
// cairo
|
2013-01-09 18:00:30 +01:00
|
|
|
#include <cairo.h>
|
2008-02-23 01:17:53 +01:00
|
|
|
#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
|
2011-05-10 23:09:54 +02:00
|
|
|
#include <boost/make_shared.hpp>
|
2012-12-03 07:46:58 +01:00
|
|
|
#include <boost/math/special_functions/round.hpp>
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-03-08 12:07:13 +01:00
|
|
|
// agg
|
|
|
|
#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-10-03 06:50:42 +02:00
|
|
|
#include "agg_rendering_buffer.h"
|
|
|
|
#include "agg_pixfmt_rgba.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"
|
|
|
|
|
2012-10-04 21:03:40 +02:00
|
|
|
// stl
|
|
|
|
#include <deque>
|
|
|
|
|
2008-02-23 01:17:53 +01:00
|
|
|
namespace mapnik
|
|
|
|
{
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
struct cairo_save_restore
|
2011-01-26 02:18:40 +01:00
|
|
|
{
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore(cairo_context & context)
|
|
|
|
: context_(context)
|
2011-01-26 02:18:40 +01:00
|
|
|
{
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.save();
|
2011-01-26 02:18:40 +01:00
|
|
|
}
|
2013-01-09 18:00:30 +01:00
|
|
|
~cairo_save_restore()
|
2011-01-26 02:18:40 +01:00
|
|
|
{
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.restore();
|
2011-01-26 02:18:40 +01:00
|
|
|
}
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_context & context_;
|
2011-01-26 02:18:40 +01:00
|
|
|
};
|
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-07-02 14:28:40 +02:00
|
|
|
cairo_face_manager::cairo_face_manager(boost::shared_ptr<freetype_engine> engine)
|
|
|
|
: font_engine_(engine)
|
2009-12-16 21:02:06 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-05 03:34:04 +02:00
|
|
|
cairo_renderer_base::cairo_renderer_base(Map const& m,
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_ptr const& cairo,
|
2012-07-05 03:34:04 +02:00
|
|
|
double scale_factor,
|
|
|
|
unsigned offset_x,
|
|
|
|
unsigned offset_y)
|
2009-12-16 21:02:06 +01:00
|
|
|
: m_(m),
|
2013-01-09 18:00:30 +01:00
|
|
|
context_(cairo),
|
2012-07-05 03:34:04 +02:00
|
|
|
width_(m.width()),
|
|
|
|
height_(m.height()),
|
|
|
|
scale_factor_(scale_factor),
|
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_),
|
2012-07-02 14:28:40 +02:00
|
|
|
face_manager_(font_engine_),
|
2012-08-25 11:43:31 +02:00
|
|
|
detector_(boost::make_shared<label_collision_detector4>(
|
|
|
|
box2d<double>(-m.buffer_size(), -m.buffer_size(),
|
|
|
|
m.width() + m.buffer_size(), m.height() + m.buffer_size())))
|
|
|
|
{
|
2013-02-21 02:55:53 +01:00
|
|
|
setup(m);
|
2012-08-25 11:43:31 +02:00
|
|
|
}
|
|
|
|
|
2013-02-26 21:05:44 +01:00
|
|
|
cairo_renderer_base::cairo_renderer_base(Map const& m,
|
|
|
|
request const& req,
|
|
|
|
cairo_ptr const& cairo,
|
|
|
|
double scale_factor,
|
|
|
|
unsigned offset_x,
|
|
|
|
unsigned offset_y)
|
|
|
|
: m_(m),
|
|
|
|
context_(cairo),
|
|
|
|
width_(req.width()),
|
|
|
|
height_(req.height()),
|
|
|
|
scale_factor_(scale_factor),
|
|
|
|
t_(req.width(),req.height(),req.extent(),offset_x,offset_y),
|
|
|
|
font_engine_(boost::make_shared<freetype_engine>()),
|
|
|
|
font_manager_(*font_engine_),
|
|
|
|
face_manager_(font_engine_),
|
|
|
|
detector_(boost::make_shared<label_collision_detector4>(
|
|
|
|
box2d<double>(-req.buffer_size(), -req.buffer_size(),
|
|
|
|
req.width() + req.buffer_size(), req.height() + req.buffer_size())))
|
|
|
|
{
|
|
|
|
setup(m);
|
|
|
|
}
|
|
|
|
|
2012-08-25 11:43:31 +02:00
|
|
|
cairo_renderer_base::cairo_renderer_base(Map const& m,
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_ptr const& cairo,
|
2012-08-25 11:43:31 +02:00
|
|
|
boost::shared_ptr<label_collision_detector4> detector,
|
|
|
|
double scale_factor,
|
|
|
|
unsigned offset_x,
|
|
|
|
unsigned offset_y)
|
|
|
|
: m_(m),
|
2013-01-09 18:00:30 +01:00
|
|
|
context_(cairo),
|
2012-08-25 11:43:31 +02:00
|
|
|
width_(m.width()),
|
|
|
|
height_(m.height()),
|
|
|
|
scale_factor_(scale_factor),
|
|
|
|
t_(m.width(),m.height(),m.get_current_extent(),offset_x,offset_y),
|
|
|
|
font_engine_(boost::make_shared<freetype_engine>()),
|
|
|
|
font_manager_(*font_engine_),
|
|
|
|
face_manager_(font_engine_),
|
|
|
|
detector_(detector)
|
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 <>
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_renderer<cairo_ptr>::cairo_renderer(Map const& m, cairo_ptr const& cairo, double scale_factor, unsigned offset_x, unsigned offset_y)
|
2012-07-13 12:17:35 +02:00
|
|
|
: feature_style_processor<cairo_renderer>(m,scale_factor),
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_renderer_base(m,cairo,scale_factor,offset_x,offset_y) {}
|
2009-12-16 21:02:06 +01:00
|
|
|
|
|
|
|
template <>
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_renderer<cairo_surface_ptr>::cairo_renderer(Map const& m, cairo_surface_ptr const& surface, double scale_factor, unsigned offset_x, unsigned offset_y)
|
2012-07-13 12:17:35 +02:00
|
|
|
: feature_style_processor<cairo_renderer>(m,scale_factor),
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_renderer_base(m,create_context(surface),scale_factor,offset_x,offset_y) {}
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2013-02-26 21:05:44 +01:00
|
|
|
template <>
|
|
|
|
cairo_renderer<cairo_ptr>::cairo_renderer(Map const& m, request const& req, cairo_ptr const& cairo, double scale_factor, unsigned offset_x, unsigned offset_y)
|
|
|
|
: feature_style_processor<cairo_renderer>(m,scale_factor),
|
|
|
|
cairo_renderer_base(m,req,cairo,scale_factor,offset_x,offset_y) {}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
cairo_renderer<cairo_surface_ptr>::cairo_renderer(Map const& m, request const& req, cairo_surface_ptr const& surface, double scale_factor, unsigned offset_x, unsigned offset_y)
|
|
|
|
: feature_style_processor<cairo_renderer>(m,scale_factor),
|
|
|
|
cairo_renderer_base(m,req, create_context(surface),scale_factor,offset_x,offset_y) {}
|
|
|
|
|
2012-08-25 11:43:31 +02:00
|
|
|
template <>
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_renderer<cairo_ptr>::cairo_renderer(Map const& m, cairo_ptr const& cairo, boost::shared_ptr<label_collision_detector4> detector, double scale_factor, unsigned offset_x, unsigned offset_y)
|
2012-08-25 11:43:31 +02:00
|
|
|
: feature_style_processor<cairo_renderer>(m,scale_factor),
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_renderer_base(m,cairo,detector,scale_factor,offset_x,offset_y) {}
|
2012-08-25 11:43:31 +02:00
|
|
|
|
|
|
|
template <>
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_renderer<cairo_surface_ptr>::cairo_renderer(Map const& m, cairo_surface_ptr const& surface, boost::shared_ptr<label_collision_detector4> detector, double scale_factor, unsigned offset_x, unsigned offset_y)
|
2012-08-25 11:43:31 +02:00
|
|
|
: feature_style_processor<cairo_renderer>(m,scale_factor),
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_renderer_base(m,create_context(surface),detector,scale_factor,offset_x,offset_y) {}
|
2012-08-25 11:43:31 +02:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
cairo_renderer_base::~cairo_renderer_base() {}
|
|
|
|
|
2013-02-21 02:55:53 +01:00
|
|
|
void cairo_renderer_base::setup(Map const& map)
|
|
|
|
{
|
|
|
|
boost::optional<color> bg = m_.background();
|
|
|
|
if (bg)
|
|
|
|
{
|
|
|
|
cairo_save_restore guard(context_);
|
|
|
|
context_.set_color(*bg);
|
|
|
|
context_.paint();
|
|
|
|
}
|
|
|
|
boost::optional<std::string> const& image_filename = map.background_image();
|
|
|
|
if (image_filename)
|
|
|
|
{
|
|
|
|
// NOTE: marker_cache returns premultiplied image, if needed
|
|
|
|
boost::optional<mapnik::marker_ptr> bg_marker = mapnik::marker_cache::instance().find(*image_filename,true);
|
|
|
|
if (bg_marker && (*bg_marker)->is_bitmap())
|
|
|
|
{
|
|
|
|
mapnik::image_ptr bg_image = *(*bg_marker)->get_bitmap_data();
|
|
|
|
int w = bg_image->width();
|
|
|
|
int h = bg_image->height();
|
|
|
|
if ( w > 0 && h > 0)
|
|
|
|
{
|
|
|
|
// repeat background-image both vertically and horizontally
|
|
|
|
unsigned x_steps = unsigned(std::ceil(width_/double(w)));
|
|
|
|
unsigned y_steps = unsigned(std::ceil(height_/double(h)));
|
|
|
|
for (unsigned x=0;x<x_steps;++x)
|
|
|
|
{
|
|
|
|
for (unsigned y=0;y<y_steps;++y)
|
|
|
|
{
|
|
|
|
agg::trans_affine matrix = agg::trans_affine_translation(
|
|
|
|
x*w,
|
|
|
|
y*h);
|
|
|
|
context_.add_image(matrix, *bg_image, 1.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: Scale=" << map.scale();
|
|
|
|
}
|
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
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();
|
2012-07-04 15:50:11 +02:00
|
|
|
box2d<double> bounds = t_.forward(t_.extent());
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.rectangle(bounds.minx(), bounds.miny(), bounds.maxx(), bounds.maxy());
|
|
|
|
context_.clip();
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2009-02-06 01:46:29 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
template <>
|
2013-01-09 18:00:30 +01:00
|
|
|
void cairo_renderer<cairo_ptr>::end_map_processing(Map const& )
|
2012-07-04 15:50:11 +02:00
|
|
|
{
|
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: End map processing";
|
|
|
|
}
|
2012-04-09 21:41:56 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
template <>
|
2013-01-09 18:00:30 +01:00
|
|
|
void cairo_renderer<cairo_surface_ptr>::end_map_processing(Map const& )
|
2012-07-04 15:50:11 +02:00
|
|
|
{
|
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: End map processing";
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.show_page();
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2012-04-09 21:41:56 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
void cairo_renderer_base::start_layer_processing(layer const& lay, box2d<double> const& query_extent)
|
|
|
|
{
|
|
|
|
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-03-13 15:56:11 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
if (lay.clear_label_cache())
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2012-08-25 11:43:31 +02:00
|
|
|
detector_->clear();
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
query_extent_ = query_extent;
|
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
void cairo_renderer_base::end_layer_processing(layer const&)
|
|
|
|
{
|
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: End layer processing";
|
|
|
|
}
|
2012-05-03 13:17:37 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
void cairo_renderer_base::start_style_processing(feature_type_style const& st)
|
|
|
|
{
|
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer:start style processing";
|
|
|
|
}
|
2012-04-18 16:09:12 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
void cairo_renderer_base::end_style_processing(feature_type_style const& st)
|
|
|
|
{
|
|
|
|
MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer:end style processing";
|
|
|
|
}
|
|
|
|
|
|
|
|
void cairo_renderer_base::process(polygon_symbolizer const& sym,
|
|
|
|
mapnik::feature_impl & feature,
|
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore guard(context_);
|
|
|
|
context_.set_operator(sym.comp_op());
|
|
|
|
context_.set_color(sym.get_fill(), sym.get_opacity());
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
agg::trans_affine tr;
|
|
|
|
evaluate_transform(tr, feature, sym.get_transform());
|
2012-05-27 23:50:09 +02:00
|
|
|
|
2012-08-14 17:04:57 +02:00
|
|
|
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag> conv_types;
|
2012-07-04 15:50:11 +02:00
|
|
|
vertex_converter<box2d<double>, cairo_context, polygon_symbolizer,
|
|
|
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
2013-01-09 18:00:30 +01:00
|
|
|
converter(query_extent_,context_,sym,t_,prj_trans,tr,1.0);
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-08-23 02:38:34 +02:00
|
|
|
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
|
2012-07-04 15:50:11 +02:00
|
|
|
converter.set<transform_tag>(); //always transform
|
|
|
|
converter.set<affine_transform_tag>();
|
2012-08-14 17:04:57 +02:00
|
|
|
if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
|
2012-07-04 15:50:11 +02:00
|
|
|
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
BOOST_FOREACH( geometry_type & geom, feature.paths())
|
|
|
|
{
|
2012-07-19 17:36:44 +02:00
|
|
|
if (geom.size() > 2)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-07-04 15:50:11 +02:00
|
|
|
converter.apply(geom);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
// fill polygon
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.fill();
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2012-03-13 15:56:11 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
void cairo_renderer_base::process(building_symbolizer const& sym,
|
|
|
|
mapnik::feature_impl & feature,
|
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
|
|
|
typedef coord_transform<CoordTransform,geometry_type> path_type;
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore guard(context_);
|
|
|
|
context_.set_operator(sym.comp_op());
|
2012-07-04 15:50:11 +02:00
|
|
|
color const& fill = sym.get_fill();
|
|
|
|
double height = 0.0;
|
|
|
|
expression_ptr height_expr = sym.height();
|
|
|
|
if (height_expr)
|
2011-12-13 15:28:18 +01:00
|
|
|
{
|
2013-01-04 08:20:30 +01:00
|
|
|
value_type result = boost::apply_visitor(evaluate<feature_impl,value_type>(feature), *height_expr);
|
2012-07-13 12:17:35 +02:00
|
|
|
height = result.to_double() * scale_factor_;
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
for (unsigned i = 0; i < feature.num_geometries(); ++i)
|
|
|
|
{
|
|
|
|
geometry_type const& geom = feature.get_geometry(i);
|
2012-01-09 13:41:38 +01:00
|
|
|
|
2012-07-19 17:36:44 +02:00
|
|
|
if (geom.size() > 2)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2012-07-04 15:50:11 +02: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;
|
2012-07-31 14:31:22 +02:00
|
|
|
double x0 = 0;
|
|
|
|
double y0 = 0;
|
|
|
|
double x, y;
|
2012-07-04 15:50:11 +02:00
|
|
|
geom.rewind(0);
|
2012-07-31 14:31:22 +02:00
|
|
|
for (unsigned cm = geom.vertex(&x, &y); cm != SEG_END;
|
|
|
|
cm = geom.vertex(&x, &y))
|
2008-02-23 01:17:53 +01:00
|
|
|
{
|
2012-07-04 15:50:11 +02:00
|
|
|
if (cm == SEG_MOVETO)
|
|
|
|
{
|
|
|
|
frame->move_to(x,y);
|
|
|
|
}
|
2013-03-01 17:06:44 +01:00
|
|
|
else if (cm == SEG_LINETO)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-07-04 15:50:11 +02:00
|
|
|
frame->line_to(x,y);
|
2012-07-31 14:31:22 +02:00
|
|
|
face_segments.push_back(segment_t(x0,y0,x,y));
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2013-03-06 11:08:02 +01:00
|
|
|
else if (cm == SEG_CLOSE)
|
2013-03-01 17:06:44 +01:00
|
|
|
{
|
|
|
|
frame->close_path();
|
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
x0 = x;
|
|
|
|
y0 = y;
|
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
std::sort(face_segments.begin(), face_segments.end(), y_order);
|
|
|
|
std::deque<segment_t>::const_iterator itr = face_segments.begin();
|
2012-07-31 14:31:22 +02:00
|
|
|
std::deque<segment_t>::const_iterator end=face_segments.end();
|
|
|
|
for (; itr != end; ++itr)
|
2012-07-04 15:50:11 +02:00
|
|
|
{
|
|
|
|
boost::scoped_ptr<geometry_type> faces(new geometry_type(Polygon));
|
|
|
|
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);
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
path_type faces_path(t_, *faces, prj_trans);
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.set_color(fill.red() * 0.8 / 255.0, fill.green() * 0.8 / 255.0,
|
2013-01-02 17:52:06 +01:00
|
|
|
fill.blue() * 0.8 / 255.0, fill.alpha() * sym.get_opacity() / 255.0);
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.add_path(faces_path);
|
|
|
|
context_.fill();
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
frame->move_to(itr->get<0>(), itr->get<1>());
|
|
|
|
frame->line_to(itr->get<0>(), itr->get<1>() + height);
|
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
geom.rewind(0);
|
2012-07-31 14:31:22 +02:00
|
|
|
for (unsigned cm = geom.vertex(&x, &y); cm != SEG_END;
|
|
|
|
cm = geom.vertex(&x, &y))
|
2012-07-04 15:50:11 +02:00
|
|
|
{
|
|
|
|
if (cm == SEG_MOVETO)
|
|
|
|
{
|
2012-07-31 14:31:22 +02:00
|
|
|
frame->move_to(x,y+height);
|
|
|
|
roof->move_to(x,y+height);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2013-03-01 17:06:44 +01:00
|
|
|
else if (cm == SEG_LINETO)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-07-31 14:31:22 +02:00
|
|
|
frame->line_to(x,y+height);
|
|
|
|
roof->line_to(x,y+height);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2013-03-01 17:06:44 +01:00
|
|
|
else if (cm == SEG_CLOSE)
|
|
|
|
{
|
|
|
|
frame->close_path();
|
|
|
|
roof->close_path();
|
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
path_type path(t_, *frame, prj_trans);
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.set_color(fill.red() * 0.8 / 255.0, fill.green() * 0.8/255.0,
|
2013-01-02 17:52:06 +01:00
|
|
|
fill.blue() * 0.8 / 255.0, fill.alpha() * sym.get_opacity() / 255.0);
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.set_line_width(scale_factor_);
|
|
|
|
context_.add_path(path);
|
|
|
|
context_.stroke();
|
2012-06-26 18:15:11 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
path_type roof_path(t_, *roof, prj_trans);
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.set_color(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-07-04 15:50:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void cairo_renderer_base::process(line_symbolizer const& sym,
|
|
|
|
mapnik::feature_impl & feature,
|
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
2012-08-14 19:43:46 +02:00
|
|
|
typedef boost::mpl::vector<clip_line_tag, transform_tag,
|
|
|
|
offset_transform_tag, affine_transform_tag,
|
2012-08-24 23:24:31 +02:00
|
|
|
simplify_tag, smooth_tag, dash_tag, stroke_tag> conv_types;
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore guard(context_);
|
2012-07-04 15:50:11 +02:00
|
|
|
mapnik::stroke const& stroke_ = sym.get_stroke();
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.set_operator(sym.comp_op());
|
|
|
|
context_.set_color(stroke_.get_color(), stroke_.get_opacity());
|
|
|
|
context_.set_line_join(stroke_.get_line_join());
|
|
|
|
context_.set_line_cap(stroke_.get_line_cap());
|
|
|
|
context_.set_miter_limit(stroke_.get_miterlimit());
|
|
|
|
context_.set_line_width(stroke_.get_width() * scale_factor_);
|
2012-07-04 15:50:11 +02:00
|
|
|
if (stroke_.has_dash())
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.set_dash(stroke_.get_dash_array(), scale_factor_);
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2012-03-23 00:37:24 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
agg::trans_affine tr;
|
|
|
|
evaluate_transform(tr, feature, sym.get_transform());
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-08-14 19:43:46 +02:00
|
|
|
box2d<double> clipping_extent = query_extent_;
|
|
|
|
if (sym.clip())
|
|
|
|
{
|
|
|
|
double padding = (double)(query_extent_.width()/width_);
|
2012-12-13 00:59:27 +01:00
|
|
|
double half_stroke = stroke_.get_width()/2.0;
|
2012-08-14 19:43:46 +02:00
|
|
|
if (half_stroke > 1)
|
|
|
|
padding *= half_stroke;
|
2013-01-17 22:53:48 +01:00
|
|
|
if (std::fabs(sym.offset()) > 0)
|
|
|
|
padding *= std::fabs(sym.offset()) * 1.2;
|
2013-03-20 00:15:50 +01:00
|
|
|
padding *= scale_factor_;
|
2012-12-11 22:56:25 +01:00
|
|
|
clipping_extent.pad(padding);
|
2012-08-14 19:43:46 +02:00
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
vertex_converter<box2d<double>, cairo_context, line_symbolizer,
|
|
|
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
2013-01-09 18:00:30 +01:00
|
|
|
converter(clipping_extent,context_,sym,t_,prj_trans,tr,scale_factor_);
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-08-14 19:43:46 +02:00
|
|
|
if (sym.clip()) converter.set<clip_line_tag>(); // optional clip (default: true)
|
2012-07-04 15:50:11 +02:00
|
|
|
converter.set<transform_tag>(); // always transform
|
2013-01-17 22:53:48 +01:00
|
|
|
if (std::fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
|
2012-07-04 15:50:11 +02:00
|
|
|
converter.set<affine_transform_tag>(); // optional affine transform
|
2012-08-14 17:04:57 +02:00
|
|
|
if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
|
2012-07-04 15:50:11 +02:00
|
|
|
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
BOOST_FOREACH( geometry_type & geom, feature.paths())
|
|
|
|
{
|
2012-07-19 17:36:44 +02:00
|
|
|
if (geom.size() > 1)
|
2012-05-09 16:45:44 +02:00
|
|
|
{
|
2012-07-04 15:50:11 +02:00
|
|
|
converter.apply(geom);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
// stroke
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.stroke();
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-08-09 18:46:55 +02:00
|
|
|
void cairo_renderer_base::render_box(box2d<double> const& b)
|
2012-07-04 15:50:11 +02:00
|
|
|
{
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore guard(context_);
|
|
|
|
context_.move_to(b.minx(), b.miny());
|
|
|
|
context_.line_to(b.minx(), b.maxy());
|
|
|
|
context_.line_to(b.maxx(), b.maxy());
|
|
|
|
context_.line_to(b.maxx(), b.miny());
|
|
|
|
context_.close_path();
|
|
|
|
context_.stroke();
|
2012-08-09 18:46:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void render_vector_marker(cairo_context & context, pixel_position const& pos, mapnik::svg_storage_type & vmarker,
|
|
|
|
agg::pod_bvector<svg::path_attributes> const & attributes,
|
|
|
|
agg::trans_affine const& tr, double opacity, bool recenter)
|
|
|
|
{
|
|
|
|
using namespace mapnik::svg;
|
|
|
|
box2d<double> bbox = vmarker.bounding_box();
|
|
|
|
|
|
|
|
agg::trans_affine mtx = tr;
|
|
|
|
|
|
|
|
if (recenter)
|
2011-01-26 02:18:40 +01:00
|
|
|
{
|
2012-08-09 18:46:55 +02:00
|
|
|
coord<double,2> c = bbox.center();
|
|
|
|
mtx = agg::trans_affine_translation(-c.x,-c.y);
|
|
|
|
mtx *= tr;
|
|
|
|
mtx.translate(pos.x, pos.y);
|
|
|
|
}
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-08-09 18:46:55 +02:00
|
|
|
agg::trans_affine transform;
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-08-09 18:46:55 +02:00
|
|
|
for(unsigned i = 0; i < attributes.size(); ++i)
|
|
|
|
{
|
|
|
|
mapnik::svg::path_attributes const& attr = attributes[i];
|
|
|
|
if (!attr.visibility_flag)
|
|
|
|
continue;
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore guard(context);
|
2012-08-09 18:46:55 +02:00
|
|
|
transform = attr.transform;
|
|
|
|
transform *= mtx;
|
2012-03-28 01:21:11 +02:00
|
|
|
|
2012-08-09 18:46:55 +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())
|
|
|
|
{
|
|
|
|
double m[6];
|
|
|
|
transform.store_to(m);
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_matrix_t matrix;
|
|
|
|
cairo_matrix_init(&matrix,m[0],m[1],m[2],m[3],m[4],m[5]);
|
|
|
|
context.transform(matrix);
|
2012-08-09 18:46:55 +02:00
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-08-09 18:46:55 +02: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-08-09 18:46:55 +02:00
|
|
|
if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT)
|
|
|
|
{
|
|
|
|
context.add_agg_path(svg_path,attr.index);
|
|
|
|
if (attr.even_odd_flag)
|
2012-07-04 15:50:11 +02:00
|
|
|
{
|
2013-01-09 18:00:30 +01:00
|
|
|
context.set_fill_rule(CAIRO_FILL_RULE_EVEN_ODD);
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2012-08-09 18:46:55 +02:00
|
|
|
else
|
2012-07-04 15:50:11 +02:00
|
|
|
{
|
2013-01-09 18:00:30 +01:00
|
|
|
context.set_fill_rule(CAIRO_FILL_RULE_WINDING);
|
2012-08-09 18:46:55 +02:00
|
|
|
}
|
|
|
|
if(attr.fill_gradient.get_gradient_type() != NO_GRADIENT)
|
|
|
|
{
|
2013-07-10 22:19:28 +02:00
|
|
|
cairo_gradient g(attr.fill_gradient,attr.fill_opacity * attr.opacity * opacity);
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-08-09 18:46:55 +02:00
|
|
|
context.set_gradient(g,bbox);
|
|
|
|
context.fill();
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2012-08-09 18:46:55 +02:00
|
|
|
else if(attr.fill_flag)
|
|
|
|
{
|
2013-07-10 22:19:28 +02:00
|
|
|
double fill_opacity = attr.fill_opacity * attr.opacity * opacity * attr.fill_color.opacity();
|
2013-01-02 20:36:22 +01:00
|
|
|
context.set_color(attr.fill_color.r/255.0,attr.fill_color.g/255.0,
|
|
|
|
attr.fill_color.b/255.0, fill_opacity);
|
2012-08-09 18:46:55 +02:00
|
|
|
context.fill();
|
|
|
|
}
|
|
|
|
}
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-08-09 18:46:55 +02:00
|
|
|
if (attr.stroke_gradient.get_gradient_type() != NO_GRADIENT || attr.stroke_flag)
|
|
|
|
{
|
|
|
|
context.add_agg_path(svg_path,attr.index);
|
|
|
|
if(attr.stroke_gradient.get_gradient_type() != NO_GRADIENT)
|
2012-07-04 15:50:11 +02:00
|
|
|
{
|
2012-08-09 18:46:55 +02: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);
|
2013-07-10 22:19:28 +02:00
|
|
|
cairo_gradient g(attr.stroke_gradient,attr.fill_opacity * attr.opacity * opacity);
|
2012-08-09 18:46:55 +02:00
|
|
|
context.set_gradient(g,bbox);
|
|
|
|
context.stroke();
|
|
|
|
}
|
|
|
|
else if (attr.stroke_flag)
|
|
|
|
{
|
2013-07-10 22:19:28 +02:00
|
|
|
double stroke_opacity = attr.stroke_opacity * attr.opacity * opacity * attr.stroke_color.opacity();
|
2013-01-02 20:36:22 +01:00
|
|
|
context.set_color(attr.stroke_color.r/255.0,attr.stroke_color.g/255.0,
|
|
|
|
attr.stroke_color.b/255.0, stroke_opacity);
|
2012-08-09 18:46:55 +02: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();
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2012-08-09 18:46:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-14 13:58:00 +02:00
|
|
|
|
2013-03-11 21:46:32 +01:00
|
|
|
void cairo_renderer_base::render_marker(pixel_position const& pos,
|
|
|
|
marker const& marker,
|
|
|
|
agg::trans_affine const& tr,
|
|
|
|
double opacity,
|
|
|
|
bool recenter)
|
2012-07-04 15:50:11 +02:00
|
|
|
|
2012-08-09 18:46:55 +02:00
|
|
|
{
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore guard(context_);
|
2012-08-09 18:46:55 +02:00
|
|
|
if (marker.is_vector())
|
|
|
|
{
|
|
|
|
mapnik::svg_path_ptr vmarker = *marker.get_vector_data();
|
|
|
|
if (vmarker)
|
|
|
|
{
|
2013-03-22 13:16:23 +01:00
|
|
|
agg::trans_affine marker_tr = tr;
|
|
|
|
marker_tr *=agg::trans_affine_scaling(scale_factor_);
|
2012-08-09 18:46:55 +02:00
|
|
|
agg::pod_bvector<svg::path_attributes> const & attributes = vmarker->attributes();
|
2013-03-22 13:16:23 +01:00
|
|
|
render_vector_marker(context_, pos, *vmarker, attributes, marker_tr, opacity, recenter);
|
2011-01-26 02:18:40 +01:00
|
|
|
}
|
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
else if (marker.is_bitmap())
|
2010-03-03 04:26:12 +01:00
|
|
|
{
|
2012-12-03 07:46:58 +01:00
|
|
|
double width = (*marker.get_bitmap_data())->width();
|
|
|
|
double height = (*marker.get_bitmap_data())->height();
|
|
|
|
double cx = 0.5 * width;
|
|
|
|
double cy = 0.5 * height;
|
2013-03-22 13:16:23 +01:00
|
|
|
agg::trans_affine marker_tr;
|
|
|
|
marker_tr *= agg::trans_affine_translation(-cx,-cy);
|
|
|
|
marker_tr *= tr;
|
|
|
|
marker_tr *= agg::trans_affine_scaling(scale_factor_);
|
|
|
|
marker_tr *= agg::trans_affine_translation(pos.x,pos.y);
|
|
|
|
context_.add_image(marker_tr, **marker.get_bitmap_data(), opacity);
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
|
|
|
}
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
void cairo_renderer_base::process(point_symbolizer const& sym,
|
|
|
|
mapnik::feature_impl & feature,
|
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
|
|
|
std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
|
2011-02-01 09:16:32 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
boost::optional<marker_ptr> marker;
|
|
|
|
if ( !filename.empty() )
|
|
|
|
{
|
2012-09-07 17:23:03 +02:00
|
|
|
marker = marker_cache::instance().find(filename, true);
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
marker.reset(boost::make_shared<mapnik::marker>());
|
|
|
|
}
|
2011-02-01 09:16:32 +01:00
|
|
|
|
2012-05-27 23:50:09 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
if (marker)
|
|
|
|
{
|
2013-05-21 07:41:59 +02:00
|
|
|
box2d<double> const& bbox = (*marker)->bounding_box();
|
|
|
|
coord2d center = bbox.center();
|
|
|
|
|
|
|
|
agg::trans_affine tr;
|
|
|
|
evaluate_transform(tr, feature, sym.get_image_transform());
|
|
|
|
agg::trans_affine_translation recenter(-center.x, -center.y);
|
|
|
|
agg::trans_affine recenter_tr = recenter * tr;
|
|
|
|
box2d<double> label_ext = bbox * recenter_tr * agg::trans_affine_scaling(scale_factor_);
|
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
for (unsigned i = 0; i < feature.num_geometries(); ++i)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2012-07-04 15:50:11 +02:00
|
|
|
geometry_type const& geom = feature.get_geometry(i);
|
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
double z = 0;
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT)
|
2012-08-21 21:51:39 +02:00
|
|
|
{
|
|
|
|
if (!label::centroid(geom, x, y))
|
|
|
|
return;
|
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
else
|
2012-08-21 21:51:39 +02:00
|
|
|
{
|
|
|
|
if (!label::interior_position(geom ,x, y))
|
|
|
|
return;
|
|
|
|
}
|
2011-01-26 02:18:40 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
prj_trans.backward(x, y, z);
|
|
|
|
t_.forward(&x, &y);
|
2013-05-21 07:41:59 +02:00
|
|
|
label_ext.re_center(x,y);
|
2012-07-04 15:50:11 +02:00
|
|
|
if (sym.get_allow_overlap() ||
|
2012-08-25 11:43:31 +02:00
|
|
|
detector_->has_placement(label_ext))
|
2012-07-04 15:50:11 +02:00
|
|
|
{
|
2012-08-16 11:37:51 +02:00
|
|
|
render_marker(pixel_position(x,y),**marker, tr, sym.get_opacity());
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
if (!sym.get_ignore_placement())
|
2012-08-25 11:43:31 +02:00
|
|
|
detector_->insert(label_ext);
|
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-07-04 15:50:11 +02:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
void cairo_renderer_base::process(shield_symbolizer const& sym,
|
|
|
|
mapnik::feature_impl & feature,
|
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
|
|
|
shield_symbolizer_helper<face_manager<freetype_engine>,
|
2012-07-06 00:40:16 +02:00
|
|
|
label_collision_detector4> helper(
|
|
|
|
sym, feature, prj_trans,
|
|
|
|
width_, height_,
|
2012-07-13 12:17:35 +02:00
|
|
|
scale_factor_,
|
2012-08-25 11:43:31 +02:00
|
|
|
t_, font_manager_, *detector_, query_extent_);
|
2013-01-09 18:00:30 +01:00
|
|
|
|
|
|
|
cairo_save_restore guard(context_);
|
|
|
|
context_.set_operator(sym.comp_op());
|
2012-07-04 15:50:11 +02:00
|
|
|
|
|
|
|
while (helper.next())
|
|
|
|
{
|
2012-07-11 11:13:38 +02:00
|
|
|
placements_type const& placements = helper.placements();
|
2012-07-04 15:50:11 +02:00
|
|
|
for (unsigned int ii = 0; ii < placements.size(); ++ii)
|
2012-05-09 16:45:44 +02:00
|
|
|
{
|
2012-12-03 07:46:58 +01:00
|
|
|
pixel_position pos = helper.get_marker_position(placements[ii]);
|
|
|
|
pos.x += 0.5 * helper.get_marker_width();
|
|
|
|
pos.y += 0.5 * helper.get_marker_height();
|
|
|
|
render_marker(pos,
|
2012-08-14 18:14:30 +02:00
|
|
|
helper.get_marker(),
|
2013-03-22 13:16:23 +01:00
|
|
|
helper.get_image_transform(),
|
2012-07-04 15:50:11 +02:00
|
|
|
sym.get_opacity());
|
2012-08-14 18:14:30 +02:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.add_text(placements[ii], face_manager_, font_manager_, scale_factor_);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
void cairo_renderer_base::process(line_pattern_symbolizer const& sym,
|
|
|
|
mapnik::feature_impl & feature,
|
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
|
|
|
typedef agg::conv_clip_polyline<geometry_type> clipped_geometry_type;
|
|
|
|
typedef coord_transform<CoordTransform,clipped_geometry_type> path_type;
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
|
2012-09-07 17:23:03 +02:00
|
|
|
boost::optional<mapnik::marker_ptr> marker = mapnik::marker_cache::instance().find(filename,true);
|
2012-07-04 15:50:11 +02:00
|
|
|
if (!marker && !(*marker)->is_bitmap()) return;
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
unsigned width((*marker)->width());
|
|
|
|
unsigned height((*marker)->height());
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore guard(context_);
|
|
|
|
context_.set_operator(sym.comp_op());
|
2012-07-04 15:50:11 +02:00
|
|
|
cairo_pattern pattern(**((*marker)->get_bitmap_data()));
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
pattern.set_extend(CAIRO_EXTEND_REPEAT);
|
|
|
|
pattern.set_filter(CAIRO_FILTER_BILINEAR);
|
|
|
|
context_.set_line_width(height * scale_factor_);
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
for (unsigned i = 0; i < feature.num_geometries(); ++i)
|
|
|
|
{
|
|
|
|
geometry_type & geom = feature.get_geometry(i);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-07-19 17:36:44 +02:00
|
|
|
if (geom.size() > 1)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-07-04 15:50: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);
|
2012-03-13 15:56:11 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
double length(0);
|
|
|
|
double x0(0), y0(0);
|
|
|
|
double x, y;
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
for (unsigned cm = path.vertex(&x, &y); cm != SEG_END; cm = path.vertex(&x, &y))
|
|
|
|
{
|
|
|
|
if (cm == SEG_MOVETO)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-07-04 15:50:11 +02:00
|
|
|
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);
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_matrix_t matrix;
|
2012-07-04 15:50:11 +02:00
|
|
|
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);
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
pattern.set_matrix(matrix);
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.set_pattern(pattern);
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.move_to(x0, y0);
|
|
|
|
context_.line_to(x, y);
|
|
|
|
context_.stroke();
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
length = length + hypot(x - x0, y - y0);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
|
|
|
|
x0 = x;
|
|
|
|
y0 = y;
|
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-07-04 15:50:11 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
void cairo_renderer_base::process(polygon_pattern_symbolizer const& sym,
|
|
|
|
mapnik::feature_impl & feature,
|
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
2012-08-15 11:55:12 +02:00
|
|
|
typedef agg::conv_clip_polygon<geometry_type> clipped_geometry_type;
|
|
|
|
typedef coord_transform<CoordTransform,clipped_geometry_type> path_type;
|
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore guard(context_);
|
|
|
|
context_.set_operator(sym.comp_op());
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
|
2012-09-07 17:23:03 +02:00
|
|
|
boost::optional<mapnik::marker_ptr> marker = mapnik::marker_cache::instance().find(filename,true);
|
2012-07-04 15:50:11 +02:00
|
|
|
if (!marker && !(*marker)->is_bitmap()) return;
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
cairo_pattern pattern(**((*marker)->get_bitmap_data()));
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
pattern.set_extend(CAIRO_EXTEND_REPEAT);
|
2008-02-23 01:17:53 +01:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.set_pattern(pattern);
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-08-15 11:55:12 +02:00
|
|
|
//pattern_alignment_e align = sym.get_alignment();
|
|
|
|
//unsigned offset_x=0;
|
|
|
|
//unsigned offset_y=0;
|
|
|
|
|
|
|
|
//if (align == LOCAL_ALIGNMENT)
|
|
|
|
//{
|
|
|
|
// double x0 = 0;
|
|
|
|
// double y0 = 0;
|
|
|
|
// if (feature.num_geometries() > 0)
|
|
|
|
// {
|
|
|
|
// clipped_geometry_type clipped(feature.get_geometry(0));
|
|
|
|
// clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy());
|
|
|
|
// path_type path(t_,clipped,prj_trans);
|
|
|
|
// path.vertex(&x0,&y0);
|
|
|
|
// }
|
|
|
|
// offset_x = unsigned(width_ - x0);
|
|
|
|
// offset_y = unsigned(height_ - y0);
|
|
|
|
//}
|
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
agg::trans_affine tr;
|
|
|
|
evaluate_transform(tr, feature, sym.get_transform());
|
2012-05-27 23:50:09 +02:00
|
|
|
|
2012-08-14 17:04:57 +02:00
|
|
|
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag> conv_types;
|
2012-07-04 15:50:11 +02:00
|
|
|
vertex_converter<box2d<double>, cairo_context, polygon_pattern_symbolizer,
|
|
|
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
2013-01-09 18:00:30 +01:00
|
|
|
converter(query_extent_,context_,sym,t_,prj_trans,tr, scale_factor_);
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-08-23 02:38:34 +02:00
|
|
|
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
|
2012-07-04 15:50:11 +02:00
|
|
|
converter.set<transform_tag>(); //always transform
|
|
|
|
converter.set<affine_transform_tag>();
|
2012-08-14 17:04:57 +02:00
|
|
|
if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
|
2012-07-04 15:50:11 +02:00
|
|
|
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
BOOST_FOREACH( geometry_type & geom, feature.paths())
|
|
|
|
{
|
2012-07-19 17:36:44 +02:00
|
|
|
if (geom.size() > 2)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2012-07-04 15:50:11 +02:00
|
|
|
converter.apply(geom);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
// fill polygon
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.fill();
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void cairo_renderer_base::process(raster_symbolizer const& sym,
|
|
|
|
mapnik::feature_impl & feature,
|
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
|
|
|
raster_ptr const& source = feature.get_raster();
|
|
|
|
if (source)
|
|
|
|
{
|
|
|
|
// If there's a colorizer defined, use it to color the raster in-place
|
|
|
|
raster_colorizer_ptr colorizer = sym.get_colorizer();
|
|
|
|
if (colorizer)
|
|
|
|
colorizer->colorize(source,feature);
|
|
|
|
|
|
|
|
box2d<double> target_ext = box2d<double>(source->ext_);
|
|
|
|
prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS);
|
2012-07-07 01:45:58 +02:00
|
|
|
box2d<double> ext = t_.forward(target_ext);
|
2013-03-08 01:22:32 +01:00
|
|
|
int start_x = static_cast<int>(std::floor(ext.minx()+.5));
|
|
|
|
int start_y = static_cast<int>(std::floor(ext.miny()+.5));
|
|
|
|
int end_x = static_cast<int>(std::floor(ext.maxx()+.5));
|
|
|
|
int end_y = static_cast<int>(std::floor(ext.maxy()+.5));
|
2012-07-04 15:50:11 +02:00
|
|
|
int raster_width = end_x - start_x;
|
|
|
|
int raster_height = end_y - start_y;
|
|
|
|
if (raster_width > 0 && raster_height > 0)
|
2010-03-03 04:23:53 +01:00
|
|
|
{
|
2012-10-03 06:50:42 +02:00
|
|
|
raster target(target_ext, raster_width,raster_height);
|
2012-07-07 01:45:58 +02:00
|
|
|
scaling_method_e scaling_method = sym.get_scaling_method();
|
|
|
|
double filter_radius = sym.calculate_filter_factor();
|
2012-10-03 06:50:42 +02:00
|
|
|
bool premultiply_source = !source->premultiplied_alpha_;
|
|
|
|
boost::optional<bool> is_premultiplied = sym.premultiplied();
|
|
|
|
if (is_premultiplied)
|
|
|
|
{
|
|
|
|
if (*is_premultiplied) premultiply_source = false;
|
|
|
|
else premultiply_source = true;
|
|
|
|
}
|
|
|
|
if (premultiply_source)
|
|
|
|
{
|
2013-03-08 01:22:32 +01:00
|
|
|
agg::rendering_buffer buffer(source->data_.getBytes(),
|
|
|
|
source->data_.width(),
|
|
|
|
source->data_.height(),
|
|
|
|
source->data_.width() * 4);
|
2012-10-03 06:50:42 +02:00
|
|
|
agg::pixfmt_rgba32 pixf(buffer);
|
|
|
|
pixf.premultiply();
|
|
|
|
}
|
2012-07-07 01:45:58 +02:00
|
|
|
if (!prj_trans.equal())
|
|
|
|
{
|
2012-09-12 22:25:40 +02:00
|
|
|
double offset_x = ext.minx() - start_x;
|
|
|
|
double offset_y = ext.miny() - start_y;
|
2012-07-07 01:45:58 +02:00
|
|
|
reproject_and_scale_raster(target, *source, prj_trans,
|
|
|
|
offset_x, offset_y,
|
|
|
|
sym.get_mesh_size(),
|
|
|
|
filter_radius,
|
|
|
|
scaling_method);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-09-12 22:25:40 +02:00
|
|
|
if (scaling_method == SCALING_BILINEAR8)
|
|
|
|
{
|
2013-03-08 01:22:32 +01:00
|
|
|
scale_image_bilinear8<image_data_32>(target.data_,
|
|
|
|
source->data_,
|
|
|
|
0.0,
|
|
|
|
0.0);
|
|
|
|
}
|
|
|
|
else
|
2012-09-12 22:25:40 +02:00
|
|
|
{
|
2013-03-07 02:41:20 +01:00
|
|
|
double image_ratio_x = ext.width() / source->data_.width();
|
|
|
|
double image_ratio_y = ext.height() / source->data_.height();
|
2012-07-07 01:45:58 +02:00
|
|
|
scale_image_agg<image_data_32>(target.data_,
|
|
|
|
source->data_,
|
|
|
|
scaling_method,
|
2013-03-07 02:41:20 +01:00
|
|
|
image_ratio_x,
|
|
|
|
image_ratio_y,
|
2012-09-12 22:25:40 +02:00
|
|
|
0.0,
|
|
|
|
0.0,
|
2012-07-07 01:45:58 +02:00
|
|
|
filter_radius);
|
|
|
|
}
|
|
|
|
}
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore guard(context_);
|
|
|
|
context_.set_operator(sym.comp_op());
|
|
|
|
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-07-04 15:50:11 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-08-09 18:46:55 +02:00
|
|
|
namespace detail {
|
|
|
|
|
|
|
|
template <typename Context, typename SvgPath, typename Attributes, typename Detector>
|
|
|
|
struct markers_dispatch
|
|
|
|
{
|
|
|
|
markers_dispatch(Context & ctx,
|
|
|
|
SvgPath & marker,
|
|
|
|
Attributes const& attributes,
|
|
|
|
Detector & detector,
|
|
|
|
markers_symbolizer const& sym,
|
|
|
|
box2d<double> const& bbox,
|
|
|
|
agg::trans_affine const& marker_trans,
|
|
|
|
double scale_factor)
|
|
|
|
:ctx_(ctx),
|
|
|
|
marker_(marker),
|
|
|
|
attributes_(attributes),
|
|
|
|
detector_(detector),
|
|
|
|
sym_(sym),
|
|
|
|
bbox_(bbox),
|
|
|
|
marker_trans_(marker_trans),
|
|
|
|
scale_factor_(scale_factor) {}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void add_path(T & path)
|
|
|
|
{
|
|
|
|
marker_placement_e placement_method = sym_.get_marker_placement();
|
|
|
|
|
2012-12-03 04:53:44 +01:00
|
|
|
if (placement_method != MARKER_LINE_PLACEMENT ||
|
|
|
|
path.type() == Point)
|
2012-08-09 18:46:55 +02:00
|
|
|
{
|
2012-08-21 21:51:39 +02:00
|
|
|
double x = 0;
|
|
|
|
double y = 0;
|
2012-12-03 04:53:44 +01:00
|
|
|
if (path.type() == LineString)
|
|
|
|
{
|
|
|
|
if (!label::middle_point(path, x, y))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
2012-08-09 18:46:55 +02:00
|
|
|
{
|
2012-08-21 21:51:39 +02:00
|
|
|
if (!label::interior_position(path, x, y))
|
|
|
|
return;
|
2012-08-09 18:46:55 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-08-21 21:51:39 +02:00
|
|
|
if (!label::centroid(path, x, y))
|
|
|
|
return;
|
2012-08-09 18:46:55 +02:00
|
|
|
}
|
|
|
|
coord2d center = bbox_.center();
|
|
|
|
agg::trans_affine matrix = agg::trans_affine_translation(-center.x, -center.y);
|
|
|
|
matrix *= marker_trans_;
|
|
|
|
matrix *=agg::trans_affine_translation(x, y);
|
|
|
|
|
|
|
|
box2d<double> transformed_bbox = bbox_ * matrix;
|
|
|
|
|
|
|
|
if (sym_.get_allow_overlap() ||
|
|
|
|
detector_.has_placement(transformed_bbox))
|
|
|
|
{
|
|
|
|
render_vector_marker(ctx_, pixel_position(x,y), marker_, attributes_, marker_trans_, sym_.get_opacity(), true);
|
|
|
|
|
|
|
|
if (!sym_.get_ignore_placement())
|
|
|
|
{
|
|
|
|
detector_.insert(transformed_bbox);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
markers_placement<T, label_collision_detector4> placement(path, bbox_, marker_trans_, detector_,
|
|
|
|
sym_.get_spacing() * scale_factor_,
|
|
|
|
sym_.get_max_error(),
|
|
|
|
sym_.get_allow_overlap());
|
|
|
|
double x, y, angle;
|
2013-06-28 21:53:08 +02:00
|
|
|
while (placement.get_point(x, y, angle, sym_.get_ignore_placement()))
|
2012-08-09 18:46:55 +02:00
|
|
|
{
|
|
|
|
agg::trans_affine matrix = marker_trans_;
|
|
|
|
matrix.rotate(angle);
|
|
|
|
render_vector_marker(ctx_, pixel_position(x,y),marker_, attributes_, matrix, sym_.get_opacity(), true);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Context & ctx_;
|
|
|
|
SvgPath & marker_;
|
|
|
|
Attributes const& attributes_;
|
|
|
|
Detector & detector_;
|
|
|
|
markers_symbolizer const& sym_;
|
|
|
|
box2d<double> const& bbox_;
|
|
|
|
agg::trans_affine const& marker_trans_;
|
|
|
|
double scale_factor_;
|
|
|
|
};
|
|
|
|
|
2012-08-14 13:58:00 +02:00
|
|
|
template <typename Context, typename ImageMarker, typename Detector>
|
|
|
|
struct markers_dispatch_2
|
|
|
|
{
|
|
|
|
markers_dispatch_2(Context & ctx,
|
|
|
|
ImageMarker & marker,
|
|
|
|
Detector & detector,
|
|
|
|
markers_symbolizer const& sym,
|
|
|
|
box2d<double> const& bbox,
|
|
|
|
agg::trans_affine const& marker_trans,
|
|
|
|
double scale_factor)
|
|
|
|
:ctx_(ctx),
|
|
|
|
marker_(marker),
|
|
|
|
detector_(detector),
|
|
|
|
sym_(sym),
|
|
|
|
bbox_(bbox),
|
|
|
|
marker_trans_(marker_trans),
|
|
|
|
scale_factor_(scale_factor) {}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void add_path(T & path)
|
|
|
|
{
|
|
|
|
marker_placement_e placement_method = sym_.get_marker_placement();
|
|
|
|
|
2012-12-03 04:53:44 +01:00
|
|
|
if (placement_method != MARKER_LINE_PLACEMENT ||
|
|
|
|
path.type() == Point)
|
2012-08-14 13:58:00 +02:00
|
|
|
{
|
2012-08-21 21:51:39 +02:00
|
|
|
double x = 0;
|
|
|
|
double y = 0;
|
2012-12-03 04:53:44 +01:00
|
|
|
if (path.type() == LineString)
|
|
|
|
{
|
|
|
|
if (!label::middle_point(path, x, y))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
2012-08-14 13:58:00 +02:00
|
|
|
{
|
2012-08-21 21:51:39 +02:00
|
|
|
if (!label::interior_position(path, x, y))
|
|
|
|
return;
|
2012-08-14 13:58:00 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-08-21 21:51:39 +02:00
|
|
|
if (!label::centroid(path, x, y))
|
|
|
|
return;
|
2012-08-14 13:58:00 +02:00
|
|
|
}
|
|
|
|
coord2d center = bbox_.center();
|
|
|
|
agg::trans_affine matrix = agg::trans_affine_translation(-center.x, -center.y);
|
|
|
|
matrix *= marker_trans_;
|
|
|
|
matrix *=agg::trans_affine_translation(x, y);
|
|
|
|
|
|
|
|
box2d<double> transformed_bbox = bbox_ * matrix;
|
|
|
|
|
|
|
|
if (sym_.get_allow_overlap() ||
|
|
|
|
detector_.has_placement(transformed_bbox))
|
|
|
|
{
|
|
|
|
ctx_.add_image(matrix, *marker_, sym_.get_opacity());
|
|
|
|
if (!sym_.get_ignore_placement())
|
|
|
|
{
|
|
|
|
detector_.insert(transformed_bbox);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
markers_placement<T, label_collision_detector4> placement(path, bbox_, marker_trans_, detector_,
|
|
|
|
sym_.get_spacing() * scale_factor_,
|
|
|
|
sym_.get_max_error(),
|
|
|
|
sym_.get_allow_overlap());
|
|
|
|
double x, y, angle;
|
2013-06-28 21:53:08 +02:00
|
|
|
while (placement.get_point(x, y, angle, sym_.get_ignore_placement()))
|
2012-08-14 13:58:00 +02:00
|
|
|
{
|
|
|
|
coord2d center = bbox_.center();
|
|
|
|
agg::trans_affine matrix = agg::trans_affine_translation(-center.x, -center.y);
|
|
|
|
matrix *= marker_trans_;
|
|
|
|
matrix *= agg::trans_affine_rotation(angle);
|
|
|
|
matrix *= agg::trans_affine_translation(x, y);
|
|
|
|
ctx_.add_image(matrix, *marker_, sym_.get_opacity());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Context & ctx_;
|
|
|
|
ImageMarker & marker_;
|
|
|
|
Detector & detector_;
|
|
|
|
markers_symbolizer const& sym_;
|
|
|
|
box2d<double> const& bbox_;
|
|
|
|
agg::trans_affine const& marker_trans_;
|
|
|
|
double scale_factor_;
|
|
|
|
};
|
|
|
|
|
2012-08-09 18:46:55 +02:00
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
void cairo_renderer_base::process(markers_symbolizer const& sym,
|
|
|
|
mapnik::feature_impl & feature,
|
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
2012-08-09 18:46:55 +02:00
|
|
|
typedef boost::mpl::vector<clip_line_tag,clip_poly_tag,transform_tag,smooth_tag> conv_types;
|
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore guard(context_);
|
|
|
|
context_.set_operator(sym.comp_op());
|
2012-03-28 01:21:11 +02:00
|
|
|
|
2012-08-09 18:46:55 +02:00
|
|
|
agg::trans_affine tr = agg::trans_affine_scaling(scale_factor_);
|
2012-05-27 23:50:09 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature);
|
2012-03-28 01:21:11 +02:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
if (!filename.empty())
|
|
|
|
{
|
2012-09-07 17:23:03 +02:00
|
|
|
boost::optional<marker_ptr> mark = mapnik::marker_cache::instance().find(filename, true);
|
2012-07-04 15:50:11 +02:00
|
|
|
if (mark && *mark)
|
2010-05-30 05:16:51 +02:00
|
|
|
{
|
2012-08-09 18:46:55 +02:00
|
|
|
agg::trans_affine geom_tr;
|
|
|
|
evaluate_transform(geom_tr, feature, sym.get_transform());
|
|
|
|
box2d<double> const& bbox = (*mark)->bounding_box();
|
2013-03-09 02:40:19 +01:00
|
|
|
setup_transform_scaling(tr, bbox.width(), bbox.height(), feature, sym);
|
2012-08-15 02:11:08 +02:00
|
|
|
evaluate_transform(tr, feature, sym.get_image_transform());
|
2012-08-09 18:46:55 +02:00
|
|
|
|
2012-08-14 13:58:00 +02:00
|
|
|
if ((*mark)->is_vector())
|
|
|
|
{
|
|
|
|
using namespace mapnik::svg;
|
|
|
|
typedef agg::pod_bvector<path_attributes> svg_attributes_type;
|
|
|
|
typedef detail::markers_dispatch<cairo_context, mapnik::svg_storage_type,
|
2012-08-09 18:46:55 +02:00
|
|
|
svg_attributes_type,label_collision_detector4> dispatch_type;
|
|
|
|
|
2012-08-14 13:58:00 +02:00
|
|
|
boost::optional<svg_path_ptr> const& stock_vector_marker = (*mark)->get_vector_data();
|
2012-02-02 02:53:35 +01:00
|
|
|
|
2012-08-14 13:58:00 +02:00
|
|
|
expression_ptr const& width_expr = sym.get_width();
|
|
|
|
expression_ptr const& height_expr = sym.get_height();
|
2012-08-09 18:46:55 +02:00
|
|
|
|
2012-08-14 13:58:00 +02:00
|
|
|
// special case for simple ellipse markers
|
|
|
|
// to allow for full control over rx/ry dimensions
|
|
|
|
if (filename == "shape://ellipse"
|
|
|
|
&& (width_expr || height_expr))
|
2012-03-28 01:21:11 +02:00
|
|
|
{
|
2012-08-14 13:58:00 +02:00
|
|
|
svg_storage_type marker_ellipse;
|
|
|
|
vertex_stl_adapter<svg_path_storage> stl_storage(marker_ellipse.source());
|
|
|
|
svg_path_adapter svg_path(stl_storage);
|
|
|
|
build_ellipse(sym, feature, marker_ellipse, svg_path);
|
|
|
|
svg_attributes_type attributes;
|
|
|
|
bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym);
|
|
|
|
agg::trans_affine marker_tr = agg::trans_affine_scaling(scale_factor_);
|
|
|
|
evaluate_transform(marker_tr, feature, sym.get_image_transform());
|
2013-01-04 03:04:01 +01:00
|
|
|
box2d<double> new_bbox = marker_ellipse.bounding_box();
|
2012-08-14 13:58:00 +02:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
dispatch_type dispatch(context_, marker_ellipse, result?attributes:(*stock_vector_marker)->attributes(),
|
2013-01-04 03:04:01 +01:00
|
|
|
*detector_, sym, new_bbox, marker_tr, scale_factor_);
|
2012-08-14 13:58:00 +02:00
|
|
|
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
|
|
|
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
|
|
|
converter(query_extent_, dispatch, sym, t_, prj_trans, marker_tr, scale_factor_);
|
|
|
|
|
|
|
|
if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true)
|
|
|
|
{
|
|
|
|
eGeomType type = feature.paths()[0].type();
|
|
|
|
if (type == Polygon)
|
|
|
|
converter.set<clip_poly_tag>();
|
2012-08-21 22:27:35 +02:00
|
|
|
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
|
|
|
|
//else if (type == LineString)
|
|
|
|
// converter.template set<clip_line_tag>();
|
2012-08-14 13:58:00 +02:00
|
|
|
// don't clip if type==Point
|
|
|
|
}
|
|
|
|
converter.set<transform_tag>(); //always transform
|
|
|
|
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
2012-11-21 02:58:39 +01:00
|
|
|
apply_markers_multi(feature, converter, sym);
|
2012-03-28 01:21:11 +02:00
|
|
|
}
|
2012-08-14 13:58:00 +02:00
|
|
|
else
|
2012-03-28 01:21:11 +02:00
|
|
|
{
|
2012-08-14 13:58:00 +02:00
|
|
|
svg_attributes_type attributes;
|
|
|
|
bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym);
|
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
dispatch_type dispatch(context_, **stock_vector_marker, result?attributes:(*stock_vector_marker)->attributes(),
|
2012-08-25 11:43:31 +02:00
|
|
|
*detector_, sym, bbox, tr, scale_factor_);
|
2012-08-14 13:58:00 +02:00
|
|
|
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
|
|
|
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
|
|
|
converter(query_extent_, dispatch, sym, t_, prj_trans, tr, scale_factor_);
|
|
|
|
|
|
|
|
if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true)
|
|
|
|
{
|
|
|
|
eGeomType type = feature.paths()[0].type();
|
|
|
|
if (type == Polygon)
|
|
|
|
converter.set<clip_poly_tag>();
|
2012-08-21 22:27:35 +02:00
|
|
|
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
|
|
|
|
//else if (type == LineString)
|
|
|
|
// converter.template set<clip_line_tag>();
|
2012-08-14 13:58:00 +02:00
|
|
|
// don't clip if type==Point
|
|
|
|
}
|
|
|
|
converter.set<transform_tag>(); //always transform
|
|
|
|
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
2012-11-21 02:58:39 +01:00
|
|
|
apply_markers_multi(feature, converter, sym);
|
2012-08-09 18:46:55 +02:00
|
|
|
}
|
|
|
|
}
|
2012-08-14 13:58:00 +02:00
|
|
|
else // raster markers
|
2012-08-09 18:46:55 +02:00
|
|
|
{
|
2012-08-14 13:58:00 +02:00
|
|
|
typedef detail::markers_dispatch_2<cairo_context,
|
|
|
|
mapnik::image_ptr,
|
|
|
|
label_collision_detector4> dispatch_type;
|
|
|
|
boost::optional<mapnik::image_ptr> marker = (*mark)->get_bitmap_data();
|
|
|
|
if ( marker )
|
2012-08-09 18:46:55 +02:00
|
|
|
{
|
2013-01-09 18:00:30 +01:00
|
|
|
dispatch_type dispatch(context_, *marker,
|
2012-08-25 11:43:31 +02:00
|
|
|
*detector_, sym, bbox, tr, scale_factor_);
|
2012-08-14 13:58:00 +02:00
|
|
|
|
|
|
|
vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
|
|
|
|
CoordTransform, proj_transform, agg::trans_affine, conv_types>
|
|
|
|
converter(query_extent_, dispatch, sym, t_, prj_trans, tr, scale_factor_);
|
|
|
|
|
|
|
|
if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true)
|
|
|
|
{
|
|
|
|
eGeomType type = feature.paths()[0].type();
|
|
|
|
if (type == Polygon)
|
|
|
|
converter.set<clip_poly_tag>();
|
2012-08-21 22:27:35 +02:00
|
|
|
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
|
|
|
|
//else if (type == LineString)
|
|
|
|
// converter.template set<clip_line_tag>();
|
2012-08-14 13:58:00 +02:00
|
|
|
// don't clip if type==Point
|
|
|
|
}
|
|
|
|
converter.set<transform_tag>(); //always transform
|
|
|
|
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
2012-11-21 02:58:39 +01:00
|
|
|
apply_markers_multi(feature, converter, sym);
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2010-05-30 05:16:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2012-07-04 15:50:11 +02:00
|
|
|
void cairo_renderer_base::process(text_symbolizer const& sym,
|
|
|
|
mapnik::feature_impl & feature,
|
|
|
|
proj_transform const& prj_trans)
|
|
|
|
{
|
2012-07-06 00:40:16 +02:00
|
|
|
text_symbolizer_helper<face_manager<freetype_engine>,
|
|
|
|
label_collision_detector4> helper(
|
|
|
|
sym, feature, prj_trans,
|
|
|
|
width_, height_,
|
2012-07-13 12:17:35 +02:00
|
|
|
scale_factor_,
|
2012-08-25 11:43:31 +02:00
|
|
|
t_, font_manager_, *detector_, query_extent_);
|
2012-07-13 12:17:35 +02:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
cairo_save_restore guard(context_);
|
|
|
|
context_.set_operator(sym.comp_op());
|
2012-05-10 13:10:37 +02:00
|
|
|
|
2012-07-11 11:13:38 +02:00
|
|
|
while (helper.next())
|
|
|
|
{
|
|
|
|
placements_type const& placements = helper.placements();
|
2012-07-04 15:50:11 +02:00
|
|
|
for (unsigned int ii = 0; ii < placements.size(); ++ii)
|
|
|
|
{
|
2013-01-09 18:00:30 +01:00
|
|
|
context_.add_text(placements[ii], face_manager_, font_manager_, scale_factor_);
|
2012-01-26 19:58:47 +01:00
|
|
|
}
|
2009-12-16 21:02:06 +01:00
|
|
|
}
|
2012-07-04 15:50:11 +02:00
|
|
|
}
|
2009-02-06 01:46:29 +01:00
|
|
|
|
2013-01-09 18:00:30 +01:00
|
|
|
template class cairo_renderer<cairo_surface_ptr>;
|
|
|
|
template class cairo_renderer<cairo_ptr>;
|
2008-02-23 01:17:53 +01:00
|
|
|
}
|
2009-06-08 21:43:49 +02:00
|
|
|
|
2012-07-13 12:17:35 +02:00
|
|
|
#endif // HAVE_CAIRO
|