VisuTwin Canvas
C++ 3D Engine — Metal Backend
Loading...
Searching...
No Matches
curve.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025-2026 Arnis Lektauers
3#include "curve.h"
4
5#include <algorithm>
6#include <cmath>
7#include <limits>
8
9#include "curveEvaluator.h"
10
11namespace visutwin::canvas
12{
13 Curve::Curve() : _eval(std::make_unique<CurveEvaluator>(this))
14 {
15 }
16
17 Curve::Curve(const std::vector<float>& data) : _eval(std::make_unique<CurveEvaluator>(this))
18 {
19 for (size_t i = 0; i + 1 < data.size(); i += 2) {
20 keys.emplace_back(data[i], data[i + 1]);
21 }
22
23 sort();
24 }
25
26 Curve::Curve(const Curve& other)
27 : keys(other.keys), type(other.type), tension(other.tension), _eval(std::make_unique<CurveEvaluator>(this))
28 {
29 }
30
32 {
33 if (this == &other) {
34 return *this;
35 }
36
37 keys = other.keys;
38 type = other.type;
39 tension = other.tension;
40 _eval = std::make_unique<CurveEvaluator>(this);
41 return *this;
42 }
43
44 Curve::Curve(Curve&& other) noexcept
45 : keys(std::move(other.keys)), type(other.type), tension(other.tension), _eval(std::make_unique<CurveEvaluator>(this))
46 {
47 }
48
49 Curve& Curve::operator=(Curve&& other) noexcept
50 {
51 if (this == &other) {
52 return *this;
53 }
54
55 keys = std::move(other.keys);
56 type = other.type;
57 tension = other.tension;
58 _eval = std::make_unique<CurveEvaluator>(this);
59 return *this;
60 }
61
62 Curve::~Curve() = default;
63
64 std::pair<float, float> Curve::add(const float time, const float value)
65 {
66 const auto key = std::make_pair(time, value);
67 const size_t len = keys.size();
68 size_t i = 0;
69
70 for (; i < len; i++) {
71 if (keys[i].first > time) {
72 break;
73 }
74 }
75
76 keys.insert(keys.begin() + static_cast<std::ptrdiff_t>(i), key);
77 return key;
78 }
79
80 std::pair<float, float> Curve::get(const size_t index) const
81 {
82 return keys[index];
83 }
84
86 {
87 std::sort(keys.begin(), keys.end(), [](const auto& a, const auto& b) {
88 return a.first < b.first;
89 });
90 }
91
92 float Curve::value(const float time)
93 {
94 return _eval->evaluate(time, true);
95 }
96
97 std::pair<float, float> Curve::closest(const float time) const
98 {
99 const size_t len = keys.size();
100 if (!len) {
101 return {0.0f, 0.0f};
102 }
103
104 float min = 2.0f;
105 std::pair<float, float> result = keys.front();
106
107 for (size_t i = 0; i < len; i++) {
108 const float diff = std::abs(time - keys[i].first);
109 if (min >= diff) {
110 min = diff;
111 result = keys[i];
112 } else {
113 break;
114 }
115 }
116
117 return result;
118 }
119
121 {
122 Curve result;
123 result.keys = keys;
124 result.type = type;
125 result.tension = tension;
126 return result;
127 }
128
129 std::vector<float> Curve::quantize(size_t precision)
130 {
131 precision = std::max<size_t>(precision, 2);
132
133 std::vector<float> values(precision, 0.0f);
134 const float step = 1.0f / static_cast<float>(precision - 1);
135
136 values[0] = _eval->evaluate(0.0f, true);
137 for (size_t i = 1; i < precision; ++i) {
138 values[i] = _eval->evaluate(step * static_cast<float>(i));
139 }
140
141 return values;
142 }
143
144 std::vector<float> Curve::quantizeClamped(const size_t precision, const float min, const float max)
145 {
146 auto result = quantize(precision);
147 for (auto& v : result) {
148 v = std::min(max, std::max(min, v));
149 }
150 return result;
151 }
152}
std::vector< float > quantizeClamped(size_t precision, float min, float max)
Definition curve.cpp:144
std::pair< float, float > add(float time, float value)
Definition curve.cpp:64
std::vector< std::pair< float, float > > keys
Definition curve.h:27
float value(float time)
Definition curve.cpp:92
Curve & operator=(const Curve &other)
Definition curve.cpp:31
std::pair< float, float > get(size_t index) const
Definition curve.cpp:80
Curve clone() const
Definition curve.cpp:120
std::vector< float > quantize(size_t precision)
Definition curve.cpp:129
std::pair< float, float > closest(float time) const
Definition curve.cpp:97