Implement offsets and multiline rendering.

This commit is contained in:
Hermann Kraus 2012-08-12 02:46:26 +02:00
parent 14891379d0
commit 37a5552bbd
4 changed files with 50 additions and 14 deletions

View file

@ -25,6 +25,7 @@
// mapnik
#include <mapnik/pixel_position.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/offset_converter.hpp>
// agg
#include "agg_basics.h"
@ -32,10 +33,18 @@
// stl
#include <vector>
#include <utility>
#include <cmath>
//boost
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
namespace mapnik
{
class vertex_cache;
typedef boost::shared_ptr<vertex_cache> 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 <typename T>
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<vertex_cache> 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;
}

View file

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

View file

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

View file

@ -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<glyph_positions>();
double offset = base_offset + layout_.height();
double offset = base_offset + layout_.height()/2.;
unsigned upside_down_glyph_count = 0;
std::vector<box2d<double> > 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<double> 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;