summaryrefslogtreecommitdiffhomepage
path: root/spline/spline.hpp
blob: 7b9b6aa33299c1263cb1ff1abb79e49b75f7b413 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/* Copyright (c) 2012-2016, Stanislaw Halik <sthalik@misaki.pl>

 * Permission to use, copy, modify, and/or distribute this
 * software for any purpose with or without fee is hereby granted,
 * provided that the above copyright notice and this permission
 * notice appear in all copies.
 */

#pragma once

#include "compat/copyable-mutex.hpp"
#include "options/options.hpp"

#include "axis-opts.hpp"

#include "export.hpp"

#include <cstddef>
#include <vector>
#include <limits>
#include <memory>
#include <functional>

#include <QObject>
#include <QPointF>
#include <QString>
#include <QMetaObject>

namespace spline_detail {

using namespace options;

class OTR_SPLINE_EXPORT base_settings : public QObject
{
    Q_OBJECT

signals:
    void recomputed() const;
};

class OTR_SPLINE_EXPORT settings final : public base_settings
{
public:
    bundle b;
    value<QList<QPointF>> points { b, "points", {} };
    axis_opts opts;
    settings(bundle const& b, const QString& axis_name, Axis idx);
    ~settings() override;
};

struct OTR_SPLINE_EXPORT base_spline_
{
    virtual inline ~base_spline_();

    virtual float get_value(double x) = 0;
    virtual float get_value_no_save(double x) const = 0;

    [[nodiscard]] virtual bool get_last_value(QPointF& point) = 0;
    virtual void set_tracking_active(bool value) = 0;

    virtual double max_input() const = 0;
    virtual double max_output() const = 0;

    using points_t = QList<QPointF>;

    virtual points_t const& get_points() const = 0;
    virtual int get_point_count() const = 0;
};

struct OTR_SPLINE_EXPORT spline_settings_mixin
{
    using base_settings = spline_detail::base_settings;

    virtual std::shared_ptr<spline_detail::base_settings> get_settings() = 0;
    virtual std::shared_ptr<const spline_detail::base_settings> get_settings() const = 0;

    virtual inline ~spline_settings_mixin();
};

struct OTR_SPLINE_EXPORT spline_modify_mixin
{
    virtual void add_point(QPointF pt) = 0;
    virtual void add_point(double x, double y) = 0;
    virtual void move_point(int idx, QPointF pt) = 0;
    virtual void remove_point(int i) = 0;
    virtual void clear() = 0;

    virtual inline ~spline_modify_mixin();
};

struct OTR_SPLINE_EXPORT base_spline : base_spline_, spline_modify_mixin, spline_settings_mixin
{
};

class OTR_SPLINE_EXPORT spline : public base_spline
{
    double bucket_size_coefficient(const QList<QPointF>& points) const;
    void update_interp_data();
    float get_value_internal(int x);
    void add_lone_point();
    float get_value_no_save_internal(double x);
    static bool sort_fn(const QPointF& one, const QPointF& two);

    static QPointF ensure_in_bounds(const QList<QPointF>& points, int i);
    static int element_count(const QList<QPointF>& points, double max_input);

    void disconnect_signals();

    std::shared_ptr<spline_detail::settings> s;
    QMetaObject::Connection conn_changed, conn_maxx, conn_maxy;

    static constexpr inline std::size_t value_count = 4096;

    std::vector<float> data = std::vector<float>(value_count, float(-16));

    mutex _mutex { mutex::recursive };
    QPointF last_input_value;
    std::shared_ptr<QObject> ctx { std::make_shared<QObject>() };

    bool activep = false;
    bool validp = false;

    points_t points;

public:
    void invalidate_settings();

    void reload();
    void save();
    void set_bundle(bundle b, const QString& axis_name, Axis axis);

    double max_input() const override;
    double max_output() const override;

    spline();
    spline(const QString& name, const QString& axis_name, Axis axis);
    ~spline() override;

    spline& operator=(const spline&) = default;
    spline(const spline&) = default;

    float get_value(double x) override;
    float get_value_no_save(double x) const override;
    [[nodiscard]] bool get_last_value(QPointF& point) override;

    void add_point(QPointF pt) override;
    void add_point(double x, double y) override;
    void move_point(int idx, QPointF pt) override;
    void remove_point(int i) override;
    void clear() override;

    points_t const& get_points() const override;

    void set_tracking_active(bool value) override;
    bundle get_bundle();
    void ensure_valid(points_t& points_);

    std::shared_ptr<spline_detail::base_settings> get_settings() override;
    std::shared_ptr<const spline_detail::base_settings> get_settings() const override;

    int get_point_count() const override;

    using settings = spline_detail::settings;
};

inline base_spline_::~base_spline_() = default;
inline spline_modify_mixin::~spline_modify_mixin() = default;
inline spline_settings_mixin::~spline_settings_mixin() = default;

} // ns spline_detail

using spline = spline_detail::spline;