src/types.cpp

Thu, 05 Dec 2013 23:20:50 +0200

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Thu, 05 Dec 2013 23:20:50 +0200
changeset 539
72ad83a67165
parent 538
2f85d4d286e5
child 541
0e38beeb050a
permissions
-rw-r--r--

- upgraded the PROPERTY macro, resulting in a major code refactor

/*
 *  LDForge: LDraw parts authoring CAD
 *  Copyright (C) 2013 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 "common.h"
#include "types.h"
#include "misc.h"
#include "ldtypes.h"
#include "file.h"

// =============================================================================
// -----------------------------------------------------------------------------
str DoFormat (QList<StringFormatArg> args)
{	assert (args.size() >= 1);
	str 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 (const Axis ax : g_Axes)
		m_coords[ax] += other[ax];
}

// =============================================================================
// -----------------------------------------------------------------------------
vertex vertex::midpoint (const vertex& other)
{	vertex mid;

	for (const Axis ax : g_Axes)
		mid[ax] = (m_coords[ax] + other[ax]) / 2;

	return mid;
}

// =============================================================================
// -----------------------------------------------------------------------------
str vertex::stringRep (bool mangled) const
{	str 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 (const Axis ax : g_Axes)
		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");
	}
}

// =============================================================================
// -----------------------------------------------------------------------------
str matrix::stringRep() const
{	str val;

	for (int i = 0; i < 9; ++i)
	{	if (i > 0)
			val += ' ';

		val += str::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 str& 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 = str::number (v);
}

StringFormatArg::StringFormatArg (const double& v)
{	m_val = str::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 StringConfig& v)
{	m_val = v.value;
}

StringFormatArg::StringFormatArg (const IntConfig& v)
{	m_val.number (v.value);
}

StringFormatArg::StringFormatArg (const FloatConfig& v)
{	m_val.number (v.value);
}

StringFormatArg::StringFormatArg (const void* v)
{	m_val.sprintf ("%p", v);
}

// =============================================================================
// -----------------------------------------------------------------------------
File::File()
{	// Make a null file
	m_file = null;
	m_textstream = null;
}

File::File (str path, OpenType rtype)
{	m_file = null;
	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 (str 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);
		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 (str msg)
{	m_file->write (msg.toUtf8(), msg.length());
}

// =============================================================================
// -----------------------------------------------------------------------------
bool File::readLine (str& 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);
}

// =============================================================================
// -----------------------------------------------------------------------------
str 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 (!LDFile::current())
		return;

	for (LDObject* obj : LDFile::current()->getObjects())
		calcObject (obj);
}

// =============================================================================
// -----------------------------------------------------------------------------
void LDBoundingBox::calcObject (LDObject* obj)
{	switch (obj->getType())
	{	case LDObject::Line:
		case LDObject::Triangle:
		case LDObject::Quad:
		case LDObject::CndLine:
		{	for (int i = 0; i < obj->vertices(); ++i)
				calcVertex (obj->getVertex (i));
		} break;

		case LDObject::Subfile:
		{	LDSubfile* ref = static_cast<LDSubfile*> (obj);
			QList<LDObject*> objs = ref->inlineContents (LDSubfile::DeepCacheInline);

			for (LDObject * obj : objs)
			{	calcObject (obj);
				delete obj;
			}
		}
		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 (const Axis ax : g_Axes)
	{	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);
}

mercurial