--- a/src/model.cpp Thu Mar 15 18:51:58 2018 +0200 +++ b/src/model.cpp Fri Mar 16 11:50:35 2018 +0200 @@ -20,12 +20,6 @@ #include "linetypes/modelobject.h" #include "documentmanager.h" #include "generics/migrate.h" -#include "linetypes/comment.h" -#include "linetypes/conditionaledge.h" -#include "linetypes/edgeline.h" -#include "linetypes/empty.h" -#include "linetypes/quadrilateral.h" -#include "linetypes/triangle.h" #include "editHistory.h" Model::Model(DocumentManager* manager) : @@ -291,244 +285,6 @@ return _manager; } -// ============================================================================= -// -static void CheckTokenCount (const QStringList& tokens, int num) -{ - if (countof(tokens) != num) - throw QString (format ("Bad amount of tokens, expected %1, got %2", num, countof(tokens))); -} - -// ============================================================================= -// -static void CheckTokenNumbers (const QStringList& tokens, int min, int max) -{ - bool ok; - QRegExp scientificRegex ("\\-?[0-9]+\\.[0-9]+e\\-[0-9]+"); - - for (int i = min; i <= max; ++i) - { - // Check for floating point - tokens[i].toDouble (&ok); - if (ok) - return; - - // Check hex - if (tokens[i].startsWith ("0x")) - { - tokens[i].mid (2).toInt (&ok, 16); - - if (ok) - return; - } - - // Check scientific notation, e.g. 7.99361e-15 - if (scientificRegex.exactMatch (tokens[i])) - return; - - throw QString (format ("Token #%1 was `%2`, expected a number (matched length: %3)", - (i + 1), tokens[i], scientificRegex.matchedLength())); - } -} - -// ============================================================================= -// -static Vertex ParseVertex (QStringList& s, const int n) -{ - Vertex v; - v.apply ([&] (Axis ax, double& a) { a = s[n + ax].toDouble(); }); - return v; -} - -static qint32 StringToNumber (QString a, bool* ok = nullptr) -{ - int base = 10; - - if (a.startsWith ("0x")) - { - a.remove (0, 2); - base = 16; - } - - return a.toLong (ok, base); -} - -// ============================================================================= -// This is the LDraw code parser function. It takes in a string containing LDraw -// code and returns the object parsed from it. parseLine never returns null, -// the object will be LDError if it could not be parsed properly. -// ============================================================================= -LDObject* Model::insertFromString(int position, QString line) -{ - try - { - QStringList tokens = line.split(" ", QString::SkipEmptyParts); - - if (countof(tokens) <= 0) - { - // Line was empty, or only consisted of whitespace - return emplaceAt<LDEmpty>(position); - } - - if (countof(tokens[0]) != 1 or not tokens[0][0].isDigit()) - throw QString ("Illogical line code"); - - int num = tokens[0][0].digitValue(); - - switch (num) - { - case 0: - { - // Comment - QString commentText = line.mid (line.indexOf ("0") + 2); - QString commentTextSimplified = commentText.simplified(); - - // Handle BFC statements - if (countof(tokens) > 2 and tokens[1] == "BFC") - { - for (BfcStatement statement : iterateEnum<BfcStatement>()) - { - if (commentTextSimplified == format("BFC %1", LDBfc::statementToString (statement))) - return emplaceAt<LDBfc>(position, statement); - } - - // MLCAD is notorious for stuffing these statements in parts it - // creates. The above block only handles valid statements, so we - // need to handle MLCAD-style invertnext, clip and noclip separately. - if (commentTextSimplified == "BFC CERTIFY INVERTNEXT") - return emplaceAt<LDBfc>(position, BfcStatement::InvertNext); - else if (commentTextSimplified == "BFC CERTIFY CLIP") - return emplaceAt<LDBfc>(position, BfcStatement::Clip); - else if (commentTextSimplified == "BFC CERTIFY NOCLIP") - return emplaceAt<LDBfc>(position, BfcStatement::NoClip); - } - - if (countof(tokens) > 2 and tokens[1] == "!LDFORGE") - { - // Handle LDForge-specific types, they're embedded into comments too - if (tokens[2] == "BEZIER_CURVE") - { - CheckTokenCount (tokens, 16); - CheckTokenNumbers (tokens, 3, 15); - LDBezierCurve* obj = emplaceAt<LDBezierCurve>(position); - obj->setColor (StringToNumber (tokens[3])); - - for (int i = 0; i < 4; ++i) - obj->setVertex (i, ParseVertex (tokens, 4 + (i * 3))); - - return obj; - } - } - - // Just a regular comment: - return emplaceAt<LDComment>(position, commentText); - } - - case 1: - { - // Subfile - CheckTokenCount (tokens, 15); - CheckTokenNumbers (tokens, 1, 13); - - Vertex referncePosition = ParseVertex (tokens, 2); // 2 - 4 - Matrix transform; - - for (int i = 0; i < 9; ++i) - transform.value(i) = tokens[i + 5].toDouble(); // 5 - 13 - - LDSubfileReference* obj = emplaceAt<LDSubfileReference>(position, tokens[14], transform, referncePosition); - obj->setColor (StringToNumber (tokens[1])); - return obj; - } - - case 2: - { - CheckTokenCount (tokens, 8); - CheckTokenNumbers (tokens, 1, 7); - - // Line - LDEdgeLine* obj = emplaceAt<LDEdgeLine>(position); - obj->setColor (StringToNumber (tokens[1])); - - for (int i = 0; i < 2; ++i) - obj->setVertex (i, ParseVertex (tokens, 2 + (i * 3))); // 2 - 7 - - return obj; - } - - case 3: - { - CheckTokenCount (tokens, 11); - CheckTokenNumbers (tokens, 1, 10); - - // Triangle - LDTriangle* obj = emplaceAt<LDTriangle>(position); - obj->setColor (StringToNumber (tokens[1])); - - for (int i = 0; i < 3; ++i) - obj->setVertex (i, ParseVertex (tokens, 2 + (i * 3))); // 2 - 10 - - return obj; - } - - case 4: - case 5: - { - CheckTokenCount (tokens, 14); - CheckTokenNumbers (tokens, 1, 13); - - // Quadrilateral / Conditional line - LDObject* obj; - - if (num == 4) - obj = emplaceAt<LDQuadrilateral>(position); - else - obj = emplaceAt<LDConditionalEdge>(position); - - obj->setColor (StringToNumber (tokens[1])); - - for (int i = 0; i < 4; ++i) - obj->setVertex (i, ParseVertex (tokens, 2 + (i * 3))); // 2 - 13 - - return obj; - } - - default: - throw QString {"Unknown line code number"}; - } - } - catch (QString& errorMessage) - { - // Strange line we couldn't parse - return emplaceAt<LDError>(position, line, errorMessage); - } -} - -/* - * Given an LDraw object string, parses it and inserts it into the model. - */ -LDObject* Model::addFromString(QString line) -{ - return insertFromString(size(), line); -} - -/* - * Replaces the given object with a new one that is parsed from the given LDraw object string. - * If the parsing fails, the object is replaced with an error object. - */ -LDObject* Model::replaceWithFromString(LDObject* object, QString line) -{ - QModelIndex index = this->indexOf(object); - - if (index.isValid()) - { - removeAt(index.row()); - return insertFromString(index.row(), line); - } - else - return nullptr; -} - IndexGenerator Model::indices() const { return {this};