1) Added line following labels. Use set_label_placement(POINT_PLACEMENT) or set_label_placement(LINE_PLACEMENT) on a text symbolizer.
2) Added placement_finder class so labels try to avoid each other. 3) Added Shield Symbolizer which is essentially a combined image/text symbolizer.
This commit is contained in:
parent
7c398909f4
commit
f76079f15b
16 changed files with 1120 additions and 78 deletions
|
@ -46,6 +46,7 @@ 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_font_engine();
|
||||
void export_projection();
|
||||
|
@ -107,6 +108,7 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
export_polygon_symbolizer();
|
||||
export_polygon_pattern_symbolizer();
|
||||
export_raster_symbolizer();
|
||||
export_shield_symbolizer();
|
||||
export_text_symbolizer();
|
||||
export_font_engine();
|
||||
export_projection();
|
||||
|
|
|
@ -41,6 +41,7 @@ void export_rule()
|
|||
using mapnik::polygon_symbolizer;
|
||||
using mapnik::polygon_pattern_symbolizer;
|
||||
using mapnik::raster_symbolizer;
|
||||
using mapnik::shield_symbolizer;
|
||||
using mapnik::text_symbolizer;
|
||||
using mapnik::symbolizer;
|
||||
using mapnik::symbolizers;
|
||||
|
@ -52,6 +53,7 @@ void export_rule()
|
|||
implicitly_convertible<polygon_symbolizer,symbolizer>();
|
||||
implicitly_convertible<polygon_pattern_symbolizer,symbolizer>();
|
||||
implicitly_convertible<raster_symbolizer,symbolizer>();
|
||||
implicitly_convertible<shield_symbolizer,symbolizer>();
|
||||
implicitly_convertible<text_symbolizer,symbolizer>();
|
||||
|
||||
class_<symbolizers>("Symbolizers",init<>("TODO"))
|
||||
|
|
39
bindings/python/mapnik_shield_symbolizer.cpp
Normal file
39
bindings/python/mapnik_shield_symbolizer.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon
|
||||
* Copyright (C) 2006 10East Corp.
|
||||
*
|
||||
* 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$
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <mapnik/shield_symbolizer.hpp>
|
||||
|
||||
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&, unsigned, mapnik::Color const&,
|
||||
std::string const&, std::string const&,unsigned,unsigned>("TODO"))
|
||||
;
|
||||
|
||||
}
|
|
@ -32,6 +32,11 @@ void export_text_symbolizer()
|
|||
using mapnik::text_symbolizer;
|
||||
using mapnik::Color;
|
||||
|
||||
enum_<mapnik::label_placement_e>("label_placement")
|
||||
.value("LINE_PLACEMENT",mapnik::line_placement)
|
||||
.value("POINT_PLACEMENT",mapnik::point_placement)
|
||||
;
|
||||
|
||||
class_<text_symbolizer>("TextSymbolizer",
|
||||
init<std::string const&,unsigned,Color const&>())
|
||||
.add_property("halo_fill",make_function(
|
||||
|
@ -41,5 +46,7 @@ void export_text_symbolizer()
|
|||
.add_property("halo_radius",
|
||||
&text_symbolizer::get_halo_radius,
|
||||
&text_symbolizer::set_halo_radius)
|
||||
.def("set_label_placement",&text_symbolizer::set_label_placement,
|
||||
"Set the placement of the label")
|
||||
;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <mapnik/feature_style_processor.hpp>
|
||||
#include <mapnik/font_engine_freetype.hpp>
|
||||
#include <mapnik/label_collision_detector.hpp>
|
||||
#include <mapnik/placement_finder.hpp>
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/config.hpp>
|
||||
|
||||
|
@ -63,6 +64,9 @@ namespace mapnik {
|
|||
void process(raster_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(shield_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(text_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
proj_transform const& prj_trans);
|
||||
|
@ -70,7 +74,9 @@ namespace mapnik {
|
|||
T & pixmap_;
|
||||
CoordTransform t_;
|
||||
face_manager<freetype_engine> font_manager_;
|
||||
label_collision_detector2 detector_;
|
||||
// label_collision_detector2 label_detector_;
|
||||
placement_finder finder_;
|
||||
label_collision_detector2 point_detector_; //Note: May want to merge this with placement_finder
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,10 @@ namespace mapnik {
|
|||
{
|
||||
names_.insert(sym.get_name());
|
||||
}
|
||||
void operator () (shield_symbolizer const& sym)
|
||||
{
|
||||
names_.insert(sym.get_name());
|
||||
}
|
||||
private:
|
||||
std::set<std::string>& names_;
|
||||
};
|
||||
|
|
|
@ -46,6 +46,10 @@ extern "C"
|
|||
// mapnik
|
||||
#include <mapnik/color.hpp>
|
||||
#include <mapnik/utils.hpp>
|
||||
#include <mapnik/ctrans.hpp>
|
||||
#include <mapnik/geometry.hpp>
|
||||
|
||||
#include <mapnik/text_path.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
|
@ -84,6 +88,7 @@ namespace mapnik
|
|||
{
|
||||
if (! FT_Set_Pixel_Sizes( face_, 0, size ))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -199,7 +204,6 @@ namespace mapnik
|
|||
template <typename T>
|
||||
struct text_renderer : private boost::noncopyable
|
||||
{
|
||||
|
||||
struct glyph_t : boost::noncopyable
|
||||
{
|
||||
FT_Glyph image;
|
||||
|
@ -216,19 +220,13 @@ namespace mapnik
|
|||
face_(face),
|
||||
fill_(0,0,0),
|
||||
halo_fill_(255,255,255),
|
||||
halo_radius_(0),
|
||||
angle_(0.0) {}
|
||||
halo_radius_(0) {}
|
||||
|
||||
void set_pixel_size(unsigned size)
|
||||
{
|
||||
face_->set_pixel_sizes(size);
|
||||
}
|
||||
|
||||
void set_angle(float angle)
|
||||
{
|
||||
angle_=angle;
|
||||
}
|
||||
|
||||
void set_fill(mapnik::Color const& fill)
|
||||
{
|
||||
fill_=fill;
|
||||
|
@ -244,7 +242,7 @@ namespace mapnik
|
|||
halo_radius_=radius;
|
||||
}
|
||||
|
||||
dimension_t prepare_glyphs(std::string const& text)
|
||||
Envelope<double> prepare_glyphs(text_path *path)
|
||||
{
|
||||
//clear glyphs
|
||||
glyphs_.clear();
|
||||
|
@ -254,43 +252,35 @@ namespace mapnik
|
|||
FT_Error error;
|
||||
|
||||
FT_Face face = face_->get_face();
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
FT_Bool use_kerning;
|
||||
FT_UInt previous = 0;
|
||||
|
||||
pen.x = 0;
|
||||
pen.y = 0;
|
||||
|
||||
use_kerning = FT_HAS_KERNING(face)>0?true:false;
|
||||
// FT_GlyphSlot slot = face->glyph;
|
||||
|
||||
FT_BBox bbox;
|
||||
bbox.xMin = bbox.yMin = 32000;
|
||||
bbox.xMax = bbox.yMax = -32000; //hmm??
|
||||
|
||||
for (std::string::const_iterator i=text.begin();i!=text.end();++i)
|
||||
for (int i = 0; i < path->num_nodes(); i++)
|
||||
{
|
||||
int c;
|
||||
double x, y, angle;
|
||||
|
||||
path->vertex(&c, &x, &y, &angle);
|
||||
|
||||
FT_BBox glyph_bbox;
|
||||
FT_Glyph image;
|
||||
|
||||
matrix.xx = (FT_Fixed)( cos( angle_ ) * 0x10000L );
|
||||
matrix.xy = (FT_Fixed)(-sin( angle_ ) * 0x10000L );
|
||||
matrix.yx = (FT_Fixed)( sin( angle_ ) * 0x10000L );
|
||||
matrix.yy = (FT_Fixed)( cos( angle_ ) * 0x10000L );
|
||||
pen.x = int(x * 64);
|
||||
pen.y = int(y * 64);
|
||||
|
||||
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
|
||||
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
|
||||
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
|
||||
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
|
||||
|
||||
FT_Set_Transform (face,&matrix,&pen);
|
||||
|
||||
FT_UInt glyph_index = FT_Get_Char_Index( face, unsigned(*i) & 0xff );
|
||||
FT_UInt glyph_index = FT_Get_Char_Index( face, unsigned(c) & 0xff );
|
||||
|
||||
if ( use_kerning && previous && glyph_index)
|
||||
{
|
||||
FT_Vector delta;
|
||||
FT_Get_Kerning(face,previous,glyph_index,
|
||||
FT_KERNING_DEFAULT,&delta);
|
||||
pen.x += delta.x;
|
||||
pen.y += delta.y;
|
||||
}
|
||||
|
||||
error = FT_Load_Glyph (face,glyph_index,FT_LOAD_DEFAULT);
|
||||
error = FT_Load_Glyph (face,glyph_index, FT_LOAD_NO_HINTING);
|
||||
if ( error )
|
||||
continue;
|
||||
|
||||
|
@ -316,17 +306,66 @@ namespace mapnik
|
|||
bbox.yMax = 0;
|
||||
}
|
||||
|
||||
pen.x += slot->advance.x;
|
||||
pen.y += slot->advance.y;
|
||||
|
||||
previous = glyph_index;
|
||||
// take ownership of the glyph
|
||||
glyphs_.push_back(new glyph_t(image));
|
||||
}
|
||||
|
||||
unsigned string_width = (bbox.xMax - bbox.xMin);
|
||||
unsigned string_height = (bbox.yMax - bbox.yMin);
|
||||
return dimension_t(string_width,string_height);
|
||||
return Envelope<double>(bbox.xMin, bbox.yMin, bbox.xMax, bbox.yMax);
|
||||
}
|
||||
|
||||
dimension_t character_dimensions(const unsigned c)
|
||||
{
|
||||
FT_Matrix matrix;
|
||||
FT_Vector pen;
|
||||
FT_Error error;
|
||||
|
||||
FT_Face face = face_->get_face();
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
|
||||
pen.x = 0;
|
||||
pen.y = 0;
|
||||
|
||||
FT_BBox glyph_bbox;
|
||||
FT_Glyph image;
|
||||
|
||||
matrix.xx = (FT_Fixed)( 1 * 0x10000L );
|
||||
matrix.xy = (FT_Fixed)( 0 * 0x10000L );
|
||||
matrix.yx = (FT_Fixed)( 0 * 0x10000L );
|
||||
matrix.yy = (FT_Fixed)( 1 * 0x10000L );
|
||||
|
||||
FT_Set_Transform (face,&matrix,&pen);
|
||||
|
||||
FT_UInt glyph_index = FT_Get_Char_Index( face, c & 0xff );
|
||||
|
||||
error = FT_Load_Glyph (face,glyph_index,FT_LOAD_NO_HINTING);
|
||||
if ( error )
|
||||
return dimension_t(0, 0);
|
||||
|
||||
error = FT_Get_Glyph( face->glyph, &image);
|
||||
if ( error )
|
||||
return dimension_t(0, 0);
|
||||
|
||||
FT_Glyph_Get_CBox(image,ft_glyph_bbox_pixels, &glyph_bbox);
|
||||
|
||||
return dimension_t(slot->advance.x >> 6, glyph_bbox.yMax - glyph_bbox.yMin);
|
||||
}
|
||||
|
||||
void get_string_info(std::string const& text, string_info *info)
|
||||
{
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
|
||||
for (std::string::const_iterator i=text.begin();i!=text.end();++i)
|
||||
{
|
||||
dimension_t char_dim = character_dimensions(*i);
|
||||
|
||||
info->add_info(*i, char_dim.first, char_dim.second);
|
||||
|
||||
width += char_dim.first;
|
||||
height = char_dim.second > height ? char_dim.second : height;
|
||||
}
|
||||
|
||||
info->set_dimensions(width, height);
|
||||
}
|
||||
|
||||
void render(double x0, double y0)
|
||||
|
@ -421,12 +460,12 @@ namespace mapnik
|
|||
|
||||
pixmap_type & pixmap_;
|
||||
face_ptr face_;
|
||||
Color fill_;
|
||||
Color halo_fill_;
|
||||
mapnik::Color fill_;
|
||||
mapnik::Color halo_fill_;
|
||||
int halo_radius_;
|
||||
float angle_;
|
||||
glyphs_t glyphs_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif // FONT_ENGINE_FREETYPE_HPP
|
||||
|
|
|
@ -83,6 +83,38 @@ namespace mapnik
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// quad_tree based label collision detector with seperate check/insert
|
||||
class label_collision_detector3 : boost::noncopyable
|
||||
{
|
||||
typedef quad_tree< Envelope<double> > tree_t;
|
||||
tree_t tree_;
|
||||
public:
|
||||
|
||||
explicit label_collision_detector3(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->intersects(box))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert(Envelope<double> const& box)
|
||||
{
|
||||
tree_.insert(box, box);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
102
include/mapnik/placement_finder.hpp
Normal file
102
include/mapnik/placement_finder.hpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2006 Artem Pavlenko
|
||||
* Copyright (C) 2006 10East Corp.
|
||||
*
|
||||
* 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 __PLACEMENT_FINDER__
|
||||
#define __PLACEMENT_FINDER__
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include <mapnik/ctrans.hpp>
|
||||
#include <mapnik/label_collision_detector.hpp>
|
||||
#include <mapnik/text_symbolizer.hpp>
|
||||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/text_path.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
struct placement
|
||||
{
|
||||
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
|
||||
placement(string_info *info_, CoordTransform *ctrans_, const proj_transform *proj_trans_, geometry_ptr geom_, label_placement_e placement_);
|
||||
|
||||
~placement();
|
||||
|
||||
string_info *info;
|
||||
|
||||
CoordTransform *ctrans;
|
||||
const proj_transform *proj_trans;
|
||||
|
||||
geometry_ptr geom;
|
||||
label_placement_e label_placement;
|
||||
std::pair<double, double> dimensions;
|
||||
|
||||
bool has_dimensions;
|
||||
|
||||
path_type shape_path;
|
||||
std::queue< Envelope<double> > envelopes;
|
||||
|
||||
//output
|
||||
double starting_x;
|
||||
double starting_y;
|
||||
|
||||
text_path path;
|
||||
|
||||
|
||||
//helpers
|
||||
std::pair<double, double> get_position_at_distance(double target_distance);
|
||||
double get_total_distance();
|
||||
void placement::clear_envelopes();
|
||||
|
||||
double total_distance_; //cache for distance
|
||||
};
|
||||
|
||||
class placement_finder : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
placement_finder(Envelope<double> e);
|
||||
|
||||
bool find_placement(placement *placement);
|
||||
|
||||
protected:
|
||||
bool find_placement_follow(placement *p);
|
||||
bool find_placement_horizontal(placement *p);
|
||||
|
||||
bool build_path_follow(placement *p, double target_distance);
|
||||
bool build_path_horizontal(placement *p, double target_distance);
|
||||
|
||||
void update_detector(placement *p);
|
||||
|
||||
label_collision_detector3 detector_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
#include <mapnik/polygon_pattern_symbolizer.hpp>
|
||||
#include <mapnik/point_symbolizer.hpp>
|
||||
#include <mapnik/raster_symbolizer.hpp>
|
||||
#include <mapnik/shield_symbolizer.hpp>
|
||||
#include <mapnik/text_symbolizer.hpp>
|
||||
#include <mapnik/filter.hpp>
|
||||
#include <mapnik/filter_visitor.hpp>
|
||||
|
@ -81,12 +82,19 @@ namespace mapnik
|
|||
return (&lhs == &rhs);
|
||||
}
|
||||
|
||||
inline bool operator==(shield_symbolizer const& lhs,
|
||||
shield_symbolizer const& rhs)
|
||||
{
|
||||
return (&lhs == &rhs);
|
||||
}
|
||||
|
||||
typedef boost::variant<point_symbolizer,
|
||||
line_symbolizer,
|
||||
line_pattern_symbolizer,
|
||||
polygon_symbolizer,
|
||||
polygon_pattern_symbolizer,
|
||||
raster_symbolizer,
|
||||
shield_symbolizer,
|
||||
text_symbolizer> symbolizer;
|
||||
|
||||
|
||||
|
|
63
include/mapnik/shield_symbolizer.hpp
Normal file
63
include/mapnik/shield_symbolizer.hpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2006 Artem Pavlenko
|
||||
* Copyright (C) 2006 10East Corp.
|
||||
*
|
||||
* 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 SHIELD_SYMBOLIZER_HPP
|
||||
#define SHIELD_SYMBOLIZER_HPP
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <mapnik/graphics.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
struct MAPNIK_DECL shield_symbolizer
|
||||
{
|
||||
explicit shield_symbolizer();
|
||||
shield_symbolizer(std::string const& 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;
|
||||
|
||||
unsigned get_text_size() const;
|
||||
Color const& get_fill() const;
|
||||
|
||||
void set_allow_overlap(bool overlap);
|
||||
bool get_allow_overlap() const;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
unsigned size_;
|
||||
Color fill_;
|
||||
boost::shared_ptr<ImageData32> symbol_;
|
||||
bool overlap_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SHIELD_SYMBOLIZER_HPP
|
149
include/mapnik/text_path.hpp
Normal file
149
include/mapnik/text_path.hpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2006 Artem Pavlenko
|
||||
* Copyright (C) 2006 10East Corp.
|
||||
*
|
||||
* 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 __TEXT_PATH_H__
|
||||
#define __TEXT_PATH_H__
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
struct character_info
|
||||
{
|
||||
int character;
|
||||
double width, height;
|
||||
|
||||
character_info() : character(0), width(0), height(0) {}
|
||||
character_info(int c_, double width_, double height_) : character(c_), width(width_), height(height_) {}
|
||||
~character_info() {}
|
||||
|
||||
character_info(const character_info &ci)
|
||||
: character(ci.character), width(ci.width), height(ci.height)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class string_info : private boost::noncopyable
|
||||
{
|
||||
protected:
|
||||
|
||||
|
||||
typedef boost::ptr_vector<character_info> characters_t;
|
||||
|
||||
characters_t characters_;
|
||||
unsigned itr_;
|
||||
|
||||
double width_;
|
||||
double height_;
|
||||
public:
|
||||
string_info() : itr_(0), width_(0), height_(0) {}
|
||||
|
||||
void add_info(int c, double width, double height)
|
||||
{
|
||||
characters_.push_back(new character_info(c, width, height));
|
||||
}
|
||||
|
||||
unsigned num_characters()
|
||||
{
|
||||
return characters_.size();
|
||||
}
|
||||
|
||||
character_info at(unsigned i)
|
||||
{
|
||||
return characters_[i];
|
||||
}
|
||||
|
||||
character_info operator[](unsigned i)
|
||||
{
|
||||
return at(i);
|
||||
}
|
||||
|
||||
void set_dimensions(double width, double height)
|
||||
{
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
}
|
||||
|
||||
std::pair<double, double> get_dimensions()
|
||||
{
|
||||
return std::pair<double, double>(width_, height_);
|
||||
}
|
||||
};
|
||||
|
||||
struct text_path : private boost::noncopyable
|
||||
{
|
||||
struct character_node : boost::noncopyable
|
||||
{
|
||||
int c;
|
||||
double x, y, angle;
|
||||
|
||||
character_node(int c_, double x_, double y_, double angle_) : c(c_), x(x_), y(y_), angle(angle_) {}
|
||||
~character_node() {}
|
||||
|
||||
void vertex(int *c_, double *x_, double *y_, double *angle_)
|
||||
{
|
||||
*c_ = c;
|
||||
*x_ = x;
|
||||
*y_ = y;
|
||||
*angle_ = angle;
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::ptr_vector<character_node> character_nodes_t;
|
||||
|
||||
character_nodes_t nodes_;
|
||||
int itr_;
|
||||
|
||||
std::pair<unsigned,unsigned> string_dimensions;
|
||||
|
||||
text_path() : itr_(0) {}
|
||||
~text_path() {}
|
||||
|
||||
void add_node(int c, double x, double y, double angle)
|
||||
{
|
||||
nodes_.push_back(new character_node(c, x, y, angle));
|
||||
}
|
||||
|
||||
void vertex(int *c, double *x, double *y, double *angle)
|
||||
{
|
||||
nodes_[itr_++].vertex(c, x, y, angle);
|
||||
}
|
||||
|
||||
int num_nodes()
|
||||
{
|
||||
return nodes_.size();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
nodes_.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -46,11 +46,13 @@ source = Split(
|
|||
map.cpp
|
||||
memory.cpp
|
||||
params.cpp
|
||||
placement_finder.cpp
|
||||
plugin.cpp
|
||||
png_reader.cpp
|
||||
point_symbolizer.cpp
|
||||
polygon_pattern_symbolizer.cpp
|
||||
save_map.cpp
|
||||
shield_symbolizer.cpp
|
||||
text_symbolizer.cpp
|
||||
tiff_reader.cpp
|
||||
wkb.cpp
|
||||
|
|
|
@ -59,6 +59,8 @@
|
|||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
|
||||
#include <mapnik/placement_finder.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
class pattern_source : private boost::noncopyable
|
||||
|
@ -92,7 +94,8 @@ namespace mapnik
|
|||
: feature_style_processor<agg_renderer>(m),
|
||||
pixmap_(pixmap),
|
||||
t_(m.getWidth(),m.getHeight(),m.getCurrentExtent()),
|
||||
detector_(Envelope<double>(-64 ,-64, m.getWidth() + 64 ,m.getHeight() + 64))
|
||||
finder_(Envelope<double>(-64 ,-64, m.getWidth() + 64 ,m.getHeight() + 64)),
|
||||
point_detector_(Envelope<double>(-64 ,-64, m.getWidth() + 64 ,m.getHeight() + 64))
|
||||
{
|
||||
Color const& bg=m.getBackground();
|
||||
pixmap_.setBackground(bg);
|
||||
|
@ -302,7 +305,7 @@ namespace mapnik
|
|||
int py=int(floor(y - 0.5 * h));
|
||||
|
||||
if (sym.get_allow_overlap() ||
|
||||
detector_.has_placement(Envelope<double>(floor(x - 0.5 * w),
|
||||
point_detector_.has_placement(Envelope<double>(floor(x - 0.5 * w),
|
||||
floor(y - 0.5 * h),
|
||||
ceil (x + 0.5 * w),
|
||||
ceil (y + 0.5 * h))))
|
||||
|
@ -313,6 +316,57 @@ namespace mapnik
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void agg_renderer<T>::process(shield_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
geometry_ptr const& geom=feature.get_geometry();
|
||||
if (geom)
|
||||
{
|
||||
std::string text = feature[sym.get_name()].to_string();
|
||||
boost::shared_ptr<ImageData32> const& data = sym.get_data();
|
||||
|
||||
if (text.length() > 0 && data)
|
||||
{
|
||||
face_ptr face = font_manager_.get_face("Bitstream Vera Sans Roman");//TODO
|
||||
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);
|
||||
|
||||
placement text_placement(&info, &t_, &prj_trans, geom, std::pair<double, double>(w, h) );
|
||||
|
||||
bool found = finder_.find_placement(&text_placement);
|
||||
if (!found) {
|
||||
return;
|
||||
}
|
||||
|
||||
double x = text_placement.starting_x;
|
||||
double y = text_placement.starting_y;
|
||||
|
||||
int px=int(floor(x - 0.5 * w));
|
||||
int py=int(floor(y - 0.5 * h));
|
||||
|
||||
pixmap_.set_rectangle_alpha(px,py,*data);
|
||||
|
||||
Envelope<double> dim = ren.prepare_glyphs(&text_placement.path);
|
||||
|
||||
//If has_placement
|
||||
|
||||
ren.render(x,y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void agg_renderer<T>::process(line_pattern_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
|
@ -422,37 +476,15 @@ namespace mapnik
|
|||
Feature const& feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
typedef coord_transform2<CoordTransform,geometry_type> path_type;
|
||||
geometry_ptr const& geom=feature.get_geometry();
|
||||
|
||||
if (geom)
|
||||
{
|
||||
double angle = 0.0;
|
||||
if (sym.get_label_placement() == line_placement &&
|
||||
geom->num_points() > 1)
|
||||
{
|
||||
|
||||
path_type path(t_,*geom,prj_trans);
|
||||
double x0,y0,x1,y1;
|
||||
path.vertex(&x0,&y0);
|
||||
path.vertex(&x1,&y1);
|
||||
double dx = x1 - x0;
|
||||
double dy = ( y1 - y0 > 1e-7 ) ? y1 - y0 : 1.0;
|
||||
|
||||
angle = atan( dx/ dy ) - 0.5 * 3.1459;
|
||||
|
||||
//TODO!!!!!!!!!!!!!!!!!!!!
|
||||
}
|
||||
|
||||
std::string text = feature[sym.get_name()].to_string();
|
||||
if (text.length() > 0)
|
||||
{
|
||||
Color const& fill = sym.get_fill();
|
||||
|
||||
double x;
|
||||
double y;
|
||||
geom->label_position(&x,&y);
|
||||
t_.forward(&x,&y);
|
||||
|
||||
face_ptr face = font_manager_.get_face("Bitstream Vera Sans Roman");//TODO
|
||||
//face_ptr face = font_manager_.get_face("Times New Roman Regular");//TODO
|
||||
if (face)
|
||||
|
@ -462,25 +494,35 @@ namespace mapnik
|
|||
ren.set_fill(fill);
|
||||
ren.set_halo_fill(sym.get_halo_fill());
|
||||
ren.set_halo_radius(sym.get_halo_radius());
|
||||
ren.set_angle(float(angle));
|
||||
|
||||
std::pair<unsigned,unsigned> dim = ren.prepare_glyphs(text);
|
||||
Envelope<double> text_box(x - 0.5*dim.first,y - 0.5 * dim.second ,
|
||||
x + 0.5*dim.first,y + 0.5 * dim.second);
|
||||
string_info info;
|
||||
|
||||
ren.get_string_info(text, &info);
|
||||
|
||||
placement text_placement(&info, &t_, &prj_trans, geom, sym.get_label_placement());
|
||||
|
||||
bool found = finder_.find_placement(&text_placement);
|
||||
if (!found) {
|
||||
return;
|
||||
}
|
||||
|
||||
double x = text_placement.starting_x;
|
||||
double y = text_placement.starting_y;
|
||||
|
||||
Envelope<double> dim = ren.prepare_glyphs(&text_placement.path);
|
||||
|
||||
Envelope<double> text_box(x + dim.minx() ,y - dim.maxy(), x + dim.maxx(),y - dim.miny());
|
||||
|
||||
if (sym.get_halo_radius() > 0)
|
||||
{
|
||||
text_box.width(text_box.width() + sym.get_halo_radius()*2);
|
||||
text_box.height(text_box.height() + sym.get_halo_radius()*2);
|
||||
}
|
||||
|
||||
if (detector_.has_placement(text_box))
|
||||
{
|
||||
ren.render(x - 0.5 * dim.first,y + 0.5 * dim.second);
|
||||
}
|
||||
ren.render(x,y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template class agg_renderer<Image32>;
|
||||
}
|
||||
|
|
434
src/placement_finder.cpp
Normal file
434
src/placement_finder.cpp
Normal file
|
@ -0,0 +1,434 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2006 Artem Pavlenko
|
||||
* Copyright (C) 2006 10East Corp.
|
||||
*
|
||||
* 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$
|
||||
|
||||
//stl
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// boost
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/ptr_container/ptr_vector.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
//mapnik
|
||||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/placement_finder.hpp>
|
||||
#include <mapnik/text_path.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
placement::placement(string_info *info_, CoordTransform *ctrans_, const proj_transform *proj_trans_, geometry_ptr geom_, std::pair<double, double> dimensions_)
|
||||
: info(info_), ctrans(ctrans_), proj_trans(proj_trans_), geom(geom_), label_placement(point_placement), dimensions(dimensions_), has_dimensions(true), shape_path(*ctrans_, *geom_, *proj_trans_), total_distance_(-1.0)
|
||||
{
|
||||
}
|
||||
|
||||
//For text
|
||||
placement::placement(string_info *info_, CoordTransform *ctrans_, const proj_transform *proj_trans_, geometry_ptr geom_, label_placement_e placement_)
|
||||
: info(info_), ctrans(ctrans_), proj_trans(proj_trans_), geom(geom_), label_placement(placement_), has_dimensions(false), shape_path(*ctrans_, *geom_, *proj_trans_), total_distance_(-1.0)
|
||||
{
|
||||
}
|
||||
|
||||
placement::~placement()
|
||||
{
|
||||
}
|
||||
|
||||
std::pair<double, double> placement::get_position_at_distance(double target_distance)
|
||||
{
|
||||
double old_x, old_y, new_x, new_y;
|
||||
double x, y;
|
||||
x = y = 0.0;
|
||||
|
||||
double distance = 0.0;
|
||||
|
||||
shape_path.rewind(0);
|
||||
shape_path.vertex(&new_x,&new_y);
|
||||
for (unsigned i = 0; i < geom->num_points() - 1; i++)
|
||||
{
|
||||
double dx, dy;
|
||||
|
||||
old_x = new_x;
|
||||
old_y = new_y;
|
||||
|
||||
shape_path.vertex(&new_x,&new_y);
|
||||
|
||||
dx = new_x - old_x;
|
||||
dy = new_y - old_y;
|
||||
|
||||
double segment_length = sqrt(dx*dx + dy*dy);
|
||||
|
||||
distance += segment_length;
|
||||
if (distance > target_distance)
|
||||
{
|
||||
x = new_x - dx*(distance - target_distance)/segment_length;
|
||||
y = new_y - dy*(distance - target_distance)/segment_length;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return std::pair<double, double>(x, y);
|
||||
}
|
||||
|
||||
double placement::get_total_distance()
|
||||
{
|
||||
if (total_distance_ < 0.0)
|
||||
{
|
||||
double old_x, old_y, new_x, new_y;
|
||||
|
||||
shape_path.rewind(0);
|
||||
|
||||
shape_path.vertex(&old_x,&old_y);
|
||||
|
||||
total_distance_ = 0.0;
|
||||
|
||||
for (unsigned i = 0; i < geom->num_points() - 1; i++)
|
||||
{
|
||||
double dx, dy;
|
||||
|
||||
shape_path.vertex(&new_x,&new_y);
|
||||
|
||||
dx = new_x - old_x;
|
||||
dy = new_y - old_y;
|
||||
|
||||
total_distance_ += sqrt(dx*dx + dy*dy);
|
||||
|
||||
old_x = new_x;
|
||||
old_y = new_y;
|
||||
}
|
||||
}
|
||||
|
||||
return total_distance_;
|
||||
}
|
||||
|
||||
void placement::clear_envelopes()
|
||||
{
|
||||
while (!envelopes.empty())
|
||||
envelopes.pop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
placement_finder::placement_finder(Envelope<double> e)
|
||||
: detector_(e)
|
||||
{
|
||||
}
|
||||
|
||||
bool placement_finder::find_placement(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;
|
||||
}
|
||||
|
||||
bool placement_finder::find_placement_follow(placement *p)
|
||||
{
|
||||
std::pair<double, double> string_dimensions = p->info->get_dimensions();
|
||||
double string_width = string_dimensions.first;
|
||||
// double string_height = string_dimensions.second;
|
||||
|
||||
double distance = p->get_total_distance();
|
||||
|
||||
//~ double delta = string_width/distance;
|
||||
double delta = distance/100.0;
|
||||
|
||||
for (double i = 0; i < (distance - string_width)/2.0; i += delta)
|
||||
{
|
||||
p->clear_envelopes();
|
||||
|
||||
if ( build_path_follow(p, (distance - string_width)/2.0 + i) ) {
|
||||
update_detector(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
p->clear_envelopes();
|
||||
|
||||
if ( build_path_follow(p, (distance - string_width)/2.0 - i) ) {
|
||||
update_detector(p);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
p->starting_x = 0;
|
||||
p->starting_y = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool placement_finder::find_placement_horizontal(placement *p)
|
||||
{
|
||||
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)
|
||||
{
|
||||
p->clear_envelopes();
|
||||
|
||||
if ( build_path_horizontal(p, distance/2.0 + i) ) {
|
||||
update_detector(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
p->clear_envelopes();
|
||||
|
||||
if ( build_path_horizontal(p, distance/2.0 - i) ) {
|
||||
update_detector(p);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
p->starting_x = 0;
|
||||
p->starting_y = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void placement_finder::update_detector(placement *p)
|
||||
{
|
||||
while (!p->envelopes.empty())
|
||||
{
|
||||
Envelope<double> e = p->envelopes.front();
|
||||
|
||||
detector_.insert(e);
|
||||
|
||||
p->envelopes.pop();
|
||||
}
|
||||
}
|
||||
|
||||
bool placement_finder::build_path_follow(placement *p, double target_distance)
|
||||
{
|
||||
double new_x, new_y, old_x, old_y;
|
||||
unsigned cur_node = 0;
|
||||
|
||||
double angle = 0.0;
|
||||
int orientation = 0;
|
||||
|
||||
p->path.clear();
|
||||
|
||||
double x, y;
|
||||
x = y = 0.0;
|
||||
|
||||
double distance = 0.0;
|
||||
|
||||
std::pair<double, double> string_dimensions = p->info->get_dimensions();
|
||||
// double string_width = string_dimensions.first;
|
||||
double string_height = string_dimensions.second;
|
||||
|
||||
p->shape_path.rewind(0);
|
||||
p->shape_path.vertex(&new_x,&new_y);
|
||||
for (unsigned i = 0; i < p->geom->num_points() - 1; i++)
|
||||
{
|
||||
double dx, dy;
|
||||
|
||||
cur_node++;
|
||||
|
||||
old_x = new_x;
|
||||
old_y = new_y;
|
||||
|
||||
p->shape_path.vertex(&new_x,&new_y);
|
||||
|
||||
dx = new_x - old_x;
|
||||
dy = new_y - old_y;
|
||||
|
||||
double segment_length = sqrt(dx*dx + dy*dy);
|
||||
|
||||
distance += segment_length;
|
||||
if (distance > target_distance)
|
||||
{
|
||||
p->starting_x = new_x - dx*(distance - target_distance)/segment_length;
|
||||
p->starting_y = new_y - dy*(distance - target_distance)/segment_length;
|
||||
|
||||
angle = atan2(-dy, dx);
|
||||
|
||||
if (angle > M_PI/2 || angle <= -M_PI/2) {
|
||||
orientation = -1;
|
||||
}
|
||||
else {
|
||||
orientation = 1;
|
||||
}
|
||||
|
||||
distance -= target_distance;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < p->info->num_characters(); i++)
|
||||
{
|
||||
character_info ci;
|
||||
unsigned c;
|
||||
|
||||
while (distance <= 0) {
|
||||
double dx, dy;
|
||||
|
||||
cur_node++;
|
||||
|
||||
if (cur_node >= p->geom->num_points()) {
|
||||
break;
|
||||
}
|
||||
|
||||
old_x = new_x;
|
||||
old_y = new_y;
|
||||
|
||||
p->shape_path.vertex(&new_x,&new_y);
|
||||
|
||||
dx = new_x - old_x;
|
||||
dy = new_y - old_y;
|
||||
|
||||
angle = atan2(-dy, dx );
|
||||
|
||||
distance += sqrt(dx*dx+dy*dy);
|
||||
}
|
||||
|
||||
if (orientation == -1) {
|
||||
ci = p->info->at(p->info->num_characters() - i - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ci = p->info->at(i);
|
||||
}
|
||||
c = ci.character;
|
||||
|
||||
Envelope<double> e;
|
||||
if (p->has_dimensions)
|
||||
{
|
||||
e.init(x, y, x + p->dimensions.first, y + p->dimensions.second);
|
||||
}
|
||||
|
||||
if (orientation == -1) {
|
||||
x = new_x - (distance - ci.width)*cos(angle);
|
||||
y = new_y + (distance - ci.width)*sin(angle);
|
||||
|
||||
//Center the text on the line.
|
||||
x += (((double)string_height/2.0) - 1.0)*cos(angle+M_PI/2);
|
||||
y -= (((double)string_height/2.0) - 1.0)*sin(angle+M_PI/2);
|
||||
|
||||
if (!p->has_dimensions)
|
||||
{
|
||||
e.init(x, y, x + ci.width*cos(angle+M_PI), y - ci.width*sin(angle+M_PI));
|
||||
e.expand_to_include(x - ci.height*sin(angle+M_PI), y - ci.height*cos(angle+M_PI));
|
||||
e.expand_to_include(x + (ci.width*cos(angle+M_PI) - ci.height*sin(angle+M_PI)), y - (ci.width*sin(angle+M_PI) + ci.height*cos(angle+M_PI)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x = new_x - distance*cos(angle);
|
||||
y = new_y + distance*sin(angle);
|
||||
|
||||
//Center the text on the line.
|
||||
x += (((double)string_height/2.0) - 1.0)*cos(angle-M_PI/2);
|
||||
y -= (((double)string_height/2.0) - 1.0)*sin(angle-M_PI/2);
|
||||
|
||||
if (!p->has_dimensions)
|
||||
{
|
||||
e.init(x, y, x + ci.width*cos(angle), y - ci.width*sin(angle));
|
||||
e.expand_to_include(x - ci.height*sin(angle), y - ci.height*cos(angle));
|
||||
e.expand_to_include(x + (ci.width*cos(angle) - ci.height*sin(angle)), y - (ci.width*sin(angle) + ci.height*cos(angle)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!detector_.has_placement(e))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
p->envelopes.push(e);
|
||||
|
||||
p->path.add_node(c, x - p->starting_x, -y + p->starting_y, (orientation == -1 ? angle + M_PI : angle));
|
||||
|
||||
distance -= ci.width;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool placement_finder::build_path_horizontal(placement *p, double target_distance)
|
||||
{
|
||||
double x, y;
|
||||
|
||||
p->path.clear();
|
||||
|
||||
std::pair<double, double> string_dimensions = p->info->get_dimensions();
|
||||
double string_width = string_dimensions.first;
|
||||
double string_height = string_dimensions.second;
|
||||
|
||||
x = -string_width/2.0;
|
||||
y = -string_height/2.0 + 1.0;
|
||||
|
||||
if (p->geom->type() == LineString)
|
||||
{
|
||||
std::pair<double, double> starting_pos = p->get_position_at_distance(target_distance);
|
||||
|
||||
p->starting_x = starting_pos.first;
|
||||
p->starting_y = starting_pos.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
p->geom->label_position(&p->starting_x, &p->starting_y);
|
||||
p->ctrans->forward(&p->starting_x, &p->starting_y);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < p->info->num_characters(); i++)
|
||||
{
|
||||
character_info ci;;
|
||||
ci = p->info->at(i);
|
||||
|
||||
unsigned c = ci.character;
|
||||
|
||||
p->path.add_node(c, x, y, 0.0);
|
||||
|
||||
Envelope<double> e;
|
||||
if (p->has_dimensions)
|
||||
{
|
||||
e.init(p->starting_x - (p->dimensions.first/2.0), p->starting_y - (p->dimensions.second/2.0), p->starting_x + (p->dimensions.first/2.0), p->starting_y + (p->dimensions.second/2.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
e.init(p->starting_x + x, p->starting_y - y, p->starting_x + x + ci.width, p->starting_y - y - ci.height);
|
||||
}
|
||||
|
||||
if (!detector_.has_placement(e))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
p->envelopes.push(e);
|
||||
|
||||
x += ci.width;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
111
src/shield_symbolizer.cpp
Normal file
111
src/shield_symbolizer.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2006 Artem Pavlenko
|
||||
* Copyright (C) 2006 10East Corp.
|
||||
*
|
||||
* 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$
|
||||
|
||||
// stl
|
||||
#include <iostream>
|
||||
// boost
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
// mapnik
|
||||
#include <mapnik/shield_symbolizer.hpp>
|
||||
#include <mapnik/image_data.hpp>
|
||||
#include <mapnik/image_reader.hpp>
|
||||
|
||||
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,
|
||||
unsigned size,
|
||||
Color const& fill,
|
||||
std::string const& file,
|
||||
std::string const& type,
|
||||
unsigned width,unsigned height)
|
||||
: name_(name), size_(size), fill_(fill), symbol_(new ImageData32(width,height))
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::scoped_ptr<ImageReader> reader(get_image_reader(type,file));
|
||||
if (reader.get())
|
||||
{
|
||||
reader->read(0,0,*symbol_);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::clog<<"exception caught..." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
shield_symbolizer::shield_symbolizer(shield_symbolizer const& rhs)
|
||||
: name_(rhs.name_),
|
||||
size_(rhs.size_),
|
||||
fill_(rhs.fill_),
|
||||
symbol_(rhs.symbol_),
|
||||
overlap_(rhs.overlap_)
|
||||
{}
|
||||
|
||||
void shield_symbolizer::set_data( boost::shared_ptr<ImageData32> symbol)
|
||||
{
|
||||
symbol_ = symbol;
|
||||
}
|
||||
|
||||
boost::shared_ptr<ImageData32> const& shield_symbolizer::get_data() const
|
||||
{
|
||||
return symbol_;
|
||||
}
|
||||
|
||||
std::string const& shield_symbolizer::get_name() const
|
||||
{
|
||||
return 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_;
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue