apply patch from Herm from #553 adding support for markers_symbolizer to Cairo renderer, new placement finder, and fill/spacing/overlap options - works nicely with new svg support being tested against markers_symbolizer
This commit is contained in:
parent
c9a4433666
commit
89f6b32b76
7 changed files with 461 additions and 273 deletions
|
@ -1,166 +0,0 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2006 Artem Pavlenko
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
//$Id$
|
||||
|
||||
#ifndef MARKERS_CONVERTER_HPP
|
||||
#define MARKERS_CONVERTER_HPP
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_trans_affine.h"
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
template <typename Locator, typename Shape, typename Detector>
|
||||
class markers_converter : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
markers_converter(Locator & locator,Shape & shape, Detector & detector);
|
||||
void rewind(unsigned path_id);
|
||||
unsigned vertex(double * x, double * y);
|
||||
private:
|
||||
enum status_e
|
||||
{
|
||||
initial,
|
||||
markers,
|
||||
polygon,
|
||||
stop
|
||||
};
|
||||
|
||||
Locator & locator_;
|
||||
Shape & shape_;
|
||||
Detector & detector_;
|
||||
status_e status_;
|
||||
agg::trans_affine transform_;
|
||||
agg::trans_affine mtx_;
|
||||
unsigned num_markers_;
|
||||
unsigned marker_;
|
||||
};
|
||||
|
||||
template <typename Locator,typename Shape,typename Detector>
|
||||
markers_converter<Locator,Shape,Detector>::markers_converter(Locator & locator,Shape & shape,
|
||||
Detector & detector)
|
||||
: locator_(locator),
|
||||
shape_(shape),
|
||||
detector_(detector),
|
||||
status_(initial),
|
||||
num_markers_(1),
|
||||
marker_(0) {}
|
||||
|
||||
template <typename Locator, typename Shape,typename Detector>
|
||||
void markers_converter<Locator,Shape,Detector>::rewind(unsigned path_id)
|
||||
{
|
||||
status_ = initial;
|
||||
marker_ = 0;
|
||||
num_markers_ = 1;
|
||||
}
|
||||
|
||||
template <typename Locator, typename Shape, typename Detector>
|
||||
unsigned markers_converter<Locator,Shape,Detector>::vertex( double * x, double * y)
|
||||
{
|
||||
unsigned cmd = agg::path_cmd_move_to;
|
||||
|
||||
double x1, y1, x2, y2;
|
||||
while (!agg::is_stop(cmd))
|
||||
{
|
||||
switch (status_)
|
||||
{
|
||||
case initial:
|
||||
if (num_markers_ == 0 )
|
||||
{
|
||||
cmd = agg::path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
locator_.rewind(marker_++);
|
||||
status_ = markers;
|
||||
num_markers_ = 0;
|
||||
break;
|
||||
case markers:
|
||||
{
|
||||
unsigned cmd1;
|
||||
while (agg::is_move_to(cmd1 = locator_.vertex(&x1,&y1)));
|
||||
if (agg::is_stop(cmd1))
|
||||
{
|
||||
status_ = stop;
|
||||
break;
|
||||
}
|
||||
unsigned cmd2 = locator_.vertex(&x2,&y2);
|
||||
if (agg::is_stop(cmd2))
|
||||
{
|
||||
status_ = stop;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
++num_markers_;
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
double d = std::sqrt(dx * dx + dy * dy);
|
||||
box2d<double> ext = shape_.extent();
|
||||
if (d > ext.width())
|
||||
{
|
||||
mtx_ = transform_;
|
||||
mtx_ *= agg::trans_affine_rotation(::atan2(dy,dx));
|
||||
double marker_x = x1 + dx * 0.5;
|
||||
double marker_y = y1 + dy * 0.5;
|
||||
|
||||
mtx_ *= agg::trans_affine_translation(marker_x,marker_y);
|
||||
|
||||
double minx = ext.minx();
|
||||
double miny = ext.miny();
|
||||
double maxx = ext.maxx();
|
||||
double maxy = ext.maxy();
|
||||
mtx_.transform(&minx,&miny);
|
||||
mtx_.transform(&maxx,&maxy);
|
||||
|
||||
box2d<double> e0(minx,miny,maxx,maxy);
|
||||
|
||||
if (detector_.has_placement(e0))
|
||||
{
|
||||
shape_.rewind(0);
|
||||
status_ = polygon;
|
||||
detector_.insert(ext);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case polygon:
|
||||
cmd = shape_.vertex(x,y);
|
||||
if (agg::is_stop(cmd))
|
||||
{
|
||||
cmd = agg::path_cmd_move_to;
|
||||
status_ = markers;
|
||||
break;
|
||||
}
|
||||
mtx_.transform(x,y);
|
||||
return cmd;
|
||||
case stop:
|
||||
cmd = agg::path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MARKERS_CONVERTER_HPP
|
246
include/mapnik/markers_placement.hpp
Normal file
246
include/mapnik/markers_placement.hpp
Normal file
|
@ -0,0 +1,246 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2010 Hermann Kraus
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef MARKERS_PLACEMENT_HPP
|
||||
#define MARKERS_PLACEMENT_HPP
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include <mapnik/box2d.hpp>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <cmath>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
template <typename Locator, typename Detector>
|
||||
class markers_placement : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
markers_placement(Locator &locator, box2d<double> size, Detector &detector, double spacing, double max_error, bool allow_overlap);
|
||||
void rewind();
|
||||
bool get_point(double *x, double *y, double *angle, bool add_to_detector = true);
|
||||
private:
|
||||
Locator &locator_;
|
||||
box2d<double> size_;
|
||||
Detector &detector_;
|
||||
double spacing_;
|
||||
bool done_;
|
||||
double last_x, last_y;
|
||||
double next_x, next_y;
|
||||
/** If a marker could not be placed at the exact point where it should
|
||||
* go the next markers distance will be a bit lower. */
|
||||
double error_;
|
||||
double max_error_;
|
||||
unsigned marker_nr_;
|
||||
bool allow_overlap_;
|
||||
box2d<double> perform_transform(double angle, double dx, double dy);
|
||||
double find_optimal_spacing(double s);
|
||||
};
|
||||
|
||||
/** Constructor for markers_placement object.
|
||||
* \param locator Path along which markers are placed (type: vertex source)
|
||||
* \param size Size of the marker
|
||||
* \param detector Collision detection
|
||||
* \param spacing Distance between markers. If the value is negative it is
|
||||
* converted to a positive value with similar magnitude, but
|
||||
* choosen to optimize marker placement. 0 = no markers
|
||||
*/
|
||||
template <typename Locator, typename Detector> markers_placement<Locator, Detector>::markers_placement(
|
||||
Locator &locator, box2d<double> size, Detector &detector, double spacing, double max_error, bool allow_overlap)
|
||||
: locator_(locator), size_(size), detector_(detector), max_error_(max_error), allow_overlap_(allow_overlap)
|
||||
{
|
||||
if (spacing >= 0)
|
||||
{
|
||||
spacing_ = spacing;
|
||||
} else if (spacing < 0)
|
||||
{
|
||||
spacing_ = find_optimal_spacing(-spacing);
|
||||
}
|
||||
rewind();
|
||||
}
|
||||
|
||||
/** Autmatically chooses spacing. */
|
||||
template <typename Locator, typename Detector> double markers_placement<Locator, Detector>::find_optimal_spacing(double s)
|
||||
{
|
||||
rewind();
|
||||
//Calculate total path length
|
||||
unsigned cmd = agg::path_cmd_move_to;
|
||||
double length = 0;
|
||||
while (!agg::is_stop(cmd))
|
||||
{
|
||||
double dx = next_x - last_x;
|
||||
double dy = next_y - last_y;
|
||||
length += std::sqrt(dx * dx + dy * dy);
|
||||
last_x = next_x;
|
||||
last_y = next_y;
|
||||
while (agg::is_move_to(cmd = locator_.vertex(&next_x, &next_y)))
|
||||
{
|
||||
//Skip over "move" commands
|
||||
last_x = next_x;
|
||||
last_y = next_y;
|
||||
}
|
||||
}
|
||||
unsigned points = round(length / s);
|
||||
if (points == 0) return 0; //Path to short
|
||||
return length / points;
|
||||
}
|
||||
|
||||
/** Start again at first marker.
|
||||
* \note Returning the same list of markers only works when they were NOT added
|
||||
* to the detector.
|
||||
*/
|
||||
template <typename Locator, typename Detector> void markers_placement<Locator, Detector>::rewind()
|
||||
{
|
||||
locator_.rewind(0);
|
||||
//Get first point
|
||||
done_ = agg::is_stop(locator_.vertex(&next_x, &next_y)) || spacing_ < size_.width();
|
||||
last_x = next_x;
|
||||
last_y = next_y; // Force request of new segment
|
||||
error_ = 0;
|
||||
marker_nr_ = 0;
|
||||
}
|
||||
|
||||
/** Get a point where the marker should be placed.
|
||||
* Each time this function is called a new point is returned.
|
||||
* \param x Return value for x position
|
||||
* \param y Return value for x position
|
||||
* \param angle Return value for rotation angle
|
||||
* \param add_to_detector Add selected position to detector
|
||||
* \return True if a place is found, false if none is found.
|
||||
*/
|
||||
template <typename Locator, typename Detector> bool markers_placement<Locator, Detector>::get_point(
|
||||
double *x, double *y, double *angle, bool add_to_detector)
|
||||
{
|
||||
if (done_) return false;
|
||||
|
||||
unsigned cmd;
|
||||
double spacing_left;
|
||||
if (marker_nr_++ == 0)
|
||||
{
|
||||
spacing_left = spacing_ / 2;
|
||||
} else
|
||||
{
|
||||
spacing_left = spacing_;
|
||||
}
|
||||
|
||||
spacing_left -= error_;
|
||||
error_ = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
//Loop exits when a position is found or when no more segments are available
|
||||
if (spacing_left < size_.width()/2)
|
||||
{
|
||||
//Do not place markers to close to the beginning of a segment
|
||||
error_ += size_.width()/2 - spacing_left;
|
||||
spacing_left = size_.width()/2;
|
||||
}
|
||||
if (abs(error_) > max_error_ * spacing_)
|
||||
{
|
||||
spacing_left += spacing_ - error_;
|
||||
error_ = 0;
|
||||
}
|
||||
double dx = next_x - last_x;
|
||||
double dy = next_y - last_y;
|
||||
double d = std::sqrt(dx * dx + dy * dy);
|
||||
if (d <= spacing_left)
|
||||
{
|
||||
//Segment is to short to place marker. Find next segment
|
||||
spacing_left -= d;
|
||||
last_x = next_x;
|
||||
last_y = next_y;
|
||||
while (agg::is_move_to(cmd = locator_.vertex(&next_x, &next_y)))
|
||||
{
|
||||
//Skip over "move" commands
|
||||
last_x = next_x;
|
||||
last_y = next_y;
|
||||
}
|
||||
if (agg::is_stop(cmd))
|
||||
{
|
||||
done_ = true;
|
||||
return false;
|
||||
}
|
||||
continue; //Try again
|
||||
}
|
||||
//Check if marker really fits in this segment
|
||||
if (d < size_.width())
|
||||
{
|
||||
//Segment to short => Skip this segment
|
||||
error_ += d + size_.width()/2 - spacing_left;
|
||||
spacing_left = d + size_.width()/2;
|
||||
continue;
|
||||
} else if (d - spacing_left < size_.width()/2)
|
||||
{
|
||||
//Segment is long enough, but we are to close to the end
|
||||
|
||||
//Note: This function moves backwards. This could lead to an infinite
|
||||
// loop when another function adds a positive offset. Therefore we
|
||||
// only move backwards when there is no offset
|
||||
if (error_ == 0)
|
||||
{
|
||||
error_ += d - size_.width()/2 - spacing_left;
|
||||
spacing_left = d - size_.width()/2;
|
||||
} else
|
||||
{
|
||||
//Skip this segment
|
||||
error_ += d + size_.width()/2 - spacing_left;
|
||||
spacing_left = d + size_.width()/2;
|
||||
}
|
||||
continue; //Force checking of max_error constraint
|
||||
}
|
||||
*angle = atan2(dy, dx);
|
||||
*x = last_x + dx * (spacing_left / d);
|
||||
*y = last_y + dy * (spacing_left / d);
|
||||
|
||||
box2d<double> box = perform_transform(*angle, *x, *y);
|
||||
if (!allow_overlap_ && !detector_.has_placement(box))
|
||||
{
|
||||
//10.0 is choosen arbitrarily
|
||||
error_ += spacing_ * max_error_ / 10.0;
|
||||
spacing_left += spacing_ * max_error_ / 10.0;
|
||||
continue;
|
||||
}
|
||||
if (add_to_detector) detector_.insert(box);
|
||||
last_x = *x;
|
||||
last_y = *y;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Rotates the size_ box and translates the position. */
|
||||
template <typename Locator, typename Detector> box2d<double> markers_placement<Locator, Detector>::perform_transform(double angle, double dx, double dy)
|
||||
{
|
||||
double c = cos(angle), s = sin(angle);
|
||||
double x1 = size_.minx();
|
||||
double x2 = size_.maxx();
|
||||
double y1 = size_.miny();
|
||||
double y2 = size_.maxy();
|
||||
|
||||
double x1_ = dx + x1 * c - y1 * s;
|
||||
double y1_ = dy + x1 * s + y1 * c;
|
||||
double x2_ = dx + x2 * c - y2 * s;
|
||||
double y2_ = dy + x2 * s + y2 * c;
|
||||
|
||||
return box2d<double>(x1_, y1_, x2_, y2_);
|
||||
}
|
||||
}; /* end namespace */
|
||||
#endif // MARKERS_PLACEMENT_HPP
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
//mapnik
|
||||
#include <mapnik/path_expression_grammar.hpp>
|
||||
#include <mapnik/color.hpp>
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
|
@ -34,17 +35,17 @@ struct MAPNIK_DECL markers_symbolizer
|
|||
{
|
||||
public:
|
||||
markers_symbolizer(path_expression_ptr filename, bool allow_overlap=false)
|
||||
: filename_(filename),
|
||||
allow_overlap_(allow_overlap) {}
|
||||
: filename_(filename), allow_overlap_(allow_overlap),
|
||||
fill_(color(0,0,255)), spacing_(100.0), max_error_(0.2) {}
|
||||
|
||||
path_expression_ptr get_filename() const
|
||||
{
|
||||
return filename_;
|
||||
return filename_;
|
||||
}
|
||||
|
||||
void set_filename(path_expression_ptr filename)
|
||||
{
|
||||
filename_ = filename;
|
||||
filename_ = filename;
|
||||
}
|
||||
|
||||
void set_allow_overlap(bool overlap)
|
||||
|
@ -52,13 +53,47 @@ public:
|
|||
allow_overlap_ = overlap;
|
||||
}
|
||||
|
||||
float get_allow_overlap() const
|
||||
bool get_allow_overlap() const
|
||||
{
|
||||
return allow_overlap_;
|
||||
}
|
||||
|
||||
void set_spacing(double spacing)
|
||||
{
|
||||
spacing_ = spacing;
|
||||
}
|
||||
|
||||
float get_spacing() const
|
||||
{
|
||||
return spacing_;
|
||||
}
|
||||
|
||||
void set_max_error(double max_error)
|
||||
{
|
||||
max_error_ = max_error;
|
||||
}
|
||||
|
||||
float get_max_error() const
|
||||
{
|
||||
return max_error_;
|
||||
}
|
||||
|
||||
void set_fill(color fill)
|
||||
{
|
||||
fill_ = fill;
|
||||
}
|
||||
|
||||
color const& get_fill() const
|
||||
{
|
||||
return fill_;
|
||||
}
|
||||
|
||||
private:
|
||||
path_expression_ptr filename_;
|
||||
bool allow_overlap_;
|
||||
color fill_;
|
||||
double spacing_;
|
||||
double max_error_;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <mapnik/svg/marker_cache.hpp>
|
||||
#include <mapnik/unicode.hpp>
|
||||
#include <mapnik/placement_finder.hpp>
|
||||
#include <mapnik/markers_converter.hpp>
|
||||
#include <mapnik/markers_placement.hpp>
|
||||
#include <mapnik/arrow.hpp>
|
||||
#include <mapnik/config_error.hpp>
|
||||
#include <mapnik/font_set.hpp>
|
||||
|
@ -816,47 +816,76 @@ template <typename T>
|
|||
void agg_renderer<T>::process(markers_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
{
|
||||
typedef coord_transform2<CoordTransform,geometry2d> path_type;
|
||||
typedef agg::pixfmt_rgba32 pixfmt;
|
||||
typedef agg::renderer_base<pixfmt> renderer_base;
|
||||
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid;
|
||||
|
||||
std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature);
|
||||
|
||||
if (!filename.empty())
|
||||
|
||||
bool svg_marker;
|
||||
arrow arrow_;
|
||||
box2d<double> extent;
|
||||
boost::optional<path_ptr> marker;
|
||||
|
||||
ras_ptr->reset();
|
||||
ras_ptr->gamma(agg::gamma_linear());
|
||||
agg::scanline_u8 sl;
|
||||
agg::rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_ * 4);
|
||||
pixfmt pixf(buf);
|
||||
renderer_base renb(pixf);
|
||||
renderer_solid ren(renb);
|
||||
|
||||
color const& fill_ = sym.get_fill();
|
||||
unsigned r = fill_.red();
|
||||
unsigned g = fill_.green();
|
||||
unsigned b = fill_.blue();
|
||||
unsigned a = fill_.alpha();
|
||||
|
||||
|
||||
for (unsigned i=0; i<feature.num_geometries(); ++i)
|
||||
{
|
||||
boost::optional<path_ptr> marker = mapnik::marker_cache::instance()->find(filename,true);
|
||||
|
||||
if (marker && *marker)
|
||||
{
|
||||
ras_ptr->reset();
|
||||
ras_ptr->gamma(agg::gamma_linear());
|
||||
agg::scanline_u8 sl;
|
||||
agg::rendering_buffer buf(pixmap_.raw_data(),width_,height_, width_ * 4);
|
||||
pixfmt pixf(buf);
|
||||
renderer_base renb(pixf);
|
||||
renderer_solid ren(renb);
|
||||
|
||||
//mtx *= agg::trans_affine_translation((lox + hix) * -0.5, (loy + hiy) * -0.5);
|
||||
//mtx *= agg::trans_affine_scaling(0.8 * std::min(im.width()/(hix-lox),im.height()/(hiy-loy)));
|
||||
//mtx *= agg::trans_affine_translation((lox + hix) * 0.5, (loy + hiy) * 0.5);
|
||||
//mtx *= agg::trans_affine_translation((im.width() - (lox + hix)) * 0.5, (im.height() - (loy + hiy)) * 0.5);
|
||||
|
||||
for (unsigned i=0;i<feature.num_geometries();++i)
|
||||
{
|
||||
agg::trans_affine mtx;
|
||||
double x,y,z=0;
|
||||
|
||||
geometry2d const& geom = feature.get_geometry(i);
|
||||
|
||||
geom.label_position(&x,&y);
|
||||
prj_trans.backward(x,y,z);
|
||||
t_.forward(&x,&y);
|
||||
mtx *= agg::trans_affine_translation(x,y);
|
||||
(*marker)->render(*ras_ptr, sl, ren, mtx, renb.clip_box(), 1.0);
|
||||
}
|
||||
}
|
||||
geometry2d const& geom = feature.get_geometry(i);
|
||||
if (geom.num_points() <= 1) continue;
|
||||
|
||||
std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature);
|
||||
|
||||
if (!filename.empty())
|
||||
{
|
||||
marker = mapnik::marker_cache::instance()->find(filename, true);
|
||||
if (marker && *marker)
|
||||
{
|
||||
svg_marker = true;
|
||||
double x1, y1, x2, y2;
|
||||
(*marker)->bounding_rect(&x1, &y1, &x2, &y2);
|
||||
extent.init(x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
svg_marker = false;
|
||||
extent = arrow_.extent();
|
||||
}
|
||||
|
||||
path_type path(t_,geom,prj_trans);
|
||||
markers_placement<path_type, label_collision_detector4> placement(path, extent, detector_, sym.get_spacing(), sym.get_max_error(), sym.get_allow_overlap());
|
||||
|
||||
double x, y, angle;
|
||||
|
||||
while (placement.get_point(&x, &y, &angle))
|
||||
{
|
||||
agg::trans_affine matrix = agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y);
|
||||
if (svg_marker)
|
||||
{
|
||||
(*marker)->render(*ras_ptr, sl, ren, matrix, renb.clip_box(), 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
agg::conv_transform<arrow, agg::trans_affine> trans(arrow_, matrix);
|
||||
ras_ptr->add_path(trans);
|
||||
ren.color(agg::rgba8(r, g, b, a));
|
||||
agg::render_scanlines(*ras_ptr, sl, ren);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/unicode.hpp>
|
||||
#include <mapnik/placement_finder.hpp>
|
||||
#include <mapnik/markers_converter.hpp>
|
||||
#include <mapnik/markers_placement.hpp>
|
||||
#include <mapnik/arrow.hpp>
|
||||
#include <mapnik/config_error.hpp>
|
||||
#include <mapnik/path_expression_grammar.hpp>
|
||||
|
@ -291,7 +291,7 @@ public:
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void add_path(T path)
|
||||
void add_path(T& path)
|
||||
{
|
||||
double x, y;
|
||||
|
||||
|
@ -357,6 +357,11 @@ public:
|
|||
context_->set_font_matrix(matrix);
|
||||
}
|
||||
|
||||
void set_matrix(Cairo::Matrix const& matrix)
|
||||
{
|
||||
context_->set_matrix(matrix);
|
||||
}
|
||||
|
||||
void show_glyph(unsigned long index, double x, double y)
|
||||
{
|
||||
Cairo::Glyph glyph;
|
||||
|
@ -948,7 +953,7 @@ void cairo_renderer_base::process(line_pattern_symbolizer const& sym,
|
|||
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);
|
||||
|
@ -1055,6 +1060,32 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
|||
Feature const& feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
typedef coord_transform2<CoordTransform,geometry2d> path_type;
|
||||
arrow arrow_;
|
||||
cairo_context context(context_);
|
||||
|
||||
color const& fill_ = sym.get_fill();
|
||||
context.set_color(fill_.red(), fill_.green(), fill_.blue(), fill_.alpha());
|
||||
|
||||
for (unsigned i = 0; i < feature.num_geometries(); ++i)
|
||||
{
|
||||
geometry2d const& geom = feature.get_geometry(i);
|
||||
|
||||
if (geom.num_points() > 1)
|
||||
{
|
||||
path_type path(t_, geom, prj_trans);
|
||||
|
||||
markers_placement<path_type, label_collision_detector4> placement(path, arrow_.extent(), detector_, sym.get_spacing(), sym.get_max_error(), sym.get_allow_overlap());
|
||||
|
||||
double x, y, angle;
|
||||
while (placement.get_point(&x, &y, &angle)) {
|
||||
Cairo::Matrix matrix = Cairo::rotation_matrix(angle) * Cairo::translation_matrix(x,y) ;
|
||||
context.set_matrix(matrix);
|
||||
context.add_path(arrow_);
|
||||
}
|
||||
}
|
||||
context.fill();
|
||||
}
|
||||
}
|
||||
|
||||
void cairo_renderer_base::process(glyph_symbolizer const& sym,
|
||||
|
|
108
src/load_map.cpp
108
src/load_map.cpp
|
@ -746,67 +746,67 @@ void map_parser::parse_markers_symbolizer( rule_type & rule, ptree const & sym )
|
|||
{
|
||||
try
|
||||
{
|
||||
optional<std::string> file = get_opt_attr<string>(sym, "file");
|
||||
optional<std::string> base = get_opt_attr<string>(sym, "base");
|
||||
optional<boolean> allow_overlap =
|
||||
get_opt_attr<boolean>(sym, "allow_overlap");
|
||||
optional<float> opacity =
|
||||
get_opt_attr<float>(sym, "opacity");
|
||||
|
||||
if (file)
|
||||
{
|
||||
try
|
||||
{
|
||||
if( base )
|
||||
{
|
||||
std::map<std::string,std::string>::const_iterator itr = file_sources_.find(*base);
|
||||
if (itr!=file_sources_.end())
|
||||
{
|
||||
*file = itr->second + "/" + *file;
|
||||
}
|
||||
}
|
||||
std::string filename("");
|
||||
optional<std::string> file = get_opt_attr<string>(sym, "file");
|
||||
optional<std::string> base = get_opt_attr<string>(sym, "base");
|
||||
|
||||
if ( relative_to_xml_ )
|
||||
{
|
||||
*file = ensure_relative_to_xml(file);
|
||||
}
|
||||
if (file)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (base)
|
||||
{
|
||||
std::map<std::string,std::string>::const_iterator itr = file_sources_.find(*base);
|
||||
if (itr!=file_sources_.end())
|
||||
{
|
||||
*file = itr->second + "/" + *file;
|
||||
}
|
||||
}
|
||||
|
||||
if ( relative_to_xml_ )
|
||||
{
|
||||
*file = ensure_relative_to_xml(file);
|
||||
}
|
||||
#ifdef MAPNIK_DEBUG
|
||||
else {
|
||||
std::clog << "\nFound relative paths in xml, leaving unchanged...\n";
|
||||
}
|
||||
else {
|
||||
std::clog << "\nFound relative paths in xml, leaving unchanged...\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
markers_symbolizer symbol(parse_path(*file));
|
||||
|
||||
if (allow_overlap)
|
||||
{
|
||||
symbol.set_allow_overlap( * allow_overlap );
|
||||
}
|
||||
if (opacity)
|
||||
{
|
||||
// TODO !!!!! symbol.set_opacity( *opacity );
|
||||
}
|
||||
rule.append(symbol);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
string msg("Failed to load marker file '" + * file);
|
||||
if (strict_)
|
||||
{
|
||||
throw config_error(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
clog << "### WARNING: " << msg << endl;
|
||||
}
|
||||
}
|
||||
|
||||
filename = *file;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
string msg("Failed to load marker file '" + *file + "'!");
|
||||
if (strict_)
|
||||
{
|
||||
throw config_error(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
clog << "### WARNING: " << msg << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
markers_symbolizer symbol(parse_path(filename));
|
||||
optional<float> opacity = get_opt_attr<float>(sym, "opacity");
|
||||
if (opacity) {
|
||||
// TODO !!!!! symbol.set_opacity( *opacity );
|
||||
}
|
||||
optional<color> c = get_opt_attr<color>(sym, "fill");
|
||||
if (c) symbol.set_fill(*c);
|
||||
optional<double> spacing = get_opt_attr<double>(sym, "spacing");
|
||||
if (spacing) symbol.set_spacing(*spacing);
|
||||
optional<double> max_error = get_opt_attr<double>(sym, "max_error");
|
||||
if (max_error) symbol.set_max_error(*max_error);
|
||||
optional<boolean> allow_overlap = get_opt_attr<boolean>(sym, "allow_overlap");
|
||||
if (allow_overlap) symbol.set_allow_overlap(*allow_overlap);
|
||||
rule.append(symbol);
|
||||
}
|
||||
catch (const config_error & ex)
|
||||
{
|
||||
ex.append_context("in MarkersSymbolizer");
|
||||
throw;
|
||||
ex.append_context("in MarkersSymbolizer");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -262,14 +262,27 @@ public:
|
|||
{
|
||||
ptree & sym_node = rule_.push_back(
|
||||
ptree::value_type("MarkersSymbolizer", ptree()))->second;
|
||||
const std::string & filename = path_processor_type::to_string( *sym.get_filename());
|
||||
// TODO!!!
|
||||
//markers_symbolizer dfl
|
||||
//if ( sym.get_allow_overlap() != dfl.get_allow_overlap() || explicit_defaults_ )
|
||||
//{
|
||||
// set_attr( sym_node, "allow_overlap", sym.get_allow_overlap() );
|
||||
//}
|
||||
|
||||
markers_symbolizer dfl(parse_path("")); //TODO: Parameter?
|
||||
std::string const& filename = path_processor_type::to_string( *sym.get_filename());
|
||||
if ( ! filename.empty() ) {
|
||||
set_attr( sym_node, "file", filename );
|
||||
}
|
||||
if (sym.get_allow_overlap() != dfl.get_allow_overlap() || explicit_defaults_)
|
||||
{
|
||||
set_attr( sym_node, "allow_overlap", sym.get_allow_overlap() );
|
||||
}
|
||||
if (sym.get_spacing() != dfl.get_spacing() || explicit_defaults_)
|
||||
{
|
||||
set_attr( sym_node, "spacing", sym.get_spacing() );
|
||||
}
|
||||
if (sym.get_max_error() != dfl.get_max_error() || explicit_defaults_)
|
||||
{
|
||||
set_attr( sym_node, "max_error", sym.get_max_error() );
|
||||
}
|
||||
if (sym.get_fill() != dfl.get_fill() || explicit_defaults_)
|
||||
{
|
||||
set_attr( sym_node, "fill", sym.get_fill() );
|
||||
}
|
||||
}
|
||||
|
||||
void operator () ( glyph_symbolizer const& sym)
|
||||
|
|
Loading…
Reference in a new issue