fix text rendering with line placement on corners

This commit is contained in:
Jiri Drbalek 2014-08-21 13:10:25 +00:00
parent 1af6f5db10
commit b7e7e29781
4 changed files with 119 additions and 4 deletions

View File

@ -76,11 +76,11 @@ bool placement_finder::find_line_placements(T & path, bool points)
// halign == H_LEFT -> don't move
if (horizontal_alignment_ == H_MIDDLE || horizontal_alignment_ == H_AUTO)
{
pp.forward(spacing/2.0);
if (!pp.forward(spacing / 2.0)) continue;
}
else if (horizontal_alignment_ == H_RIGHT)
{
pp.forward(pp.length());
if (!pp.forward(pp.length())) continue;
}
if (move_dx_ != 0.0) path_move_dx(pp, move_dx_);

View File

@ -110,7 +110,7 @@ public:
// Skip a certain amount of space.
// This function automatically calculates new points if the position is not exactly
// This functions automatically calculate new points if the position is not exactly
// on a point on the path.
bool forward(double length);
@ -118,6 +118,8 @@ public:
bool backward(double length);
// Move in any direction (based on sign of length). Returns false if it reaches either end of the path.
bool move(double length);
// Move to given distance.
bool move_to_distance(double distance);
// Work on next subpath. Returns false if the is no next subpath.
bool next_subpath();
@ -139,6 +141,10 @@ private:
bool next_segment();
bool previous_segment();
double current_segment_angle();
void find_line_circle_intersection(
double cx, double cy, double radius,
double x1, double y1, double x2, double y2,
double & ix, double & iy) const;
// Position as calculated by last move/forward/next call.
pixel_position current_position_;
// First pixel of current segment.

View File

@ -214,7 +214,7 @@ bool placement_finder::single_line_placement(vertex_cache &pp, text_upright_e or
{
if (current_cluster != static_cast<int>(glyph.char_index))
{
if (!off_pp.move(sign * (layout.cluster_width(current_cluster) + last_glyph_spacing)))
if (!off_pp.move_to_distance(sign * (layout.cluster_width(current_cluster) + last_glyph_spacing)))
{
return false;
}

View File

@ -236,6 +236,8 @@ bool vertex_cache::backward(double length)
bool vertex_cache::move(double length)
{
if (current_segment_ == current_subpath_->vector.end()) return false;
position_ += length;
length += position_in_segment_;
while (length >= current_segment_->length)
@ -254,6 +256,67 @@ bool vertex_cache::move(double length)
return true;
}
bool vertex_cache::move_to_distance(double distance)
{
if (current_segment_ == current_subpath_->vector.end()) return false;
double position_in_segment = position_in_segment_ + distance;
if (position_in_segment < .0 || position_in_segment >= current_segment_->length)
{
// If there isn't enough distance left on this segment
// then we need to search until we find the line segment that ends further than distance away
double abs_distance = std::abs(distance);
double new_abs_distance = .0;
pixel_position inner_pos; // Inside circle.
pixel_position outer_pos; // Outside circle.
position_ -= position_in_segment_;
if (distance > .0)
{
do
{
position_ += current_segment_->length;
if (!next_segment()) return false;
new_abs_distance = (current_position_ - current_segment_->pos).length();
}
while (new_abs_distance < abs_distance);
inner_pos = segment_starting_point_;
outer_pos = current_segment_->pos;
}
else
{
do
{
if (!previous_segment()) return false;
position_ -= current_segment_->length;
new_abs_distance = (current_position_ - segment_starting_point_).length();
}
while (new_abs_distance < abs_distance);
inner_pos = current_segment_->pos;
outer_pos = segment_starting_point_;
}
find_line_circle_intersection(current_position_.x, current_position_.y, abs_distance,
inner_pos.x, inner_pos.y, outer_pos.x, outer_pos.y,
current_position_.x, current_position_.y);
position_in_segment_ = (current_position_ - segment_starting_point_).length();
position_ += position_in_segment_;
}
else
{
position_ += distance;
distance += position_in_segment_;
double factor = distance / current_segment_->length;
position_in_segment_ = distance;
current_position_ = segment_starting_point_ + (current_segment_->pos - segment_starting_point_) * factor;
}
return true;
}
void vertex_cache::rewind(unsigned)
{
vertex_subpath_ = subpaths_.begin();
@ -297,4 +360,50 @@ void vertex_cache::restore_state(state const& s)
angle_valid_ = false;
}
void vertex_cache::find_line_circle_intersection(
double cx, double cy, double radius,
double x1, double y1, double x2, double y2,
double & ix, double & iy) const
{
double dx = x2 - x1;
double dy = y2 - y1;
double A = dx * dx + dy * dy;
double B = 2 * (dx * (x1 - cx) + dy * (y1 - cy));
double C = (x1 - cx) * (x1 - cx) + (y1 - cy) * (y1 - cy) - radius * radius;
double det = B * B - 4 * A * C;
if (A <= 1.0e-7 || det < 0)
{
// Should never happen.
// No real solutions.
return;
}
else if (det == 0)
{
// Could potentially happen....
// One solution.
double t = -B / (2 * A);
ix = x1 + t * dx;
iy = y1 + t * dy;
return;
}
else
{
// Two solutions.
// Always use the 1st one
// We only really have one solution here, as we know the line segment will start in the circle and end outside
double t = (-B + std::sqrt(det)) / (2 * A);
ix = x1 + t * dx;
iy = y1 + t * dy;
//t = (-B - std::sqrt(det)) / (2 * A);
//ix = x1 + t * dx;
//iy = y1 + t * dy;
return;
}
}
} //ns mapnik