5#include <fifechan/widgets/curvegraph.hpp>
7#include <fifechan/exception.hpp>
8#include <fifechan/graphics.hpp>
9#include <fifechan/math.hpp>
78 ((
getSelectionMode() & Widget::SelectionMode::Background) == Widget::SelectionMode::Background)) {
91 if (active && (
getSelectionMode() & Widget::SelectionMode::Border) == Widget::SelectionMode::Border) {
112 for (
size_t i = 0; i <
m_curveData.size() - 1; ++i) {
127 PointVector newPoints;
133 int const elements = newPoints.size();
135 auto it = newPoints.begin();
138 for (; it != newPoints.end(); ++it) {
139 Point const & next = *it;
140 auto const rx =
static_cast<float>(old.x - next.x);
141 auto const ry =
static_cast<float>(old.y - next.y);
146 int lines =
static_cast<int>(std::ceil((distance / elements) /
m_thickness));
148 lines = std::max(lines, 2);
150 float const step = 1.0F /
static_cast<float>(lines - 1);
153 for (
int i = 0; i <= (elements * lines); ++i) {
166 if (t >=
static_cast<double>(elements)) {
167 return points.back();
173 int const n = elements - 1;
175 double const mu =
static_cast<double>(t) /
static_cast<double>(elements);
176 double munk =
Mathd::Pow(1.0 - mu,
static_cast<double>(n));
178 for (
int i = 0; i <= n; ++i) {
182 double blend = muk * munk;
186 blend *=
static_cast<double>(tmpn);
189 blend /=
static_cast<double>(tmpi);
193 blend /=
static_cast<double>(diffn);
197 px +=
static_cast<double>(points[i].x) * blend;
198 py +=
static_cast<double>(points[i].y) * blend;
201 return Point(
static_cast<int>(px),
static_cast<int>(py));
206 if (points.empty()) {
210 int const n = points.size() - 1;
220 newPoints.push_back(points[0]);
221 p.x = (2 * points[0].x + points[1].x) / 3;
222 p.y = (2 * points[0].y + points[1].y) / 3;
223 newPoints.push_back(p);
224 p.x = 2 * p.x - points[0].x;
225 p.y = 2 * p.y - points[0].y;
226 newPoints.push_back(p);
227 newPoints.push_back(points[1]);
232 std::vector<float> xrhs(
static_cast<size_t>(n));
233 std::vector<float> yrhs(
static_cast<size_t>(n));
235 xrhs[0] =
static_cast<float>(points[0].x + (2 * points[1].x));
236 yrhs[0] =
static_cast<float>(points[0].y + (2 * points[1].y));
238 xrhs[n - 1] =
static_cast<float>((8 * points[n - 1].x + points[n].x) / 2.0F);
239 yrhs[n - 1] =
static_cast<float>((8 * points[n - 1].y + points[n].y) / 2.0F);
241 for (
int i = 1; i < n - 1; ++i) {
242 xrhs[i] =
static_cast<float>((4 * points[i].x) + (2 * points[i + 1].x));
243 yrhs[i] =
static_cast<float>((4 * points[i].y) + (2 * points[i + 1].y));
246 std::vector<float> x(
static_cast<size_t>(n));
247 std::vector<float> y(
static_cast<size_t>(n));
248 std::vector<float> xtmp(
static_cast<size_t>(n));
249 std::vector<float> ytmp(
static_cast<size_t>(n));
255 for (
int i = 1; i < n; i++) {
258 xb = (i < n - 1 ? 4.0F : 3.5F) - xtmp[i];
259 yb = (i < n - 1 ? 4.0F : 3.5F) - ytmp[i];
260 x[i] = (xrhs[i] - x[i - 1]) / xb;
261 y[i] = (yrhs[i] - y[i - 1]) / yb;
264 for (
int i = 1; i < n; i++) {
265 x[n - i - 1] -= xtmp[n - i] * x[n - i];
266 y[n - i - 1] -= ytmp[n - i] * y[n - i];
270 newPoints.push_back(points[0]);
271 for (
int i = 0; i < n - 1; ++i) {
272 p.x =
static_cast<int>(x[i]);
273 p.y =
static_cast<int>(y[i]);
274 newPoints.push_back(p);
275 p.x =
static_cast<int>((2 * points[i + 1].x) - x[i + 1]);
276 p.y =
static_cast<int>((2 * points[i + 1].y) - y[i + 1]);
277 newPoints.push_back(p);
279 newPoints.push_back(points[i + 1]);
281 p.x =
static_cast<int>(x[n - 1]);
282 p.y =
static_cast<int>(y[n - 1]);
283 newPoints.push_back(p);
284 p.x =
static_cast<int>((points[n].x + x[n - 1]) / 2);
285 p.y =
static_cast<int>((points[n].y + y[n - 1]) / 2);
286 newPoints.push_back(p);
288 newPoints.push_back(points[n]);
unsigned int m_thickness
Stroke thickness in pixels.
unsigned int getThickness() const
Get stroke thickness in pixels.
PointVector m_data
Raw input point data.
bool m_opaque
True if the curve is drawn opaque.
bool m_acp
Whether automatic control points are enabled.
PointVector const & getPointVector() const
Get the current point vector.
void setOpaque(bool opaque)
Sets the opacity of the graph.
void setThickness(unsigned int thickness)
Set stroke thickness in pixels.
Point getBezierPoint(PointVector const &points, int elements, float t)
Helper that returns an interpolated Point.
void setAutomaticControlPoints(bool acp)
Enable/disable automatic computation of bezier control points.
bool m_needUpdate
Internal flag marking that the precalculated curve data needs update.
bool isAutomaticControlPoints() const
Return whether automatic control points are enabled.
void addControlPoints(PointVector const &points, PointVector &newPoints)
Helper that adds the control points for bezier curves.
CurveGraph()
Default constructor.
void draw(Graphics *graphics) override
Draws this widget.
void setPointVector(PointVector const &data)
Set the raw point vector used to draw the curve.
void update()
Precalculate bezier curve.
void resetPointVector()
Reset the stored data to an empty vector.
PointVector m_curveData
Precalculated curve points (bezier/interpolated).
Abstract interface providing primitive drawing functions (lines, rectangles, etc.).
virtual void drawPolyLine(PointVector const &points, unsigned int width)=0
Draws lines between points with given width.
virtual void setColor(Color const &color)=0
Sets the color to use when drawing.
virtual void fillRectangle(Rectangle const &rectangle)=0
Draws a filled rectangle.
virtual void drawRoundStroke(int x1, int y1, int x2, int y2, unsigned int width)
Draws a round brush stroke along the line segment.
static float Sqrt(float _val)
static double Pow(double _base, double _exponent)
Represents a 2D coordinate (X, Y).