Store the value of sin(angle) and cos(angle) instead of recomputing them every time.

This commit is contained in:
Hermann Kraus 2012-08-11 19:14:28 +02:00
parent 503c1862ba
commit 2e22d740cf
8 changed files with 66 additions and 86 deletions

View file

@ -90,6 +90,7 @@ public:
void clip(const box2d_type &other);
bool from_string(const std::string& s);
bool valid() const;
void move(T x, T y);
// define some operators
box2d_type& operator+=(box2d_type const& other);

View file

@ -28,6 +28,7 @@
namespace mapnik
{
struct rotation;
/** Store a pixel position. */
struct pixel_position
{
@ -62,7 +63,7 @@ struct pixel_position
y = 0;
}
pixel_position rotate(double sina_, double cosa_) const;
pixel_position rotate(rotation const& rot) const;
pixel_position operator~()
{
return pixel_position(x, -y);

View file

@ -28,6 +28,7 @@
#include <mapnik/text/layout.hpp>
#include <mapnik/text_placements/base.hpp>
#include <mapnik/text/placements_list.hpp>
#include <mapnik/text/rotation.hpp>
//stl
@ -76,13 +77,12 @@ private:
static double normalize_angle(double angle);
double get_spacing(double path_length, double layout_width) const;
bool collision(box2d<double> const& box) const;
box2d<double> get_bbox(glyph_info const& glyph, pixel_position const& pos, rotation rot);
Feature const& feature_;
DetectorType &detector_;
box2d<double> const& extent_;
double angle_; //in rad
// Precalculated values for maximum performance
double sina_;
double cosa_;
rotation orientation_;
text_layout layout_;
text_placement_info_ptr info_;
bool valid_;

View file

@ -25,6 +25,7 @@
#include <mapnik/box2d.hpp>
#include <mapnik/pixel_position.hpp>
#include <mapnik/text/glyph_info.hpp>
#include <mapnik/text/rotation.hpp>
//stl
#include <vector>
@ -37,11 +38,11 @@ struct glyph_info;
struct glyph_position
{
glyph_position(glyph_info const& glyph, pixel_position const& pos, double angle)
: glyph(&glyph), pos(pos), angle(angle) { }
glyph_position(glyph_info const& glyph, pixel_position const& pos, rotation const& rot)
: glyph(&glyph), pos(pos), rot(rot) { }
glyph_info const* glyph;
pixel_position pos;
double angle;
rotation rot;
};
/** Stores positions of glphys.
@ -57,20 +58,13 @@ public:
const_iterator begin() const;
const_iterator end() const;
void push_back(glyph_info const& glyph, pixel_position offset, double angle);
/** Is each character rotated by the same angle?
* This function is used to avoid costly trigonometric function calls when not necessary. */
bool is_constant_angle() const;
double get_angle() const;
void push_back(glyph_info const& glyph, pixel_position offset, rotation const& rot);
pixel_position const& get_base_point() const;
void set_base_point(pixel_position base_point);
private:
std::vector<glyph_position> data_;
pixel_position base_point_;
double angle_;
bool const_angle_;
};
typedef boost::shared_ptr<glyph_positions> glyph_positions_ptr;

View file

@ -0,0 +1,23 @@
#ifndef MAPNIK_ROTATION_HPP
#define MAPNIK_ROTATION_HPP
#include <cmath>
namespace mapnik
{
struct rotation
{
rotation() : sin(0), cos(1.) { }
rotation(double sin_, double cos_) : sin(sin_), cos(cos_) { }
rotation(double angle) : sin(std::sin(angle)), cos(std::cos(angle)) {}
void reset() { sin = 0.; cos = 1.;}
void init(double angle) { sin = std::sin(angle); cos = std::cos(angle); }
double sin;
double cos;
rotation operator~() { return rotation(sin, -cos); }
rotation operator!() { return rotation(-sin, cos); }
};
}
#endif // ROTATION_HPP

View file

@ -702,12 +702,10 @@ public:
glyph.face->set_character_sizes(text_size);
Cairo::Matrix matrix;
double sina = sin(itr->angle);
double cosa = cos(itr->angle);
matrix.xx = text_size * cosa;
matrix.xy = text_size * sina;
matrix.yx = text_size * -sina;
matrix.yy = text_size * cosa;
matrix.xx = text_size * itr->rot.cos;
matrix.xy = text_size * itr->rot.sin;
matrix.yx = text_size * -itr->rot.sin;
matrix.yy = text_size * itr->rot.cos;
matrix.x0 = 0;
matrix.y0 = 0;

View file

@ -64,15 +64,13 @@ bool placement_finder_ng::next_position()
{
// https://github.com/mapnik/mapnik/issues/1352
mapnik::evaluate<Feature, value_type> evaluator(feature_);
angle_ = boost::apply_visitor(
orientation_.init(
boost::apply_visitor(
evaluator,
*(info_->properties.orientation)).to_double() * M_PI / 180.0;
*(info_->properties.orientation)).to_double() * M_PI / 180.0);
} else {
angle_ = 0.0;
orientation_.reset();
}
cosa_ = std::cos(angle_);
sina_ = std::sin(angle_);
init_alignment();
return true;
}
@ -156,16 +154,16 @@ pixel_position placement_finder_ng::alignment_offset() const
}
// Output is centered around (0,0)
static void rotated_box2d(box2d<double> &box, double sina, double cosa, double width, double height)
static void rotated_box2d(box2d<double> &box, rotation const& rot, double width, double height)
{
double new_width = width * cosa + height * sina;
double new_height = width * sina + height * cosa;
double new_width = width * rot.cos + height * rot.sin;
double new_height = width * rot.sin + height * rot.cos;
box.init(-new_width/2., -new_height/2., new_width/2., new_height/2.);
}
pixel_position pixel_position::rotate(double sina, double cosa) const
pixel_position pixel_position::rotate(rotation const& rot) const
{
return pixel_position(x * cosa - y * sina, x * sina + y * cosa);
return pixel_position(x * rot.cos - y * rot.sin, x * rot.sin + y * rot.cos);
}
@ -175,11 +173,11 @@ bool placement_finder_ng::find_point_placement(pixel_position pos)
glyph_positions_ptr glyphs = boost::make_shared<glyph_positions>();
pixel_position displacement = scale_factor_ * info_->properties.displacement + alignment_offset();
if (info_->properties.rotate_displacement) displacement = displacement.rotate(-sina_, cosa_);
if (info_->properties.rotate_displacement) displacement = displacement.rotate(!orientation_);
glyphs->set_base_point(pos + displacement);
box2d<double> bbox;
rotated_box2d(bbox, sina_, cosa_, layout_.width(), layout_.height());
rotated_box2d(bbox, orientation_, layout_.width(), layout_.height());
bbox.re_center(glyphs->get_base_point().x, glyphs->get_base_point().y);
if (collision(bbox)) return false;
@ -212,7 +210,7 @@ bool placement_finder_ng::find_point_placement(pixel_position pos)
for (; glyph_itr != glyph_end; glyph_itr++)
{
// place the character relative to the center of the string envelope
glyphs->push_back(*glyph_itr, pixel_position(x, y).rotate(sina_, cosa_), angle_); //TODO: Store cosa, sina instead
glyphs->push_back(*glyph_itr, pixel_position(x, y).rotate(orientation_), orientation_);
if (glyph_itr->width)
{
//Only advance if glyph is not part of a multiple glyph sequence
@ -308,7 +306,8 @@ bool placement_finder_ng::single_line_placement(vertex_cache &pp, text_upright_e
double last_cluster_angle = 999;
signed current_cluster = -1;
pixel_position cluster_offset;
double angle, sina, cosa;
double angle;
rotation rot;
text_line::const_iterator glyph_itr = (*line_itr)->begin(), glyph_end = (*line_itr)->end();
for (; glyph_itr != glyph_end; glyph_itr++)
@ -320,8 +319,7 @@ bool placement_finder_ng::single_line_placement(vertex_cache &pp, text_upright_e
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)));
sina = sin(angle);
cosa = cos(angle);
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)
{
@ -334,13 +332,13 @@ bool placement_finder_ng::single_line_placement(vertex_cache &pp, text_upright_e
pixel_position pos = pp.current_position() + cluster_offset;
//Center the text on the line
pos.y = -pos.y - char_height/2.0*cosa;
pos.x = pos.x + char_height/2.0*sina;
pos.y = -pos.y - char_height/2.0*rot.cos;
pos.x = pos.x + char_height/2.0*rot.sin;
cluster_offset.x += cosa * glyph_itr->width;
cluster_offset.y -= sina * glyph_itr->width;
cluster_offset.x += rot.cos * glyph_itr->width;
cluster_offset.y -= rot.sin * glyph_itr->width;
glyphs->push_back(glyph, pos, angle); //TODO: Store cosa, sina instead
glyphs->push_back(glyph, pos, rot);
}
}
s.restore();
@ -410,7 +408,7 @@ bool placement_finder_ng::collision(const box2d<double> &box) const
glyph_positions::glyph_positions()
: base_point_(), const_angle_(true)
: base_point_()
{
}
@ -425,27 +423,10 @@ glyph_positions::const_iterator glyph_positions::end() const
return data_.end();
}
void glyph_positions::push_back(const glyph_info &glyph, pixel_position offset, double angle)
void glyph_positions::push_back(const glyph_info &glyph, pixel_position offset, rotation const& rot)
{
if (data_.empty())
{
angle_ = angle;
} else
{
if (angle != angle_) const_angle_ = false;
}
data_.push_back(glyph_position(glyph, offset, angle));
}
bool glyph_positions::is_constant_angle() const
{
return const_angle_;
}
double glyph_positions::get_angle() const
{
return angle_;
data_.push_back(glyph_position(glyph, offset, rot));
}
pixel_position const& glyph_positions::get_base_point() const

View file

@ -26,36 +26,18 @@ void text_renderer<T>::prepare_glyphs(glyph_positions_ptr pos)
FT_Vector pen;
FT_Error error;
bool constant_angle = pos->is_constant_angle();
double sina, cosa;
if (constant_angle)
{
double angle = pos->get_angle();
cosa = cos(angle);
sina = sin(angle);
matrix.xx = (FT_Fixed)( cosa * 0x10000L);
matrix.xy = (FT_Fixed)(-sina * 0x10000L);
matrix.yx = (FT_Fixed)( sina * 0x10000L);
matrix.yy = (FT_Fixed)( cosa * 0x10000L);
}
glyph_positions::const_iterator itr = pos->begin(), end = pos->end();
for (; itr != end; itr++)
{
glyph_info const& glyph = *(itr->glyph);
glyph.face->set_character_sizes(glyph.format->text_size * scale_factor_); //TODO: Optimize this?
if (!constant_angle)
{
double angle = itr->angle;
cosa = cos(angle);
sina = sin(angle);
matrix.xx = (FT_Fixed)( cosa * 0x10000L);
matrix.xy = (FT_Fixed)(-sina * 0x10000L);
matrix.yx = (FT_Fixed)( sina * 0x10000L);
matrix.yy = (FT_Fixed)( cosa * 0x10000L);
}
matrix.xx = (FT_Fixed)( itr->rot.cos * 0x10000L);
matrix.xy = (FT_Fixed)(-itr->rot.sin * 0x10000L);
matrix.yx = (FT_Fixed)( itr->rot.sin * 0x10000L);
matrix.yy = (FT_Fixed)( itr->rot.cos * 0x10000L);
pixel_position pos = itr->pos + glyph.offset.rotate(sina, cosa);
pixel_position pos = itr->pos + glyph.offset.rotate(itr->rot);
pen.x = int(pos.x * 64);
pen.y = int(pos.y * 64);