mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 05:47:34 +00:00
LibGfx: Improve AA stroke_path() line intersections a little
- Simplify both straight lines case - Simplify rotation by constant 90 degrees - Remove some unnecessary rounding and hacks
This commit is contained in:
parent
d140d0f880
commit
2376385f0c
1 changed files with 37 additions and 46 deletions
|
@ -269,8 +269,11 @@ void AntiAliasingPainter::stroke_path(Path const& path, Color color, float thick
|
|||
}
|
||||
|
||||
// Check if the figure was started and closed as line at the same position.
|
||||
if (thickness > 1 && previous_was_line && path.segments().size() >= 2 && path.segments().first().point() == cursor && (path.segments().first().type() == Segment::Type::LineTo || (path.segments().first().type() == Segment::Type::MoveTo && path.segments()[1].type() == Segment::Type::LineTo)))
|
||||
if (thickness > 1 && previous_was_line && path.segments().size() >= 2 && path.segments().first().point() == cursor
|
||||
&& (path.segments().first().type() == Segment::Type::LineTo
|
||||
|| (path.segments().first().type() == Segment::Type::MoveTo && path.segments()[1].type() == Segment::Type::LineTo))) {
|
||||
stroke_segment_intersection(first_line.value().a(), first_line.value().b(), last_line, color, thickness);
|
||||
}
|
||||
}
|
||||
|
||||
void AntiAliasingPainter::draw_elliptical_arc(FloatPoint p1, FloatPoint p2, FloatPoint center, FloatPoint radii, float x_axis_rotation, float theta_1, float theta_delta, Color color, float thickness, Painter::LineStyle style)
|
||||
|
@ -697,79 +700,67 @@ void AntiAliasingPainter::stroke_segment_intersection(FloatPoint current_line_a,
|
|||
|
||||
// Starting point of the current line is where the last line ended... this is an intersection.
|
||||
auto intersection = current_line_a;
|
||||
auto previous_line_b = (previous_line.a());
|
||||
|
||||
// If both are straight lines we can simply draw a rectangle at the intersection.
|
||||
if ((current_line_a.x() == current_line_b.x() || current_line_a.y() == current_line_b.y()) && (previous_line.a().x() == previous_line.b().x() || previous_line.a().y() == previous_line.b().y())) {
|
||||
intersection = m_transform.map(current_line_a);
|
||||
|
||||
// Adjust coordinates to handle rounding offsets.
|
||||
auto intersection_rect = IntSize(thickness, thickness);
|
||||
float drawing_edge_offset = fmodf(thickness, 2.0f) < 0.5f && thickness > 3 ? 1 : 0;
|
||||
auto integer_part = [](float x) { return floorf(x); };
|
||||
auto round = [&](float x) { return integer_part(x + 0.5f); };
|
||||
|
||||
if (thickness == 1)
|
||||
drawing_edge_offset = -1;
|
||||
if (current_line_a.x() == current_line_b.x() && previous_line.a().x() == previous_line.b().x()) {
|
||||
intersection_rect.set_height(1);
|
||||
}
|
||||
if (current_line_a.y() == current_line_b.y() && previous_line.a().y() == previous_line.b().y()) {
|
||||
intersection_rect.set_width(1);
|
||||
drawing_edge_offset = thickness == 1 ? -1 : 0;
|
||||
intersection.set_x(intersection.x() - 1 + (thickness == 1 ? 1 : 0));
|
||||
intersection.set_y(intersection.y() + (thickness > 3 && fmodf(thickness, 2.0f) < 0.5f ? 1 : 0));
|
||||
}
|
||||
|
||||
m_underlying_painter.fill_rect(IntRect::centered_on({ round(intersection.x()) + drawing_edge_offset, round(intersection.y()) + drawing_edge_offset }, intersection_rect), color);
|
||||
// If both are straight lines we can simply draw a rectangle at the intersection (or nothing).
|
||||
auto current_vertical = current_line_a.x() == current_line_b.x();
|
||||
auto current_horizontal = current_line_a.y() == current_line_b.y();
|
||||
auto previous_vertical = previous_line.a().x() == previous_line.b().x();
|
||||
auto previous_horizontal = previous_line.a().y() == previous_line.b().y();
|
||||
if (previous_horizontal && current_horizontal)
|
||||
return;
|
||||
if (previous_vertical && current_vertical)
|
||||
return;
|
||||
if ((previous_horizontal || previous_vertical) && (current_horizontal || current_vertical)) {
|
||||
intersection = m_transform.map(current_line_a);
|
||||
// Note: int_thickness used here to match behaviour of draw_line()
|
||||
int int_thickness = AK::ceil(thickness);
|
||||
return fill_rect(FloatRect(intersection, { thickness, thickness }).translated(-int_thickness / 2), color);
|
||||
}
|
||||
|
||||
auto previous_line_a = previous_line.a();
|
||||
float scale_to_move_current = (thickness / 2) / intersection.distance_from(current_line_b);
|
||||
float scale_to_move_previous = (thickness / 2) / intersection.distance_from(previous_line_b);
|
||||
float scale_to_move_previous = (thickness / 2) / intersection.distance_from(previous_line_a);
|
||||
|
||||
// Move the point on the line by half of the thickness.
|
||||
double offset_current_edge_x = scale_to_move_current * (current_line_b.x() - intersection.x());
|
||||
double offset_current_edge_y = scale_to_move_current * (current_line_b.y() - intersection.y());
|
||||
double offset_prev_edge_x = scale_to_move_previous * (previous_line_b.x() - intersection.x());
|
||||
double offset_prev_edge_y = scale_to_move_previous * (previous_line_b.y() - intersection.y());
|
||||
float offset_current_edge_x = scale_to_move_current * (current_line_b.x() - intersection.x());
|
||||
float offset_current_edge_y = scale_to_move_current * (current_line_b.y() - intersection.y());
|
||||
float offset_prev_edge_x = scale_to_move_previous * (previous_line_a.x() - intersection.x());
|
||||
float offset_prev_edge_y = scale_to_move_previous * (previous_line_a.y() - intersection.y());
|
||||
|
||||
// Rotate the point by 90 and 270 degrees to get the points for both edges.
|
||||
double rad_90deg = 0.5 * M_PI;
|
||||
FloatPoint current_rotated_90deg = { (offset_current_edge_x * cos(rad_90deg) - offset_current_edge_y * sin(rad_90deg)), (offset_current_edge_x * sin(rad_90deg) + offset_current_edge_y * cos(rad_90deg)) };
|
||||
FloatPoint current_rotated_270deg = intersection - current_rotated_90deg;
|
||||
FloatPoint previous_rotated_90deg = { (offset_prev_edge_x * cos(rad_90deg) - offset_prev_edge_y * sin(rad_90deg)), (offset_prev_edge_x * sin(rad_90deg) + offset_prev_edge_y * cos(rad_90deg)) };
|
||||
FloatPoint previous_rotated_270deg = intersection - previous_rotated_90deg;
|
||||
FloatPoint current_rotated_90deg(-offset_current_edge_y, offset_current_edge_x);
|
||||
FloatPoint previous_rotated_90deg(-offset_prev_edge_y, offset_prev_edge_x);
|
||||
auto current_rotated_270deg = intersection - current_rotated_90deg;
|
||||
auto previous_rotated_270deg = intersection - previous_rotated_90deg;
|
||||
|
||||
// Translate coordinates to the intersection point.
|
||||
current_rotated_90deg += intersection;
|
||||
previous_rotated_90deg += intersection;
|
||||
|
||||
FloatLine outer_line_current_90 = FloatLine({ current_rotated_90deg, current_line_b - static_cast<FloatPoint>(intersection - current_rotated_90deg) });
|
||||
FloatLine outer_line_current_270 = FloatLine({ current_rotated_270deg, current_line_b - static_cast<FloatPoint>(intersection - current_rotated_270deg) });
|
||||
FloatLine outer_line_prev_270 = FloatLine({ previous_rotated_270deg, previous_line_b - static_cast<FloatPoint>(intersection - previous_rotated_270deg) });
|
||||
FloatLine outer_line_prev_90 = FloatLine({ previous_rotated_90deg, previous_line_b - static_cast<FloatPoint>(intersection - previous_rotated_90deg) });
|
||||
FloatLine outer_line_current_90(current_rotated_90deg, current_line_b - (intersection - current_rotated_90deg));
|
||||
FloatLine outer_line_current_270(current_rotated_270deg, current_line_b - (intersection - current_rotated_270deg));
|
||||
FloatLine outer_line_prev_270(previous_rotated_270deg, previous_line_a - (intersection - previous_rotated_270deg));
|
||||
FloatLine outer_line_prev_90(previous_rotated_90deg, previous_line_a - (intersection - previous_rotated_90deg));
|
||||
|
||||
Optional<FloatPoint> edge_spike_90 = outer_line_current_90.intersected(outer_line_prev_270);
|
||||
auto edge_spike_90 = outer_line_current_90.intersected(outer_line_prev_270);
|
||||
Optional<FloatPoint> edge_spike_270;
|
||||
|
||||
if (edge_spike_90.has_value()) {
|
||||
edge_spike_270 = intersection + (intersection - edge_spike_90.value());
|
||||
edge_spike_270 = intersection + (intersection - *edge_spike_90);
|
||||
} else {
|
||||
edge_spike_270 = outer_line_current_270.intersected(outer_line_prev_90);
|
||||
if (edge_spike_270.has_value()) {
|
||||
edge_spike_90 = intersection + (intersection - edge_spike_270.value());
|
||||
}
|
||||
if (edge_spike_270.has_value())
|
||||
edge_spike_90 = intersection + (intersection - *edge_spike_270);
|
||||
}
|
||||
|
||||
Path intersection_edge_path;
|
||||
intersection_edge_path.move_to(current_rotated_90deg);
|
||||
if (edge_spike_90.has_value())
|
||||
intersection_edge_path.line_to(edge_spike_90.value());
|
||||
intersection_edge_path.line_to(*edge_spike_90);
|
||||
intersection_edge_path.line_to(previous_rotated_270deg);
|
||||
intersection_edge_path.line_to(current_rotated_270deg);
|
||||
if (edge_spike_270.has_value())
|
||||
intersection_edge_path.line_to(edge_spike_270.value());
|
||||
intersection_edge_path.line_to(*edge_spike_270);
|
||||
intersection_edge_path.line_to(previous_rotated_90deg);
|
||||
intersection_edge_path.close();
|
||||
fill_path(intersection_edge_path, color);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue