Added minimum_distance property to text symbolizers. This prevents the same label from appearing within N pixels (across features).
Shield symbolizer is now a subclass of text symbolizer. Some small improvements to text rendering. Fixed up placement finder for horizontal placement. Cleaned up placement finder.
This commit is contained in:
parent
560de0b9b1
commit
9fe4a94c98
14 changed files with 293 additions and 320 deletions
|
@ -49,8 +49,8 @@ void export_line_pattern_symbolizer();
|
|||
void export_polygon_symbolizer();
|
||||
void export_polygon_pattern_symbolizer();
|
||||
void export_raster_symbolizer();
|
||||
void export_shield_symbolizer();
|
||||
void export_text_symbolizer();
|
||||
void export_shield_symbolizer();
|
||||
void export_font_engine();
|
||||
void export_projection();
|
||||
|
||||
|
@ -124,8 +124,8 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
export_polygon_symbolizer();
|
||||
export_polygon_pattern_symbolizer();
|
||||
export_raster_symbolizer();
|
||||
export_shield_symbolizer();
|
||||
export_text_symbolizer();
|
||||
export_shield_symbolizer();
|
||||
export_font_engine();
|
||||
export_projection();
|
||||
export_coord();
|
||||
|
|
|
@ -29,14 +29,11 @@ void export_shield_symbolizer()
|
|||
{
|
||||
using namespace boost::python;
|
||||
using mapnik::shield_symbolizer;
|
||||
|
||||
class_<shield_symbolizer>("ShieldSymbolizer",
|
||||
init<>("Default Shield Symbolizer - 4x4 black square"))
|
||||
.def (init< std::string const&, std::string const&, unsigned, mapnik::Color const&,
|
||||
std::string const&, std::string const&,unsigned,unsigned>("TODO"))
|
||||
.add_property("avoid_edges",
|
||||
&shield_symbolizer::get_avoid_edges,
|
||||
&shield_symbolizer::set_avoid_edges)
|
||||
using mapnik::text_symbolizer;
|
||||
|
||||
class_< shield_symbolizer, bases<text_symbolizer> >("ShieldSymbolizer",
|
||||
init< std::string const&, std::string const&, unsigned, mapnik::Color const&,
|
||||
std::string const&, std::string const&,unsigned,unsigned>("TODO"))
|
||||
;
|
||||
|
||||
}
|
||||
|
|
|
@ -67,6 +67,9 @@ void export_text_symbolizer()
|
|||
.add_property("avoid_edges",
|
||||
&text_symbolizer::get_avoid_edges,
|
||||
&text_symbolizer::set_avoid_edges)
|
||||
.add_property("minimum_distance",
|
||||
&text_symbolizer::get_minimum_distance,
|
||||
&text_symbolizer::set_minimum_distance)
|
||||
|
||||
.add_property("label_placement",
|
||||
&text_symbolizer::get_label_placement,
|
||||
|
|
|
@ -75,8 +75,8 @@ namespace mapnik {
|
|||
T & pixmap_;
|
||||
CoordTransform t_;
|
||||
face_manager<freetype_engine> font_manager_;
|
||||
label_collision_detector3 detector_;
|
||||
placement_finder<label_collision_detector3> finder_;
|
||||
label_collision_detector4 detector_;
|
||||
placement_finder<label_collision_detector4> finder_;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -304,11 +304,13 @@ namespace mapnik
|
|||
return dimension_t(slot->advance.x >> 6, glyph_bbox.yMax - glyph_bbox.yMin);
|
||||
}
|
||||
|
||||
void get_string_info(std::wstring const& text, string_info *info)
|
||||
void get_string_info(string_info *info)
|
||||
{
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
|
||||
|
||||
std::wstring text = info->get_string();
|
||||
|
||||
for (std::wstring::const_iterator i=text.begin();i!=text.end();++i)
|
||||
{
|
||||
dimension_t char_dim = character_dimensions(*i);
|
||||
|
|
|
@ -131,6 +131,77 @@ namespace mapnik
|
|||
tree_.clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//quad tree based label collission detector so labels dont appear within a given distance
|
||||
class label_collision_detector4 : boost::noncopyable
|
||||
{
|
||||
struct label
|
||||
{
|
||||
label(Envelope<double> const& b) : box(b) {}
|
||||
label(Envelope<double> const& b, std::wstring const& t) : box(b), text(t) {}
|
||||
|
||||
Envelope<double> box;
|
||||
std::wstring text;
|
||||
};
|
||||
|
||||
typedef quad_tree< label > tree_t;
|
||||
tree_t tree_;
|
||||
public:
|
||||
|
||||
explicit label_collision_detector4(Envelope<double> const& extent)
|
||||
: tree_(extent) {}
|
||||
|
||||
bool has_placement(Envelope<double> const& box)
|
||||
{
|
||||
tree_t::query_iterator itr = tree_.query_in_box(box);
|
||||
tree_t::query_iterator end = tree_.query_end();
|
||||
|
||||
for ( ;itr != end; ++itr)
|
||||
{
|
||||
if (itr->box.intersects(box))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool has_placement(Envelope<double> const& box, std::wstring const& text, double distance)
|
||||
{
|
||||
Envelope<double> bigger_box(box.minx() - distance, box.miny() - distance, box.maxx() + distance, box.maxy() + distance);
|
||||
|
||||
tree_t::query_iterator itr = tree_.query_in_box(bigger_box);
|
||||
tree_t::query_iterator end = tree_.query_end();
|
||||
|
||||
for ( ;itr != end; ++itr)
|
||||
{
|
||||
if (itr->box.intersects(box) || (text == itr->text && itr->box.intersects(bigger_box)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void insert(Envelope<double> const& box)
|
||||
{
|
||||
tree_.insert(label(box), box);
|
||||
}
|
||||
|
||||
void insert(Envelope<double> const& box, std::wstring const& text)
|
||||
{
|
||||
tree_.insert(label(box, text), box);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
tree_.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,37 +49,34 @@ namespace mapnik
|
|||
{
|
||||
typedef coord_transform2<CoordTransform,geometry_type> path_type;
|
||||
|
||||
//For shields
|
||||
placement(string_info *info_,
|
||||
CoordTransform *ctrans_,
|
||||
const proj_transform *proj_trans_,
|
||||
geometry_ptr geom_,
|
||||
std::pair<double, double> dimensions_);
|
||||
|
||||
//For text
|
||||
template <typename SymbolizerT>
|
||||
placement(string_info *info_,
|
||||
CoordTransform *ctrans_,
|
||||
const proj_transform *proj_trans_,
|
||||
geometry_ptr geom_,
|
||||
position const& displacement,
|
||||
label_placement_e placement_);
|
||||
SymbolizerT sym);
|
||||
|
||||
~placement();
|
||||
|
||||
//helpers
|
||||
std::pair<double, double> get_position_at_distance(double target_distance);
|
||||
double get_total_distance();
|
||||
void clear_envelopes();
|
||||
|
||||
unsigned path_size() const;
|
||||
|
||||
string_info *info;
|
||||
|
||||
CoordTransform *ctrans;
|
||||
const proj_transform *proj_trans;
|
||||
|
||||
geometry_ptr geom;
|
||||
path_type shape_path;
|
||||
|
||||
double total_distance_; //cache for distance
|
||||
|
||||
position displacement_;
|
||||
label_placement_e label_placement;
|
||||
std::pair<double, double> dimensions;
|
||||
|
||||
bool has_dimensions;
|
||||
|
||||
path_type shape_path;
|
||||
std::queue< Envelope<double> > envelopes;
|
||||
|
||||
//output
|
||||
|
@ -88,13 +85,6 @@ namespace mapnik
|
|||
// caching output
|
||||
placement_element current_placement;
|
||||
|
||||
//helpers
|
||||
std::pair<double, double> get_position_at_distance(double target_distance);
|
||||
double get_total_distance();
|
||||
void clear_envelopes();
|
||||
|
||||
double total_distance_; //cache for distance
|
||||
|
||||
int wrap_width;
|
||||
int text_ratio;
|
||||
|
||||
|
@ -103,8 +93,12 @@ namespace mapnik
|
|||
bool force_odd_labels; //Always try render an odd amount of labels
|
||||
|
||||
double max_char_angle_delta;
|
||||
double minimum_distance;
|
||||
|
||||
bool avoid_edges;
|
||||
|
||||
bool has_dimensions;
|
||||
std::pair<double, double> dimensions;
|
||||
};
|
||||
|
||||
|
||||
|
@ -115,7 +109,7 @@ namespace mapnik
|
|||
public:
|
||||
//e is the dimensions of the map, buffer is the buffer used for collission detection.
|
||||
placement_finder(DetectorT & detector,Envelope<double> const& e);
|
||||
bool find_placements(placement *p);
|
||||
void find_placements(placement *p);
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
|
@ -123,9 +117,10 @@ namespace mapnik
|
|||
bool find_placement_horizontal(placement *p);
|
||||
bool build_path_follow(placement *p, double target_distance);
|
||||
bool build_path_horizontal(placement *p, double target_distance);
|
||||
std::vector<double> get_ideal_placements(placement *p);
|
||||
void update_detector(placement *p);
|
||||
Envelope<double> dimensions_;
|
||||
DetectorT & detector_;
|
||||
Envelope<double> dimensions_;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -27,43 +27,28 @@
|
|||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <mapnik/graphics.hpp>
|
||||
#include <mapnik/text_symbolizer.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
struct MAPNIK_DECL shield_symbolizer
|
||||
{
|
||||
explicit shield_symbolizer();
|
||||
shield_symbolizer(std::string const& name,
|
||||
std::string const& face_name,
|
||||
unsigned size,
|
||||
Color const& fill,
|
||||
std::string const& file,
|
||||
std::string const& type,
|
||||
unsigned width,unsigned height);
|
||||
shield_symbolizer(shield_symbolizer const& rhs);
|
||||
void set_data (boost::shared_ptr<ImageData32> symbol);
|
||||
boost::shared_ptr<ImageData32> const& get_data() const;
|
||||
|
||||
std::string const& get_name() const;
|
||||
std::string const& get_face_name() const;
|
||||
struct MAPNIK_DECL shield_symbolizer : public text_symbolizer
|
||||
{
|
||||
shield_symbolizer(std::string const& name,
|
||||
std::string const& face_name,
|
||||
unsigned size,
|
||||
Color const& fill,
|
||||
std::string const& file,
|
||||
std::string const& type,
|
||||
unsigned width,unsigned height);
|
||||
|
||||
|
||||
void set_background_image(boost::shared_ptr<ImageData32>);
|
||||
boost::shared_ptr<ImageData32> const& get_background_image() const;
|
||||
|
||||
unsigned get_text_size() const;
|
||||
Color const& get_fill() const;
|
||||
|
||||
void set_allow_overlap(bool overlap);
|
||||
bool get_allow_overlap() const;
|
||||
|
||||
void set_avoid_edges(bool avoid);
|
||||
bool get_avoid_edges() const;
|
||||
private:
|
||||
std::string name_;
|
||||
std::string face_name_;
|
||||
unsigned size_;
|
||||
Color fill_;
|
||||
boost::shared_ptr<ImageData32> symbol_;
|
||||
bool overlap_;
|
||||
bool avoid_edges_;
|
||||
};
|
||||
private:
|
||||
boost::shared_ptr<ImageData32> background_image_;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SHIELD_SYMBOLIZER_HPP
|
||||
|
|
|
@ -53,14 +53,17 @@ namespace mapnik
|
|||
|
||||
typedef boost::ptr_vector<character_info> characters_t;
|
||||
|
||||
std::wstring string_;
|
||||
characters_t characters_;
|
||||
unsigned itr_;
|
||||
|
||||
double width_;
|
||||
double height_;
|
||||
public:
|
||||
string_info() : itr_(0), width_(0), height_(0) {}
|
||||
|
||||
string_info(std::wstring string)
|
||||
: string_(string),
|
||||
width_(0),
|
||||
height_(0) {}
|
||||
|
||||
void add_info(int c, double width, double height)
|
||||
{
|
||||
characters_.push_back(new character_info(c, width, height));
|
||||
|
@ -91,6 +94,10 @@ namespace mapnik
|
|||
{
|
||||
return std::pair<double, double>(width_, height_);
|
||||
}
|
||||
|
||||
std::wstring get_string() {
|
||||
return string_;
|
||||
}
|
||||
};
|
||||
|
||||
struct text_path
|
||||
|
|
|
@ -28,8 +28,10 @@
|
|||
#include <string>
|
||||
// boost
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
// mapnik
|
||||
#include <mapnik/color.hpp>
|
||||
#include <mapnik/graphics.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
|
@ -74,9 +76,10 @@ namespace mapnik
|
|||
position const& get_displacement() const;
|
||||
void set_avoid_edges(bool avoid);
|
||||
bool get_avoid_edges() const;
|
||||
void set_minimum_distance(double distance);
|
||||
double get_minimum_distance() const;
|
||||
void set_allow_overlap(bool overlap);
|
||||
bool get_allow_overlap() const;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::string face_name_;
|
||||
|
@ -94,6 +97,7 @@ namespace mapnik
|
|||
position anchor_;
|
||||
position displacement_;
|
||||
bool avoid_edges_;
|
||||
double minimum_distance_;
|
||||
bool overlap_;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -340,39 +340,35 @@ namespace mapnik
|
|||
if (geom && geom->num_points() > 0)
|
||||
{
|
||||
std::wstring text = feature[sym.get_name()].to_unicode();
|
||||
boost::shared_ptr<ImageData32> const& data = sym.get_data();
|
||||
boost::shared_ptr<ImageData32> const& data = sym.get_background_image();
|
||||
|
||||
if (text.length() > 0 && data)
|
||||
{
|
||||
face_ptr face = font_manager_.get_face(sym.get_face_name());
|
||||
if (face)
|
||||
{
|
||||
int w = data->width();
|
||||
int h = data->height();
|
||||
|
||||
text_renderer<mapnik::Image32> ren(pixmap_,face);
|
||||
ren.set_pixel_size(sym.get_text_size());
|
||||
ren.set_fill(sym.get_fill());
|
||||
|
||||
string_info info;
|
||||
ren.get_string_info(text, &info);
|
||||
string_info info(text);
|
||||
ren.get_string_info(&info);
|
||||
|
||||
placement text_placement(&info, &t_, &prj_trans, geom, std::pair<double, double>(w, h) );
|
||||
placement text_placement(&info, &t_, &prj_trans, geom, sym);
|
||||
text_placement.avoid_edges = sym.get_avoid_edges();
|
||||
|
||||
bool found = finder_.find_placements(&text_placement);
|
||||
if (!found) {
|
||||
return;
|
||||
}
|
||||
|
||||
finder_.find_placements(&text_placement);
|
||||
|
||||
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii)
|
||||
{
|
||||
{
|
||||
int w = data->width();
|
||||
int h = data->height();
|
||||
|
||||
double x = text_placement.placements[ii].starting_x;
|
||||
double y = text_placement.placements[ii].starting_y;
|
||||
|
||||
int px=int(floor(x - 0.5 * w));
|
||||
int py=int(floor(y - 0.5 * h));
|
||||
int px=int(x - (w/2));
|
||||
int py=int(y - (h/2));
|
||||
|
||||
pixmap_.set_rectangle_alpha(px,py,*data);
|
||||
|
||||
|
@ -512,25 +508,12 @@ namespace mapnik
|
|||
ren.set_halo_fill(sym.get_halo_fill());
|
||||
ren.set_halo_radius(sym.get_halo_radius());
|
||||
|
||||
string_info info;
|
||||
string_info info(text);
|
||||
ren.get_string_info(&info);
|
||||
|
||||
ren.get_string_info(text, &info);
|
||||
|
||||
placement text_placement(&info, &t_, &prj_trans, geom,
|
||||
sym.get_displacement(),
|
||||
sym.get_label_placement());
|
||||
placement text_placement(&info, &t_, &prj_trans, geom, sym);
|
||||
|
||||
text_placement.text_ratio = sym.get_text_ratio();
|
||||
text_placement.wrap_width = sym.get_wrap_width();
|
||||
text_placement.label_spacing = sym.get_label_spacing();
|
||||
text_placement.label_position_tolerance = sym.get_label_position_tolerance();
|
||||
text_placement.force_odd_labels = sym.get_force_odd_labels();
|
||||
text_placement.max_char_angle_delta = sym.get_max_char_angle_delta();
|
||||
text_placement.avoid_edges = sym.get_avoid_edges();
|
||||
|
||||
bool allow_overlap = sym.get_allow_overlap(); //FIXME!!!
|
||||
|
||||
if ( !finder_.find_placements(&text_placement)) return;
|
||||
finder_.find_placements(&text_placement);
|
||||
|
||||
for (unsigned int ii = 0; ii < text_placement.placements.size(); ++ ii)
|
||||
{
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/placement_finder.hpp>
|
||||
#include <mapnik/text_path.hpp>
|
||||
#include <mapnik/shield_symbolizer.hpp>
|
||||
#include <mapnik/text_symbolizer.hpp>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
|
@ -45,56 +47,61 @@
|
|||
|
||||
namespace mapnik
|
||||
{
|
||||
//For shields
|
||||
template<>
|
||||
placement::placement(string_info *info_,
|
||||
CoordTransform *ctrans_,
|
||||
const proj_transform *proj_trans_,
|
||||
geometry_ptr geom_,
|
||||
std::pair<double, double> dimensions_)
|
||||
CoordTransform *ctrans_,
|
||||
const proj_transform *proj_trans_,
|
||||
geometry_ptr geom_,
|
||||
shield_symbolizer sym)
|
||||
: info(info_),
|
||||
ctrans(ctrans_),
|
||||
proj_trans(proj_trans_),
|
||||
geom(geom_),
|
||||
displacement_(0,0),
|
||||
label_placement(point_placement),
|
||||
dimensions(dimensions_),
|
||||
has_dimensions(true),
|
||||
shape_path(*ctrans_, *geom_, *proj_trans_),
|
||||
total_distance_(-1.0),
|
||||
wrap_width(0),
|
||||
text_ratio(0),
|
||||
label_spacing(0),
|
||||
label_position_tolerance(0),
|
||||
force_odd_labels(false),
|
||||
max_char_angle_delta(0.0), avoid_edges(false)
|
||||
displacement_(sym.get_displacement()),
|
||||
label_placement(sym.get_label_placement()),
|
||||
wrap_width(sym.get_wrap_width()),
|
||||
text_ratio(sym.get_text_ratio()),
|
||||
label_spacing(sym.get_label_spacing()),
|
||||
label_position_tolerance(sym.get_label_position_tolerance()),
|
||||
force_odd_labels(sym.get_force_odd_labels()),
|
||||
max_char_angle_delta(sym.get_max_char_angle_delta()),
|
||||
minimum_distance(sym.get_minimum_distance()),
|
||||
avoid_edges(sym.get_avoid_edges()),
|
||||
has_dimensions(true),
|
||||
dimensions(std::make_pair(sym.get_background_image()->width(),
|
||||
sym.get_background_image()->height()))
|
||||
{
|
||||
}
|
||||
|
||||
//For text
|
||||
|
||||
template<>
|
||||
placement::placement(string_info *info_,
|
||||
CoordTransform *ctrans_,
|
||||
const proj_transform *proj_trans_,
|
||||
geometry_ptr geom_,
|
||||
position const& displacement,
|
||||
label_placement_e placement_)
|
||||
CoordTransform *ctrans_,
|
||||
const proj_transform *proj_trans_,
|
||||
geometry_ptr geom_,
|
||||
text_symbolizer sym)
|
||||
: info(info_),
|
||||
ctrans(ctrans_),
|
||||
proj_trans(proj_trans_),
|
||||
geom(geom_),
|
||||
displacement_(displacement),
|
||||
label_placement(placement_),
|
||||
has_dimensions(false),
|
||||
geom(geom_),
|
||||
shape_path(*ctrans_, *geom_, *proj_trans_),
|
||||
total_distance_(-1.0),
|
||||
wrap_width(0),
|
||||
text_ratio(0),
|
||||
label_spacing(0),
|
||||
label_position_tolerance(0),
|
||||
force_odd_labels(false),
|
||||
max_char_angle_delta(0.0),
|
||||
avoid_edges(false)
|
||||
displacement_(sym.get_displacement()),
|
||||
label_placement(sym.get_label_placement()),
|
||||
wrap_width(sym.get_wrap_width()),
|
||||
text_ratio(sym.get_text_ratio()),
|
||||
label_spacing(sym.get_label_spacing()),
|
||||
label_position_tolerance(sym.get_label_position_tolerance()),
|
||||
force_odd_labels(sym.get_force_odd_labels()),
|
||||
max_char_angle_delta(sym.get_max_char_angle_delta()),
|
||||
minimum_distance(sym.get_minimum_distance()),
|
||||
avoid_edges(sym.get_avoid_edges()),
|
||||
has_dimensions(false),
|
||||
dimensions()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
placement::~placement()
|
||||
{
|
||||
|
@ -185,50 +192,43 @@ namespace mapnik
|
|||
placement_finder<DetectorT>::placement_finder(DetectorT & detector,Envelope<double> const& e)
|
||||
: detector_(detector),
|
||||
dimensions_(e)
|
||||
//detector_(Envelope<double>(e.minx() - buffer, e.miny() - buffer, e.maxx() + buffer, e.maxy() + buffer))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename DetectorT>
|
||||
bool placement_finder<DetectorT>::find_placements(placement *p)
|
||||
std::vector<double> placement_finder<DetectorT>::get_ideal_placements(placement *p)
|
||||
{
|
||||
if (p->label_placement == point_placement)
|
||||
{
|
||||
return find_placement_horizontal(p);
|
||||
}
|
||||
else if (p->label_placement == line_placement)
|
||||
{
|
||||
return find_placement_follow(p);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
std::vector<double> ideal_label_distances;
|
||||
|
||||
template <typename DetectorT>
|
||||
bool placement_finder<DetectorT>::find_placement_follow(placement *p)
|
||||
{
|
||||
std::pair<double, double> string_dimensions = p->info->get_dimensions();
|
||||
double string_width = string_dimensions.first;
|
||||
|
||||
double distance = p->get_total_distance();
|
||||
|
||||
if (string_width > distance)
|
||||
if (p->label_placement == line_placement && string_width > distance)
|
||||
{
|
||||
return false;
|
||||
//Empty!
|
||||
return ideal_label_distances;
|
||||
}
|
||||
|
||||
int num_labels = 0;
|
||||
if (p->label_spacing)
|
||||
if (p->label_spacing && p->label_placement == line_placement)
|
||||
num_labels = static_cast<int> (floor(distance / (p->label_spacing + string_width)));
|
||||
else if (p->label_spacing && p->label_placement == point_placement)
|
||||
num_labels = static_cast<int> (floor(distance / p->label_spacing));
|
||||
|
||||
if (p->force_odd_labels && num_labels%2 == 0)
|
||||
num_labels--;
|
||||
if (num_labels <= 0)
|
||||
num_labels = 1;
|
||||
|
||||
double ideal_spacing = distance/num_labels;
|
||||
std::vector<double> ideal_label_distances;
|
||||
|
||||
double middle = (distance / 2.0) - (string_width/2.0); //try draw text centered
|
||||
double middle; //try draw text centered
|
||||
if (p->label_placement == line_placement)
|
||||
middle = (distance / 2.0) - (string_width/2.0);
|
||||
else if (p->label_placement == point_placement)
|
||||
middle = distance / 2.0;
|
||||
|
||||
if (num_labels % 2) //odd amount of labels
|
||||
{
|
||||
|
@ -248,91 +248,59 @@ namespace mapnik
|
|||
ideal_label_distances.push_back(middle + (ideal_spacing/2.0) + (a*ideal_spacing));
|
||||
}
|
||||
}
|
||||
|
||||
double delta;
|
||||
double tolerance;
|
||||
|
||||
if (p->label_position_tolerance > 0)
|
||||
|
||||
if (p->label_position_tolerance == 0)
|
||||
{
|
||||
tolerance = p->label_position_tolerance;
|
||||
delta = std::max ( 1.0, p->label_position_tolerance/100.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tolerance = ideal_spacing/2.0;
|
||||
delta = ideal_spacing/100.0;
|
||||
p->label_position_tolerance = unsigned(ideal_spacing/2.0);
|
||||
}
|
||||
|
||||
|
||||
bool FoundPlacement = false;
|
||||
std::vector<double>::const_iterator itr = ideal_label_distances.begin();
|
||||
std::vector<double>::const_iterator end = ideal_label_distances.end();
|
||||
for (; itr != end; ++itr)
|
||||
{
|
||||
//std::clog << "Trying to find txt placement at distance: " << *itr << std::endl;
|
||||
for (double i = 0; i < tolerance; i += delta)
|
||||
{
|
||||
if (*itr + i > distance || *itr -i < 0.0)
|
||||
continue;
|
||||
|
||||
p->clear_envelopes();
|
||||
|
||||
// check position +- delta for valid placement
|
||||
if ( build_path_follow(p, *itr + i) ) {
|
||||
update_detector(p);
|
||||
FoundPlacement = true;
|
||||
break;
|
||||
}
|
||||
|
||||
p->clear_envelopes();
|
||||
if ( build_path_follow(p, *itr - i) ) {
|
||||
update_detector(p);
|
||||
FoundPlacement = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (FoundPlacement)
|
||||
// std::clog << "Found Placement" << string_width << " " << distance << std::endl;
|
||||
|
||||
return FoundPlacement;
|
||||
return ideal_label_distances;
|
||||
}
|
||||
|
||||
|
||||
template <typename DetectorT>
|
||||
bool placement_finder<DetectorT>::find_placement_horizontal(placement *p)
|
||||
void placement_finder<DetectorT>::find_placements(placement *p)
|
||||
{
|
||||
if (p->path_size() == 1) // point geometry
|
||||
{
|
||||
if ( build_path_horizontal(p, 0) )
|
||||
{
|
||||
update_detector(p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
double distance = p->get_total_distance();
|
||||
//~ double delta = string_width/distance;
|
||||
double delta = distance/100.0;
|
||||
|
||||
for (double i = 0; i < distance/2.0; i += delta)
|
||||
|
||||
std::vector<double> ideal_label_distances = get_ideal_placements(p);
|
||||
|
||||
double delta, tolerance, distance;
|
||||
distance = p->get_total_distance();
|
||||
tolerance = p->label_position_tolerance;
|
||||
delta = std::max ( 1.0, tolerance/100.0);
|
||||
|
||||
std::vector<double>::const_iterator itr = ideal_label_distances.begin();
|
||||
std::vector<double>::const_iterator end = ideal_label_distances.end();
|
||||
for (; itr != end; ++itr)
|
||||
{
|
||||
p->clear_envelopes();
|
||||
|
||||
if ( build_path_horizontal(p, distance/2.0 + i) ) {
|
||||
update_detector(p);
|
||||
return true;
|
||||
bool placed = false;
|
||||
for (double i = 0; i < tolerance && !placed; i += delta)
|
||||
{
|
||||
for (int s = 1; s != -1; s-=2) {
|
||||
if (*itr + i*s > distance || *itr + i*s < 0.0) {
|
||||
continue;
|
||||
}
|
||||
p->clear_envelopes();
|
||||
// check position +- delta for valid placement
|
||||
if ((p->label_placement == line_placement &&
|
||||
build_path_follow(p, *itr + (i*s)) ) ||
|
||||
(p->label_placement == point_placement &&
|
||||
build_path_horizontal(p, *itr + (i*s))) )
|
||||
{
|
||||
update_detector(p);
|
||||
placed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p->clear_envelopes();
|
||||
|
||||
if ( build_path_horizontal(p, distance/2.0 - i) ) {
|
||||
update_detector(p);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DetectorT>
|
||||
|
@ -342,7 +310,7 @@ namespace mapnik
|
|||
{
|
||||
Envelope<double> e = p->envelopes.front();
|
||||
|
||||
detector_.insert(e);
|
||||
detector_.insert(e, p->info->get_string());
|
||||
|
||||
p->envelopes.pop();
|
||||
}
|
||||
|
@ -493,7 +461,7 @@ namespace mapnik
|
|||
e.expand_to_include(render_x + (ci.width*cos(render_angle) - ci.height*sin(render_angle)), render_y - (ci.width*sin(render_angle) + ci.height*cos(render_angle)));
|
||||
}
|
||||
|
||||
if (!detector_.has_placement(e))
|
||||
if (!detector_.has_placement(e, p->info->get_string(), p->minimum_distance))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -529,7 +497,7 @@ namespace mapnik
|
|||
bool placement_finder<DetectorT>::build_path_horizontal(placement *p, double target_distance)
|
||||
{
|
||||
double x, y;
|
||||
|
||||
|
||||
p->current_placement.path.clear();
|
||||
|
||||
std::pair<double, double> string_dimensions = p->info->get_dimensions();
|
||||
|
@ -630,7 +598,7 @@ namespace mapnik
|
|||
unsigned int index_to_wrap_at = line_breaks[line_number];
|
||||
double line_width = line_widths[line_number];
|
||||
|
||||
x = -line_width/2.0;
|
||||
x = -line_width/2.0 - 1.0;
|
||||
y = -string_height/2.0 + 1.0;
|
||||
|
||||
for (unsigned i = 0; i < p->info->num_characters(); i++)
|
||||
|
@ -668,7 +636,7 @@ namespace mapnik
|
|||
p->current_placement.starting_y - y - ci.height);
|
||||
}
|
||||
|
||||
if (!detector_.has_placement(e))
|
||||
if (!detector_.has_placement(e, p->info->get_string(), p->minimum_distance))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -694,6 +662,6 @@ namespace mapnik
|
|||
detector_.clear();
|
||||
}
|
||||
|
||||
template class placement_finder<label_collision_detector3>;
|
||||
template class placement_finder<label_collision_detector4>;
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -34,14 +34,6 @@
|
|||
|
||||
namespace mapnik
|
||||
{
|
||||
shield_symbolizer::shield_symbolizer()
|
||||
: symbol_(new ImageData32(4,4)),
|
||||
overlap_(false)
|
||||
{
|
||||
//default point symbol is black 4x4px square
|
||||
symbol_->set(0xff000000);
|
||||
}
|
||||
|
||||
shield_symbolizer::shield_symbolizer(
|
||||
std::string const& name,
|
||||
std::string const& face_name,
|
||||
|
@ -50,14 +42,15 @@ namespace mapnik
|
|||
std::string const& file,
|
||||
std::string const& type,
|
||||
unsigned width,unsigned height)
|
||||
: name_(name), face_name_(face_name), size_(size), fill_(fill), symbol_(new ImageData32(width,height)), avoid_edges_(false)
|
||||
: text_symbolizer(name, face_name, size, fill),
|
||||
background_image_(new ImageData32(width, height))
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::scoped_ptr<ImageReader> reader(get_image_reader(type,file));
|
||||
if (reader.get())
|
||||
{
|
||||
reader->read(0,0,*symbol_);
|
||||
reader->read(0,0,*background_image_);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
|
@ -65,65 +58,15 @@ namespace mapnik
|
|||
std::clog << "exception caught..." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
shield_symbolizer::shield_symbolizer(shield_symbolizer const& rhs)
|
||||
: name_(rhs.name_),
|
||||
face_name_(rhs.face_name_),
|
||||
size_(rhs.size_),
|
||||
fill_(rhs.fill_),
|
||||
symbol_(rhs.symbol_),
|
||||
overlap_(rhs.overlap_),
|
||||
avoid_edges_(rhs.avoid_edges_)
|
||||
{}
|
||||
|
||||
void shield_symbolizer::set_data( boost::shared_ptr<ImageData32> symbol)
|
||||
|
||||
void shield_symbolizer::set_background_image(boost::shared_ptr<ImageData32> background_image)
|
||||
{
|
||||
symbol_ = symbol;
|
||||
background_image_ = background_image;
|
||||
}
|
||||
|
||||
boost::shared_ptr<ImageData32> const& shield_symbolizer::get_data() const
|
||||
boost::shared_ptr<ImageData32> const& shield_symbolizer::get_background_image() const
|
||||
{
|
||||
return symbol_;
|
||||
}
|
||||
|
||||
std::string const& shield_symbolizer::get_name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
std::string const& shield_symbolizer::get_face_name() const
|
||||
{
|
||||
return face_name_;
|
||||
}
|
||||
|
||||
void shield_symbolizer::set_allow_overlap(bool overlap)
|
||||
{
|
||||
overlap_ = overlap;
|
||||
}
|
||||
|
||||
bool shield_symbolizer::get_allow_overlap() const
|
||||
{
|
||||
return overlap_;
|
||||
}
|
||||
|
||||
unsigned shield_symbolizer::get_text_size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
Color const& shield_symbolizer::get_fill() const
|
||||
{
|
||||
return fill_;
|
||||
}
|
||||
|
||||
bool shield_symbolizer::get_avoid_edges() const
|
||||
{
|
||||
return avoid_edges_;
|
||||
}
|
||||
|
||||
void shield_symbolizer::set_avoid_edges(bool avoid)
|
||||
{
|
||||
avoid_edges_ = avoid;
|
||||
return background_image_;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,32 +22,34 @@
|
|||
|
||||
//$Id$
|
||||
|
||||
|
||||
//stl
|
||||
#include <iostream>
|
||||
|
||||
// boost
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
//mapnik
|
||||
#include <mapnik/text_symbolizer.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
text_symbolizer::text_symbolizer(std::string const& name, std::string const& face_name, unsigned size,Color const& fill)
|
||||
: name_(name),
|
||||
: name_(name),
|
||||
face_name_(face_name),
|
||||
size_(size),
|
||||
size_(size),
|
||||
text_ratio_(0),
|
||||
wrap_width_(0),
|
||||
label_spacing_(0),
|
||||
label_position_tolerance_(0),
|
||||
force_odd_labels_(false),
|
||||
max_char_angle_delta_(0),
|
||||
fill_(fill),
|
||||
halo_fill_(Color(255,255,255)),
|
||||
halo_radius_(0),
|
||||
label_p_(point_placement),
|
||||
anchor_(0.0,0.5),
|
||||
displacement_(0.0,0.0),
|
||||
fill_(fill),
|
||||
halo_fill_(Color(255,255,255)),
|
||||
halo_radius_(0),
|
||||
label_p_(point_placement),
|
||||
anchor_(0.0,0.5),
|
||||
displacement_(0.0,0.0),
|
||||
avoid_edges_(false),
|
||||
minimum_distance_(0.0),
|
||||
overlap_(false) {}
|
||||
|
||||
text_symbolizer::text_symbolizer(text_symbolizer const& rhs)
|
||||
: name_(rhs.name_),
|
||||
face_name_(rhs.face_name_),
|
||||
|
@ -65,6 +67,7 @@ namespace mapnik
|
|||
anchor_(rhs.anchor_),
|
||||
displacement_(rhs.displacement_),
|
||||
avoid_edges_(rhs.avoid_edges_),
|
||||
minimum_distance_(rhs.minimum_distance_),
|
||||
overlap_(rhs.overlap_) {}
|
||||
|
||||
text_symbolizer& text_symbolizer::operator=(text_symbolizer const& other)
|
||||
|
@ -87,7 +90,9 @@ namespace mapnik
|
|||
anchor_ = other.anchor_;
|
||||
displacement_ = other.displacement_;
|
||||
avoid_edges_ = other.avoid_edges_;
|
||||
minimum_distance_ = other.minimum_distance_;
|
||||
overlap_ = other.overlap_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -230,13 +235,23 @@ namespace mapnik
|
|||
avoid_edges_ = avoid;
|
||||
}
|
||||
|
||||
void text_symbolizer::set_allow_overlap(bool overlap)
|
||||
{
|
||||
overlap_ = overlap;
|
||||
}
|
||||
double text_symbolizer::get_minimum_distance() const
|
||||
{
|
||||
return minimum_distance_;
|
||||
}
|
||||
|
||||
void text_symbolizer::set_minimum_distance(double distance)
|
||||
{
|
||||
minimum_distance_ = distance;
|
||||
}
|
||||
|
||||
void text_symbolizer::set_allow_overlap(bool overlap)
|
||||
{
|
||||
overlap_ = overlap;
|
||||
}
|
||||
|
||||
bool text_symbolizer::get_allow_overlap() const
|
||||
{
|
||||
bool text_symbolizer::get_allow_overlap() const
|
||||
{
|
||||
return overlap_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue