diff --git a/include/mapnik/font_engine_freetype.hpp b/include/mapnik/font_engine_freetype.hpp index cbce5e43e..fd35e834b 100644 --- a/include/mapnik/font_engine_freetype.hpp +++ b/include/mapnik/font_engine_freetype.hpp @@ -345,8 +345,8 @@ struct text_renderer : private boost::noncopyable text_renderer (pixmap_type & pixmap, face_manager &font_manager_, stroker & s); box2d prepare_glyphs(text_path *path); - void render(double x0, double y0); - void render_id(int feature_id,double x0, double y0, double min_radius=1.0); + void render(pixel_position pos); + void render_id(int feature_id, pixel_position pos, double min_radius=1.0); private: void render_bitmap(FT_Bitmap *bitmap, unsigned rgba, int x, int y, double opacity) diff --git a/include/mapnik/pixel_position.hpp b/include/mapnik/pixel_position.hpp index 600327056..db75d7fb8 100644 --- a/include/mapnik/pixel_position.hpp +++ b/include/mapnik/pixel_position.hpp @@ -27,8 +27,8 @@ struct pixel_position { double x; double y; - pixel_coord(double x, double y) : x(x), y(y) { } - pixel_coord() : x(0), y(0) { } + pixel_position(double x, double y) : x(x), y(y) { } + pixel_position() : x(0), y(0) { } }; #endif // MAPNIK_PIXEL_POSITION_HPP diff --git a/include/mapnik/placement_finder.hpp b/include/mapnik/placement_finder.hpp index d7821165b..a4a4320c2 100644 --- a/include/mapnik/placement_finder.hpp +++ b/include/mapnik/placement_finder.hpp @@ -96,8 +96,17 @@ private: string_info &info_; text_symbolizer_properties &p; text_placement_info π + /** Length of the longest line after linebreaks. + * Before find_line_breaks() this is the total length of the string. + */ double string_width_; + /** Height of the string after linebreaks. + * Before find_line_breaks() this is the total length of the string. + */ double string_height_; + /** Height of the tallest font in the first line not including line spacing. + * Used to determine the correct offset for the first line. + */ double first_line_space_; vertical_alignment_e valign_; horizontal_alignment_e halign_; diff --git a/include/mapnik/text_path.hpp b/include/mapnik/text_path.hpp index 3f4db3b31..7905f25ce 100644 --- a/include/mapnik/text_path.hpp +++ b/include/mapnik/text_path.hpp @@ -25,6 +25,7 @@ // mapnik #include +#include //stl #include @@ -124,18 +125,23 @@ class text_path : boost::noncopyable struct character_node { int c; - double x, y, angle; + pixel_position pos; + double angle; char_properties *format; character_node(int c_, double x_, double y_, double angle_, char_properties *format_) - : c(c_), x(x_), y(y_), angle(angle_), format(format_) {} + : c(c_), pos(x_, y_), angle(angle_), format(format_) + { + + } + ~character_node() {} void vertex(int *c_, double *x_, double *y_, double *angle_, char_properties **format_) { *c_ = c; - *x_ = x; - *y_ = y; + *x_ = pos.x; + *y_ = pos.y; *angle_ = angle; *format_ = format; } @@ -145,16 +151,11 @@ class text_path : boost::noncopyable public: typedef std::vector character_nodes_t; character_nodes_t nodes_; - double starting_x; - double starting_y; -// std::pair string_dimensions; + pixel_position center; text_path() - : itr_(0), - starting_x(0), - starting_y(0) - + : itr_(0) { } diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index 6dad62d7b..946c08e66 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -57,10 +57,8 @@ void agg_renderer::process(shield_symbolizer const& sym, std::pair marker_pos = helper.get_marker_position(placement->placements[ii]); render_marker(marker_pos.first, marker_pos.second, helper.get_marker(), helper.get_transform(), sym.get_opacity()); - double x = placement->placements[ii].starting_x; - double y = placement->placements[ii].starting_y; ren.prepare_glyphs(&(placement->placements[ii])); - ren.render(x, y); + ren.render(placement->placements[ii].center); } } } diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index b31c87723..f88a48c74 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -46,10 +46,8 @@ void agg_renderer::process(text_symbolizer const& sym, while ((placement = helper.get_placement())) { for (unsigned int ii = 0; ii < placement->placements.size(); ++ii) { - double x = placement->placements[ii].starting_x; - double y = placement->placements[ii].starting_y; ren.prepare_glyphs(&(placement->placements[ii])); - ren.render(x, y); + ren.render(placement->placements[ii].center); } } } diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 025310373..17f11e6f0 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -575,8 +575,8 @@ public: cairo_face_manager & manager, face_manager &font_manager) { - double sx = path.starting_x; - double sy = path.starting_y; + double sx = path.center.x; + double sy = path.center.y; path.rewind(); diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index 61eaf59ef..617a85f50 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -379,25 +379,25 @@ box2d text_renderer::prepare_glyphs(text_path *path) } template -void text_renderer::render(double x0, double y0) +void text_renderer::render(pixel_position pos) { FT_Error error; FT_Vector start; unsigned height = pixmap_.height(); - start.x = static_cast(x0 * (1 << 6)); - start.y = static_cast((height - y0) * (1 << 6)); + start.x = static_cast(pos.x * (1 << 6)); + start.y = static_cast((height - pos.y) * (1 << 6)); // now render transformed glyphs - typename glyphs_t::iterator pos; - for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos) + typename glyphs_t::iterator itr; + for (itr = glyphs_.begin(); itr != glyphs_.end(); ++itr) { - double halo_radius = pos->properties->halo_radius; + double halo_radius = itr->properties->halo_radius; //make sure we've got reasonable values. if (halo_radius <= 0.0 || halo_radius > 1024.0) continue; stroker_.init(halo_radius); FT_Glyph g; - error = FT_Glyph_Copy(pos->image, &g); + error = FT_Glyph_Copy(itr->image, &g); if (!error) { FT_Glyph_Transform(g,0,&start); @@ -407,49 +407,49 @@ void text_renderer::render(double x0, double y0) { FT_BitmapGlyph bit = (FT_BitmapGlyph)g; - render_bitmap(&bit->bitmap, pos->properties->halo_fill.rgba(), + render_bitmap(&bit->bitmap, itr->properties->halo_fill.rgba(), bit->left, - height - bit->top, pos->properties->text_opacity); + height - bit->top, itr->properties->text_opacity); } } FT_Done_Glyph(g); } //render actual text - for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos) + for (itr = glyphs_.begin(); itr != glyphs_.end(); ++itr) { - FT_Glyph_Transform(pos->image,0,&start); + FT_Glyph_Transform(itr->image,0,&start); - error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1); + error = FT_Glyph_To_Bitmap( &(itr->image),FT_RENDER_MODE_NORMAL,0,1); if ( ! error ) { - FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image; - render_bitmap(&bit->bitmap, pos->properties->fill.rgba(), + FT_BitmapGlyph bit = (FT_BitmapGlyph)itr->image; + render_bitmap(&bit->bitmap, itr->properties->fill.rgba(), bit->left, - height - bit->top, pos->properties->text_opacity); + height - bit->top, itr->properties->text_opacity); } } } template -void text_renderer::render_id(int feature_id,double x0, double y0, double min_radius) +void text_renderer::render_id(int feature_id, pixel_position pos, double min_radius) { FT_Error error; FT_Vector start; unsigned height = pixmap_.height(); - start.x = static_cast(x0 * (1 << 6)); - start.y = static_cast((height - y0) * (1 << 6)); + start.x = static_cast(pos.x * (1 << 6)); + start.y = static_cast((height - pos.y) * (1 << 6)); // now render transformed glyphs - typename glyphs_t::iterator pos; - for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos) + typename glyphs_t::iterator itr; + for (itr = glyphs_.begin(); itr != glyphs_.end(); ++itr) { - stroker_.init(std::max(pos->properties->halo_radius, min_radius)); + stroker_.init(std::max(itr->properties->halo_radius, min_radius)); FT_Glyph g; - error = FT_Glyph_Copy(pos->image, &g); + error = FT_Glyph_Copy(itr->image, &g); if (!error) { FT_Glyph_Transform(g,0,&start); @@ -473,11 +473,11 @@ void text_renderer::render_id(int feature_id,double x0, double y0, double min boost::mutex freetype_engine::mutex_; #endif std::map > freetype_engine::name2file_; -template void text_renderer::render(double, double); +template void text_renderer::render(pixel_position); template text_renderer::text_renderer(image_32&, face_manager&, stroker&); template box2dtext_renderer::prepare_glyphs(text_path*); -template void text_renderer::render_id(int, double, double, double); +template void text_renderer::render_id(int, pixel_position, double); template text_renderer::text_renderer(grid&, face_manager&, stroker&); template box2dtext_renderer::prepare_glyphs(text_path*); } diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp index ad6544577..d612d9284 100644 --- a/src/grid/process_shield_symbolizer.cpp +++ b/src/grid/process_shield_symbolizer.cpp @@ -66,10 +66,8 @@ void grid_renderer::process(shield_symbolizer const& sym, helper.get_marker(), helper.get_transform(), sym.get_opacity()); - double x = floor(placement->placements[ii].starting_x); - double y = floor(placement->placements[ii].starting_y); ren.prepare_glyphs(&(placement->placements[ii])); - ren.render_id(feature->id(), x, y, 2); + ren.render_id(feature->id(),placement->placements[ii].center, 2); } } if (placement_found) diff --git a/src/grid/process_text_symbolizer.cpp b/src/grid/process_text_symbolizer.cpp index 3278933f4..ac09c935b 100644 --- a/src/grid/process_text_symbolizer.cpp +++ b/src/grid/process_text_symbolizer.cpp @@ -47,10 +47,8 @@ void grid_renderer::process(text_symbolizer const& sym, placement_found = true; for (unsigned int ii = 0; ii < placement->placements.size(); ++ii) { - double x = placement->placements[ii].starting_x; - double y = placement->placements[ii].starting_y; ren.prepare_glyphs(&(placement->placements[ii])); - ren.render_id(feature->id(),x,y,2); + ren.render_id(feature->id(), placement->placements[ii].center,2); } } if (placement_found) pixmap_.add_feature(feature); diff --git a/src/metawriter.cpp b/src/metawriter.cpp index da56f35f2..c107021c4 100644 --- a/src/metawriter.cpp +++ b/src/metawriter.cpp @@ -202,8 +202,8 @@ void metawriter_json_stream::add_text(text_placement_info const& p, char_properties *format; current_placement.rewind(); for (int i = 0; i < current_placement.num_nodes(); ++i) { - int cx = current_placement.starting_x; - int cy = current_placement.starting_y; + int cx = current_placement.center.x; + int cy = current_placement.center.y; current_placement.vertex(&c, &x, &y, &angle, &format); if (cx+x >= 0 && cx+x < width_ && cy-y >= 0 && cy-y < height_) inside = true; if (angle > 0.001 || angle < -0.001) straight = false; @@ -225,10 +225,10 @@ void metawriter_json_stream::add_text(text_placement_info const& p, maxy = std::max(maxy, y+ci.ymax); miny = std::min(miny, y+ci.ymin); } - add_box(box2d(current_placement.starting_x+minx, - current_placement.starting_y-miny, - current_placement.starting_x+maxx, - current_placement.starting_y-maxy), feature, t, properties); + add_box(box2d(current_placement.center.x+minx, + current_placement.center.y-miny, + current_placement.center.x+maxx, + current_placement.center.y-maxy), feature, t, properties); continue; } @@ -247,8 +247,8 @@ void metawriter_json_stream::add_text(text_placement_info const& p, double x0, y0, x1, y1, x2, y2, x3, y3; double sina = sin(angle); double cosa = cos(angle); - x0 = current_placement.starting_x + x - sina*ci.ymin; - y0 = current_placement.starting_y - y - cosa*ci.ymin; + x0 = current_placement.center.x + x - sina*ci.ymin; + y0 = current_placement.center.y - y - cosa*ci.ymin; x1 = x0 + ci.width * cosa; y1 = y0 - ci.width * sina; x2 = x0 + (ci.width * cosa - ci.height() * sina); diff --git a/src/placement_finder.cpp b/src/placement_finder.cpp index d01a64721..6964a8970 100644 --- a/src/placement_finder.cpp +++ b/src/placement_finder.cpp @@ -234,7 +234,7 @@ void placement_finder::find_line_breaks() double line_height = 0.0; //Height of tallest char in line double word_width = 0.0; //Current unfinished word width double word_height = 0.0; - //line_width, word_width does include char width + spacing, but not the spacing after the last char + //line_width and word_width include char width + spacing, but not the spacing after the last char for (unsigned int ii = 0; ii < info_.num_characters(); ii++) { @@ -317,26 +317,32 @@ template void placement_finder::adjust_position(text_path *current_placement, double label_x, double label_y) { // if needed, adjust for desired vertical alignment - current_placement->starting_y = label_y; // no adjustment, default is MIDDLE + current_placement->center.y = label_y; // no adjustment, default is MIDDLE if (valign_ == V_TOP) - current_placement->starting_y -= 0.5 * string_height_; // move center up by 1/2 the total height - else if (valign_ == V_BOTTOM) { - current_placement->starting_y += 0.5 * string_height_; // move center down by the 1/2 the total height - current_placement->starting_y -= first_line_space_; - } else if (valign_ == V_MIDDLE) { - current_placement->starting_y -= first_line_space_/2.0; + { + current_placement->center.y -= 0.5 * string_height_; // move center up by 1/2 the total height + } else if (valign_ == V_BOTTOM) + { + current_placement->center.y += 0.5 * string_height_; // move center down by the 1/2 the total height + current_placement->center.y -= first_line_space_; + } else if (valign_ == V_MIDDLE) + { + current_placement->center.y -= first_line_space_/2.0; } // set horizontal position to middle of text - current_placement->starting_x = label_x; // no adjustment, default is MIDDLE + current_placement->center.x = label_x; // no adjustment, default is MIDDLE if (halign_ == H_LEFT) - current_placement->starting_x -= 0.5 * string_width_; // move center left by 1/2 the string width - else if (halign_ == H_RIGHT) - current_placement->starting_x += 0.5 * string_width_; // move center right by 1/2 the string width + { + current_placement->center.x -= 0.5 * string_width_; // move center left by 1/2 the string width + } else if (halign_ == H_RIGHT) + { + current_placement->center.x += 0.5 * string_width_; // move center right by 1/2 the string width + } // adjust text envelope position by user's x-y displacement (dx, dy) - current_placement->starting_x += pi.get_scale_factor() * p.displacement.first; - current_placement->starting_y += pi.get_scale_factor() * p.displacement.second; + current_placement->center.x += pi.get_scale_factor() * p.displacement.first; + current_placement->center.y += pi.get_scale_factor() * p.displacement.second; } @@ -416,19 +422,19 @@ void placement_finder::find_point_placement(double label_x, double la /*x axis: left to right, y axis: top to bottom (negative values higher)*/ if (pi.has_dimensions) { - e.init(current_placement->starting_x - (pi.dimensions.first/2.0), // Top Left - current_placement->starting_y - (pi.dimensions.second/2.0), + e.init(current_placement->center.x - (pi.dimensions.first/2.0), // Top Left + current_placement->center.y - (pi.dimensions.second/2.0), - current_placement->starting_x + (pi.dimensions.first/2.0), // Bottom Right - current_placement->starting_y + (pi.dimensions.second/2.0)); + current_placement->center.x + (pi.dimensions.first/2.0), // Bottom Right + current_placement->center.y + (pi.dimensions.second/2.0)); } else { - e.init(current_placement->starting_x + dx, // Bottom Left - current_placement->starting_y - dy - ci.ymin, /*ymin usually <0 */ + e.init(current_placement->center.x + dx, // Bottom Left + current_placement->center.y - dy - ci.ymin, /*ymin usually <0 */ - current_placement->starting_x + dx + ci.width, // Top Right - current_placement->starting_y - dy - ci.ymax); + current_placement->center.x + dx + ci.width, // Top Right + current_placement->center.y - dy - ci.ymax); } // if there is an overlap with existing envelopes, then exit - no placement @@ -465,10 +471,10 @@ void placement_finder::find_point_placement(double label_x, double la { BOOST_FOREACH(box2d box, pi.additional_boxes) { - box2d pt(box.minx() + current_placement->starting_x, - box.miny() + current_placement->starting_y, - box.maxx() + current_placement->starting_x, - box.maxy() + current_placement->starting_y); + box2d pt(box.minx() + current_placement->center.x, + box.miny() + current_placement->center.y, + box.maxx() + current_placement->center.x, + box.maxy() + current_placement->center.y); // abort the whole placement if the additional envelopes can't be placed. if (!detector_.has_point_placement(pt, p.minimum_distance)) return; @@ -618,8 +624,8 @@ void placement_finder::find_line_placements(PathT & shape_path) //Offset all the characters by this angle for (unsigned i = 0; i < current_placement->nodes_.size(); i++) { - current_placement->nodes_[i].x += pi.get_scale_factor() * displacement*cos(anglesum+M_PI/2); - current_placement->nodes_[i].y += pi.get_scale_factor() * displacement*sin(anglesum+M_PI/2); + current_placement->nodes_[i].pos.x += pi.get_scale_factor() * displacement*cos(anglesum+M_PI/2); + current_placement->nodes_[i].pos.y += pi.get_scale_factor() * displacement*sin(anglesum+M_PI/2); } } @@ -699,8 +705,8 @@ std::auto_ptr placement_finder::get_placement_offset(const return std::auto_ptr(NULL); } - current_placement->starting_x = old_x + dx*distance/segment_length; - current_placement->starting_y = old_y + dy*distance/segment_length; + current_placement->center.x = old_x + dx*distance/segment_length; + current_placement->center.y = old_y + dy*distance/segment_length; double angle = atan2(-dy, dx); bool orientation_forced = (orientation != 0); //Wether the orientation was set by the caller @@ -808,8 +814,8 @@ std::auto_ptr placement_finder::get_placement_offset(const render_y -= cwidth*sina + (char_height-2)*cosa; render_angle += M_PI; } - current_placement->add_node(c,render_x - current_placement->starting_x, - -render_y + current_placement->starting_y, + current_placement->add_node(c,render_x - current_placement->center.x, + -render_y + current_placement->center.y, render_angle, ci.format); //Normalise to 0 <= angle < 2PI @@ -856,8 +862,8 @@ bool placement_finder::test_placement(const std::auto_ptr double x, y, angle; char_properties *properties; current_placement->vertex(&c, &x, &y, &angle, &properties); - x = current_placement->starting_x + x; - y = current_placement->starting_y - y; + x = current_placement->center.x + x; + y = current_placement->center.y - y; double sina = fast_sin(angle); double cosa = fast_cos(angle); @@ -1011,5 +1017,4 @@ typedef label_collision_detector4 DetectorType; template class placement_finder; template void placement_finder::find_point_placements(PathType &); template void placement_finder::find_line_placements(PathType &); - } // namespace diff --git a/src/symbolizer_helpers.cpp b/src/symbolizer_helpers.cpp index 27da787c1..9c84d5d49 100644 --- a/src/symbolizer_helpers.cpp +++ b/src/symbolizer_helpers.cpp @@ -231,7 +231,7 @@ text_placement_info_ptr shield_symbolizer_helper::get_p point_itr_ = points_.begin(); continue; //Reexecute size check } - position const& pos = placement_->properties.displacement; + position const& text_disp = placement_->properties.displacement; double label_x = point_itr_->first + shield_pos.first; double label_y = point_itr_->second + shield_pos.second; @@ -247,14 +247,12 @@ text_placement_info_ptr shield_symbolizer_helper::get_p } //Found a label placement but not necessarily also a marker placement // check to see if image overlaps anything too, there is only ever 1 placement found for points and verticies - double x = floor(placement_->placements[0].starting_x); - double y = floor(placement_->placements[0].starting_y); if (!sym_.get_unlock_image()) { // center image at text center position // remove displacement from image label - double lx = x - pos.first; - double ly = y - pos.second; + double lx = placement_->placements[0].center.x - text_disp.first; + double ly = placement_->placements[0].center.y - text_disp.second; marker_x_ = lx - 0.5 * marker_w_; marker_y_ = ly - 0.5 * marker_h_; marker_ext_.re_center(lx, ly); @@ -340,11 +338,8 @@ std::pair shield_symbolizer_helper::get_marke { position const& pos = placement_->properties.displacement; if (placement_->properties.label_placement == LINE_PLACEMENT) { - double x = floor(p.starting_x); - double y = floor(p.starting_y); - - double lx = x - pos.first; - double ly = y - pos.second; + double lx = p.center.x - pos.first; + double ly = p.center.y - pos.second; int px = lx - 0.5*marker_w_; int py = ly - 0.5*marker_h_; marker_ext_.re_center(lx, ly);