+ applied patch from Jochen Topf :

* text_convert="none|toupper|tolower"
 Convert all text to upper/lower case before rendering. "none" doesn't do
 anything with the text and is the default. Works for labels along lines
 or at points.

* line_spacing="<number>"
 Add this many pixels space between two lines in text labels that have
 been broken into several lines. Default is 0. Doesn't do anything for
 labels along lines.

* character_spacing="<number>"
 Add this many pixels space between two characters in a text. Default is 0.
 Currently only works for text labels on point geometries. This should
 also be implemented for labels along lines, but I'll leave that for
 another day.

* wrap_character="<character>"
 Instead of breaking text into lines on spaces, use this character. This
 is useful, when you want to make sure that labels are broken at the right
 spot. Note that you'll probably want to make wrap_width small so that
 your lines are actually broken, otherwise you'll see the wrap_character
 in the output. Default is ' ' (space). Doesn't do anything for labels
 along lines.
This commit is contained in:
Artem Pavlenko 2009-07-20 15:30:19 +00:00
parent 8676d23081
commit 85ecc33d7f
8 changed files with 169 additions and 12 deletions

View file

@ -58,6 +58,7 @@ namespace mapnik
boost::ptr_vector<placement_element> placements; boost::ptr_vector<placement_element> placements;
int wrap_width; int wrap_width;
unsigned char wrap_char;
int text_ratio; int text_ratio;
int label_spacing; // distance between repeated labels on a single geometry int label_spacing; // distance between repeated labels on a single geometry
@ -81,7 +82,7 @@ namespace mapnik
placement_finder(DetectorT & detector); placement_finder(DetectorT & detector);
//Try place a single label at the given point //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); void find_point_placement(placement & p, double pos_x, double pos_y, vertical_alignment_e = MIDDLE, unsigned line_spacing=0, unsigned character_spacing=0);
//Iterate over the given path, placing point labels with respect to label_spacing //Iterate over the given path, placing point labels with respect to label_spacing
template <typename T> template <typename T>

View file

@ -55,6 +55,16 @@ namespace mapnik
DEFINE_ENUM( vertical_alignment_e, vertical_alignment ); DEFINE_ENUM( vertical_alignment_e, vertical_alignment );
enum text_convert
{
NONE = 0,
TOUPPER,
TOLOWER,
text_convert_MAX
};
DEFINE_ENUM( text_convert_e, text_convert );
typedef boost::tuple<double,double> position; typedef boost::tuple<double,double> position;
struct MAPNIK_DECL text_symbolizer struct MAPNIK_DECL text_symbolizer
@ -70,6 +80,14 @@ namespace mapnik
void set_text_ratio(unsigned ratio); void set_text_ratio(unsigned ratio);
unsigned get_wrap_width() const; // width to wrap text at, or trigger ratio unsigned get_wrap_width() const; // width to wrap text at, or trigger ratio
void set_wrap_width(unsigned ratio); void set_wrap_width(unsigned ratio);
unsigned char get_wrap_char() const; // character used to wrap lines
void set_wrap_char(unsigned char character);
text_convert_e get_text_convert() const; // text conversion on strings before display
void set_text_convert(text_convert_e convert);
unsigned get_line_spacing() const; // spacing between lines of text
void set_line_spacing(unsigned spacing);
unsigned get_character_spacing() const; // spacing between characters in text
void set_character_spacing(unsigned spacing);
unsigned get_label_spacing() const; // spacing between repeated labels on lines unsigned get_label_spacing() const; // spacing between repeated labels on lines
void set_label_spacing(unsigned spacing); void set_label_spacing(unsigned spacing);
unsigned get_label_position_tolerance() const; //distance the label can be moved on the line to fit, if 0 the default is used unsigned get_label_position_tolerance() const; //distance the label can be moved on the line to fit, if 0 the default is used
@ -111,6 +129,10 @@ namespace mapnik
unsigned size_; unsigned size_;
unsigned text_ratio_; unsigned text_ratio_;
unsigned wrap_width_; unsigned wrap_width_;
unsigned char wrap_char_;
text_convert_e text_convert_;
unsigned line_spacing_;
unsigned character_spacing_;
unsigned label_spacing_; unsigned label_spacing_;
unsigned label_position_tolerance_; unsigned label_position_tolerance_;
bool force_odd_labels_; bool force_odd_labels_;

View file

@ -764,6 +764,15 @@ namespace mapnik
typedef coord_transform2<CoordTransform,geometry2d> path_type; typedef coord_transform2<CoordTransform,geometry2d> path_type;
UnicodeString text = feature[sym.get_name()].to_unicode(); UnicodeString text = feature[sym.get_name()].to_unicode();
if ( sym.get_text_convert() == TOUPPER)
{
text = text.toUpper();
}
else if ( sym.get_text_convert() == TOLOWER)
{
text = text.toLower();
}
if ( text.length() > 0 ) if ( text.length() > 0 )
{ {
color const& fill = sym.get_fill(); color const& fill = sym.get_fill();
@ -807,7 +816,7 @@ namespace mapnik
geom.label_position(&label_x, &label_y); geom.label_position(&label_x, &label_y);
prj_trans.backward(label_x,label_y, z); prj_trans.backward(label_x,label_y, z);
t_.forward(&label_x,&label_y); t_.forward(&label_x,&label_y);
finder.find_point_placement(text_placement,label_x,label_y,sym.get_vertical_alignment()); finder.find_point_placement(text_placement,label_x,label_y,sym.get_vertical_alignment(),sym.get_line_spacing(),sym.get_character_spacing());
finder.update_detector(text_placement); finder.update_detector(text_placement);
} }
else if ( geom.num_points() > 1 && sym.get_label_placement() == LINE_PLACEMENT) else if ( geom.num_points() > 1 && sym.get_label_placement() == LINE_PLACEMENT)

View file

@ -1006,6 +1006,14 @@ namespace mapnik
typedef coord_transform2<CoordTransform,geometry2d> path_type; typedef coord_transform2<CoordTransform,geometry2d> path_type;
UnicodeString text = feature[sym.get_name()].to_unicode(); UnicodeString text = feature[sym.get_name()].to_unicode();
if ( sym.get_text_convert() == TOUPPER)
{
text = text.toUpper();
}
else if ( sym.get_text_convert() == TOLOWER)
{
text = text.toLower();
}
if (text.length() > 0) if (text.length() > 0)
{ {

View file

@ -885,6 +885,33 @@ namespace mapnik
text_symbol.set_wrap_width(*wrap_width); text_symbol.set_wrap_width(*wrap_width);
} }
// character used to break long strings
optional<std::string> wrap_char =
get_opt_attr<std::string>(sym, "wrap_character");
if (wrap_char && (*wrap_char).size() > 0)
{
text_symbol.set_wrap_char((*wrap_char)[0]);
}
// text conversion before rendering
text_convert_e tconvert =
get_attr<text_convert_e>(sym, "text_convert", NONE);
text_symbol.set_text_convert(tconvert);
// spacing between text lines
optional<unsigned> line_spacing = get_opt_attr<unsigned>(sym, "line_spacing");
if (line_spacing)
{
text_symbol.set_line_spacing(*line_spacing);
}
// spacing between characters in text
optional<unsigned> character_spacing = get_opt_attr<unsigned>(sym, "character_spacing");
if (character_spacing)
{
text_symbol.set_character_spacing(*character_spacing);
}
// spacing between repeated labels on lines // spacing between repeated labels on lines
optional<unsigned> spacing = get_opt_attr<unsigned>(sym, "spacing"); optional<unsigned> spacing = get_opt_attr<unsigned>(sym, "spacing");
if (spacing) if (spacing)

View file

