src/model.h

Mon, 06 Mar 2017 00:43:43 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Mon, 06 Mar 2017 00:43:43 +0200
changeset 1198
f7151e4cd90f
parent 1188
872c4a3f4151
permissions
-rw-r--r--

MathFunctions is now a namespace.

/*
 *  LDForge: LDraw parts authoring CAD
 *  Copyright (C) 2013 - 2017 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/>.
 */

#pragma once
#include "main.h"
#include "linetypes/modelobject.h"
#include "types/resourcevector.h"

/*
 * This class represents a LDraw model, consisting of a vector of objects. It manages LDObject ownership.
 */
class Model : public QObject
{
	Q_OBJECT

public:
	using Filter = std::function<bool(LDObject*)>;
	using Callback = std::function<void(LDObject*, int)>;

	Model(class DocumentManager* manager);
	Model(const Model& other) = delete;

	template<typename T, typename... Args> T* append(Args&& ...args);
	LDObject* appendFromString(QString line);
	LDObject* const* begin();
	void clear();
	class DocumentManager* documentManager() const;
	LDObject* const* end();
	LDObject* getObject(int position) const;
	template<typename T, typename... Args> T* insert(int position, Args&& ...args);
	LDObject* insertFromString(int position, QString line);
	bool isEmpty() const;
	void merge(Model& other, int position = -1, Filter filter = nullptr, Callback callback = nullptr);
	const ResourceVector<LDObject>& objects() const;
	void recountTriangles();
	void remove(LDObject* object);
	void removeAt(int position);
	template<typename T, typename... Args> T* replace(LDObject* object, Args&& ...args);
	void replace(LDObject* object, Model& model);
	LDObject* replaceWithFromString(LDObject* object, QString line);
	int size() const;
	bool swapObjects(LDObject* one, LDObject* other);
	int triangleCount() const;

signals:
	void objectAdded(LDObject* object, int position);
	void aboutToRemoveObject(LDObject* object, int position);
	void objectModified(LDObject* object);
	void objectsSwapped(LDObject* one, LDObject* other);

protected:
	template<typename T, typename... Args> T* constructObject(Args&& ...args);

	ResourceVector<LDObject> _objects;
	class DocumentManager* _manager;
	mutable int _triangleCount = 0;
	mutable bool _needsTriangleRecount;

private:
	void finalizeNewObject(int position, LDObject* object);
	ResourceVector<LDObject>& mutableObjects();
};

int countof(Model& model);

/*
 * Given an LDObject type as the template parameter, and any number of variadic parameters, constructs an LDObject derivative
 * and inserts it into this model. The variadic parameters and this model pointer are passed to the constructor. The constructed object
 * is added to the end of the model.
 *
 * For instance, the LDLine contains a constructor as such:
 *
 *     LDLine(Vertex v1, Vertex v2, Model* model);
 *
 * This constructor can be invoked as such:
 *
 *     model->append<LDLine>(v1, v2);
 */
template<typename T, typename... Args>
T* Model::append(Args&& ...args)
{
	T* object = _objects.append<T>(args..., this);
	finalizeNewObject(size() - 1, object);
	return object;
}

/*
 * Like append<>() but also takes a position as the first argument and emplaces the object at the given position instead of the
 * end of the model.
 */
template<typename T, typename... Args>
T* Model::insert(int position, Args&& ...args)
{
	T* object = _objects.insert<T>(position, args..., this);
	finalizeNewObject(position, object);
	return object;
}

/*
 * Like append<>() but instead of inserting the constructed object, the new object replaces the object given in the first parameter.
 * If the old object cannot be replaced, the new object will not be constructed at all.
 */
template<typename T, typename... Args>
T* Model::replace(LDObject* object, Args&& ...args)
{
	if (object->model() == this)
	{
		int position = object->lineNumber();
		removeAt(position);
		T* replacement = _objects.insert<T>(position, args..., this);
		finalizeNewObject(position, replacement);
		return replacement;
	}
	else
	{
		return nullptr;
	}
}

mercurial