+ 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:
Artem Pavlenko 2009-03-30 20:47:26 +00:00
parent e7c9d02fd3
commit 10f55a678b
9 changed files with 140 additions and 65 deletions

View file

@ -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,

View file

@ -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_;
};
}

View file

@ -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_;

View file

@ -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']

View file

@ -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)

View file

@ -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)

View file

@ -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;

View file

@ -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() );

View file

@ -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);