@ -75,6 +75,7 @@ namespace mapnik
displacement_(sym.get_displacement()), displacement_(sym.get_displacement()),
label_placement(sym.get_label_placement()), label_placement(sym.get_label_placement()),
wrap_width(sym.get_wrap_width()), wrap_width(sym.get_wrap_width()),
wrap_char(sym.get_wrap_char()),
text_ratio(sym.get_text_ratio()), text_ratio(sym.get_text_ratio()),
label_spacing(sym.get_label_spacing()), label_spacing(sym.get_label_spacing()),
label_position_tolerance(sym.get_label_position_tolerance()), label_position_tolerance(sym.get_label_position_tolerance()),
@ -214,7 +215,9 @@ namespace mapnik
void placement_finder<DetectorT>::find_point_placement(placement & p, void placement_finder<DetectorT>::find_point_placement(placement & p,
double label_x, double label_x,
double label_y, double label_y,
vertical_alignment_e valign) vertical_alignment_e valign,
unsigned line_spacing,
unsigned character_spacing)
{ {
double x, y; double x, y;
std::auto_ptr<placement_element> current_placement(new placement_element); std::auto_ptr<placement_element> current_placement(new placement_element);
@ -239,7 +242,7 @@ namespace mapnik
std::vector<double> line_heights; std::vector<double> line_heights;
if (wrap_at < string_width && p.info.num_characters() > 0) if (wrap_at < string_width && p.info.num_characters() > 0)
{ {
int last_space = 0; int last_wrap_char = 0;
string_width = 0; string_width = 0;
string_height = 0; string_height = 0;
double line_width = 0; double line_width = 0;
@ -251,13 +254,15 @@ namespace mapnik
character_info ci; character_info ci;
ci = p.info.at(ii); ci = p.info.at(ii);
unsigned c = ci.character; unsigned cwidth = ci.width + character_spacing;
word_width += ci.width;
word_height = word_height > ci.height ? word_height : ci.height;
if (c == ' ') unsigned c = ci.character;
word_width += cwidth;
word_height = word_height > (ci.height + line_spacing) ? word_height : (ci.height + line_spacing);
if (c == p.wrap_char)
{ {
last_space = ii; last_wrap_char = ii;
line_width += word_width; line_width += word_width;
line_height = line_height > word_height ? line_height : word_height; line_height = line_height > word_height ? line_height : word_height;
word_width = 0; word_width = 0;
@ -266,13 +271,13 @@ namespace mapnik
if (line_width > 0 && line_width > wrap_at) if (line_width > 0 && line_width > wrap_at)
{ {
// Remove width of breaking space character since it is not rendered // Remove width of breaking space character since it is not rendered
line_width -= ci.width; line_width -= cwidth;
string_width = string_width > line_width ? string_width : line_width; string_width = string_width > line_width ? string_width : line_width;
string_height += line_height; string_height += line_height;
line_breaks.push_back(last_space); line_breaks.push_back(last_wrap_char);
line_widths.push_back(line_width); line_widths.push_back(line_width);
line_heights.push_back(line_height); line_heights.push_back(line_height);
ii = last_space; ii = last_wrap_char;
line_width = 0; line_width = 0;
line_height = 0; line_height = 0;
word_width = 0; word_width = 0;
@ -326,6 +331,8 @@ namespace mapnik
character_info ci; character_info ci;
ci = p.info.at(i); ci = p.info.at(i);
unsigned cwidth = ci.width + character_spacing;
unsigned c = ci.character; unsigned c = ci.character;
if (i == index_to_wrap_at) if (i == index_to_wrap_at)
{ {
@ -367,7 +374,7 @@ p.minimum_distance)))
p.envelopes.push(e); p.envelopes.push(e);
} }
x += ci.width; x += cwidth;
} }
p.placements.push_back(current_placement.release()); p.placements.push_back(current_placement.release());
//update_detector(p); //update_detector(p);

View file

@ -275,6 +275,22 @@ namespace mapnik
{ {
set_attr( node, "wrap_width", sym.get_wrap_width() ); set_attr( node, "wrap_width", sym.get_wrap_width() );
} }
if (sym.get_wrap_char() != dfl.get_wrap_char() || explicit_defaults_ )
{
set_attr( node, "wrap_character", std::string(1, sym.get_wrap_char()) );
}
if (sym.get_text_convert() != dfl.get_text_convert() || explicit_defaults_ )
{
set_attr( node, "text_convert", sym.get_text_convert() );
}
if (sym.get_line_spacing() != dfl.get_line_spacing() || explicit_defaults_ )
{
set_attr( node, "line_spacing", sym.get_line_spacing() );
}
if (sym.get_character_spacing() != dfl.get_character_spacing() || explicit_defaults_ )
{
set_attr( node, "character_spacing", sym.get_character_spacing() );
}
if (sym.get_label_spacing() != dfl.get_label_spacing() || explicit_defaults_ ) if (sym.get_label_spacing() != dfl.get_label_spacing() || explicit_defaults_ )
{ {
set_attr( node, "spacing", sym.get_label_spacing() ); set_attr( node, "spacing", sym.get_label_spacing() );

View file

@ -48,6 +48,17 @@ static const char * vertical_alignment_strings[] = {
IMPLEMENT_ENUM( mapnik::vertical_alignment_e, vertical_alignment_strings ); IMPLEMENT_ENUM( mapnik::vertical_alignment_e, vertical_alignment_strings );
static const char * text_convert_strings[] = {
"none",
"toupper",
"tolower",
""
};
IMPLEMENT_ENUM( mapnik::text_convert_e, text_convert_strings );
namespace mapnik namespace mapnik
{ {
text_symbolizer::text_symbolizer(std::string const& name, std::string const& face_name, unsigned size, color const& fill) text_symbolizer::text_symbolizer(std::string const& name, std::string const& face_name, unsigned size, color const& fill)
@ -57,6 +68,10 @@ namespace mapnik
size_(size), size_(size),
text_ratio_(0), text_ratio_(0),
wrap_width_(0), wrap_width_(0),
wrap_char_(' '),
text_convert_(NONE),
line_spacing_(0),
character_spacing_(0),
label_spacing_(0), label_spacing_(0),
label_position_tolerance_(0), label_position_tolerance_(0),
force_odd_labels_(false), force_odd_labels_(false),
@ -78,6 +93,10 @@ namespace mapnik
size_(size), size_(size),
text_ratio_(0), text_ratio_(0),
wrap_width_(0), wrap_width_(0),
wrap_char_(' '),
text_convert_(NONE),
line_spacing_(0),
character_spacing_(0),
label_spacing_(0), label_spacing_(0),
label_position_tolerance_(0), label_position_tolerance_(0),
force_odd_labels_(false), force_odd_labels_(false),
@ -99,6 +118,10 @@ namespace mapnik
size_(rhs.size_), size_(rhs.size_),
text_ratio_(rhs.text_ratio_), text_ratio_(rhs.text_ratio_),
wrap_width_(rhs.wrap_width_), wrap_width_(rhs.wrap_width_),
wrap_char_(rhs.wrap_char_),
text_convert_(rhs.text_convert_),
line_spacing_(rhs.line_spacing_),
character_spacing_(rhs.character_spacing_),
label_spacing_(rhs.label_spacing_), label_spacing_(rhs.label_spacing_),
label_position_tolerance_(rhs.label_position_tolerance_), label_position_tolerance_(rhs.label_position_tolerance_),
force_odd_labels_(rhs.force_odd_labels_), force_odd_labels_(rhs.force_odd_labels_),
@ -124,6 +147,10 @@ namespace mapnik
size_ = other.size_; size_ = other.size_;
text_ratio_ = other.text_ratio_; text_ratio_ = other.text_ratio_;
wrap_width_ = other.wrap_width_; wrap_width_ = other.wrap_width_;
wrap_char_ = other.wrap_char_;
text_convert_ = other.text_convert_;
line_spacing_ = other.line_spacing_;
character_spacing_ = other.character_spacing_;
label_spacing_ = other.label_spacing_; label_spacing_ = other.label_spacing_;
label_position_tolerance_ = other.label_position_tolerance_; label_position_tolerance_ = other.label_position_tolerance_;
force_odd_labels_ = other.force_odd_labels_; force_odd_labels_ = other.force_odd_labels_;
@ -191,6 +218,46 @@ namespace mapnik
wrap_width_ = width; wrap_width_ = width;
} }
unsigned char text_symbolizer::get_wrap_char() const
{
return wrap_char_;
}
void text_symbolizer::set_wrap_char(unsigned char character)
{
wrap_char_ = character;
}
text_convert_e text_symbolizer::get_text_convert() const
{
return text_convert_;
}
void text_symbolizer::set_text_convert(text_convert_e convert)
{
text_convert_ = convert;
}
unsigned text_symbolizer::get_line_spacing() const
{
return line_spacing_;
}
void text_symbolizer::set_line_spacing(unsigned spacing)
{
line_spacing_ = spacing;
}
unsigned text_symbolizer::get_character_spacing() const
{
return character_spacing_;
}
void text_symbolizer::set_character_spacing(unsigned spacing)
{
character_spacing_ = spacing;
}
unsigned text_symbolizer::get_label_spacing() const unsigned text_symbolizer::get_label_spacing() const
{ {
return label_spacing_; return label_spacing_;