Thu, 04 Jan 2018 20:21:36 +0200
simplified Matrix
/* * LDForge: LDraw parts authoring CAD * Copyright (C) 2013 - 2015 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 <QObject> #include <QStringList> #include <QTextStream> #include <QFile> #include <assert.h> #include "main.h" #include "basics.h" #include "miscallenous.h" #include "ldObject.h" #include "ldDocument.h" Vertex::Vertex() : QVector3D {0, 0, 0} {} Vertex::Vertex(const QVector3D& a) : QVector3D(a) {} Vertex::Vertex(qreal xpos, qreal ypos, qreal zpos) : QVector3D(xpos, ypos, zpos) {} void Vertex::transform(const Matrix& matr, const Vertex& pos) { double x2 = (matr[0] * x()) +(matr[1] * y()) +(matr[2] * z()) + pos.x(); double y2 = (matr[3] * x()) +(matr[4] * y()) +(matr[5] * z()) + pos.y(); double z2 = (matr[6] * x()) +(matr[7] * y()) +(matr[8] * z()) + pos.z(); setX(x2); setY(y2); setZ(z2); } void Vertex::apply(ApplyFunction func) { double newX = x(), newY = y(), newZ = z(); func(X, newX); func(Y, newY); func(Z, newZ); *this = Vertex(newX, newY, newZ); } void Vertex::apply(ApplyConstFunction func) const { func(X, x()); func(Y, y()); func(Z, z()); } double Vertex::operator[](Axis ax) const { switch(ax) { case X: return x(); case Y: return y(); case Z: return z(); } return 0.0; } void Vertex::setCoordinate(Axis ax, qreal value) { switch(ax) { case X: setX(value); break; case Y: setY(value); break; case Z: setZ(value); break; } } QString Vertex::toString(bool mangled) const { if (mangled) return format("(%1, %2, %3)", x(), y(), z()); return format("%1 %2 %3", x(), y(), z()); } Vertex Vertex::operator*(qreal scalar) const { return Vertex(x() * scalar, y() * scalar, z() * scalar); } Vertex& Vertex::operator+= (const Vertex& other) { setX(x() + other.x()); setY(y() + other.y()); setZ(z() + other.z()); return *this; } Vertex Vertex::operator+(const Vertex& other) const { Vertex result(*this); result += other; return result; } Vertex& Vertex::operator*= (qreal scalar) { setX(x() * scalar); setY(y() * scalar); setZ(z() * scalar); return *this; } bool Vertex::operator<(const Vertex& other) const { if (x() != other.x()) return x() < other.x(); if (y() != other.y()) return y() < other.y(); if (z() != other.z()) return z() < other.z(); return false; } Matrix::Matrix() : coefficients {1, 0, 0, 0, 1, 0, 0, 0, 1} {} Matrix::Matrix(std::initializer_list<double> values) { if (values.size() == 9) memcpy(&coefficients[0], values.begin(), sizeof coefficients); } QString Matrix::toString() const { QString val; for (int i = 0; i < countof(coefficients); ++i) { if (i > 0) val += ' '; val += QString::number(coefficients[i]); } return val; } void Matrix::zero() { for (int i = 0; i < countof(coefficients); ++i) coefficients[i] = 0; } Matrix Matrix::operator*(const Matrix& other) const { Matrix result; result.zero(); for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) for (int k = 0; k < 3; ++k) result(i, j) += (*this)(i, k) * other(k, j); return result; } Matrix& Matrix::operator=(const Matrix& other) { for (int i = 0; i < countof(coefficients); ++i) (*this)[i] = other[i]; return *this; } double Matrix::determinant() const { return (*this)(0, 0) * (*this)(1, 1) * (*this)(2, 2) + (*this)(0, 1) * (*this)(1, 2) * (*this)(2, 0) + (*this)(0, 2) * (*this)(1, 0) * (*this)(2, 1) - (*this)(0, 2) * (*this)(1, 1) * (*this)(2, 0) - (*this)(0, 1) * (*this)(1, 0) * (*this)(2, 2) - (*this)(0, 0) * (*this)(1, 2) * (*this)(2, 1); } bool Matrix::operator== (const Matrix& other) const { for (int i = 0; i < countof(coefficients); ++i) { if ((*this)[i] != other[i]) return false; } return true; } LDBoundingBox::LDBoundingBox() { reset(); } // ============================================================================= // void LDBoundingBox::calcObject(LDObject* obj) { switch(obj->type()) { case OBJ_Line: case OBJ_Triangle: case OBJ_Quad: case OBJ_CondLine: for (int i = 0; i < obj->numVertices(); ++i) calcVertex(obj->vertex(i)); break; case OBJ_SubfileReference: for (LDObject* it : static_cast<LDSubfileReference*>(obj)->inlineContents(true, false)) { calcObject(it); it->destroy(); } break; default: break; } } // ============================================================================= // LDBoundingBox& LDBoundingBox::operator<<(const Vertex& v) { calcVertex(v); return *this; } // ============================================================================= // LDBoundingBox& LDBoundingBox::operator<<(LDObject* obj) { calcObject(obj); return *this; } // ============================================================================= // void LDBoundingBox::calcVertex(const Vertex& vertex) { m_vertex0.setX(qMin(vertex.x(), m_vertex0.x())); m_vertex0.setY(qMin(vertex.y(), m_vertex0.y())); m_vertex0.setZ(qMin(vertex.z(), m_vertex0.z())); m_vertex1.setX(qMax(vertex.x(), m_vertex1.x())); m_vertex1.setY(qMax(vertex.y(), m_vertex1.y())); m_vertex1.setZ(qMax(vertex.z(), m_vertex1.z())); m_isEmpty = false; } // ============================================================================= // // Clears the bounding box // void LDBoundingBox::reset() { m_vertex0 = Vertex(10000.0, 10000.0, 10000.0); m_vertex1 = Vertex(-10000.0, -10000.0, -10000.0); m_isEmpty = true; } // ============================================================================= // // Returns the length of the bounding box on the longest measure. // double LDBoundingBox::longestMeasurement() const { double xscale = (m_vertex0.x() - m_vertex1.x()); double yscale = (m_vertex0.y() - m_vertex1.y()); double zscale = (m_vertex0.z() - m_vertex1.z()); double size = zscale; if (xscale > yscale) { if (xscale > zscale) size = xscale; } else if (yscale > zscale) size = yscale; if (qAbs(size) >= 2.0) return qAbs(size / 2); return 1.0; } // ============================================================================= // // Yields the center of the bounding box. // Vertex LDBoundingBox::center() const { return Vertex( (m_vertex0.x() + m_vertex1.x()) / 2, (m_vertex0.y() + m_vertex1.y()) / 2, (m_vertex0.z() + m_vertex1.z()) / 2); } bool LDBoundingBox::isEmpty() const { return m_isEmpty; } const Vertex& LDBoundingBox::vertex0() const { return m_vertex0; } const Vertex& LDBoundingBox::vertex1() const { return m_vertex1; }