+ add support for vertical_alignment (text_symbolizer)
valid values are : top, middle, bottom default to middle which can now center multi-line text
This commit is contained in:
parent
e7c9d02fd3
commit
10f55a678b
9 changed files with 140 additions and 65 deletions
|
@ -38,7 +38,12 @@ void export_text_symbolizer()
|
|||
.value("LINE_PLACEMENT",LINE_PLACEMENT)
|
||||
.value("POINT_PLACEMENT",POINT_PLACEMENT)
|
||||
;
|
||||
|
||||
enumeration_<vertical_alignment_e>("vertical_alignment")
|
||||
.value("TOP",TOP)
|
||||
.value("MIDDLE",MIDDLE)
|
||||
.value("BOTTOM",BOTTOM)
|
||||
;
|
||||
|
||||
class_<text_symbolizer>("TextSymbolizer",
|
||||
init<std::string const&,std::string const&, unsigned,color const&>())
|
||||
.add_property("halo_fill",make_function(
|
||||
|
@ -98,6 +103,12 @@ void export_text_symbolizer()
|
|||
&text_symbolizer::get_label_placement,
|
||||
&text_symbolizer::set_label_placement,
|
||||
"Set/get the placement of the label")
|
||||
|
||||
.add_property("vertical_alignment",
|
||||
&text_symbolizer::get_vertical_alignment,
|
||||
&text_symbolizer::set_vertical_alignment,
|
||||
"Set/get the vertical alignment of the label")
|
||||
|
||||
.add_property("allow_overlap",
|
||||
&text_symbolizer::get_allow_overlap,
|
||||
&text_symbolizer::set_allow_overlap,
|
||||
|
|
|
@ -71,62 +71,67 @@ namespace mapnik
|
|||
bool allow_overlap;
|
||||
std::pair<double, double> dimensions;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename DetectorT>
|
||||
class placement_finder : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
placement_finder(DetectorT & detector);
|
||||
public:
|
||||
placement_finder(DetectorT & detector);
|
||||
|
||||
//Try place a single label at the given point
|
||||
void find_point_placement(placement & p, double, double);
|
||||
//Try place a single label at the given point
|
||||
void find_point_placement(placement & p, double pos_x, double pos_y, vertical_alignment_e = MIDDLE);
|
||||
|
||||
//Iterate over the given path, placing point labels with respect to label_spacing
|
||||
template <typename T>
|
||||
void find_point_placements(placement & p, T & path);
|
||||
//Iterate over the given path, placing point labels with respect to label_spacing
|
||||
template <typename T>
|
||||
void find_point_placements(placement & p, T & path);
|
||||
|
||||
//Iterate over the given path, placing line-following labels with respect to label_spacing
|
||||
template <typename T>
|
||||
void find_line_placements(placement & p, T & path);
|
||||
|
||||
void update_detector(placement & p);
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
///Helpers for find_line_placement
|
||||
|
||||
///Returns a possible placement on the given line, does not test for collisions
|
||||
//index: index of the node the current line ends on
|
||||
//distance: distance along the given index that the placement should start at, this includes the offset,
|
||||
// as such it may be > or < the length of the current line, so this must be checked for
|
||||
//orientation: if set to != 0 the placement will be attempted with the given orientation
|
||||
// otherwise it will autodetect the orientation.
|
||||
// If >= 50% of the characters end up upside down, it will be retried the other way.
|
||||
// RETURN: 1/-1 depending which way up the string ends up being.
|
||||
std::auto_ptr<placement_element> get_placement_offset(placement & p,
|
||||
const std::vector<vertex2d> & path_positions,
|
||||
const std::vector<double> & path_distances,
|
||||
int & orientation, unsigned index, double distance);
|
||||
|
||||
///Tests wether the given placement_element be placed without a collision
|
||||
// Returns true if it can
|
||||
// NOTE: This edits p.envelopes so it can be used afterwards (you must clear it otherwise)
|
||||
bool test_placement(placement & p, const std::auto_ptr<placement_element> & current_placement, const int & orientation);
|
||||
|
||||
///Does a line-circle intersect calculation
|
||||
// NOTE: Follow the strict pre conditions
|
||||
// Pre Conditions: x1,y1 is within radius distance of cx,cy. x2,y2 is outside radius distance of cx,cy
|
||||
// This means there is exactly one intersect point
|
||||
// Result is returned in ix, iy
|
||||
void find_line_circle_intersection(
|
||||
const double &cx, const double &cy, const double &radius,
|
||||
const double &x1, const double &y1, const double &x2, const double &y2,
|
||||
double &ix, double &iy);
|
||||
|
||||
///General Internals
|
||||
|
||||
|
||||
|
||||
//Iterate over the given path, placing line-following labels with respect to label_spacing
|
||||
template <typename T>
|
||||
void find_line_placements(placement & p, T & path);
|
||||
|
||||
void update_detector(placement & p);
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
///Helpers for find_line_placement
|
||||
|
||||
///Returns a possible placement on the given line, does not test for collisions
|
||||
//index: index of the node the current line ends on
|
||||
//distance: distance along the given index that the placement should start at, this includes the offset,
|
||||
// as such it may be > or < the length of the current line, so this must be checked for
|
||||
//orientation: if set to != 0 the placement will be attempted with the given orientation
|
||||
// otherwise it will autodetect the orientation.
|
||||
// If >= 50% of the characters end up upside down, it will be retried the other way.
|
||||
// RETURN: 1/-1 depending which way up the string ends up being.
|
||||
std::auto_ptr<placement_element> get_placement_offset(placement & p, const std::vector<vertex2d> & path_positions, const std::vector<double> & path_distances, int & orientation, unsigned index, double distance);
|
||||
|
||||
///Tests wether the given placement_element be placed without a collision
|
||||
// Returns true if it can
|
||||
// NOTE: This edits p.envelopes so it can be used afterwards (you must clear it otherwise)
|
||||
bool test_placement(placement & p, const std::auto_ptr<placement_element> & current_placement, const int & orientation);
|
||||
|
||||
///Does a line-circle intersect calculation
|
||||
// NOTE: Follow the strict pre conditions
|
||||
// Pre Conditions: x1,y1 is within radius distance of cx,cy. x2,y2 is outside radius distance of cx,cy
|
||||
// This means there is exactly one intersect point
|
||||
// Result is returned in ix, iy
|
||||
void find_line_circle_intersection(
|
||||
const double &cx, const double &cy, const double &radius,
|
||||
const double &x1, const double &y1, const double &x2, const double &y2,
|
||||
double &ix, double &iy);
|
||||
|
||||
///General Internals
|
||||
|
||||
|
||||
|
||||
DetectorT & detector_;
|
||||
Envelope<double> const& dimensions_;
|
||||
DetectorT & detector_;
|
||||
Envelope<double> const& dimensions_;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,17 @@ namespace mapnik
|
|||
};
|
||||
|
||||
DEFINE_ENUM( label_placement_e, label_placement_enum );
|
||||
|
||||
|
||||
enum vertical_alignment
|
||||
{
|
||||
TOP = 0,
|
||||
MIDDLE,
|
||||
BOTTOM,
|
||||
vertical_alignment_MAX
|
||||
};
|
||||
|
||||
DEFINE_ENUM( vertical_alignment_e, vertical_alignment );
|
||||
|
||||
typedef boost::tuple<double,double> position;
|
||||
|
||||
struct MAPNIK_DECL text_symbolizer
|
||||
|
@ -82,6 +92,8 @@ namespace mapnik
|
|||
unsigned get_halo_radius() const;
|
||||
void set_label_placement(label_placement_e label_p);
|
||||
label_placement_e get_label_placement() const;
|
||||
void set_vertical_alignment(vertical_alignment_e valign);
|
||||
vertical_alignment get_vertical_alignment() const;
|
||||
void set_anchor(double x, double y);
|
||||
position const& get_anchor() const;
|
||||
void set_displacement(double x, double y);
|
||||
|
@ -107,6 +119,7 @@ namespace mapnik
|
|||
color halo_fill_;
|
||||
unsigned halo_radius_;
|
||||
label_placement_e label_p_;
|
||||
vertical_alignment_e valign_;
|
||||
position anchor_;
|
||||
position displacement_;
|
||||
bool avoid_edges_;
|
||||
|
|
|
@ -28,6 +28,8 @@ Import('env')
|
|||
ABI_VERSION = env['ABI_VERSION']
|
||||
|
||||
prefix = env['PREFIX']
|
||||
print "PREFIX=%s" % prefix
|
||||
|
||||
install_prefix = env['DESTDIR'] + '/' + prefix
|
||||
|
||||
libraries = env['LIBS']
|
||||
|
|
|
@ -805,7 +805,7 @@ namespace mapnik
|
|||
geom.label_position(&label_x, &label_y);
|
||||
prj_trans.backward(label_x,label_y, z);
|
||||
t_.forward(&label_x,&label_y);
|
||||
finder.find_point_placement(text_placement,label_x,label_y);
|
||||
finder.find_point_placement(text_placement,label_x,label_y,sym.get_vertical_alignment());
|
||||
finder.update_detector(text_placement);
|
||||
}
|
||||
else if ( geom.num_points() > 1 && sym.get_label_placement() == LINE_PLACEMENT)
|
||||
|
|
|
@ -778,7 +778,10 @@ namespace mapnik
|
|||
label_placement_e placement =
|
||||
get_attr<label_placement_e>(sym, "placement", POINT_PLACEMENT);
|
||||
text_symbol.set_label_placement( placement );
|
||||
// vertical alignment
|
||||
vertical_alignment_e valign = get_attr<vertical_alignment_e>(sym, "vertical_alignment", BOTTOM);
|
||||
|
||||
text_symbol.set_vertical_alignment(valign);
|
||||
// halo fill and radius
|
||||
optional<color> halo_fill = get_opt_attr<color>(sym, "halo_fill");
|
||||
if (halo_fill)
|
||||
|
|
|
@ -212,7 +212,9 @@ namespace mapnik
|
|||
|
||||
template <typename DetectorT>
|
||||
void placement_finder<DetectorT>::find_point_placement(placement & p,
|
||||
double label_x, double label_y)
|
||||
double label_x,
|
||||
double label_y,
|
||||
vertical_alignment_e valign)
|
||||
{
|
||||
double x, y;
|
||||
std::auto_ptr<placement_element> current_placement(new placement_element);
|
||||
|
@ -293,22 +295,32 @@ namespace mapnik
|
|||
}
|
||||
|
||||
p.info.set_dimensions(string_width, string_height);
|
||||
|
||||
|
||||
current_placement->starting_x = label_x;
|
||||
current_placement->starting_y = label_y;
|
||||
|
||||
current_placement->starting_x += boost::tuples::get<0>(p.displacement_);
|
||||
current_placement->starting_y += boost::tuples::get<1>(p.displacement_);
|
||||
|
||||
|
||||
unsigned int line_number = 0;
|
||||
unsigned int index_to_wrap_at = line_breaks[line_number];
|
||||
double line_width = line_widths[line_number];
|
||||
double line_height = line_heights[line_number];
|
||||
|
||||
current_placement->starting_x = label_x;
|
||||
if (valign == BOTTOM)
|
||||
{
|
||||
current_placement->starting_y = label_y;
|
||||
}
|
||||
else if (valign == MIDDLE)
|
||||
{
|
||||
current_placement->starting_y = label_y - 0.5 * (line_heights.size() - 1) * line_height ;
|
||||
}
|
||||
else // TOP
|
||||
{
|
||||
current_placement->starting_y = label_y - line_heights.size() * line_height;
|
||||
}
|
||||
|
||||
current_placement->starting_x += boost::tuples::get<0>(p.displacement_);
|
||||
current_placement->starting_y += boost::tuples::get<1>(p.displacement_);
|
||||
|
||||
x = -line_width/2.0;
|
||||
y = -line_height/2.0;
|
||||
|
||||
|
||||
for (unsigned i = 0; i < p.info.num_characters(); i++)
|
||||
{
|
||||
character_info ci;
|
||||
|
|
|
@ -258,6 +258,12 @@ namespace mapnik
|
|||
{
|
||||
set_attr( node, "placement", sym.get_label_placement() );
|
||||
}
|
||||
|
||||
if (sym.get_vertical_alignment() != dfl.get_vertical_alignment() )
|
||||
{
|
||||
set_attr( node, "vertical_alignment", sym.get_vertical_alignment() );
|
||||
}
|
||||
|
||||
if (sym.get_halo_radius() != dfl.get_halo_radius())
|
||||
{
|
||||
set_attr( node, "halo_radius", sym.get_halo_radius() );
|
||||
|
|
|
@ -38,6 +38,16 @@ static const char * label_placement_strings[] = {
|
|||
|
||||
IMPLEMENT_ENUM( mapnik::label_placement_e, label_placement_strings );
|
||||
|
||||
static const char * vertical_alignment_strings[] = {
|
||||
"top",
|
||||
"middle",
|
||||
"bottom",
|
||||
""
|
||||
};
|
||||
|
||||
|
||||
IMPLEMENT_ENUM( mapnik::vertical_alignment_e, vertical_alignment_strings );
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
text_symbolizer::text_symbolizer(std::string const& name, std::string const& face_name, unsigned size, color const& fill)
|
||||
|
@ -55,6 +65,7 @@ namespace mapnik
|
|||
halo_fill_(color(255,255,255)),
|
||||
halo_radius_(0),
|
||||
label_p_(POINT_PLACEMENT),
|
||||
valign_(BOTTOM),
|
||||
anchor_(0.0,0.5),
|
||||
displacement_(0.0,0.0),
|
||||
avoid_edges_(false),
|
||||
|
@ -75,6 +86,7 @@ namespace mapnik
|
|||
halo_fill_(color(255,255,255)),
|
||||
halo_radius_(0),
|
||||
label_p_(POINT_PLACEMENT),
|
||||
valign_(BOTTOM),
|
||||
anchor_(0.0,0.5),
|
||||
displacement_(0.0,0.0),
|
||||
avoid_edges_(false),
|
||||
|
@ -95,6 +107,7 @@ namespace mapnik
|
|||
halo_fill_(rhs.halo_fill_),
|
||||
halo_radius_(rhs.halo_radius_),
|
||||
label_p_(rhs.label_p_),
|
||||
valign_(rhs.valign_),
|
||||
anchor_(rhs.anchor_),
|
||||
displacement_(rhs.displacement_),
|
||||
avoid_edges_(rhs.avoid_edges_),
|
||||
|
@ -119,15 +132,15 @@ namespace mapnik
|
|||
halo_fill_ = other.halo_fill_;
|
||||
halo_radius_ = other.halo_radius_;
|
||||
label_p_ = other.label_p_;
|
||||
valign_ = other.valign_;
|
||||
anchor_ = other.anchor_;
|
||||
displacement_ = other.displacement_;
|
||||
avoid_edges_ = other.avoid_edges_;
|
||||
minimum_distance_ = other.minimum_distance_;
|
||||
overlap_ = other.overlap_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
std::string const& text_symbolizer::get_name() const
|
||||
{
|
||||
return name_;
|
||||
|
@ -268,6 +281,16 @@ namespace mapnik
|
|||
return label_p_;
|
||||
}
|
||||
|
||||
void text_symbolizer::set_vertical_alignment(vertical_alignment_e valign)
|
||||
{
|
||||
valign_ = valign;
|
||||
}
|
||||
|
||||
vertical_alignment text_symbolizer::get_vertical_alignment() const
|
||||
{
|
||||
return valign_;
|
||||
}
|
||||
|
||||
void text_symbolizer::set_anchor(double x, double y)
|
||||
{
|
||||
anchor_ = boost::make_tuple(x,y);
|
||||
|
|
Loading…
Add table
Reference in a new issue