mirror of
https://github.com/mapnik/mapnik.git
synced 2025-12-08 20:13:09 +00:00
fix text rendering with line placement on corners
This commit is contained in:
parent
1af6f5db10
commit
b7e7e29781
@ -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_);
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user