Sat, 08 Apr 2023 12:55:11 +0300
Fix BFC formatting not working due to being evaluated after comment format
/* * LDForge: LDraw parts authoring CAD * Copyright (C) 2013 - 2020 Teemu Piippo * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #pragma once #include <algorithm> #include <cmath> #include <cinttypes> #include <compare> #include <deque> #include <memory> #include <optional> #include <set> #include <type_traits> #include <QDataStream> #include <QDateTime> #include <QDebug> #include <QObject> #include <QPointF> #include <QSet> #include <QString> #include <QStringList> #include <QVariant> #include <QVector> #include <QMdiArea> #include <glm/glm.hpp> #include "src/geometry.h" #include "src/typeconversions.h" #define SIG(A, B) (A), &std::decay_t<decltype(*(A))>::B template<typename T> using opt = std::optional<T>; using std::chrono::steady_clock; //! \brief Return type of qHash. unsigned int on Qt5, unsigned long on Qt6. using hash_t = decltype(qHash(0)); //! \brief Index type of QVector, int on Qt5, qsizetype on Qt6 using index_t = QVector<int>::size_type; Q_DECLARE_METATYPE(glm::vec3) Q_DECLARE_METATYPE(glm::mat4) struct ModelId { std::int32_t value; constexpr auto operator<=>(const ModelId&) const = default; }; struct ElementId { std::int32_t value; constexpr auto operator<=>(const ElementId& other) const = default; }; constexpr auto qHash(ElementId id) { return qHash(id.value); } //! \brief count the amount of elements in a basic array template<typename T, int N> constexpr int countof(T(&)[N]) { return N; } template<int N, typename T, glm::qualifier Q> constexpr QPointF toQPointF(const glm::vec<N, T, Q>& vec) { return {double_cast(vec.x), double_cast(vec.y)}; } constexpr glm::vec2 toVec2(const QPointF& point) { return {point.x(), point.y()}; } template<typename T, typename R, typename K> const R* findInMap(const std::map<T, R>& map, K&& key) { auto pair = map.find(key); if (pair != map.end()) { return &pair->second; } else { return nullptr; } } template<typename T, typename R, typename K> R* findInMap(std::map<T, R>& map, K&& key) { static_assert(std::is_convertible_v<K, T>, "bad type for key parameter"); auto pair = map.find(key); if (pair != map.end()) { return &pair->second; } else { return nullptr; } } template<typename T, typename R> void removeFromMap(std::map<T, R>& map, T&& key) { const auto it = map.find(key); if (it != map.end()) { map.erase(it); } } constexpr float pi = M_PIf; inline QSizeF sizeToSizeF(const QSize& size) { return {static_cast<qreal>(size.width()), static_cast<qreal>(size.height())}; } //! \brief Hints to the specified vector that a certain amount of new elements //! are going to be added. template<typename T> void reserveMore(std::vector<T>& vector, std::size_t amount) { vector.reserve(vector.size() + amount); } inline QString vectorToString(const glm::vec2& vec) { return QStringLiteral("(%1, %2)") .arg(double_cast(vec.x)) .arg(double_cast(vec.y)); } inline QString vectorToString(const glm::vec3& vec) { return QStringLiteral("(%1, %2, %3)") .arg(double_cast(vec.x)) .arg(double_cast(vec.y)) .arg(double_cast(vec.z)); } inline QString vectorToString(const glm::vec4& vec) { return QStringLiteral("%1, %2, %3, %4)") .arg(double_cast(vec.x)) .arg(double_cast(vec.y)) .arg(double_cast(vec.z)) .arg(double_cast(vec.w)); } template<typename T, typename IdentifierType> struct TypeValue { T value; auto operator<=>(const TypeValue& other) const = default; }; template<typename T, typename R> int qHash(TypeValue<T, R> value) { return qHash(value.value); } /** * Iterates a @c glm::mat */ template<int X, int Y, typename T, glm::qualifier Q, typename Fn> void iter_matrix(const glm::mat<X, Y, T, Q>& matrix, Fn&& fn) { for (int i = 0; i < X; ++i) { for (int j = 0; j < Y; ++j) { fn(i, j, matrix[i][j]); } } } inline QDataStream& operator<<(QDataStream& stream, const glm::vec3& vec) { return stream << vec.x << vec.y << vec.z; } inline QDataStream& operator>>(QDataStream& stream, glm::vec3& vec) { return stream >> vec.x >> vec.y >> vec.z; } template<int X, int Y, typename T, glm::qualifier Q> QDataStream& operator<<(QDataStream& stream, const glm::mat<X, Y, T, Q>& mat) { iter_matrix(mat, [&stream](int, int, float x) { stream << x; }); return stream; } template<int X, int Y, typename T, glm::qualifier Q> QDataStream& operator>>(QDataStream& stream, glm::mat<X, Y, T, Q>& mat) { iter_matrix(mat, [&stream](int, int, float x) { stream >> x; }); return stream; } //! \brief Converts a pointer value to an \c std::optional value. If p has a //! value, it will be copied into the result value. template<typename T> std::optional<T> pointerToOptional(const T* p) { std::optional<T> result; if (p != nullptr) { result = *p; } return result; } // some magic code from https://en.cppreference.com/w/cpp/utility/variant/visit // for use with std::visit template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; // http://stackoverflow.com/a/18204188/3629665 template<typename T> constexpr T rotl10(T x) { return (x << 10) | ((x >> 22) & 0x000000ff); } template<typename T> constexpr T rotl20(T x) { return (x << 20) | ((x >> 12) & 0x000000ff); } inline QString quoted(QString string) { if (string.contains("'")) { string.replace("\"", "\\\""); string = "\"" + string + "\""; } else { string = "'" + string + "'"; } return string; } inline QString vertexToString(const glm::vec3& vertex) { return QStringLiteral("%1 %2 %3").arg(vertex.x).arg(vertex.y).arg(vertex.z); } inline QString vertexToStringParens(const glm::vec3& vertex) { return QStringLiteral("(%1 %2 %3)").arg(vertex.x).arg(vertex.y).arg(vertex.z); } inline QString transformToString(const glm::mat4& matrix) { return QStringLiteral("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12") .arg(matrix[3][0]).arg(matrix[3][1]).arg(matrix[3][2]) .arg(matrix[0][0]).arg(matrix[1][0]).arg(matrix[2][0]) .arg(matrix[0][1]).arg(matrix[1][1]).arg(matrix[2][1]) .arg(matrix[0][2]).arg(matrix[1][2]).arg(matrix[2][2]); } template<typename T, glm::qualifier Q> constexpr auto qHash(const glm::vec<3, T, Q>& key) { return qHash(key.x) ^ rotl10(qHash(key.y)) ^ rotl20(qHash(key.z)); } template<typename T, typename Fn> void forValueInMap(T&& map, Fn&& fn) { for (const auto& it : map) { fn(it.second); } } inline QString joined(QString value, const QString& separator, const QString& element) { if (not value.isEmpty()) { value += separator; } value += element; return value; } template<typename T> struct GraphEdge { T from; T to; }; template<typename T> using Graph = std::deque<GraphEdge<T>>; struct Message { QDateTime time; enum Type { Info, Warning, Error } type; QString text; }; Q_DECLARE_METATYPE(Message) inline Message logInfo(const QString text) { return Message{.time = QDateTime::currentDateTime(), .type = Message::Info, .text = text}; } inline Message logWarning(const QString text) { return Message{.time = QDateTime::currentDateTime(), .type = Message::Warning, .text = text}; } inline Message logError(const QString text) { return Message{.time = QDateTime::currentDateTime(), .type = Message::Error, .text = text}; }