mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-24 02:12:09 -05:00
LibGfx: Add Painter::draw_quadratic_bezier_curve()
Also adds a QuadraticBezierCurveTo mode to Gfx::Path
This commit is contained in:
parent
73a7a589c2
commit
9f3f98d4c0
5 changed files with 75 additions and 2 deletions
|
@ -1049,6 +1049,47 @@ void Painter::draw_line(const Point& p1, const Point& p2, Color color, int thick
|
|||
}
|
||||
}
|
||||
|
||||
static void draw_split_quadratic_bezier_curve(Painter& painter, const Point& original_control, const Point& p1, const Point& p2, Color color, int thickness, bool dotted)
|
||||
{
|
||||
auto po1_midpoint = original_control + p1;
|
||||
po1_midpoint /= 2;
|
||||
|
||||
auto po2_midpoint = original_control + p2;
|
||||
po2_midpoint /= 2;
|
||||
|
||||
auto new_segment = po1_midpoint + po2_midpoint;
|
||||
new_segment /= 2;
|
||||
|
||||
painter.draw_quadratic_bezier_curve(po1_midpoint, p1, new_segment, color, thickness, dotted);
|
||||
painter.draw_quadratic_bezier_curve(po2_midpoint, new_segment, p2, color, thickness, dotted);
|
||||
}
|
||||
|
||||
static bool can_approximate_bezier_curve(const Point& p1, const Point& p2, const Point& control)
|
||||
{
|
||||
constexpr static int tolerance = 15;
|
||||
|
||||
auto p1x = 3 * control.x() - 2 * p1.x() - p2.x();
|
||||
auto p1y = 3 * control.y() - 2 * p1.y() - p2.y();
|
||||
auto p2x = 3 * control.x() - 2 * p2.x() - p1.x();
|
||||
auto p2y = 3 * control.y() - 2 * p2.y() - p1.y();
|
||||
|
||||
p1x = p1x * p1x;
|
||||
p1y = p1y * p1y;
|
||||
p2x = p2x * p2x;
|
||||
p2y = p2y * p2y;
|
||||
|
||||
return max(p1x, p2x) + max(p1y, p2y) <= tolerance;
|
||||
}
|
||||
|
||||
void Painter::draw_quadratic_bezier_curve(const Point& control_point, const Point& p1, const Point& p2, Color color, int thickness, bool dotted)
|
||||
{
|
||||
if (can_approximate_bezier_curve(p1, p2, control_point)) {
|
||||
draw_line(p1, p2, color, thickness, dotted);
|
||||
} else {
|
||||
draw_split_quadratic_bezier_curve(*this, control_point, p1, p2, color, thickness, dotted);
|
||||
}
|
||||
}
|
||||
|
||||
void Painter::add_clip_rect(const Rect& rect)
|
||||
{
|
||||
state().clip_rect.intersect(rect.translated(m_clip_origin.location()));
|
||||
|
@ -1087,6 +1128,11 @@ void Painter::stroke_path(const Path& path, Color color, int thickness)
|
|||
draw_line(Point(cursor.x(), cursor.y()), Point(segment.point.x(), segment.point.y()), color, thickness);
|
||||
cursor = segment.point;
|
||||
break;
|
||||
case Path::Segment::Type::QuadraticBezierCurveTo:
|
||||
ASSERT(segment.through.has_value());
|
||||
draw_quadratic_bezier_curve(Point(segment.through.value().x(), segment.through.value().y()), Point(cursor.x(), cursor.y()), Point(segment.point.x(), segment.point.y()), color, thickness);
|
||||
cursor = segment.point;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ public:
|
|||
void draw_ellipse_intersecting(const Rect&, Color, int thickness = 1);
|
||||
void set_pixel(const Point&, Color);
|
||||
void draw_line(const Point&, const Point&, Color, int thickness = 1, bool dotted = false);
|
||||
void draw_quadratic_bezier_curve(const Point& control_point, const Point&, const Point&, Color, int thickness = 1, bool dotted = false);
|
||||
void draw_scaled_bitmap(const Rect& dst_rect, const Gfx::Bitmap&, const Rect& src_rect);
|
||||
void blit(const Point&, const Gfx::Bitmap&, const Rect& src_rect, float opacity = 1.0f);
|
||||
void blit_dimmed(const Point&, const Gfx::Bitmap&, const Rect& src_rect);
|
||||
|
|
|
@ -59,6 +59,9 @@ String Path::to_string() const
|
|||
case Segment::Type::LineTo:
|
||||
builder.append("LineTo");
|
||||
break;
|
||||
case Segment::Type::QuadraticBezierCurveTo:
|
||||
builder.append("QuadraticBezierCurveTo");
|
||||
break;
|
||||
case Segment::Type::Invalid:
|
||||
builder.append("Invalid");
|
||||
break;
|
||||
|
|
|
@ -39,13 +39,15 @@ public:
|
|||
Invalid,
|
||||
MoveTo,
|
||||
LineTo,
|
||||
QuadraticBezierCurveTo,
|
||||
};
|
||||
|
||||
Type type { Type::Invalid };
|
||||
FloatPoint point;
|
||||
Optional<FloatPoint> through {};
|
||||
};
|
||||
|
||||
Path() {}
|
||||
Path() { }
|
||||
|
||||
void move_to(const FloatPoint& point)
|
||||
{
|
||||
|
@ -57,6 +59,11 @@ public:
|
|||
m_segments.append({ Segment::Type::LineTo, point });
|
||||
}
|
||||
|
||||
void quadratic_bezier_curve_to(const FloatPoint& through, const FloatPoint& point)
|
||||
{
|
||||
m_segments.append({ Segment::Type::QuadraticBezierCurveTo, point, through });
|
||||
}
|
||||
|
||||
void close();
|
||||
|
||||
const Vector<Segment>& segments() const { return m_segments; }
|
||||
|
|
|
@ -38,7 +38,7 @@ class Rect;
|
|||
|
||||
class Point {
|
||||
public:
|
||||
Point() {}
|
||||
Point() { }
|
||||
Point(int x, int y)
|
||||
: m_x(x)
|
||||
, m_y(y)
|
||||
|
@ -107,6 +107,22 @@ public:
|
|||
}
|
||||
Point operator+(const Point& other) const { return { m_x + other.m_x, m_y + other.m_y }; }
|
||||
|
||||
Point& operator*=(int factor)
|
||||
{
|
||||
m_x *= factor;
|
||||
m_y *= factor;
|
||||
return *this;
|
||||
}
|
||||
Point operator*(int factor) const { return { m_x * factor, m_y * factor }; }
|
||||
|
||||
Point& operator/=(int factor)
|
||||
{
|
||||
m_x /= factor;
|
||||
m_y /= factor;
|
||||
return *this;
|
||||
}
|
||||
Point operator/(int factor) const { return { m_x / factor, m_y / factor }; }
|
||||
|
||||
String to_string() const;
|
||||
|
||||
bool is_null() const { return !m_x && !m_y; }
|
||||
|
|
Loading…
Add table
Reference in a new issue