Wed, 08 Jan 2014 13:57:10 +0200
- if loading another file to replace an explicitly loaded file, this file won't get closed automatically and thus needs to be manually closed. We also need to check that it's safe to close before doing this. Also fixed a rather argh problem with ::save not using the proper path...
/* * LDForge: LDraw parts authoring CAD * Copyright (C) 2013, 2014 Santeri 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 "types.h" #include "misc.h" #include "ldtypes.h" #include "document.h" // ============================================================================= // ----------------------------------------------------------------------------- QString DoFormat (QList<StringFormatArg> args) { assert (args.size() >= 1); QString text = args[0].value(); for (uchar i = 1; i < args.size(); ++i) text = text.arg (args[i].value()); return text; } // ============================================================================= // ----------------------------------------------------------------------------- Vertex::Vertex (double x, double y, double z) { m_coords[X] = x; m_coords[Y] = y; m_coords[Z] = z; } // ============================================================================= // ----------------------------------------------------------------------------- void Vertex::move (const Vertex& other) { for_axes (ax) m_coords[ax] += other[ax]; } // ============================================================================= // ----------------------------------------------------------------------------- double Vertex::distanceTo (const Vertex& other) const { double dx = abs (x() - other.x()); double dy = abs (y() - other.y()); double dz = abs (z() - other.z()); return sqrt ((dx * dx) + (dy * dy) + (dz * dz)); } // ============================================================================= // ----------------------------------------------------------------------------- Vertex Vertex::midpoint (const Vertex& other) { Vertex mid; for_axes (ax) mid[ax] = (m_coords[ax] + other[ax]) / 2; return mid; } // ============================================================================= // ----------------------------------------------------------------------------- QString Vertex::stringRep (bool mangled) const { QString fmtstr = "%1 %2 %3"; if (mangled) fmtstr = "(%1, %2, %3)"; return fmt (fmtstr, coord (X), coord (Y), coord (Z)); } // ============================================================================= // ----------------------------------------------------------------------------- void Vertex::transform (Matrix matr, 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]; x() = x2; y() = y2; z() = z2; } // ============================================================================= // ----------------------------------------------------------------------------- Vertex Vertex::operator-() const { return Vertex (-m_coords[X], -m_coords[Y], -m_coords[Z]); } // ============================================================================= // ----------------------------------------------------------------------------- bool Vertex::operator!= (const Vertex& other) const { return !operator== (other); } // ============================================================================= // ----------------------------------------------------------------------------- double& Vertex::operator[] (const Axis ax) { return coord ( (int) ax); } const double& Vertex::operator[] (const Axis ax) const { return coord ( (int) ax); } double& Vertex::operator[] (const int ax) { return coord (ax); } const double& Vertex::operator[] (const int ax) const { return coord (ax); } // ============================================================================= // ----------------------------------------------------------------------------- bool Vertex::operator== (const Vertex& other) const { return coord (X) == other[X] && coord (Y) == other[Y] && coord (Z) == other[Z]; } // ============================================================================= // ----------------------------------------------------------------------------- Vertex& Vertex::operator/= (const double d) { for_axes (ax) m_coords[ax] /= d; return *this; } // ============================================================================= // ----------------------------------------------------------------------------- Vertex Vertex::operator/ (const double d) const { Vertex other (*this); return other /= d; } // ============================================================================= // ----------------------------------------------------------------------------- Vertex& Vertex::operator+= (const Vertex& other) { move (other); return *this; } // ============================================================================= // ----------------------------------------------------------------------------- Vertex Vertex::operator+ (const Vertex& other) const { Vertex newvert (*this); newvert.move (other); return newvert; } // ============================================================================= // ----------------------------------------------------------------------------- int Vertex::operator< (const Vertex& other) const { if (operator== (other)) return false; if (coord (X) < other[X]) return true; if (coord (X) > other[X]) return false; if (coord (Y) < other[Y]) return true; if (coord (Y) > other[Y]) return false; return coord (Z) < other[Z]; } // ============================================================================= // ----------------------------------------------------------------------------- Matrix::Matrix (double vals[]) { for (int i = 0; i < 9; ++i) m_vals[i] = vals[i]; } // ============================================================================= // ----------------------------------------------------------------------------- Matrix::Matrix (double fillval) { for (int i = 0; i < 9; ++i) m_vals[i] = fillval; } // ============================================================================= // ----------------------------------------------------------------------------- Matrix::Matrix (initlist<double> vals) { assert (vals.size() == 9); memcpy (&m_vals[0], & (*vals.begin()), sizeof m_vals); } // ============================================================================= // ----------------------------------------------------------------------------- void Matrix::puts() const { for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) log ("%1\t", m_vals[ (i * 3) + j]); log ("\n"); } } // ============================================================================= // ----------------------------------------------------------------------------- QString Matrix::stringRep() const { QString val; for (int i = 0; i < 9; ++i) { if (i > 0) val += ' '; val += QString::number (m_vals[i]); } return val; } // ============================================================================= // ----------------------------------------------------------------------------- void Matrix::zero() { memset (&m_vals[0], 0, sizeof m_vals); } // ============================================================================= // ----------------------------------------------------------------------------- Matrix Matrix::mult (Matrix other) const { Matrix val; val.zero(); for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) for (int k = 0; k < 3; ++k) val[(i * 3) + j] += m_vals[(i * 3) + k] * other[(k * 3) + j]; return val; } // ============================================================================= // ----------------------------------------------------------------------------- Matrix& Matrix::operator= (Matrix other) { memcpy (&m_vals[0], &other.m_vals[0], sizeof m_vals); return *this; } // ============================================================================= // ----------------------------------------------------------------------------- double Matrix::getDeterminant() const { return (val (0) * val (4) * val (8)) + (val (1) * val (5) * val (6)) + (val (2) * val (3) * val (7)) - (val (2) * val (4) * val (6)) - (val (1) * val (3) * val (8)) - (val (0) * val (5) * val (7)); } // ============================================================================= // ----------------------------------------------------------------------------- bool Matrix::operator== (const Matrix& other) const { for (int i = 0; i < 9; ++i) if (val (i) != other[i]) return false; return true; } // ============================================================================= // ----------------------------------------------------------------------------- StringFormatArg::StringFormatArg (const QString& v) { m_val = v; } StringFormatArg::StringFormatArg (const char& v) { m_val = v; } StringFormatArg::StringFormatArg (const uchar& v) { m_val = v; } StringFormatArg::StringFormatArg (const QChar& v) { m_val = v; } StringFormatArg::StringFormatArg (const float& v) { m_val = QString::number (v); } StringFormatArg::StringFormatArg (const double& v) { m_val = QString::number (v); } StringFormatArg::StringFormatArg (const Vertex& v) { m_val = v.stringRep (false); } StringFormatArg::StringFormatArg (const Matrix& v) { m_val = v.stringRep(); } StringFormatArg::StringFormatArg (const char* v) { m_val = v; } StringFormatArg::StringFormatArg (const void* v) { m_val.sprintf ("%p", v); } // ============================================================================= // ----------------------------------------------------------------------------- File::File() { // Make a null file m_file = null; m_textstream = null; } File::File (QString path, OpenType rtype) { m_file = null; m_path = path; open (path, rtype); } File::File (FILE* fp, OpenType rtype) { m_file = null; open (fp, rtype); } // ============================================================================= // ----------------------------------------------------------------------------- File::~File() { if (m_file) { m_file->close(); delete m_file; if (m_textstream) delete m_textstream; } } // ============================================================================= // ----------------------------------------------------------------------------- bool File::open (FILE* fp, OpenType rtype) { return open ("", rtype, fp); } bool File::open (QString path, OpenType rtype, FILE* fp) { close(); if (!m_file) m_file = new QFile; m_file->setFileName (path); bool result; QIODevice::OpenMode mode = (rtype == Read) ? QIODevice::ReadOnly : (rtype == Write) ? QIODevice::WriteOnly : QIODevice::Append; if (fp) result = m_file->open (fp, mode); else result = m_file->open (mode); if (result) { m_textstream = new QTextStream (m_file); m_path = path; return true; } delete m_file; m_file = null; return false; } // ============================================================================= // ----------------------------------------------------------------------------- File::iterator File::begin() { return iterator (this); } File::iterator& File::end() { return m_endIterator; } // ============================================================================= // ----------------------------------------------------------------------------- void File::write (QString msg) { m_file->write (msg.toUtf8(), msg.length()); } // ============================================================================= // ----------------------------------------------------------------------------- bool File::readLine (QString& line) { if (!m_textstream || m_textstream->atEnd()) return false; line = m_textstream->readLine(); return true; } // ============================================================================= // ----------------------------------------------------------------------------- bool File::atEnd() const { assert (m_textstream != null); return m_textstream->atEnd(); } // ============================================================================= // ----------------------------------------------------------------------------- bool File::isNull() const { return m_file == null; } bool File::operator!() const { return isNull(); } // ============================================================================= // ----------------------------------------------------------------------------- void File::close() { if (!m_file) return; delete m_file; m_file = null; if (m_textstream) { delete m_textstream; m_textstream = null; } } // ============================================================================= // ----------------------------------------------------------------------------- bool File::flush() { return m_file->flush(); } // ============================================================================= // ----------------------------------------------------------------------------- File::operator bool() const { return !isNull(); } // ============================================================================= // ----------------------------------------------------------------------------- void File::rewind() { m_file->seek (0); } // ============================================================================= // ----------------------------------------------------------------------------- File::iterator::iterator (File* f) : m_file (f) { operator++(); } // ============================================================================= // ----------------------------------------------------------------------------- void File::iterator::operator++() { m_gotdata = m_file->readLine (m_text); } // ============================================================================= // ----------------------------------------------------------------------------- QString File::iterator::operator*() { return m_text; } // ============================================================================= // The prime contestant for the weirdest operator== 2013 award? // ----------------------------------------------------------------------------- bool File::iterator::operator== (File::iterator& other) { return (other.m_file == null && !m_gotdata); } // ============================================================================= // ----------------------------------------------------------------------------- bool File::iterator::operator!= (File::iterator& other) { return !operator== (other); } // ============================================================================= // ----------------------------------------------------------------------------- LDBoundingBox::LDBoundingBox() { reset(); } // ============================================================================= // ----------------------------------------------------------------------------- void LDBoundingBox::calculate() { reset(); if (!getCurrentDocument()) return; for (LDObject* obj : getCurrentDocument()->getObjects()) calcObject (obj); } // ============================================================================= // ----------------------------------------------------------------------------- void LDBoundingBox::calcObject (LDObject* obj) { switch (obj->getType()) { case LDObject::ELine: case LDObject::ETriangle: case LDObject::EQuad: case LDObject::ECondLine: { for (int i = 0; i < obj->vertices(); ++i) calcVertex (obj->getVertex (i)); } break; case LDObject::ESubfile: { LDSubfile* ref = static_cast<LDSubfile*> (obj); QList<LDObject*> objs = ref->inlineContents (LDSubfile::DeepCacheInline); for (LDObject * obj : objs) { calcObject (obj); obj->deleteSelf(); } } 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& v) { for_axes (ax) { if (v[ax] < m_Vertex0[ax]) m_Vertex0[ax] = v[ax]; if (v[ax] > m_Vertex1[ax]) m_Vertex1[ax] = v[ax]; } setEmpty (false); } // ============================================================================= // ----------------------------------------------------------------------------- void LDBoundingBox::reset() { m_Vertex0[X] = m_Vertex0[Y] = m_Vertex0[Z] = 0x7FFFFFFF; m_Vertex1[X] = m_Vertex1[Y] = m_Vertex1[Z] = 0xFFFFFFFF; setEmpty (true); } // ============================================================================= // ----------------------------------------------------------------------------- double LDBoundingBox::size() 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; } elif (yscale > zscale) size = yscale; if (abs (size) >= 2.0f) return abs (size / 2); return 1.0f; } // ============================================================================= // ----------------------------------------------------------------------------- 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); }