src/basics.h

changeset 206
654661eab7f3
parent 196
6bcb284679d4
child 207
5315358a7d91
equal deleted inserted replaced
205:1a4342d80de7 206:654661eab7f3
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18 18
19 #pragma once 19 #pragma once
20 #include <algorithm> 20 #include <algorithm>
21 #include <cstdio>
22 #include <cstdlib>
23 #include <cstring>
24 #include <cmath> 21 #include <cmath>
22 #include <compare>
23 #include <memory>
25 #include <optional> 24 #include <optional>
26 #include <type_traits> 25 #include <type_traits>
27 #include <QMatrix4x4> 26 #include <QDataStream>
27 #include <QDebug>
28 #include <QObject> 28 #include <QObject>
29 #include <QPointF> 29 #include <QPointF>
30 #include <QSet> 30 #include <QSet>
31 #include <QString> 31 #include <QString>
32 #include <QStringList> 32 #include <QStringList>
33 #include <QVariant> 33 #include <QVariant>
34 #include <QVector> 34 #include <QVector>
35 #include <QVector3D>
36 #include <glm/glm.hpp> 35 #include <glm/glm.hpp>
37 36 #include "geometry.h"
38 using GLRotationMatrix = QMatrix4x4; 37 #include "functional.h"
39 38
40 enum Axis 39 template<typename T>
41 { 40 using opt = std::optional<T>;
42 X = 0, 41
43 Y = 1, 42 Q_DECLARE_METATYPE(glm::vec3)
44 Z = 2 43 Q_DECLARE_METATYPE(glm::mat4)
45 }; 44
46 45 //! \brief count the amount of elements in a basic array
47 enum Result
48 {
49 Success = 0,
50 PartialSuccess,
51 Failure
52 };
53
54 constexpr bool failed(Result r)
55 {
56 return r == Failure;
57 }
58
59 enum Winding
60 {
61 NoWinding,
62 Anticlockwise,
63 Clockwise,
64 };
65
66 /*
67 * Special operator definition that implements the XOR operator for windings.
68 * However, if either winding is NoWinding, then this function returns NoWinding.
69 */
70 inline Winding operator^(Winding one, Winding other)
71 {
72 if (one == NoWinding or other == NoWinding)
73 return NoWinding;
74 else
75 return static_cast<Winding>(static_cast<int>(one) ^ static_cast<int>(other));
76 }
77
78 inline Winding& operator^=(Winding& one, Winding other)
79 {
80 one = one ^ other;
81 return one;
82 }
83
84 template<typename T, int N> 46 template<typename T, int N>
85 constexpr int countof(T const (&)[N]) 47 constexpr int countof(T(&)[N])
86 { 48 {
87 return N; 49 return N;
88 } 50 }
89 51
90 /** 52 //! \brief casts @c x to a suitable unsigned integer
91 * @brief casts @c x to a suitable unsigned integer
92 */
93 template<typename T> 53 template<typename T>
94 constexpr auto unsigned_cast(T x) 54 constexpr auto unsigned_cast(T x)
95 -> std::enable_if_t<std::is_integral_v<T>, std::make_unsigned_t<T>> 55 -> std::enable_if_t<std::is_integral_v<T>, std::make_unsigned_t<T>>
96 { 56 {
97 return static_cast<std::make_unsigned_t<T>>(x); 57 return static_cast<std::make_unsigned_t<T>>(x);
98 } 58 }
99 59
100 /** 60 //! \brief casts @c x to a suitable signed integer
101 * @brief casts @c x to a suitable signed integer
102 */
103 template<typename T> 61 template<typename T>
104 constexpr auto signed_cast(T x) 62 constexpr auto signed_cast(T x)
105 -> std::enable_if_t<std::is_integral_v<T>, std::make_signed_t<T>> 63 -> std::enable_if_t<std::is_integral_v<T>, std::make_signed_t<T>>
106 { 64 {
107 return static_cast<std::make_signed_t<T>>(x); 65 return static_cast<std::make_signed_t<T>>(x);
108 } 66 }
109 67
110 68 //! \brief casts floating point values to float
111 /** 69 template<typename T>
112 * @brief casts floating point values to float, converting non-floating point values causes an error 70 constexpr auto float_cast(T x)
113 * @param[in] x floating point value to cast 71 -> std::enable_if_t<std::is_floating_point_v<T>, float>
114 * @returns float
115 */
116 template<typename T>
117 auto toFloat(T x) -> std::enable_if_t<std::is_floating_point_v<T>, float>
118 { 72 {
119 return static_cast<float>(x); 73 return static_cast<float>(x);
120 } 74 }
121 75
122 /** 76 //! \brief casts floating point values to double
123 * @brief casts floating point values to double, converting non-floating point values causes an error 77 template<typename T>
124 * @param[in] x floating point value to cast 78 constexpr auto double_cast(T x)
125 * @returns double 79 -> std::enable_if_t<std::is_floating_point_v<T>, double>
126 */
127 template<typename T>
128 auto toDouble(T x) -> std::enable_if_t<std::is_floating_point_v<T>, double>
129 { 80 {
130 return static_cast<double>(x); 81 return static_cast<double>(x);
131 } 82 }
132 83
133 /** 84 //! \brief casts floating point values to qreal
134 * @brief casts floating point values to qreal, converting non-floating point values causes an error 85 template<typename T>
135 * @param[in] x floating point value to cast 86 constexpr auto qreal_cast(T x)
136 * @returns qreal 87 -> std::enable_if_t<std::is_floating_point_v<T>, qreal>
137 */
138 template<typename T>
139 auto toQreal(T x) -> std::enable_if_t<std::is_floating_point_v<T>, qreal>
140 { 88 {
141 return static_cast<qreal>(x); 89 return static_cast<qreal>(x);
142 } 90 }
143 91
144 template<int N, typename T, glm::qualifier Q> 92 template<int N, typename T, glm::qualifier Q>
145 inline QPoint toQPoint(const glm::vec<N, T, Q>& vec) 93 constexpr QPointF toQPointF(const glm::vec<N, T, Q>& vec)
146 { 94 {
147 return {static_cast<int>(vec.x), static_cast<int>(vec.y)}; 95 return {double_cast(vec.x), double_cast(vec.y)};
148 } 96 }
149 97
150 template<int N, typename T, glm::qualifier Q> 98 constexpr glm::vec2 toVec2(const QPointF& point)
151 inline QPointF toQPointF(const glm::vec<N, T, Q>& vec)
152 {
153 return {toDouble(vec.x), toDouble(vec.y)};
154 }
155
156 inline glm::vec2 toVec2(const QPoint& point)
157 { 99 {
158 return {point.x(), point.y()}; 100 return {point.x(), point.y()};
159 } 101 }
160 102
161 inline glm::vec2 toVec2(const QPointF& point) 103
162 {
163 return {point.x(), point.y()};
164 }
165
166 /*
167 * coalesce(arg1, arg2, ..., argn)
168 * Returns the first of the given arguments that evaluates to true.
169 */
170 template<typename T>
171 T coalesce(T&& arg)
172 {
173 // recursion base: 1 argument
174 return arg;
175 }
176
177 template<typename T, typename... Rest>
178 std::common_type_t<T, Rest...> coalesce(T&& arg, Rest&&... rest)
179 {
180 // general case: n arguments
181 return arg ? arg : coalesce(rest...);
182 }
183
184 /**
185 * @brief Finds an element in a map and possibly returns a reference to it if find
186 * @param map
187 * @param key
188 * @returns the value or nullptr if not found
189 */
190 template<typename T, typename R, typename K> 104 template<typename T, typename R, typename K>
191 const R* findInMap(const std::map<T, R>& map, K&& key) 105 const R* findInMap(const std::map<T, R>& map, K&& key)
192 { 106 {
193 auto pair = map.find(key); 107 auto pair = map.find(key);
194 if (pair != map.end()) 108 if (pair != map.end())
199 { 113 {
200 return nullptr; 114 return nullptr;
201 } 115 }
202 } 116 }
203 117
204 /**
205 * @brief Finds an element in a map and possibly returns a reference to it if find
206 * @param map
207 * @param key
208 * @returns the value or no value if not found
209 */
210 template<typename T, typename R, typename K> 118 template<typename T, typename R, typename K>
211 R* findInMap(std::map<T, R>& map, K&& key) 119 R* findInMap(std::map<T, R>& map, K&& key)
212 { 120 {
213 auto pair = map.find(key); 121 auto pair = map.find(key);
214 if (pair != map.end()) 122 if (pair != map.end())
219 { 127 {
220 return nullptr; 128 return nullptr;
221 } 129 }
222 } 130 }
223 131
132 template<typename T, typename R>
133 void removeFromMap(std::map<T, R>& map, T&& key)
134 {
135 const auto it = map.find(key);
136 if (it != map.end()) {
137 map.erase(it);
138 }
139 }
140
224 template<typename T = float> 141 template<typename T = float>
225 constexpr std::enable_if_t<std::is_floating_point_v<T>, T> pi = static_cast<T>(M_PIl); 142 constexpr std::enable_if_t<std::is_floating_point_v<T>, T> pi = static_cast<T>(M_PIl);
226 constexpr double infinity = std::numeric_limits<double>::infinity(); 143
227 144 inline QSizeF sizeToSizeF(const QSize& size)
228 145 {
229 Q_DECLARE_METATYPE(glm::vec3) 146 return {static_cast<qreal>(size.width()), static_cast<qreal>(size.height())};
230 Q_DECLARE_METATYPE(glm::mat4) 147 }
148
149 //! \brief Hints to the specified vector that a certain amount of new elements
150 //! are going to be added.
151 template<typename T>
152 void reserveMore(std::vector<T>& vector, std::size_t amount)
153 {
154 vector.reserve(vector.size() + amount);
155 }
156
157 inline QString vectorToString(const glm::vec2& vec)
158 {
159 return QStringLiteral("(%1, %2)")
160 .arg(double_cast(vec.x))
161 .arg(double_cast(vec.y));
162 }
163
164 inline QString vectorToString(const glm::vec3& vec)
165 {
166 return QStringLiteral("(%1, %2, %3)")
167 .arg(double_cast(vec.x))
168 .arg(double_cast(vec.y))
169 .arg(double_cast(vec.z));
170 }
171
172 inline QString vectorToString(const glm::vec4& vec)
173 {
174 return QStringLiteral("%1, %2, %3, %4)")
175 .arg(double_cast(vec.x))
176 .arg(double_cast(vec.y))
177 .arg(double_cast(vec.z))
178 .arg(double_cast(vec.w));
179 }
180
181 template<typename T, typename IdentifierType>
182 struct TypeValue
183 {
184 T value;
185 auto operator<=>(TypeValue other) const = default;
186 };
187
188 template<typename T, typename R>
189 int qHash(TypeValue<T, R> value)
190 {
191 return qHash(value.value);
192 }
193
194 /**
195 * Iterates a @c glm::mat
196 */
197 template<int X, int Y, typename T, glm::qualifier Q, typename Fn>
198 void iter_matrix(const glm::mat<X, Y, T, Q>& matrix, Fn&& fn)
199 {
200 for (int i = 0; i < X; ++i)
201 {
202 for (int j = 0; j < Y; ++j)
203 {
204 fn(i, j, matrix[i][j]);
205 }
206 }
207 }
208
209 inline QDataStream& operator<<(QDataStream& stream, const glm::vec3& vec)
210 {
211 return stream << vec.x << vec.y << vec.z;
212 }
213
214 inline QDataStream& operator>>(QDataStream& stream, glm::vec3& vec)
215 {
216 return stream >> vec.x >> vec.y >> vec.z;
217 }
218
219 template<int X, int Y, typename T, glm::qualifier Q>
220 QDataStream& operator<<(QDataStream& stream, const glm::mat<X, Y, T, Q>& mat)
221 {
222 iter_matrix(mat, [&stream](int, int, float x)
223 {
224 stream << x;
225 });
226 return stream;
227 }
228
229 template<int X, int Y, typename T, glm::qualifier Q>
230 QDataStream& operator>>(QDataStream& stream, glm::mat<X, Y, T, Q>& mat)
231 {
232 iter_matrix(mat, [&stream](int, int, float x)
233 {
234 stream >> x;
235 });
236 return stream;
237 }
238
239 //! \brief Converts a pointer value to an \c std::optional value. If p has a
240 //! value, it will be copied into the result value.
241 template<typename T>
242 std::optional<T> pointerToOptional(const T* p)
243 {
244 std::optional<T> result;
245 if (p != nullptr) {
246 result = *p;
247 }
248 return result;
249 }
250
251 // some magic code from https://en.cppreference.com/w/cpp/utility/variant/visit
252 // for use with std::visit
253 template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
254 template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
255
256 // http://stackoverflow.com/a/18204188/3629665
257 template<typename T>
258 constexpr T rotl10(T x)
259 {
260 return (x << 10) | ((x >> 22) & 0x000000ff);
261 }
262
263 template<typename T>
264 constexpr T rotl20(T x)
265 {
266 return (x << 20) | ((x >> 12) & 0x000000ff);
267 }
268
269 inline QString quoted(QString string)
270 {
271 if (string.contains("'"))
272 {
273 string.replace("\"", "\\\"");
274 string = "\"" + string + "\"";
275 }
276 else
277 {
278 string = "'" + string + "'";
279 }
280 return string;
281 }
282
283 inline QString vertexToString(const glm::vec3& vertex)
284 {
285 return QStringLiteral("%1 %2 %3").arg(vertex.x).arg(vertex.y).arg(vertex.z);
286 }
287
288 inline QString vertexToStringParens(const glm::vec3& vertex)
289 {
290 return QStringLiteral("(%1 %2 %3)").arg(vertex.x).arg(vertex.y).arg(vertex.z);
291 }
292
293 inline QString transformToString(const glm::mat4& matrix)
294 {
295 return QStringLiteral("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12")
296 .arg(matrix[3][0], matrix[3][1], matrix[3][2])
297 .arg(matrix[0][0], matrix[1][0], matrix[2][0])
298 .arg(matrix[0][1], matrix[1][1], matrix[2][1])
299 .arg(matrix[0][2], matrix[1][2], matrix[2][2]);
300 }
301
302 template<typename T, glm::qualifier Q>
303 constexpr unsigned int qHash(const glm::vec<3, T, Q>& key)
304 {
305 return qHash(key.x) ^ rotl10(qHash(key.y)) ^ rotl20(qHash(key.z));
306 }

mercurial