Implement auto-upright.
This commit is contained in:
parent
5115658ecc
commit
6a27a2ae76
5 changed files with 87 additions and 32 deletions
|
@ -71,7 +71,8 @@ private:
|
|||
void init_alignment();
|
||||
pixel_position alignment_offset() const;
|
||||
|
||||
bool single_line_placement(vertex_cache &pp, signed orientation);
|
||||
bool single_line_placement(vertex_cache &pp, text_upright_e orientation);
|
||||
static double normalize_angle(double angle);
|
||||
Feature const& feature_;
|
||||
DetectorType &detector_;
|
||||
box2d<double> const& extent_;
|
||||
|
|
|
@ -71,10 +71,9 @@ public:
|
|||
|
||||
pixel_position const& current_position() const { return current_position_; }
|
||||
|
||||
double angle(double width);
|
||||
double angle(double width=0.);
|
||||
|
||||
bool next_subpath();
|
||||
bool next_segment();
|
||||
|
||||
/** Moves all positions to a parallel line in the specified distance. */
|
||||
void set_offset(double offset);
|
||||
|
@ -86,12 +85,16 @@ public:
|
|||
* on a point on the path.
|
||||
*/
|
||||
bool forward(double length);
|
||||
bool backward(double length);
|
||||
bool move(double length); //Move works in both directions
|
||||
|
||||
state save_state() const;
|
||||
void restore_state(state s);
|
||||
|
||||
|
||||
private:
|
||||
bool next_segment();
|
||||
bool previous_segment();
|
||||
pixel_position current_position_;
|
||||
pixel_position segment_starting_point_;
|
||||
std::vector<segment_vector> subpaths_;
|
||||
|
@ -159,21 +162,24 @@ vertex_cache::vertex_cache(T &path)
|
|||
|
||||
double vertex_cache::angle(double width)
|
||||
{
|
||||
if (width + position_in_segment_ < current_segment_->length)
|
||||
/* IMPORTANT NOTE: See note about coordinate systems in placement_finder::find_point_placement()
|
||||
* for imformation about why the y axis is inverted! */
|
||||
double tmp = width + position_in_segment_;
|
||||
if ((tmp <= current_segment_->length) && (tmp >= 0))
|
||||
{
|
||||
//Only calculate angle on request as it is expensive
|
||||
if (!angle_valid_)
|
||||
{
|
||||
angle_ = atan2(current_segment_->pos.y - segment_starting_point_.y,
|
||||
angle_ = atan2(-(current_segment_->pos.y - segment_starting_point_.y),
|
||||
current_segment_->pos.x - segment_starting_point_.x);
|
||||
}
|
||||
return angle_;
|
||||
return width >= 0 ? angle_ : angle_ + M_PI;
|
||||
} else
|
||||
{
|
||||
state s = save_state();
|
||||
pixel_position const& old_pos = s.position();
|
||||
forward(width);
|
||||
double angle = atan2(current_position_.y - old_pos.y,
|
||||
move(width);
|
||||
double angle = atan2(-(current_position_.y - old_pos.y),
|
||||
current_position_.x - old_pos.x);
|
||||
restore_state(s);
|
||||
return angle;
|
||||
|
@ -205,8 +211,23 @@ bool vertex_cache::next_segment()
|
|||
segment_starting_point_ = current_segment_->pos; //Next segments starts at the end of the current one
|
||||
if (current_segment_ == current_subpath_->vector.end()) return false;
|
||||
current_segment_++;
|
||||
if (current_segment_ == current_subpath_->vector.end()) return false;
|
||||
angle_valid_ = false;
|
||||
if (current_segment_ == current_subpath_->vector.end()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vertex_cache::previous_segment()
|
||||
{
|
||||
if (current_segment_ == current_subpath_->vector.begin()) return false;
|
||||
current_segment_--;
|
||||
angle_valid_ = false;
|
||||
if (current_segment_ == current_subpath_->vector.begin())
|
||||
{
|
||||
//First segment is special
|
||||
segment_starting_point_ = current_segment_->pos;
|
||||
return true;
|
||||
}
|
||||
segment_starting_point_ = (current_segment_-1)->pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -220,19 +241,41 @@ bool vertex_cache::forward(double length)
|
|||
if (length < 0)
|
||||
{
|
||||
MAPNIK_LOG_ERROR(vertex_cache) << "vertex_cache::forward() called with negative argument!\n";
|
||||
return false;
|
||||
}
|
||||
return move(length);
|
||||
}
|
||||
|
||||
bool vertex_cache::backward(double length)
|
||||
{
|
||||
if (length < 0)
|
||||
{
|
||||
MAPNIK_LOG_ERROR(vertex_cache) << "vertex_cache::backward() called with negative argument!\n";
|
||||
return false;
|
||||
}
|
||||
return move(-length);
|
||||
}
|
||||
|
||||
bool vertex_cache::move(double length)
|
||||
{
|
||||
length += position_in_segment_;
|
||||
while (length >= current_segment_->length)
|
||||
{
|
||||
length -= current_segment_->length;
|
||||
if (!next_segment()) return false; //Skip all complete segments
|
||||
}
|
||||
while (length < 0)
|
||||
{
|
||||
if (!previous_segment()) return false;
|
||||
length += current_segment_->length;
|
||||
}
|
||||
double factor = length / current_segment_->length;
|
||||
position_in_segment_ = length;
|
||||
current_position_ = segment_starting_point_ + (current_segment_->pos - segment_starting_point_) * factor;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
vertex_cache::state vertex_cache::save_state() const
|
||||
{
|
||||
state s;
|
||||
|
|
|
@ -301,7 +301,7 @@ bool placement_finder_ng::find_line_placements(T & path)
|
|||
do
|
||||
{
|
||||
vertex_cache::state s = pp.save_state();
|
||||
success = single_line_placement(pp, 0) || success;
|
||||
success = single_line_placement(pp, info_->properties.upright) || success;
|
||||
pp.restore_state(s);
|
||||
} while (pp.forward(spacing));
|
||||
}
|
||||
|
@ -309,52 +309,54 @@ bool placement_finder_ng::find_line_placements(T & path)
|
|||
}
|
||||
|
||||
|
||||
bool placement_finder_ng::single_line_placement(vertex_cache &pp, signed orientation)
|
||||
bool placement_finder_ng::single_line_placement(vertex_cache &pp, text_upright_e orientation)
|
||||
{
|
||||
std::cout << "single_line" << pp.current_position().x << ", " << pp.current_position().y << "\n";
|
||||
/* IMPORTANT NOTE: See note about coordinate systems in find_point_placement()! */
|
||||
text_upright_e real_orientation = orientation;
|
||||
if (orientation == UPRIGHT_AUTO)
|
||||
{
|
||||
double angle = normalize_angle(pp.angle());
|
||||
real_orientation = (angle > 0.5*M_PI && angle < 1.5*M_PI) ? UPRIGHT_LEFT : UPRIGHT_RIGHT;
|
||||
}
|
||||
double sign = 1;
|
||||
if (real_orientation == UPRIGHT_LEFT)
|
||||
{
|
||||
sign = -1;
|
||||
pp.forward(layout_.width());
|
||||
}
|
||||
|
||||
double base_offset = alignment_offset().y + info_->properties.displacement.y;
|
||||
glyph_positions_ptr glyphs = boost::make_shared<glyph_positions>();
|
||||
|
||||
/* IMPORTANT NOTE:
|
||||
x and y are relative to the center of the text
|
||||
coordinate system:
|
||||
x: grows from left to right
|
||||
y: grows from bottom to top (all values are negative!)
|
||||
*/
|
||||
|
||||
double offset = base_offset + layout_.height();
|
||||
unsigned upside_down_glyph_count = 0;
|
||||
|
||||
text_layout::const_iterator line_itr = layout_.begin(), line_end = layout_.end();
|
||||
for (; line_itr != line_end; line_itr++)
|
||||
{
|
||||
double char_height = (*line_itr)->max_char_height();
|
||||
offset -= (*line_itr)->height();
|
||||
// reset to begining of line position
|
||||
pp.set_offset(offset);
|
||||
|
||||
text_line::const_iterator glyph_itr = (*line_itr)->begin(), glyph_end = (*line_itr)->end();
|
||||
for (; glyph_itr != glyph_end; glyph_itr++)
|
||||
{
|
||||
double angle = pp.angle(glyph_itr->width);
|
||||
double angle = normalize_angle(pp.angle(sign * glyph_itr->width));
|
||||
double sina = sin(angle);
|
||||
double cosa = cos(angle);
|
||||
pixel_position pos = pp.current_position();
|
||||
//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.x = pos.x + char_height/2.0*sina;
|
||||
|
||||
// if (orientation < 0)
|
||||
// {
|
||||
// // rotate in place
|
||||
// render_x += cwidth*cosa - char_height*sina;
|
||||
// render_y -= cwidth*sina + char_height*cosa;
|
||||
// render_angle += M_PI;
|
||||
// }
|
||||
if (angle > M_PI/2. && angle < 1.5*M_PI)
|
||||
upside_down_glyph_count++;
|
||||
|
||||
glyphs->push_back(*glyph_itr, pos, -angle); //TODO: Store cosa, sina instead
|
||||
glyphs->push_back(*glyph_itr, pos, angle); //TODO: Store cosa, sina instead
|
||||
if (glyph_itr->width)
|
||||
{
|
||||
//Only advance if glyph is not part of a multiple glyph sequence
|
||||
pp.forward(glyph_itr->width + glyph_itr->format->character_spacing);
|
||||
pp.move(sign * (glyph_itr->width + glyph_itr->format->character_spacing));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -362,6 +364,15 @@ bool placement_finder_ng::single_line_placement(vertex_cache &pp, signed orienta
|
|||
return true;
|
||||
}
|
||||
|
||||
double placement_finder_ng::normalize_angle(double angle)
|
||||
{
|
||||
while (angle >= 2*M_PI)
|
||||
angle -= 2*M_PI;
|
||||
while (angle < 0)
|
||||
angle += 2*M_PI;
|
||||
return angle;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
|
|
|
@ -86,7 +86,6 @@ static const char * text_upright_strings[] = {
|
|||
"auto",
|
||||
"left",
|
||||
"right",
|
||||
"capitalize",
|
||||
""
|
||||
};
|
||||
IMPLEMENT_ENUM(text_upright_e, text_upright_strings)
|
||||
|
|
|
@ -480,6 +480,7 @@ compile_get_opt_attr(label_placement_e);
|
|||
compile_get_opt_attr(vertical_alignment_e);
|
||||
compile_get_opt_attr(horizontal_alignment_e);
|
||||
compile_get_opt_attr(justify_alignment_e);
|
||||
compile_get_opt_attr(text_upright_e);
|
||||
compile_get_opt_attr(expression_ptr);
|
||||
compile_get_attr(std::string);
|
||||
compile_get_attr(filter_mode_e);
|
||||
|
|
Loading…
Reference in a new issue