src/basics.cpp

Thu, 04 Jan 2018 20:21:36 +0200

author
Santeri Piippo
date
Thu, 04 Jan 2018 20:21:36 +0200
changeset 1219
8e39b5d7c562
parent 1218
e0b59d183f96
child 1222
34def2630300
permissions
-rw-r--r--

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;
}

mercurial