diff --git a/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp b/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp index c70a8b388e..ef37f29b3c 100644 --- a/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp +++ b/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp @@ -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(intersection - current_rotated_90deg) }); - FloatLine outer_line_current_270 = FloatLine({ current_rotated_270deg, current_line_b - static_cast(intersection - current_rotated_270deg) }); - FloatLine outer_line_prev_270 = FloatLine({ previous_rotated_270deg, previous_line_b - static_cast(intersection - previous_rotated_270deg) }); - FloatLine outer_line_prev_90 = FloatLine({ previous_rotated_90deg, previous_line_b - static_cast(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 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 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);