6#include <fifechan/widgets/curvegraph.hpp>
15#include "fifechan/exception.hpp"
16#include "fifechan/graphics.hpp"
17#include "fifechan/math.hpp"
79 assert(
"graphics must not be null" && graphics !=
nullptr);
85 ((
getSelectionMode() & Widget::SelectionMode::Background) == Widget::SelectionMode::Background)) {
98 if (active && (
getSelectionMode() & Widget::SelectionMode::Border) == Widget::SelectionMode::Border) {
119 for (
size_t i = 0; i <
m_curveData.size() - 1; ++i) {
140 int const elements = newPoints.size();
142 auto it = newPoints.begin();
145 for (; it != newPoints.end(); ++it) {
146 Point const & next = *it;
147 auto const rx =
static_cast<float>(old.x - next.x);
148 auto const ry =
static_cast<float>(old.y - next.y);
153 int lines =
static_cast<int>(std::ceil((distance / elements) /
m_thickness));
155 lines = std::max(lines, 2);
157 float const step = 1.0F /
static_cast<float>(lines - 1);
160 for (
int i = 0; i <= (elements * lines); ++i) {
173 if (t >=
static_cast<double>(elements)) {
174 return points.back();
180 int const n = elements - 1;
182 double const mu =
static_cast<double>(t) /
static_cast<double>(elements);
183 double munk =
Mathd::Pow(1.0 - mu,
static_cast<double>(n));
185 for (
int i = 0; i <= n; ++i) {
189 double blend = muk * munk;
193 blend *=
static_cast<double>(tmpn);
196 blend /=
static_cast<double>(tmpi);
200 blend /=
static_cast<double>(diffn);
204 px +=
static_cast<double>(points.at(i).x) * blend;
205 py +=
static_cast<double>(points.at(i).y) * blend;
208 return Point(
static_cast<int>(px),
static_cast<int>(py));
213 if (points.empty()) {
217 int const n = points.size() - 1;
227 newPoints.push_back(points.at(0));
228 p.x = ((2 * points.at(0).x) + points.at(1).x) / 3;
229 p.y = ((2 * points.at(0).y) + points.at(1).y) / 3;
230 newPoints.push_back(p);
231 p.x = (2 * p.x) - points.at(0).x;
232 p.y = (2 * p.y) - points.at(0).y;
233 newPoints.push_back(p);
234 newPoints.push_back(points.at(1));
239 std::vector<float> xrhs(
static_cast<size_t>(n));
240 std::vector<float> yrhs(
static_cast<size_t>(n));
242 xrhs.at(0) =
static_cast<float>(points.at(0).x + (2 * points.at(1).x));
243 yrhs.at(0) =
static_cast<float>(points.at(0).y + (2 * points.at(1).y));
245 xrhs.at(n - 1) =
static_cast<float>(((8 * points.at(n - 1).x) + points.at(n).x) / 2.0F);
246 yrhs.at(n - 1) =
static_cast<float>(((8 * points.at(n - 1).y) + points.at(n).y) / 2.0F);
248 for (
int i = 1; i < n - 1; ++i) {
249 xrhs.at(i) =
static_cast<float>((4 * points.at(i).x) + (2 * points.at(i + 1).x));
250 yrhs.at(i) =
static_cast<float>((4 * points.at(i).y) + (2 * points.at(i + 1).y));
253 std::vector<float> x(
static_cast<size_t>(n));
254 std::vector<float> y(
static_cast<size_t>(n));
255 std::vector<float> xtmp(
static_cast<size_t>(n));
256 std::vector<float> ytmp(
static_cast<size_t>(n));
259 x.at(0) = xrhs.at(0) / xb;
260 y.at(0) = yrhs.at(0) / yb;
262 for (
int i = 1; i < n; i++) {
265 xb = (i < n - 1 ? 4.0F : 3.5F) - xtmp.at(i);
266 yb = (i < n - 1 ? 4.0F : 3.5F) - ytmp.at(i);
267 x.at(i) = (xrhs.at(i) - x.at(i - 1)) / xb;
268 y.at(i) = (yrhs.at(i) - y.at(i - 1)) / yb;
271 for (
int i = 1; i < n; i++) {
272 x.at(n - i - 1) -= xtmp.at(n - i) * x.at(n - i);
273 y.at(n - i - 1) -= ytmp.at(n - i) * y.at(n - i);
277 newPoints.push_back(points.at(0));
278 for (
int i = 0; i < n - 1; ++i) {
279 p.x =
static_cast<int>(x.at(i));
280 p.y =
static_cast<int>(y.at(i));
281 newPoints.push_back(p);
282 p.x =
static_cast<int>((2 * points.at(i + 1).x) - x.at(i + 1));
283 p.y =
static_cast<int>((2 * points.at(i + 1).y) - y.at(i + 1));
284 newPoints.push_back(p);
286 newPoints.push_back(points.at(i + 1));
288 p.x =
static_cast<int>(x.at(n - 1));
289 p.y =
static_cast<int>(y.at(n - 1));
290 newPoints.push_back(p);
291 p.x =
static_cast<int>((points.at(n).x + x.at(n - 1)) / 2);
292 p.y =
static_cast<int>((points.at(n).y + y.at(n - 1)) / 2);
293 newPoints.push_back(p);
295 newPoints.push_back(points.at(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.
static 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.
static 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).
Used replacement tokens by configure_file():
std::vector< Point > PointVector
A list of points.