From 37a5552bbd8980d11134df02540d041634862b80 Mon Sep 17 00:00:00 2001 From: Hermann Kraus Date: Sun, 12 Aug 2012 02:46:26 +0200 Subject: [PATCH] Implement offsets and multiline rendering. --- include/mapnik/vertex_cache.hpp | 40 ++++++++++++++++++++++++++++---- src/text/face.cpp | 2 +- src/text/layout.cpp | 4 ++-- src/text/placement_finder_ng.cpp | 18 ++++++++------ 4 files changed, 50 insertions(+), 14 deletions(-) diff --git a/include/mapnik/vertex_cache.hpp b/include/mapnik/vertex_cache.hpp index d76eee53f..93f1a5041 100644 --- a/include/mapnik/vertex_cache.hpp +++ b/include/mapnik/vertex_cache.hpp @@ -25,6 +25,7 @@ // mapnik #include #include +#include // agg #include "agg_basics.h" @@ -32,10 +33,18 @@ // stl #include #include +#include + +//boost +#include +#include namespace mapnik { +class vertex_cache; +typedef boost::shared_ptr vertex_cache_ptr; + /** Caches all path points and their lengths. Allows easy moving in both directions. */ class vertex_cache { @@ -62,6 +71,7 @@ public: double position_in_segment; pixel_position current_position; pixel_position segment_starting_point; + double position_; friend class vertex_cache; public: pixel_position const& position() const { return current_position; } @@ -91,7 +101,7 @@ public: bool next_subpath(); /** Moves all positions to a parallel line in the specified distance. */ - void set_offset(double offset); + vertex_cache &get_offseted(double offset, double region_width); /** Skip a certain amount of space. @@ -125,8 +135,11 @@ private: double position_in_segment_; mutable double angle_; mutable bool angle_valid_; + vertex_cache_ptr offseted_line_; + double position_; }; + template vertex_cache::vertex_cache(T &path) : current_position_(), @@ -139,7 +152,9 @@ vertex_cache::vertex_cache(T &path) first_subpath_(true), position_in_segment_(0.), angle_(0.), - angle_valid_(false) + angle_valid_(false), + offseted_line_(), + position_(0.) { path.rewind(0); unsigned cmd; @@ -248,9 +263,22 @@ bool vertex_cache::previous_segment() return true; } -void vertex_cache::set_offset(double offset) +vertex_cache & vertex_cache::get_offseted(double offset, double region_width) { - MAPNIK_LOG_DEBUG(vertex_cache) << "set_offset: unimplemented\n"; + if (fabs(offset) < 0.01) + { + return *this; + } + //TODO: Cache offseted lines + offset_converter converter(*this); + converter.set_offset(offset); + offseted_line_ = vertex_cache_ptr(new vertex_cache(converter)); + offseted_line_->rewind_subpath(); //TODO: Multiple subpath support + double seek = (position_ + region_width/2.) * offseted_line_->length() / length() - region_width/2.; + if (seek < 0) seek = 0; + if (seek > offseted_line_->length()) seek = offseted_line_->length(); + offseted_line_->move(seek); + return *offseted_line_; } bool vertex_cache::forward(double length) @@ -275,6 +303,7 @@ bool vertex_cache::backward(double length) bool vertex_cache::move(double length) { + position_ += length; length += position_in_segment_; while (length >= current_segment_->length) { @@ -300,6 +329,7 @@ void vertex_cache::rewind_subpath() position_in_segment_ = 0; segment_starting_point_ = current_position_; angle_valid_ = false; + position_ = 0; } void vertex_cache::rewind(unsigned) @@ -331,6 +361,7 @@ vertex_cache::state vertex_cache::save_state() const s.position_in_segment = position_in_segment_; s.current_position = current_position_; s.segment_starting_point = segment_starting_point_; + s.position_ = position_; return s; } @@ -340,6 +371,7 @@ void vertex_cache::restore_state(state const& s) position_in_segment_ = s.position_in_segment; current_position_ = s.current_position; segment_starting_point_ = s.segment_starting_point; + position_ = s.position_; angle_valid_ = false; } diff --git a/src/text/face.cpp b/src/text/face.cpp index 39b94dc6f..04fd34ab4 100644 --- a/src/text/face.cpp +++ b/src/text/face.cpp @@ -78,7 +78,7 @@ void font_face::glyph_dimensions(glyph_info &glyph) const matrix.yx = (FT_Fixed)( 0 * 0x10000L ); matrix.yy = (FT_Fixed)( 1 * 0x10000L ); - FT_Set_Transform(face_, &matrix, &pen); //TODO: Matrix is always only set to the identity matrix. This seems to be useless. + FT_Set_Transform(face_, &matrix, &pen); if (FT_Load_Glyph (face_, glyph.glyph_index, FT_LOAD_NO_HINTING)) return; if (FT_Get_Glyph(face_->glyph, &image)) return; diff --git a/src/text/layout.cpp b/src/text/layout.cpp index 0cb8045fc..aed2e04c9 100644 --- a/src/text/layout.cpp +++ b/src/text/layout.cpp @@ -218,12 +218,12 @@ void text_layout::clear() double text_layout::height() const { - return height_; //TODO + return height_; } double text_layout::width() const { - return width_; //TODO + return width_; } text_layout::const_iterator text_layout::begin() const diff --git a/src/text/placement_finder_ng.cpp b/src/text/placement_finder_ng.cpp index fd071db78..ae00f5a9a 100644 --- a/src/text/placement_finder_ng.cpp +++ b/src/text/placement_finder_ng.cpp @@ -296,7 +296,7 @@ bool placement_finder_ng::single_line_placement(vertex_cache &pp, text_upright_e double base_offset = alignment_offset().y + info_->properties.displacement.y; glyph_positions_ptr glyphs = boost::make_shared(); - double offset = base_offset + layout_.height(); + double offset = base_offset + layout_.height()/2.; unsigned upside_down_glyph_count = 0; std::vector > bboxes; @@ -306,8 +306,11 @@ bool placement_finder_ng::single_line_placement(vertex_cache &pp, text_upright_e for (; line_itr != line_end; line_itr++) { double char_height = (*line_itr)->max_char_height(); - offset -= (*line_itr)->height(); - pp.set_offset(offset); + //Only subtract half the line height here and half at the end because text is automatically + //centered on the line + offset -= (*line_itr)->height()/2; + vertex_cache &off_pp = pp.get_offseted(offset, sign*layout_.width()); + vertex_cache::scoped_state off_state(off_pp); //TODO: Remove this when a clean implementation in vertex_cache::get_offseted was done double last_cluster_angle = 999; signed current_cluster = -1; @@ -321,10 +324,10 @@ bool placement_finder_ng::single_line_placement(vertex_cache &pp, text_upright_e glyph_info const& glyph = *glyph_itr; if (current_cluster != glyph.char_index) { - if (!pp.move(sign * layout_.cluster_width(current_cluster))) return false; + if (!off_pp.move(sign * layout_.cluster_width(current_cluster))) return false; current_cluster = glyph.char_index; //Only calculate new angle at the start of each cluster! - angle = normalize_angle(pp.angle(sign * layout_.cluster_width(current_cluster))); + angle = normalize_angle(off_pp.angle(sign * layout_.cluster_width(current_cluster))); rot.init(angle); if ((info_->properties.max_char_angle_delta > 0) && (last_cluster_angle != 999) && fabs(normalize_angle(angle-last_cluster_angle)) > info_->properties.max_char_angle_delta) @@ -336,7 +339,7 @@ bool placement_finder_ng::single_line_placement(vertex_cache &pp, text_upright_e } if (abs(angle) > M_PI/2) upside_down_glyph_count++; - pixel_position pos = pp.current_position() + cluster_offset; + pixel_position pos = off_pp.current_position() + cluster_offset; //Center the text on the line pos.y = -pos.y - char_height/2.0*rot.cos; pos.x = pos.x + char_height/2.0*rot.sin; @@ -349,6 +352,8 @@ bool placement_finder_ng::single_line_placement(vertex_cache &pp, text_upright_e bboxes.push_back(bbox); glyphs->push_back(glyph, pos, rot); } + //See comment above + offset -= (*line_itr)->height()/2; } s.restore(); if (orientation == UPRIGHT_AUTO && (upside_down_glyph_count > layout_.get_text().length()/2)) @@ -429,7 +434,6 @@ box2d placement_finder_ng::get_bbox(glyph_info const& glyph, pixel_posit (0/ymin) (width/ymin) Add glyph offset in y direction, but not in x direction (as we use the full cluster width anyways)! */ - std::cout << glyph.offset << glyph.width << "," << glyph.ymin << glyph.ymax << "\n"; double width = layout_.cluster_width(glyph.char_index); if (glyph.width <= 0) width = -width; pixel_position tmp, tmp2;