11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
22PROMEKI_NAMESPACE_BEGIN
49template <
typename T,
size_t NumValues>
class Point {
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) {
62 d[i] =
static_cast<T
>(parts[i].trim().toDouble(&err));
63 if (err.isError())
return Error::Invalid;
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();
85 Point(
const Array<T, NumValues> &val) : d(val) {}
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)...} {}
103 operator String()
const {
return toString(); }
106 operator const Array<T, NumValues> &()
const {
return d; }
109 bool operator==(
const Array<T, NumValues> &val)
const {
return d == val; }
112 bool operator!=(
const Array<T, NumValues> &val)
const {
return d != val; }
115 Point &operator+=(
const Array<T, NumValues> &val) {
121 Point &operator-=(
const Array<T, NumValues> &val) {
127 Point &operator*=(
const Array<T, NumValues> &val) {
133 Point &operator/=(
const Array<T, NumValues> &val) {
139 template <
size_t N = NumValues,
typename std::enable_if_t<N >= 1,
int> = 0>
const T &x()
const {
144 template <
size_t N = NumValues,
typename std::enable_if_t<N >= 1,
int> = 0> T &x() {
return d[0]; }
147 template <
size_t N = NumValues,
typename std::enable_if_t<N >= 1,
int> = 0>
void setX(
const T &val) {
153 template <
size_t N = NumValues,
typename std::enable_if_t<N >= 2,
int> = 0>
const T &y()
const {
158 template <
size_t N = NumValues,
typename std::enable_if_t<N >= 2,
int> = 0> T &y() {
return d[1]; }
161 template <
size_t N = NumValues,
typename std::enable_if_t<N >= 2,
int> = 0>
void setY(
const T &val) {
167 template <
size_t N = NumValues,
typename std::enable_if_t<N >= 3,
int> = 0>
const T &z()
const {
172 template <
size_t N = NumValues,
typename std::enable_if_t<N >= 3,
int> = 0> T &z() {
return d[2]; }
175 template <
size_t N = NumValues,
typename std::enable_if_t<N >= 3,
int> = 0>
void setZ(
const T &val) {
181 String toString()
const {
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]));
188 result += String::dec(
static_cast<int64_t
>(d[i]));
199 template <
typename U>
double distanceTo(
const Point<U, NumValues> &other)
const {
201 for (
size_t i = 0; i < NumValues; ++i) {
202 double diff =
static_cast<double>(d[i]) -
static_cast<double>(other.d[i]);
205 return std::sqrt(sum);
214 Point<T, NumValues> lerp(
const Point<T, NumValues> &other,
double t)
const {
return d.lerp(other, t); }
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) {
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]);
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]) {
250 friend Point operator+(
const Array<T, NumValues> &lh,
const Array<T, NumValues> &rh) {
251 return Point(lh + rh);
255 friend Point operator-(
const Array<T, NumValues> &lh,
const Array<T, NumValues> &rh) {
256 return Point(lh - rh);
260 friend Point operator*(
const Array<T, NumValues> &lh,
const Array<T, NumValues> &rh) {
261 return Point(lh * rh);
265 friend Point operator/(
const Array<T, NumValues> &lh,
const Array<T, NumValues> &rh) {
266 return Point(lh / rh);
270 Array<T, NumValues> d;
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>;
302template <
typename T, std::
size_t NumValues>
303struct std::formatter<promeki::Point<T, NumValues>> : promeki::ToStringFormatter<promeki::Point<T, NumValues>> {};