Mon, 20 Jun 2022 22:21:53 +0300
fix typo
/* * 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 <QAbstractListModel> #include <memory> #include "basics.h" #include "colors.h" struct SubfileReference { QString name; glm::mat4 transformation; bool inverted = false; }; template<typename T> struct Colored : T { ldraw::Color color; }; struct Comment { QString text; }; struct ParseError { QString code; }; struct Empty {}; struct CircularFraction { unsigned int segments; unsigned int divisions; }; constexpr bool operator<(const CircularFraction& p, const CircularFraction& q) { // a/b < c/d // a < c * b / d // a * d < c * b return p.segments * q.divisions < q.segments / p.divisions; } struct CircularPrimitive { enum Type { Circle, Disc, Cylinder, CylinderOpen, CylinderClosed, DiscNegative, Chord, } type; static constexpr int NUM_TYPES = Chord + 1; CircularFraction fraction; glm::mat4 transformation; }; Q_DECLARE_METATYPE(CircularPrimitive::Type) struct CircleToolOptions { CircularFraction fraction; CircularPrimitive::Type type; }; using ModelElement = std::variant< Colored<SubfileReference>, Colored<LineSegment>, Colored<Triangle>, Colored<Quadrilateral>, Colored<ConditionalEdge>, Colored<CircularPrimitive>, Comment, Empty, ParseError>; using PolygonElement = Colored<std::variant< LineSegment, Triangle, Quadrilateral, ConditionalEdge>>; template<typename T> struct remove_color {}; template<typename T> struct remove_color<Colored<T>> { using type = T; }; template<typename T> struct remove_color<Colored<T>&> { using type = T&; }; template<typename T> struct remove_color<const Colored<T>&> { using type = const T&; }; template<typename T> struct remove_color<Colored<T>&&> { using type = T&&; }; template<typename T> using remove_color_t = typename remove_color<T>::type; static_assert(std::is_same_v<remove_color_t<Colored<Triangle>>, Triangle>); static_assert(std::is_same_v<remove_color_t<Colored<Triangle>&>, Triangle&>); static_assert(std::is_same_v<remove_color_t<const Colored<Triangle>&>, const Triangle&>); template<typename T> constexpr remove_color_t<T&&> extract_colored(T&& x) { return static_cast<remove_color_t<T&&>>(x); } template<typename Ret, typename Fn1, typename Fn2, typename Fn3, typename Fn4, typename T> constexpr auto visitPolygon(Fn1&& f1, Fn2&& f2, Fn3&& f3, Fn4&& f4, T&& element) { if (std::holds_alternative<LineSegment>(element)) { return f1(std::get<LineSegment>(element)); } else if (std::holds_alternative<Triangle>(element)) { return f2(std::get<Triangle>(element)); } else if (std::holds_alternative<Quadrilateral>(element)) { return f3(std::get<Quadrilateral>(element)); } else { return f4(std::get<ConditionalEdge>(element)); } } template<typename T, typename Fn> constexpr void visitPoints(Fn&& func, T&& element) { visitPolygon<void>( [&func](transfer_cvref_t<T&&, LineSegment> edge) { func(edge.p1); func(edge.p2); }, [&func](transfer_cvref_t<T&&, Triangle>& tri) { func(tri.p1); func(tri.p2); func(tri.p3); }, [&func](transfer_cvref_t<T&&, Quadrilateral>& quad) { func(quad.p1); func(quad.p2); func(quad.p3); func(quad.p4); }, [&func](transfer_cvref_t<T&&, ConditionalEdge>& cedge) { func(cedge.p1); func(cedge.p2); func(cedge.c1); func(cedge.c2); }, element); } QString modelElementToString(const ModelElement& element); struct ModelId { std::int32_t value; constexpr auto operator<=>(const ModelId& other) const = default; }; constexpr int qHash(ModelId id) { return qHash(id.value); } class Model : public QAbstractListModel { Q_OBJECT struct Entry { ModelElement data; ModelId id; }; std::vector<Entry> body; std::map<ModelId, int> positions; ModelId runningId = {1}; public: Model(QObject* parent); virtual ~Model(); ModelId append(const ModelElement& value); const ModelElement& at(int position) const; ModelId idAt(int position) const; void assignAt(int position, const ModelElement& element); std::optional<int> find(ModelId id) const; void remove(int index); int rowCount(const QModelIndex&) const override; QVariant data(const QModelIndex& index, int role) const override; const ModelElement& operator[](int index) const; int size() const; auto operator[](int index) { struct { Model& model; int index; operator const ModelElement&() { return model.at(index); } auto& operator=(const ModelElement& newData) { model.assignAt(index, newData); return *this; } const auto* operator&() { return &(this->operator const ModelElement&()); } } result{*this, index}; return result; } }; void save(const Model& model, QIODevice *device); void updateHeaderNameField(Model& model, const QString &name); template<typename T> void iterate(const Model& model, std::function<void(const T&)> fn) { for (int i = 0; i < model.size(); ++i) { if (std::holds_alternative<T>(model[i])) { fn(std::get<T>(model[i])); } } } constexpr Colored<LineSegment> edge(const glm::vec3& p1, const glm::vec3& p2) { return Colored<LineSegment>{{.p1 = p1, .p2 = p2}, EDGE_COLOR}; } constexpr Colored<Triangle> triangle(const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& p3) { return Colored<Triangle>{{.p1 = p1, .p2 = p2, .p3 = p3}, MAIN_COLOR}; } constexpr Colored<Quadrilateral> quadrilateral( const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& p3, const glm::vec3& p4) { return Colored<Quadrilateral>{{.p1 = p1, .p2 = p2, .p3 = p3, .p4 = p4}, MAIN_COLOR}; }