Store the value of sin(angle) and cos(angle) instead of recomputing them every time.
This commit is contained in:
parent
503c1862ba
commit
2e22d740cf
8 changed files with 66 additions and 86 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
23
include/mapnik/text/rotation.hpp
Normal file
23
include/mapnik/text/rotation.hpp
Normal 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
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue