Tue, 14 Feb 2017 14:59:26 +0200
Renamed ldObject.cpp → linetypes/modelobject.cpp
--- a/CMakeLists.txt Tue Feb 14 14:53:06 2017 +0200 +++ b/CMakeLists.txt Tue Feb 14 14:59:26 2017 +0200 @@ -42,7 +42,6 @@ src/guiutilities.cpp src/hierarchyelement.cpp src/lddocument.cpp - src/ldObject.cpp src/ldpaths.cpp src/main.cpp src/mainwindow.cpp @@ -76,6 +75,7 @@ src/linetypes/conditionaledge.cpp src/linetypes/edgeline.cpp src/linetypes/empty.cpp + src/linetypes/modelobject.cpp src/toolsets/algorithmtoolset.cpp src/toolsets/basictoolset.cpp src/toolsets/extprogramtoolset.cpp @@ -104,7 +104,6 @@ src/guiutilities.h src/hierarchyelement.h src/lddocument.h - src/ldObject.h src/ldobjectiterator.h src/ldpaths.h src/macros.h @@ -140,6 +139,7 @@ src/linetypes/conditionaledge.h src/linetypes/edgeline.h src/linetypes/empty.h + src/linetypes/modelobject.h src/toolsets/algorithmtoolset.h src/toolsets/basictoolset.h src/toolsets/extprogramtoolset.h
--- a/src/basics.cpp Tue Feb 14 14:53:06 2017 +0200 +++ b/src/basics.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -17,7 +17,7 @@ */ #include "miscallenous.h" -#include "ldObject.h" +#include "linetypes/modelobject.h" #include "lddocument.h" Vertex::Vertex() :
--- a/src/dialogs/generateprimitivedialog.cpp Tue Feb 14 14:53:06 2017 +0200 +++ b/src/dialogs/generateprimitivedialog.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "../ldObject.h" +#include "../linetypes/modelobject.h" #include "generateprimitivedialog.h" #include "ui_generateprimitivedialog.h"
--- a/src/dialogs/newpartdialog.h Tue Feb 14 14:53:06 2017 +0200 +++ b/src/dialogs/newpartdialog.h Tue Feb 14 14:59:26 2017 +0200 @@ -19,7 +19,7 @@ #pragma once #include <QDialog> #include "../main.h" -#include "../ldObject.h" +#include "../linetypes/modelobject.h" class NewPartDialog : public QDialog, HierarchyElement {
--- a/src/documentloader.cpp Tue Feb 14 14:53:06 2017 +0200 +++ b/src/documentloader.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -18,7 +18,7 @@ #include "documentloader.h" #include "lddocument.h" -#include "ldObject.h" +#include "linetypes/modelobject.h" #include "mainwindow.h" #include "dialogs/openprogressdialog.h"
--- a/src/editHistory.cpp Tue Feb 14 14:53:06 2017 +0200 +++ b/src/editHistory.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -17,7 +17,7 @@ */ #include "editHistory.h" -#include "ldObject.h" +#include "linetypes/modelobject.h" #include "lddocument.h" #include "miscallenous.h" #include "mainwindow.h"
--- a/src/editHistory.h Tue Feb 14 14:53:06 2017 +0200 +++ b/src/editHistory.h Tue Feb 14 14:59:26 2017 +0200 @@ -18,7 +18,7 @@ #pragma once #include "main.h" -#include "ldObject.h" +#include "linetypes/modelobject.h" class AbstractHistoryEntry;
--- a/src/editmodes/circleMode.cpp Tue Feb 14 14:53:06 2017 +0200 +++ b/src/editmodes/circleMode.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -19,7 +19,7 @@ #include <QPainter> #include "circleMode.h" #include "../miscallenous.h" -#include "../ldObject.h" +#include "../linetypes/modelobject.h" #include "../lddocument.h" #include "../ringFinder.h" #include "../primitives.h"
--- a/src/editmodes/curvemode.cpp Tue Feb 14 14:53:06 2017 +0200 +++ b/src/editmodes/curvemode.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -17,7 +17,7 @@ */ #include "curvemode.h" -#include "../ldObject.h" +#include "../linetypes/modelobject.h" #include "../canvas.h" CurveMode::CurveMode (Canvas* canvas) :
--- a/src/editmodes/drawMode.cpp Tue Feb 14 14:53:06 2017 +0200 +++ b/src/editmodes/drawMode.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -19,7 +19,7 @@ #include <QPainter> #include <QMouseEvent> #include "drawMode.h" -#include "../ldObject.h" +#include "../linetypes/modelobject.h" #include "../glrenderer.h" #include "../linetypes/edgeline.h"
--- a/src/editmodes/rectangleMode.cpp Tue Feb 14 14:53:06 2017 +0200 +++ b/src/editmodes/rectangleMode.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -19,7 +19,7 @@ #include <QPainter> #include <QMouseEvent> #include "rectangleMode.h" -#include "../ldObject.h" +#include "../linetypes/modelobject.h" #include "../canvas.h" RectangleMode::RectangleMode (Canvas* canvas) :
--- a/src/ldObject.cpp Tue Feb 14 14:53:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,825 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013 - 2017 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/>. - */ - -#include <assert.h> -#include "documentmanager.h" -#include "ldObject.h" -#include "lddocument.h" -#include "miscallenous.h" -#include "mainwindow.h" -#include "editHistory.h" -#include "canvas.h" -#include "colors.h" -#include "glcompiler.h" -#include "linetypes/edgeline.h" - -// List of all LDObjects -QMap<qint32, LDObject*> g_allObjects; - -enum { MAX_LDOBJECT_IDS = (1 << 24) }; - -#define LDOBJ_DEFAULT_CTOR(T,BASE) \ - T :: T (Model* model) : \ - BASE {model} {} - -// ============================================================================= -// LDObject constructors -// -LDObject::LDObject (Model* model) : - m_isHidden {false}, - m_isSelected {false}, - _model {model}, - m_coords {Origin} -{ - assert(_model != nullptr); - - // Let's hope that nobody goes to create 17 million objects anytime soon... - static qint32 nextId = 1; // 0 shalt be null - if (nextId < MAX_LDOBJECT_IDS) - m_id = nextId++; - else - m_id = 0; - - if (m_id != 0) - g_allObjects[m_id] = this; - - m_randomColor = QColor::fromHsv (rand() % 360, rand() % 256, rand() % 96 + 128); -} - -LDSubfileReference::LDSubfileReference (Model* model) : - LDMatrixObject (model) {} - -LDOBJ_DEFAULT_CTOR (LDError, LDObject) -LDOBJ_DEFAULT_CTOR (LDTriangle, LDObject) -LDOBJ_DEFAULT_CTOR (LDQuadrilateral, LDObject) -LDOBJ_DEFAULT_CTOR (LDBfc, LDObject) -LDOBJ_DEFAULT_CTOR (LDBezierCurve, LDObject) - -LDObject::~LDObject() -{ - // Delete the GL lists - if (g_win) - g_win->renderer()->forgetObject(this); - - // Remove this object from the list of LDObjects - g_allObjects.erase(g_allObjects.find(id())); -} - -// ============================================================================= -// -QString LDSubfileReference::asText() const -{ - QString val = format ("1 %1 %2 ", color(), position()); - val += transformationMatrix().toString(); - val += ' '; - val += fileInfo()->name(); - return val; -} - -// ============================================================================= -// -QString LDTriangle::asText() const -{ - QString val = format ("3 %1", color()); - - for (int i = 0; i < 3; ++i) - val += format (" %1", vertex (i)); - - return val; -} - -// ============================================================================= -// -QString LDQuadrilateral::asText() const -{ - QString val = format ("4 %1", color()); - - for (int i = 0; i < 4; ++i) - val += format (" %1", vertex (i)); - - return val; -} - -QString LDBezierCurve::asText() const -{ - QString result = format ("0 !LDFORGE BEZIER_CURVE %1", color()); - - // Add the coordinates - for (int i = 0; i < 4; ++i) - result += format (" %1", vertex (i)); - - return result; -} - -// ============================================================================= -// -QString LDError::asText() const -{ - return contents(); -} - -// ============================================================================= -// -QString LDBfc::asText() const -{ - return format ("0 BFC %1", statementToString()); -} - -// ============================================================================= -// -// Swap this object with another. -// -void LDObject::swap (LDObject* other) -{ - if (model() == other->model()) - model()->swapObjects (this, other); -} - -int LDObject::triangleCount() const -{ - return 0; -} - -int LDSubfileReference::triangleCount() const -{ - return fileInfo()->triangleCount(); -} - -int LDTriangle::triangleCount() const -{ - return 1; -} - -int LDQuadrilateral::triangleCount() const -{ - return 2; -} - -int LDObject::numVertices() const -{ - return 0; -} - -// ============================================================================= -// -LDTriangle::LDTriangle (const Vertex& v1, const Vertex& v2, const Vertex& v3, Model* model) : - LDObject {model} -{ - setVertex (0, v1); - setVertex (1, v2); - setVertex (2, v3); -} - -// ============================================================================= -// -LDQuadrilateral::LDQuadrilateral (const Vertex& v1, const Vertex& v2, const Vertex& v3, const Vertex& v4, Model* model) : - LDObject {model} -{ - setVertex (0, v1); - setVertex (1, v2); - setVertex (2, v3); - setVertex (3, v4); -} - -// ============================================================================= -// -LDBezierCurve::LDBezierCurve(const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3, Model* model) : - LDObject {model} -{ - setVertex (0, v0); - setVertex (1, v1); - setVertex (2, v2); - setVertex (3, v3); -} - -// ============================================================================= -// -void LDObject::setDocument (Model* model) -{ - _model = model; -} - -// ============================================================================= -// -static void TransformObject (LDObject* obj, Matrix transform, Vertex pos, LDColor parentcolor) -{ - switch (obj->type()) - { - case LDObjectType::EdgeLine: - case LDObjectType::ConditionalEdge: - case LDObjectType::Triangle: - case LDObjectType::Quadrilateral: - for (int i = 0; i < obj->numVertices(); ++i) - { - Vertex v = obj->vertex (i); - v.transform (transform, pos); - obj->setVertex (i, v); - } - break; - - case LDObjectType::SubfileReference: - { - LDSubfileReference* ref = static_cast<LDSubfileReference*> (obj); - Matrix newMatrix = transform * ref->transformationMatrix(); - Vertex newpos = ref->position(); - newpos.transform (transform, pos); - ref->setPosition (newpos); - ref->setTransformationMatrix (newMatrix); - } - break; - - default: - break; - } - - if (obj->color() == MainColor) - obj->setColor (parentcolor); -} - -// ============================================================================= -// ----------------------------------------------------------------------------- -void LDSubfileReference::inlineContents(Model& model, bool deep, bool render) -{ - Model inlined {this->model()->documentManager()}; - fileInfo()->inlineContents(inlined, deep, render); - - // Transform the objects - for (LDObject* object : inlined) - TransformObject(object, transformationMatrix(), position(), color()); - - model.merge(inlined); -} - -// ============================================================================= -// -LDPolygon* LDObject::getPolygon() -{ - LDObjectType ot = type(); - int num = (ot == LDObjectType::EdgeLine) ? 2 - : (ot == LDObjectType::Triangle) ? 3 - : (ot == LDObjectType::Quadrilateral) ? 4 - : (ot == LDObjectType::ConditionalEdge) ? 5 - : 0; - - if (num == 0) - return nullptr; - - LDPolygon* data = new LDPolygon; - data->id = id(); - data->num = num; - data->color = color().index(); - - for (int i = 0; i < data->numVertices(); ++i) - data->vertices[i] = vertex (i); - - return data; -} - -LDColor LDObject::defaultColor() const -{ - return MainColor; -} - -bool LDObject::isColored() const -{ - return true; -} - -bool LDObject::isScemantic() const -{ - return true; -} - -bool LDObject::hasMatrix() const -{ - return false; -} - -// ============================================================================= -// -QList<LDPolygon> LDSubfileReference::inlinePolygons() -{ - QList<LDPolygon> data = fileInfo()->inlinePolygons(); - - for (LDPolygon& entry : data) - { - for (int i = 0; i < entry.numVertices(); ++i) - entry.vertices[i].transform (transformationMatrix(), position()); - } - - return data; -} - -// ============================================================================= -// -// Index (i.e. line number) of this object -// -int LDObject::lineNumber() const -{ - if (model()) - { - for (int i = 0; i < model()->size(); ++i) - { - if (model()->getObject(i) == this) - return i; - } - } - - return -1; -} - -// ============================================================================= -// -// Object after this in the current file -// -LDObject* LDObject::next() const -{ - return model()->getObject(lineNumber() + 1); -} - -// ============================================================================= -// -// Object prior to this in the current file -// -LDObject* LDObject::previous() const -{ - return model()->getObject(lineNumber() - 1); -} - -// ============================================================================= -// -// Is the previous object INVERTNEXT? -// -bool LDObject::previousIsInvertnext (LDBfc*& ptr) -{ - LDObject* prev = previous(); - - if (prev and prev->type() == LDObjectType::Bfc and static_cast<LDBfc*> (prev)->statement() == BfcStatement::InvertNext) - { - ptr = static_cast<LDBfc*> (prev); - return true; - } - - return false; -} - -// ============================================================================= -// -// Moves this object using the given vertex as a movement List -// -void LDObject::move (Vertex vect) -{ - if (hasMatrix()) - { - LDMatrixObject* mo = static_cast<LDMatrixObject*> (this); - mo->setPosition (mo->position() + vect); - } - else - { - for (int i = 0; i < numVertices(); ++i) - setVertex (i, vertex (i) + vect); - } -} - -bool LDObject::isHidden() const -{ - return m_isHidden; -} - -void LDObject::setHidden (bool value) -{ - m_isHidden = value; -} - -bool LDObject::isSelected() const -{ - return m_isSelected; -} - -qint32 LDObject::id() const -{ - return m_id; -} - -LDColor LDObject::color() const -{ - return m_color; -} - -QColor LDObject::randomColor() const -{ - return m_randomColor; -} - -Model* LDObject::model() const -{ - return _model; -} - -// ============================================================================= -// -void LDObject::invert() {} -void LDBfc::invert() {} -void LDError::invert() {} - -// ============================================================================= -// -void LDTriangle::invert() -{ - // Triangle goes 0 -> 1 -> 2, reversed: 0 -> 2 -> 1. - // Thus, we swap 1 and 2. - Vertex tmp = vertex (1); - setVertex (1, vertex (2)); - setVertex (2, tmp); - - return; -} - -// ============================================================================= -// -void LDQuadrilateral::invert() -{ - // Quad: 0 -> 1 -> 2 -> 3 - // reversed: 0 -> 3 -> 2 -> 1 - // Thus, we swap 1 and 3. - Vertex tmp = vertex (1); - setVertex (1, vertex (3)); - setVertex (3, tmp); -} - -// ============================================================================= -// -void LDSubfileReference::invert() -{ - if (model() == nullptr) - return; - - // Check whether subfile is flat - int axisSet = (1 << X) | (1 << Y) | (1 << Z); - Model model {this->model()->documentManager()}; - fileInfo()->inlineContents(model, true, false); - - for (LDObject* obj : model.objects()) - { - for (int i = 0; i < obj->numVertices(); ++i) - { - Vertex const& vrt = obj->vertex (i); - - if (axisSet & (1 << X) and vrt.x() != 0.0) - axisSet &= ~(1 << X); - - if (axisSet & (1 << Y) and vrt.y() != 0.0) - axisSet &= ~(1 << Y); - - if (axisSet & (1 << Z) and vrt.z() != 0.0) - axisSet &= ~(1 << Z); - } - - if (axisSet == 0) - break; - } - - if (axisSet != 0) - { - // Subfile has all vertices zero on one specific plane, so it is flat. - // Let's flip it. - Matrix matrixModifier = Matrix::identity; - - if (axisSet & (1 << X)) - matrixModifier(0, 0) = -1; - - if (axisSet & (1 << Y)) - matrixModifier(1, 1) = -1; - - if (axisSet & (1 << Z)) - matrixModifier(2, 2) = -1; - - setTransformationMatrix (transformationMatrix() * matrixModifier); - return; - } - - // Subfile is not flat. Resort to invertnext. - int idx = lineNumber(); - - if (idx > 0) - { - LDBfc* bfc = dynamic_cast<LDBfc*> (previous()); - - if (bfc and bfc->statement() == BfcStatement::InvertNext) - { - // This is prefixed with an invertnext, thus remove it. - this->model()->remove(bfc); - return; - } - } - - // Not inverted, thus prefix it with a new invertnext. - this->model()->emplaceAt<LDBfc>(idx, BfcStatement::InvertNext); -} - -// ============================================================================= -// -void LDBezierCurve::invert() -{ - // A Bézier curve's control points probably need to be, though. - Vertex tmp = vertex (1); - setVertex (1, vertex (0)); - setVertex (0, tmp); - tmp = vertex (3); - setVertex (3, vertex (2)); - setVertex (2, tmp); -} - -// ============================================================================= -// -LDObject* LDObject::fromID(qint32 id) -{ - return g_allObjects.value(id); -} - -// ============================================================================= -// -void LDObject::setColor (LDColor color) -{ - changeProperty(&m_color, color); -} - -// ============================================================================= -// -// Get a vertex by index -// -const Vertex& LDObject::vertex (int i) const -{ - return m_coords[i]; -} - -// ============================================================================= -// -// Set a vertex to the given value -// -void LDObject::setVertex (int i, const Vertex& vert) -{ - changeProperty(&m_coords[i], vert); -} - -LDMatrixObject::LDMatrixObject (Model* model) : - LDObject (model), - m_position (Origin) {} - -LDMatrixObject::LDMatrixObject (const Matrix& transform, const Vertex& pos, Model* model) : - LDObject (model), - m_position (pos), - m_transformationMatrix (transform) {} - -void LDMatrixObject::setCoordinate (const Axis ax, double value) -{ - Vertex v = position(); - - switch (ax) - { - case X: v.setX (value); break; - case Y: v.setY (value); break; - case Z: v.setZ (value); break; - } - - setPosition (v); -} - -const Vertex& LDMatrixObject::position() const -{ - return m_position; -} - -// ============================================================================= -// -void LDMatrixObject::setPosition (const Vertex& a) -{ - changeProperty(&m_position, a); -} - -// ============================================================================= -// -const Matrix& LDMatrixObject::transformationMatrix() const -{ - return m_transformationMatrix; -} - -void LDMatrixObject::setTransformationMatrix (const Matrix& val) -{ - changeProperty(&m_transformationMatrix, val); -} - -LDError::LDError (QString contents, QString reason, Model* model) : - LDObject (model), - m_contents (contents), - m_reason (reason) {} - -QString LDError::reason() const -{ - return m_reason; -} - -QString LDError::contents() const -{ - return m_contents; -} - -QString LDError::fileReferenced() const -{ - return m_fileReferenced; -} - -void LDError::setFileReferenced (QString value) -{ - m_fileReferenced = value; -} - -LDBfc::LDBfc (const BfcStatement type, Model* model) : - LDObject {model}, - m_statement {type} {} - -BfcStatement LDBfc::statement() const -{ - return m_statement; -} - -void LDBfc::setStatement (BfcStatement value) -{ - m_statement = value; -} - -QString LDBfc::statementToString() const -{ - return LDBfc::statementToString (statement()); -} - -QString LDBfc::statementToString (BfcStatement statement) -{ - static const char* statementStrings[] = - { - "CERTIFY CCW", - "CCW", - "CERTIFY CW", - "CW", - "NOCERTIFY", - "INVERTNEXT", - "CLIP", - "CLIP CCW", - "CLIP CW", - "NOCLIP", - }; - - if ((int) statement >= 0 and (int) statement < countof (statementStrings)) - return QString::fromLatin1 (statementStrings[(int) statement]); - else - return ""; -} - -Vertex LDBezierCurve::pointAt (qreal t) const -{ - if (t >= 0.0 and t <= 1.0) - { - Vertex result; - result += pow (1.0 - t, 3) * vertex (0); - result += (3 * pow (1.0 - t, 2) * t) * vertex (2); - result += (3 * (1.0 - t) * pow (t, 2)) * vertex (3); - result += pow (t, 3) * vertex (1); - return result; - } - else - return Vertex(); -} - -void LDBezierCurve::rasterize(Model& model, int segments) -{ - QVector<LDPolygon> polygons = rasterizePolygons(segments); - - for (LDPolygon& poly : polygons) - { - LDEdgeLine* line = model.emplace<LDEdgeLine>(poly.vertices[0], poly.vertices[1]); - line->setColor (poly.color); - } -} - -QVector<LDPolygon> LDBezierCurve::rasterizePolygons(int segments) -{ - QVector<LDPolygon> result; - QVector<Vertex> parms; - parms.append (pointAt (0.0)); - - for (int i = 1; i < segments; ++i) - parms.append (pointAt (double (i) / segments)); - - parms.append (pointAt (1.0)); - LDPolygon poly; - poly.color = color().index(); - poly.id = id(); - poly.num = 2; - - for (int i = 0; i < segments; ++i) - { - poly.vertices[0] = parms[i]; - poly.vertices[1] = parms[i + 1]; - result << poly; - } - - return result; -} - -LDSubfileReference::LDSubfileReference(LDDocument* reference, const Matrix& transformationMatrix, - const Vertex& position, Model* model) : - LDMatrixObject {transformationMatrix, position, model}, - m_fileInfo {reference} {} - -// ============================================================================= -// -LDDocument* LDSubfileReference::fileInfo() const -{ - return m_fileInfo; -} - -void LDSubfileReference::setFileInfo (LDDocument* newReferee) -{ - changeProperty(&m_fileInfo, newReferee); - - if (model()) - model()->recountTriangles(); - - // If it's an immediate subfile reference (i.e. this subfile is in an opened document), we need to pre-compile the - // GL polygons for the document if they don't exist already. - if (newReferee and - newReferee->isFrozen() == false and - newReferee->polygonData().isEmpty()) - { - newReferee->initializeCachedData(); - } -} - -void LDObject::getVertices (QSet<Vertex>& verts) const -{ - for (int i = 0; i < numVertices(); ++i) - verts.insert(vertex(i)); -} - -void LDSubfileReference::getVertices (QSet<Vertex>& verts) const -{ - verts.unite(fileInfo()->inlineVertices()); -} - -QString LDObject::objectListText() const -{ - if (numVertices() > 0) - { - QString result; - - for (int i = 0; i < numVertices(); ++i) - { - if (i != 0) - result += ", "; - - result += vertex(i).toString (true); - } - - return result; - } - else - { - return typeName(); - } -} - -QString LDError::objectListText() const -{ - return "ERROR: " + asText(); -} - -QString LDSubfileReference::objectListText() const -{ - QString result = format ("%1 %2, (", fileInfo()->getDisplayName(), position().toString(true)); - - for (int i = 0; i < 9; ++i) - result += format("%1%2", transformationMatrix().value(i), (i != 8) ? " " : ""); - - result += ')'; - return result; -} - -QString LDBfc::objectListText() const -{ - return statementToString(); -}
--- a/src/ldObject.h Tue Feb 14 14:53:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,351 +0,0 @@ -/* - * LDForge: LDraw parts authoring CAD - * Copyright (C) 2013 - 2017 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 <type_traits> -#include "main.h" -#include "basics.h" -#include "glShared.h" -#include "colors.h" - -class Model; -class LDDocument; - -/* - * Object type codes. - */ -enum LDObjectType -{ - SubfileReference, // Object represents a sub-file reference - Quadrilateral, // Object represents a quadrilateral - Triangle, // Object represents a triangle - EdgeLine, // Object represents a line - ConditionalEdge, // Object represents a conditional line - Bfc, // Object represents a BFC statement - Comment, // Object represents a comment - Error, // Object is the result of failed parsing - Empty, // Object represents an empty line - BezierCurve, // Object represents a Bézier curve - _End -}; - -MAKE_ITERABLE_ENUM(LDObjectType) - -/* - * Represents one line of code in an LDraw model file. - */ -class LDObject : public QObject -{ - Q_OBJECT - -public: - virtual QString asText() const = 0; // This object as LDraw code - LDColor color() const; - virtual LDColor defaultColor() const; // What color does the object default to? - Model* model() const; - LDPolygon* getPolygon(); - virtual void getVertices (QSet<Vertex>& verts) const; - virtual bool hasMatrix() const; // Does this object have a matrix and position? (see LDMatrixObject) - qint32 id() const; - virtual void invert(); // Inverts this object (winding is reversed) - virtual bool isColored() const; - bool isHidden() const; - virtual bool isScemantic() const; // Does this object have meaning in the part model? - bool isSelected() const; - int lineNumber() const; - void move (Vertex vect); - LDObject* next() const; - virtual int numVertices() const; - virtual QString objectListText() const; - LDObject* previous() const; - bool previousIsInvertnext(class LDBfc*& ptr); - QColor randomColor() const; - void setColor (LDColor color); - void setHidden (bool value); - void setVertex (int i, const Vertex& vert); - void swap (LDObject* other); - virtual int triangleCount() const; - virtual LDObjectType type() const = 0; - virtual QString typeName() const = 0; - const Vertex& vertex (int i) const; - - static LDObject* fromID(qint32 id); - -signals: - void codeChanged(QString before, QString after); - -protected: - friend class Model; - LDObject (Model* model = nullptr); - virtual ~LDObject(); - void setDocument(Model* model); - - template<typename T> - void changeProperty(T* property, const T& value); - -private: - bool m_isHidden; - bool m_isSelected; - Model* _model; - qint32 m_id; - LDColor m_color; - QColor m_randomColor; - Vertex m_coords[4]; -}; - -/* - * Base class for objects with matrices. - */ -class LDMatrixObject : public LDObject -{ - Vertex m_position; - -public: - const Vertex& position() const; - void setCoordinate (const Axis ax, double value); - void setPosition (const Vertex& a); - void setTransformationMatrix (const Matrix& value); - const Matrix& transformationMatrix() const; - -protected: - LDMatrixObject (Model* model = nullptr); - LDMatrixObject (const Matrix& transformationMatrix, const Vertex& pos, Model* model = nullptr); - -private: - Matrix m_transformationMatrix; -}; - -/* - * Represents a line in the LDraw file that could not be properly parsed. - */ -class LDError : public LDObject -{ -public: - static constexpr LDObjectType SubclassType = LDObjectType::Error; - - virtual LDObjectType type() const override - { - return SubclassType; - } - - virtual QString asText() const override; - virtual void invert() override; - QString reason() const; - QString contents() const; - QString fileReferenced() const; - void setFileReferenced (QString value); - QString objectListText() const override; - bool isColored() const override { return false; } - QString typeName() const override { return "error"; } - -protected: - friend class Model; - LDError (Model* model); - LDError (QString contents, QString reason, Model* model = nullptr); - -private: - QString m_fileReferenced; // If this error was caused by inability to open a file, what file was that? - QString m_contents; // The LDraw code that was being parsed - QString m_reason; -}; - -/* - * Represents a 0 BFC statement in the LDraw code. - */ -enum class BfcStatement -{ - CertifyCCW, - CCW, - CertifyCW, - CW, - NoCertify, - InvertNext, - Clip, - ClipCCW, - ClipCW, - NoClip, - _End -}; - -MAKE_ITERABLE_ENUM(BfcStatement) - -class LDBfc : public LDObject -{ - public: - static constexpr LDObjectType SubclassType = LDObjectType::Bfc; - - virtual LDObjectType type() const override - { - return SubclassType; - } - - virtual QString asText() const override; - virtual void invert() override; -protected: - friend class Model; - LDBfc (Model* model); - -public: - bool isScemantic() const override { return statement() == BfcStatement::InvertNext; } - QString objectListText() const override; - BfcStatement statement() const; - void setStatement (BfcStatement value); - QString statementToString() const; - bool isColored() const override { return false; } - QString typeName() const override { return "bfc"; } - - static QString statementToString (BfcStatement statement); - -protected: - LDBfc (const BfcStatement type, Model* model = nullptr); - -private: - BfcStatement m_statement; -}; - -/* - * Represents a single code-1 subfile reference. - */ -class LDSubfileReference : public LDMatrixObject -{ -public: - static constexpr LDObjectType SubclassType = LDObjectType::SubfileReference; - - virtual LDObjectType type() const override - { - return SubclassType; - } - - virtual QString asText() const override; - virtual void invert() override; - LDDocument* fileInfo() const; - virtual void getVertices (QSet<Vertex>& verts) const override; - void inlineContents(Model& model, bool deep, bool render); - QList<LDPolygon> inlinePolygons(); - QString objectListText() const override; - void setFileInfo (LDDocument* fileInfo); - int triangleCount() const override; - bool hasMatrix() const override { return true; } - QString typeName() const override { return "subfilereference"; } - -protected: - friend class Model; - LDSubfileReference (Model* model); - LDSubfileReference(LDDocument* reference, const Matrix& transformationMatrix, const Vertex& position, Model* model = nullptr); - -private: - LDDocument* m_fileInfo; -}; - -/* - * Represents a single code-3 triangle in the LDraw code file. - */ -class LDTriangle : public LDObject -{ -public: - static constexpr LDObjectType SubclassType = LDObjectType::Triangle; - - virtual LDObjectType type() const override - { - return SubclassType; - } - - virtual QString asText() const override; - virtual void invert() override; - int triangleCount() const override; - int numVertices() const override { return 3; } - QString typeName() const override { return "triangle"; } - -protected: - friend class Model; - LDTriangle (Model* model); - LDTriangle (Vertex const& v1, Vertex const& v2, Vertex const& v3, Model* model = nullptr); -}; - -/* - * Represents a single code-4 quadrilateral. - */ -class LDQuadrilateral : public LDObject -{ -public: - static constexpr LDObjectType SubclassType = LDObjectType::Quadrilateral; - - virtual LDObjectType type() const override - { - return SubclassType; - } - - QString asText() const override; - void invert() override; - int triangleCount() const override; - int numVertices() const override { return 4; } - QString typeName() const override { return "quad"; } - -protected: - friend class Model; - LDQuadrilateral (Model* model); - LDQuadrilateral (const Vertex& v1, const Vertex& v2, const Vertex& v3, const Vertex& v4, Model* model = nullptr); -}; - -/* - * Models a Bézier curve. It is stored as a special comment in the LDraw code file and can be inlined down into line segments. - */ -class LDBezierCurve : public LDObject -{ -public: - static constexpr LDObjectType SubclassType = LDObjectType::BezierCurve; - - virtual LDObjectType type() const override - { - return SubclassType; - } - - virtual QString asText() const override; - virtual void invert() override; - Vertex pointAt (qreal t) const; - void rasterize(Model& model, int segments); - QVector<LDPolygon> rasterizePolygons (int segments); - int numVertices() const override { return 4; } - LDColor defaultColor() const override { return EdgeColor; } - QString typeName() const override { return "beziercurve"; } - -protected: - friend class Model; - LDBezierCurve (Model* model); - LDBezierCurve (const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3, Model* model = nullptr); -}; - -enum -{ - LowResolution = 16, - HighResolution = 48 -}; - -/* - * Changes a property in a manner that emits the appropriate signal to notify that the object changed. - */ -template<typename T> -void LDObject::changeProperty(T* property, const T& value) -{ - if (*property != value) - { - QString before = asText(); - *property = value; - emit codeChanged(before, asText()); - } -}
--- a/src/lddocument.h Tue Feb 14 14:53:06 2017 +0200 +++ b/src/lddocument.h Tue Feb 14 14:59:26 2017 +0200 @@ -19,7 +19,7 @@ #pragma once #include <QObject> #include "main.h" -#include "ldObject.h" +#include "linetypes/modelobject.h" #include "editHistory.h" #include "glShared.h" #include "model.h"
--- a/src/ldobjectiterator.h Tue Feb 14 14:53:06 2017 +0200 +++ b/src/ldobjectiterator.h Tue Feb 14 14:59:26 2017 +0200 @@ -17,7 +17,7 @@ */ #pragma once -#include "ldObject.h" +#include "linetypes/modelobject.h" #include "lddocument.h" template<typename T>
--- a/src/linetypes/comment.h Tue Feb 14 14:53:06 2017 +0200 +++ b/src/linetypes/comment.h Tue Feb 14 14:59:26 2017 +0200 @@ -17,7 +17,7 @@ */ #pragma once -#include "../ldObject.h" +#include "../linetypes/modelobject.h" /* * Represents a line type 0 comment in the LDraw model.
--- a/src/linetypes/edgeline.h Tue Feb 14 14:53:06 2017 +0200 +++ b/src/linetypes/edgeline.h Tue Feb 14 14:59:26 2017 +0200 @@ -17,7 +17,7 @@ */ #pragma once -#include "../ldObject.h" +#include "../linetypes/modelobject.h" /* * Represents a single code-2 line in the LDraw code file.
--- a/src/linetypes/empty.h Tue Feb 14 14:53:06 2017 +0200 +++ b/src/linetypes/empty.h Tue Feb 14 14:59:26 2017 +0200 @@ -17,7 +17,7 @@ */ #pragma once -#include "../ldObject.h" +#include "../linetypes/modelobject.h" /* * Represents an empty line in the LDraw code file.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/linetypes/modelobject.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -0,0 +1,825 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2017 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/>. + */ + +#include <assert.h> +#include "../documentmanager.h" +#include "../linetypes/modelobject.h" +#include "../lddocument.h" +#include "../miscallenous.h" +#include "../mainwindow.h" +#include "../editHistory.h" +#include "../canvas.h" +#include "../colors.h" +#include "../glcompiler.h" +#include "edgeline.h" + +// List of all LDObjects +QMap<qint32, LDObject*> g_allObjects; + +enum { MAX_LDOBJECT_IDS = (1 << 24) }; + +#define LDOBJ_DEFAULT_CTOR(T,BASE) \ + T :: T (Model* model) : \ + BASE {model} {} + +// ============================================================================= +// LDObject constructors +// +LDObject::LDObject (Model* model) : + m_isHidden {false}, + m_isSelected {false}, + _model {model}, + m_coords {Origin} +{ + assert(_model != nullptr); + + // Let's hope that nobody goes to create 17 million objects anytime soon... + static qint32 nextId = 1; // 0 shalt be null + if (nextId < MAX_LDOBJECT_IDS) + m_id = nextId++; + else + m_id = 0; + + if (m_id != 0) + g_allObjects[m_id] = this; + + m_randomColor = QColor::fromHsv (rand() % 360, rand() % 256, rand() % 96 + 128); +} + +LDSubfileReference::LDSubfileReference (Model* model) : + LDMatrixObject (model) {} + +LDOBJ_DEFAULT_CTOR (LDError, LDObject) +LDOBJ_DEFAULT_CTOR (LDTriangle, LDObject) +LDOBJ_DEFAULT_CTOR (LDQuadrilateral, LDObject) +LDOBJ_DEFAULT_CTOR (LDBfc, LDObject) +LDOBJ_DEFAULT_CTOR (LDBezierCurve, LDObject) + +LDObject::~LDObject() +{ + // Delete the GL lists + if (g_win) + g_win->renderer()->forgetObject(this); + + // Remove this object from the list of LDObjects + g_allObjects.erase(g_allObjects.find(id())); +} + +// ============================================================================= +// +QString LDSubfileReference::asText() const +{ + QString val = format ("1 %1 %2 ", color(), position()); + val += transformationMatrix().toString(); + val += ' '; + val += fileInfo()->name(); + return val; +} + +// ============================================================================= +// +QString LDTriangle::asText() const +{ + QString val = format ("3 %1", color()); + + for (int i = 0; i < 3; ++i) + val += format (" %1", vertex (i)); + + return val; +} + +// ============================================================================= +// +QString LDQuadrilateral::asText() const +{ + QString val = format ("4 %1", color()); + + for (int i = 0; i < 4; ++i) + val += format (" %1", vertex (i)); + + return val; +} + +QString LDBezierCurve::asText() const +{ + QString result = format ("0 !LDFORGE BEZIER_CURVE %1", color()); + + // Add the coordinates + for (int i = 0; i < 4; ++i) + result += format (" %1", vertex (i)); + + return result; +} + +// ============================================================================= +// +QString LDError::asText() const +{ + return contents(); +} + +// ============================================================================= +// +QString LDBfc::asText() const +{ + return format ("0 BFC %1", statementToString()); +} + +// ============================================================================= +// +// Swap this object with another. +// +void LDObject::swap (LDObject* other) +{ + if (model() == other->model()) + model()->swapObjects (this, other); +} + +int LDObject::triangleCount() const +{ + return 0; +} + +int LDSubfileReference::triangleCount() const +{ + return fileInfo()->triangleCount(); +} + +int LDTriangle::triangleCount() const +{ + return 1; +} + +int LDQuadrilateral::triangleCount() const +{ + return 2; +} + +int LDObject::numVertices() const +{ + return 0; +} + +// ============================================================================= +// +LDTriangle::LDTriangle (const Vertex& v1, const Vertex& v2, const Vertex& v3, Model* model) : + LDObject {model} +{ + setVertex (0, v1); + setVertex (1, v2); + setVertex (2, v3); +} + +// ============================================================================= +// +LDQuadrilateral::LDQuadrilateral (const Vertex& v1, const Vertex& v2, const Vertex& v3, const Vertex& v4, Model* model) : + LDObject {model} +{ + setVertex (0, v1); + setVertex (1, v2); + setVertex (2, v3); + setVertex (3, v4); +} + +// ============================================================================= +// +LDBezierCurve::LDBezierCurve(const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3, Model* model) : + LDObject {model} +{ + setVertex (0, v0); + setVertex (1, v1); + setVertex (2, v2); + setVertex (3, v3); +} + +// ============================================================================= +// +void LDObject::setDocument (Model* model) +{ + _model = model; +} + +// ============================================================================= +// +static void TransformObject (LDObject* obj, Matrix transform, Vertex pos, LDColor parentcolor) +{ + switch (obj->type()) + { + case LDObjectType::EdgeLine: + case LDObjectType::ConditionalEdge: + case LDObjectType::Triangle: + case LDObjectType::Quadrilateral: + for (int i = 0; i < obj->numVertices(); ++i) + { + Vertex v = obj->vertex (i); + v.transform (transform, pos); + obj->setVertex (i, v); + } + break; + + case LDObjectType::SubfileReference: + { + LDSubfileReference* ref = static_cast<LDSubfileReference*> (obj); + Matrix newMatrix = transform * ref->transformationMatrix(); + Vertex newpos = ref->position(); + newpos.transform (transform, pos); + ref->setPosition (newpos); + ref->setTransformationMatrix (newMatrix); + } + break; + + default: + break; + } + + if (obj->color() == MainColor) + obj->setColor (parentcolor); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void LDSubfileReference::inlineContents(Model& model, bool deep, bool render) +{ + Model inlined {this->model()->documentManager()}; + fileInfo()->inlineContents(inlined, deep, render); + + // Transform the objects + for (LDObject* object : inlined) + TransformObject(object, transformationMatrix(), position(), color()); + + model.merge(inlined); +} + +// ============================================================================= +// +LDPolygon* LDObject::getPolygon() +{ + LDObjectType ot = type(); + int num = (ot == LDObjectType::EdgeLine) ? 2 + : (ot == LDObjectType::Triangle) ? 3 + : (ot == LDObjectType::Quadrilateral) ? 4 + : (ot == LDObjectType::ConditionalEdge) ? 5 + : 0; + + if (num == 0) + return nullptr; + + LDPolygon* data = new LDPolygon; + data->id = id(); + data->num = num; + data->color = color().index(); + + for (int i = 0; i < data->numVertices(); ++i) + data->vertices[i] = vertex (i); + + return data; +} + +LDColor LDObject::defaultColor() const +{ + return MainColor; +} + +bool LDObject::isColored() const +{ + return true; +} + +bool LDObject::isScemantic() const +{ + return true; +} + +bool LDObject::hasMatrix() const +{ + return false; +} + +// ============================================================================= +// +QList<LDPolygon> LDSubfileReference::inlinePolygons() +{ + QList<LDPolygon> data = fileInfo()->inlinePolygons(); + + for (LDPolygon& entry : data) + { + for (int i = 0; i < entry.numVertices(); ++i) + entry.vertices[i].transform (transformationMatrix(), position()); + } + + return data; +} + +// ============================================================================= +// +// Index (i.e. line number) of this object +// +int LDObject::lineNumber() const +{ + if (model()) + { + for (int i = 0; i < model()->size(); ++i) + { + if (model()->getObject(i) == this) + return i; + } + } + + return -1; +} + +// ============================================================================= +// +// Object after this in the current file +// +LDObject* LDObject::next() const +{ + return model()->getObject(lineNumber() + 1); +} + +// ============================================================================= +// +// Object prior to this in the current file +// +LDObject* LDObject::previous() const +{ + return model()->getObject(lineNumber() - 1); +} + +// ============================================================================= +// +// Is the previous object INVERTNEXT? +// +bool LDObject::previousIsInvertnext (LDBfc*& ptr) +{ + LDObject* prev = previous(); + + if (prev and prev->type() == LDObjectType::Bfc and static_cast<LDBfc*> (prev)->statement() == BfcStatement::InvertNext) + { + ptr = static_cast<LDBfc*> (prev); + return true; + } + + return false; +} + +// ============================================================================= +// +// Moves this object using the given vertex as a movement List +// +void LDObject::move (Vertex vect) +{ + if (hasMatrix()) + { + LDMatrixObject* mo = static_cast<LDMatrixObject*> (this); + mo->setPosition (mo->position() + vect); + } + else + { + for (int i = 0; i < numVertices(); ++i) + setVertex (i, vertex (i) + vect); + } +} + +bool LDObject::isHidden() const +{ + return m_isHidden; +} + +void LDObject::setHidden (bool value) +{ + m_isHidden = value; +} + +bool LDObject::isSelected() const +{ + return m_isSelected; +} + +qint32 LDObject::id() const +{ + return m_id; +} + +LDColor LDObject::color() const +{ + return m_color; +} + +QColor LDObject::randomColor() const +{ + return m_randomColor; +} + +Model* LDObject::model() const +{ + return _model; +} + +// ============================================================================= +// +void LDObject::invert() {} +void LDBfc::invert() {} +void LDError::invert() {} + +// ============================================================================= +// +void LDTriangle::invert() +{ + // Triangle goes 0 -> 1 -> 2, reversed: 0 -> 2 -> 1. + // Thus, we swap 1 and 2. + Vertex tmp = vertex (1); + setVertex (1, vertex (2)); + setVertex (2, tmp); + + return; +} + +// ============================================================================= +// +void LDQuadrilateral::invert() +{ + // Quad: 0 -> 1 -> 2 -> 3 + // reversed: 0 -> 3 -> 2 -> 1 + // Thus, we swap 1 and 3. + Vertex tmp = vertex (1); + setVertex (1, vertex (3)); + setVertex (3, tmp); +} + +// ============================================================================= +// +void LDSubfileReference::invert() +{ + if (model() == nullptr) + return; + + // Check whether subfile is flat + int axisSet = (1 << X) | (1 << Y) | (1 << Z); + Model model {this->model()->documentManager()}; + fileInfo()->inlineContents(model, true, false); + + for (LDObject* obj : model.objects()) + { + for (int i = 0; i < obj->numVertices(); ++i) + { + Vertex const& vrt = obj->vertex (i); + + if (axisSet & (1 << X) and vrt.x() != 0.0) + axisSet &= ~(1 << X); + + if (axisSet & (1 << Y) and vrt.y() != 0.0) + axisSet &= ~(1 << Y); + + if (axisSet & (1 << Z) and vrt.z() != 0.0) + axisSet &= ~(1 << Z); + } + + if (axisSet == 0) + break; + } + + if (axisSet != 0) + { + // Subfile has all vertices zero on one specific plane, so it is flat. + // Let's flip it. + Matrix matrixModifier = Matrix::identity; + + if (axisSet & (1 << X)) + matrixModifier(0, 0) = -1; + + if (axisSet & (1 << Y)) + matrixModifier(1, 1) = -1; + + if (axisSet & (1 << Z)) + matrixModifier(2, 2) = -1; + + setTransformationMatrix (transformationMatrix() * matrixModifier); + return; + } + + // Subfile is not flat. Resort to invertnext. + int idx = lineNumber(); + + if (idx > 0) + { + LDBfc* bfc = dynamic_cast<LDBfc*> (previous()); + + if (bfc and bfc->statement() == BfcStatement::InvertNext) + { + // This is prefixed with an invertnext, thus remove it. + this->model()->remove(bfc); + return; + } + } + + // Not inverted, thus prefix it with a new invertnext. + this->model()->emplaceAt<LDBfc>(idx, BfcStatement::InvertNext); +} + +// ============================================================================= +// +void LDBezierCurve::invert() +{ + // A Bézier curve's control points probably need to be, though. + Vertex tmp = vertex (1); + setVertex (1, vertex (0)); + setVertex (0, tmp); + tmp = vertex (3); + setVertex (3, vertex (2)); + setVertex (2, tmp); +} + +// ============================================================================= +// +LDObject* LDObject::fromID(qint32 id) +{ + return g_allObjects.value(id); +} + +// ============================================================================= +// +void LDObject::setColor (LDColor color) +{ + changeProperty(&m_color, color); +} + +// ============================================================================= +// +// Get a vertex by index +// +const Vertex& LDObject::vertex (int i) const +{ + return m_coords[i]; +} + +// ============================================================================= +// +// Set a vertex to the given value +// +void LDObject::setVertex (int i, const Vertex& vert) +{ + changeProperty(&m_coords[i], vert); +} + +LDMatrixObject::LDMatrixObject (Model* model) : + LDObject (model), + m_position (Origin) {} + +LDMatrixObject::LDMatrixObject (const Matrix& transform, const Vertex& pos, Model* model) : + LDObject (model), + m_position (pos), + m_transformationMatrix (transform) {} + +void LDMatrixObject::setCoordinate (const Axis ax, double value) +{ + Vertex v = position(); + + switch (ax) + { + case X: v.setX (value); break; + case Y: v.setY (value); break; + case Z: v.setZ (value); break; + } + + setPosition (v); +} + +const Vertex& LDMatrixObject::position() const +{ + return m_position; +} + +// ============================================================================= +// +void LDMatrixObject::setPosition (const Vertex& a) +{ + changeProperty(&m_position, a); +} + +// ============================================================================= +// +const Matrix& LDMatrixObject::transformationMatrix() const +{ + return m_transformationMatrix; +} + +void LDMatrixObject::setTransformationMatrix (const Matrix& val) +{ + changeProperty(&m_transformationMatrix, val); +} + +LDError::LDError (QString contents, QString reason, Model* model) : + LDObject (model), + m_contents (contents), + m_reason (reason) {} + +QString LDError::reason() const +{ + return m_reason; +} + +QString LDError::contents() const +{ + return m_contents; +} + +QString LDError::fileReferenced() const +{ + return m_fileReferenced; +} + +void LDError::setFileReferenced (QString value) +{ + m_fileReferenced = value; +} + +LDBfc::LDBfc (const BfcStatement type, Model* model) : + LDObject {model}, + m_statement {type} {} + +BfcStatement LDBfc::statement() const +{ + return m_statement; +} + +void LDBfc::setStatement (BfcStatement value) +{ + m_statement = value; +} + +QString LDBfc::statementToString() const +{ + return LDBfc::statementToString (statement()); +} + +QString LDBfc::statementToString (BfcStatement statement) +{ + static const char* statementStrings[] = + { + "CERTIFY CCW", + "CCW", + "CERTIFY CW", + "CW", + "NOCERTIFY", + "INVERTNEXT", + "CLIP", + "CLIP CCW", + "CLIP CW", + "NOCLIP", + }; + + if ((int) statement >= 0 and (int) statement < countof (statementStrings)) + return QString::fromLatin1 (statementStrings[(int) statement]); + else + return ""; +} + +Vertex LDBezierCurve::pointAt (qreal t) const +{ + if (t >= 0.0 and t <= 1.0) + { + Vertex result; + result += pow (1.0 - t, 3) * vertex (0); + result += (3 * pow (1.0 - t, 2) * t) * vertex (2); + result += (3 * (1.0 - t) * pow (t, 2)) * vertex (3); + result += pow (t, 3) * vertex (1); + return result; + } + else + return Vertex(); +} + +void LDBezierCurve::rasterize(Model& model, int segments) +{ + QVector<LDPolygon> polygons = rasterizePolygons(segments); + + for (LDPolygon& poly : polygons) + { + LDEdgeLine* line = model.emplace<LDEdgeLine>(poly.vertices[0], poly.vertices[1]); + line->setColor (poly.color); + } +} + +QVector<LDPolygon> LDBezierCurve::rasterizePolygons(int segments) +{ + QVector<LDPolygon> result; + QVector<Vertex> parms; + parms.append (pointAt (0.0)); + + for (int i = 1; i < segments; ++i) + parms.append (pointAt (double (i) / segments)); + + parms.append (pointAt (1.0)); + LDPolygon poly; + poly.color = color().index(); + poly.id = id(); + poly.num = 2; + + for (int i = 0; i < segments; ++i) + { + poly.vertices[0] = parms[i]; + poly.vertices[1] = parms[i + 1]; + result << poly; + } + + return result; +} + +LDSubfileReference::LDSubfileReference(LDDocument* reference, const Matrix& transformationMatrix, + const Vertex& position, Model* model) : + LDMatrixObject {transformationMatrix, position, model}, + m_fileInfo {reference} {} + +// ============================================================================= +// +LDDocument* LDSubfileReference::fileInfo() const +{ + return m_fileInfo; +} + +void LDSubfileReference::setFileInfo (LDDocument* newReferee) +{ + changeProperty(&m_fileInfo, newReferee); + + if (model()) + model()->recountTriangles(); + + // If it's an immediate subfile reference (i.e. this subfile is in an opened document), we need to pre-compile the + // GL polygons for the document if they don't exist already. + if (newReferee and + newReferee->isFrozen() == false and + newReferee->polygonData().isEmpty()) + { + newReferee->initializeCachedData(); + } +} + +void LDObject::getVertices (QSet<Vertex>& verts) const +{ + for (int i = 0; i < numVertices(); ++i) + verts.insert(vertex(i)); +} + +void LDSubfileReference::getVertices (QSet<Vertex>& verts) const +{ + verts.unite(fileInfo()->inlineVertices()); +} + +QString LDObject::objectListText() const +{ + if (numVertices() > 0) + { + QString result; + + for (int i = 0; i < numVertices(); ++i) + { + if (i != 0) + result += ", "; + + result += vertex(i).toString (true); + } + + return result; + } + else + { + return typeName(); + } +} + +QString LDError::objectListText() const +{ + return "ERROR: " + asText(); +} + +QString LDSubfileReference::objectListText() const +{ + QString result = format ("%1 %2, (", fileInfo()->getDisplayName(), position().toString(true)); + + for (int i = 0; i < 9; ++i) + result += format("%1%2", transformationMatrix().value(i), (i != 8) ? " " : ""); + + result += ')'; + return result; +} + +QString LDBfc::objectListText() const +{ + return statementToString(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/linetypes/modelobject.h Tue Feb 14 14:59:26 2017 +0200 @@ -0,0 +1,351 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2017 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 <type_traits> +#include "../main.h" +#include "../basics.h" +#include "../glShared.h" +#include "../colors.h" + +class Model; +class LDDocument; + +/* + * Object type codes. + */ +enum LDObjectType +{ + SubfileReference, // Object represents a sub-file reference + Quadrilateral, // Object represents a quadrilateral + Triangle, // Object represents a triangle + EdgeLine, // Object represents a line + ConditionalEdge, // Object represents a conditional line + Bfc, // Object represents a BFC statement + Comment, // Object represents a comment + Error, // Object is the result of failed parsing + Empty, // Object represents an empty line + BezierCurve, // Object represents a Bézier curve + _End +}; + +MAKE_ITERABLE_ENUM(LDObjectType) + +/* + * Represents one line of code in an LDraw model file. + */ +class LDObject : public QObject +{ + Q_OBJECT + +public: + virtual QString asText() const = 0; // This object as LDraw code + LDColor color() const; + virtual LDColor defaultColor() const; // What color does the object default to? + Model* model() const; + LDPolygon* getPolygon(); + virtual void getVertices (QSet<Vertex>& verts) const; + virtual bool hasMatrix() const; // Does this object have a matrix and position? (see LDMatrixObject) + qint32 id() const; + virtual void invert(); // Inverts this object (winding is reversed) + virtual bool isColored() const; + bool isHidden() const; + virtual bool isScemantic() const; // Does this object have meaning in the part model? + bool isSelected() const; + int lineNumber() const; + void move (Vertex vect); + LDObject* next() const; + virtual int numVertices() const; + virtual QString objectListText() const; + LDObject* previous() const; + bool previousIsInvertnext(class LDBfc*& ptr); + QColor randomColor() const; + void setColor (LDColor color); + void setHidden (bool value); + void setVertex (int i, const Vertex& vert); + void swap (LDObject* other); + virtual int triangleCount() const; + virtual LDObjectType type() const = 0; + virtual QString typeName() const = 0; + const Vertex& vertex (int i) const; + + static LDObject* fromID(qint32 id); + +signals: + void codeChanged(QString before, QString after); + +protected: + friend class Model; + LDObject (Model* model = nullptr); + virtual ~LDObject(); + void setDocument(Model* model); + + template<typename T> + void changeProperty(T* property, const T& value); + +private: + bool m_isHidden; + bool m_isSelected; + Model* _model; + qint32 m_id; + LDColor m_color; + QColor m_randomColor; + Vertex m_coords[4]; +}; + +/* + * Base class for objects with matrices. + */ +class LDMatrixObject : public LDObject +{ + Vertex m_position; + +public: + const Vertex& position() const; + void setCoordinate (const Axis ax, double value); + void setPosition (const Vertex& a); + void setTransformationMatrix (const Matrix& value); + const Matrix& transformationMatrix() const; + +protected: + LDMatrixObject (Model* model = nullptr); + LDMatrixObject (const Matrix& transformationMatrix, const Vertex& pos, Model* model = nullptr); + +private: + Matrix m_transformationMatrix; +}; + +/* + * Represents a line in the LDraw file that could not be properly parsed. + */ +class LDError : public LDObject +{ +public: + static constexpr LDObjectType SubclassType = LDObjectType::Error; + + virtual LDObjectType type() const override + { + return SubclassType; + } + + virtual QString asText() const override; + virtual void invert() override; + QString reason() const; + QString contents() const; + QString fileReferenced() const; + void setFileReferenced (QString value); + QString objectListText() const override; + bool isColored() const override { return false; } + QString typeName() const override { return "error"; } + +protected: + friend class Model; + LDError (Model* model); + LDError (QString contents, QString reason, Model* model = nullptr); + +private: + QString m_fileReferenced; // If this error was caused by inability to open a file, what file was that? + QString m_contents; // The LDraw code that was being parsed + QString m_reason; +}; + +/* + * Represents a 0 BFC statement in the LDraw code. + */ +enum class BfcStatement +{ + CertifyCCW, + CCW, + CertifyCW, + CW, + NoCertify, + InvertNext, + Clip, + ClipCCW, + ClipCW, + NoClip, + _End +}; + +MAKE_ITERABLE_ENUM(BfcStatement) + +class LDBfc : public LDObject +{ + public: + static constexpr LDObjectType SubclassType = LDObjectType::Bfc; + + virtual LDObjectType type() const override + { + return SubclassType; + } + + virtual QString asText() const override; + virtual void invert() override; +protected: + friend class Model; + LDBfc (Model* model); + +public: + bool isScemantic() const override { return statement() == BfcStatement::InvertNext; } + QString objectListText() const override; + BfcStatement statement() const; + void setStatement (BfcStatement value); + QString statementToString() const; + bool isColored() const override { return false; } + QString typeName() const override { return "bfc"; } + + static QString statementToString (BfcStatement statement); + +protected: + LDBfc (const BfcStatement type, Model* model = nullptr); + +private: + BfcStatement m_statement; +}; + +/* + * Represents a single code-1 subfile reference. + */ +class LDSubfileReference : public LDMatrixObject +{ +public: + static constexpr LDObjectType SubclassType = LDObjectType::SubfileReference; + + virtual LDObjectType type() const override + { + return SubclassType; + } + + virtual QString asText() const override; + virtual void invert() override; + LDDocument* fileInfo() const; + virtual void getVertices (QSet<Vertex>& verts) const override; + void inlineContents(Model& model, bool deep, bool render); + QList<LDPolygon> inlinePolygons(); + QString objectListText() const override; + void setFileInfo (LDDocument* fileInfo); + int triangleCount() const override; + bool hasMatrix() const override { return true; } + QString typeName() const override { return "subfilereference"; } + +protected: + friend class Model; + LDSubfileReference (Model* model); + LDSubfileReference(LDDocument* reference, const Matrix& transformationMatrix, const Vertex& position, Model* model = nullptr); + +private: + LDDocument* m_fileInfo; +}; + +/* + * Represents a single code-3 triangle in the LDraw code file. + */ +class LDTriangle : public LDObject +{ +public: + static constexpr LDObjectType SubclassType = LDObjectType::Triangle; + + virtual LDObjectType type() const override + { + return SubclassType; + } + + virtual QString asText() const override; + virtual void invert() override; + int triangleCount() const override; + int numVertices() const override { return 3; } + QString typeName() const override { return "triangle"; } + +protected: + friend class Model; + LDTriangle (Model* model); + LDTriangle (Vertex const& v1, Vertex const& v2, Vertex const& v3, Model* model = nullptr); +}; + +/* + * Represents a single code-4 quadrilateral. + */ +class LDQuadrilateral : public LDObject +{ +public: + static constexpr LDObjectType SubclassType = LDObjectType::Quadrilateral; + + virtual LDObjectType type() const override + { + return SubclassType; + } + + QString asText() const override; + void invert() override; + int triangleCount() const override; + int numVertices() const override { return 4; } + QString typeName() const override { return "quad"; } + +protected: + friend class Model; + LDQuadrilateral (Model* model); + LDQuadrilateral (const Vertex& v1, const Vertex& v2, const Vertex& v3, const Vertex& v4, Model* model = nullptr); +}; + +/* + * Models a Bézier curve. It is stored as a special comment in the LDraw code file and can be inlined down into line segments. + */ +class LDBezierCurve : public LDObject +{ +public: + static constexpr LDObjectType SubclassType = LDObjectType::BezierCurve; + + virtual LDObjectType type() const override + { + return SubclassType; + } + + virtual QString asText() const override; + virtual void invert() override; + Vertex pointAt (qreal t) const; + void rasterize(Model& model, int segments); + QVector<LDPolygon> rasterizePolygons (int segments); + int numVertices() const override { return 4; } + LDColor defaultColor() const override { return EdgeColor; } + QString typeName() const override { return "beziercurve"; } + +protected: + friend class Model; + LDBezierCurve (Model* model); + LDBezierCurve (const Vertex& v0, const Vertex& v1, const Vertex& v2, const Vertex& v3, Model* model = nullptr); +}; + +enum +{ + LowResolution = 16, + HighResolution = 48 +}; + +/* + * Changes a property in a manner that emits the appropriate signal to notify that the object changed. + */ +template<typename T> +void LDObject::changeProperty(T* property, const T& value) +{ + if (*property != value) + { + QString before = asText(); + *property = value; + emit codeChanged(before, asText()); + } +}
--- a/src/mainwindow.h Tue Feb 14 14:53:06 2017 +0200 +++ b/src/mainwindow.h Tue Feb 14 14:59:26 2017 +0200 @@ -24,7 +24,7 @@ #include <QRadioButton> #include <QTreeWidget> #include <QMetaMethod> -#include "ldObject.h" +#include "linetypes/modelobject.h" #include "colors.h" #include "doublemap.h"
--- a/src/mathfunctions.cpp Tue Feb 14 14:53:06 2017 +0200 +++ b/src/mathfunctions.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -17,7 +17,7 @@ */ #include "mathfunctions.h" -#include "ldObject.h" +#include "linetypes/modelobject.h" #include "miscallenous.h"
--- a/src/model.cpp Tue Feb 14 14:53:06 2017 +0200 +++ b/src/model.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -17,7 +17,7 @@ */ #include "model.h" -#include "ldObject.h" +#include "linetypes/modelobject.h" #include "documentmanager.h" #include "linetypes/comment.h" #include "linetypes/conditionaledge.h"
--- a/src/model.h Tue Feb 14 14:53:06 2017 +0200 +++ b/src/model.h Tue Feb 14 14:59:26 2017 +0200 @@ -18,7 +18,7 @@ #pragma once #include "main.h" -#include "ldObject.h" +#include "linetypes/modelobject.h" /* * This class represents a LDraw model, consisting of a vector of objects. It manages LDObject ownership.
--- a/src/toolsets/basictoolset.cpp Tue Feb 14 14:53:06 2017 +0200 +++ b/src/toolsets/basictoolset.cpp Tue Feb 14 14:59:26 2017 +0200 @@ -24,7 +24,7 @@ #include <QVBoxLayout> #include "../canvas.h" #include "../lddocument.h" -#include "../ldObject.h" +#include "../linetypes/modelobject.h" #include "../ldobjectiterator.h" #include "../mainwindow.h" #include "../dialogs/colorselector.h"