libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
point.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
13#include <cmath>
14#include <type_traits>
15#include <promeki/namespace.h>
16#include <promeki/string.h>
17#include <promeki/stringlist.h>
18#include <promeki/error.h>
19#include <promeki/logger.h>
20#include <promeki/array.h>
21
22PROMEKI_NAMESPACE_BEGIN
23
49template <typename T, size_t NumValues> class Point {
50 public:
57 static Error fromString(const String &val, Point &d) {
58 StringList parts = val.split(",");
59 if (parts.size() != NumValues) return Error::Invalid;
60 for (size_t i = 0; i < NumValues; ++i) {
61 Error err;
62 d[i] = static_cast<T>(parts[i].trim().toDouble(&err));
63 if (err.isError()) return Error::Invalid;
64 }
65 return Error::Ok;
66 }
67
74 static Point fromString(const String &str, Error *err = nullptr) {
75 Array<T, NumValues> d;
76 Error e = fromString(str, d);
77 if (err != nullptr) *err = e;
78 return e.isOk() ? d : Point();
79 }
80
82 Point() : d{} {}
83
85 Point(const Array<T, NumValues> &val) : d(val) {}
86
95 template <typename... Args, typename = std::enable_if_t<sizeof...(Args) == NumValues &&
96 (std::is_convertible_v<Args, T> && ...)>>
97 Point(Args... args) : d{static_cast<T>(args)...} {}
98
100 ~Point() {}
101
103 operator String() const { return toString(); }
104
106 operator const Array<T, NumValues> &() const { return d; }
107
109 bool operator==(const Array<T, NumValues> &val) const { return d == val; }
110
112 bool operator!=(const Array<T, NumValues> &val) const { return d != val; }
113
115 Point &operator+=(const Array<T, NumValues> &val) {
116 d += val;
117 return *this;
118 }
119
121 Point &operator-=(const Array<T, NumValues> &val) {
122 d -= val;
123 return *this;
124 }
125
127 Point &operator*=(const Array<T, NumValues> &val) {
128 d *= val;
129 return *this;
130 }
131
133 Point &operator/=(const Array<T, NumValues> &val) {
134 d /= val;
135 return *this;
136 }
137
139 template <size_t N = NumValues, typename std::enable_if_t<N >= 1, int> = 0> const T &x() const {
140 return d[0];
141 }
142
144 template <size_t N = NumValues, typename std::enable_if_t<N >= 1, int> = 0> T &x() { return d[0]; }
145
147 template <size_t N = NumValues, typename std::enable_if_t<N >= 1, int> = 0> void setX(const T &val) {
148 d[0] = val;
149 return;
150 }
151
153 template <size_t N = NumValues, typename std::enable_if_t<N >= 2, int> = 0> const T &y() const {
154 return d[1];
155 }
156
158 template <size_t N = NumValues, typename std::enable_if_t<N >= 2, int> = 0> T &y() { return d[1]; }
159
161 template <size_t N = NumValues, typename std::enable_if_t<N >= 2, int> = 0> void setY(const T &val) {
162 d[1] = val;
163 return;
164 }
165
167 template <size_t N = NumValues, typename std::enable_if_t<N >= 3, int> = 0> const T &z() const {
168 return d[2];
169 }
170
172 template <size_t N = NumValues, typename std::enable_if_t<N >= 3, int> = 0> T &z() { return d[2]; }
173
175 template <size_t N = NumValues, typename std::enable_if_t<N >= 3, int> = 0> void setZ(const T &val) {
176 d[2] = val;
177 return;
178 }
179
181 String toString() const {
182 String result;
183 for (size_t i = 0; i < NumValues; ++i) {
184 if (i > 0) result += ", ";
185 if constexpr (std::is_floating_point_v<T>) {
186 result += String::number(static_cast<double>(d[i]));
187 } else {
188 result += String::dec(static_cast<int64_t>(d[i]));
189 }
190 }
191 return result;
192 }
193
199 template <typename U> double distanceTo(const Point<U, NumValues> &other) const {
200 double sum = 0;
201 for (size_t i = 0; i < NumValues; ++i) {
202 double diff = static_cast<double>(d[i]) - static_cast<double>(other.d[i]);
203 sum += diff * diff;
204 }
205 return std::sqrt(sum);
206 }
207
214 Point<T, NumValues> lerp(const Point<T, NumValues> &other, double t) const { return d.lerp(other, t); }
215
222 template <typename U>
223 Point<T, NumValues> clamp(const Point<U, NumValues> &minVal, const Point<U, NumValues> &maxVal) const {
224 Point<T, NumValues> result;
225 for (size_t i = 0; i < NumValues; ++i) {
226 T val = d[i];
227 if (val < static_cast<T>(minVal.d[i])) val = static_cast<T>(minVal.d[i]);
228 if (val > static_cast<T>(maxVal.d[i])) val = static_cast<T>(maxVal.d[i]);
229 result.d[i] = val;
230 }
231 return result;
232 }
233
240 bool isWithinBounds(const Point<T, NumValues> &min, const Point<T, NumValues> &max) const {
241 for (size_t i = 0; i < NumValues; ++i) {
242 if (d[i] < min.d[i] || d[i] > max.d[i]) {
243 return false;
244 }
245 }
246 return true;
247 }
248
250 friend Point operator+(const Array<T, NumValues> &lh, const Array<T, NumValues> &rh) {
251 return Point(lh + rh);
252 }
253
255 friend Point operator-(const Array<T, NumValues> &lh, const Array<T, NumValues> &rh) {
256 return Point(lh - rh);
257 }
258
260 friend Point operator*(const Array<T, NumValues> &lh, const Array<T, NumValues> &rh) {
261 return Point(lh * rh);
262 }
263
265 friend Point operator/(const Array<T, NumValues> &lh, const Array<T, NumValues> &rh) {
266 return Point(lh / rh);
267 }
268
269 private:
270 Array<T, NumValues> d;
271};
272
274using Point2Di32 = Point<int32_t, 2>;
276using Point2Df = Point<float, 2>;
278using Point2Dd = Point<double, 2>;
280using Point3Di32 = Point<int32_t, 3>;
282using Point3Df = Point<float, 3>;
284using Point3Dd = Point<double, 3>;
286using Point4Di32 = Point<int32_t, 4>;
288using Point4Df = Point<float, 4>;
290using Point4Dd = Point<double, 4>;
291
292PROMEKI_NAMESPACE_END
293
302template <typename T, std::size_t NumValues>
303struct std::formatter<promeki::Point<T, NumValues>> : promeki::ToStringFormatter<promeki::Point<T, NumValues>> {};
304
305#endif // PROMEKI_ENABLE_CORE