src/linetypes/object.h

Mon, 11 May 2020 12:18:04 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Mon, 11 May 2020 12:18:04 +0300
changeset 88
14e51640c189
parent 87
93ec4d630346
child 89
7abaf1d64719
permissions
-rw-r--r--

finetuning in multiplyfactordialog

#pragma once
#include <QPointF>
#include <QString>
#include <QStringView>
#include "main.h"
#include "colors.h"
#include "gl/common.h"

namespace ldraw
{
	struct GetPolygonsContext;
	enum class Property;
	class Object;
	class ColoredObject;
	class Empty;
	class UnhandledProperty;
	template<int N>
	class PolygonObject;
}

class DocumentManager;

struct ldraw::GetPolygonsContext
{
	::DocumentManager* documents;
};

/**
 * @brief Different properties that can be queried with getProperty
 */
enum class ldraw::Property
{
	Color, // Color of the object
	Text, // Text contained in a comment
	Point0, // First vertex in a polygon or edge line
	Point1, // Second vertex in a polygon or edge line
	Point2, // Third vertex in a polygon
	Point3, // Fourth vertex in a quadrilateral
	Transformation, // 4x4 transformation matrix of a subfile reference
	ReferenceName, // Subfile reference name
	IsInverted, // Whether or not the object has been inverted with BFC INVERTNEXT
	ErrorMessage // For error lines, why parsing failed
};

// Mapping of properties to types
#define LDFORGE_DEFINE_PROPERTY_TYPE(PROPERTY, TYPE) \
	namespace ldraw { \
		template<> struct PropertyType<ldraw::Property::PROPERTY> { using type = TYPE; }; \
	}

namespace ldraw
{
	template<ldraw::Property property>
	struct PropertyType
	{
	};

	template<ldraw::Property property>
	using PropertyType_t = typename PropertyType<property>::type;

	struct PropertyKeyValue
	{
		Property key;
		QVariant value;
	};

	constexpr Property pointProperty(int n)
	{
		Q_ASSERT(n >= 0 and n < 4);
		return static_cast<Property>(static_cast<int>(Property::Point0) + n);
	}
}

LDFORGE_DEFINE_PROPERTY_TYPE(Color, int)
LDFORGE_DEFINE_PROPERTY_TYPE(Text, QString)
LDFORGE_DEFINE_PROPERTY_TYPE(Point0, glm::vec3)
LDFORGE_DEFINE_PROPERTY_TYPE(Point1, glm::vec3)
LDFORGE_DEFINE_PROPERTY_TYPE(Point2, glm::vec3)
LDFORGE_DEFINE_PROPERTY_TYPE(Point3, glm::vec3)
LDFORGE_DEFINE_PROPERTY_TYPE(Transformation, glm::mat4)
LDFORGE_DEFINE_PROPERTY_TYPE(ReferenceName, QString)
LDFORGE_DEFINE_PROPERTY_TYPE(IsInverted, bool)
LDFORGE_DEFINE_PROPERTY_TYPE(ErrorMessage, QString)

#define LDRAW_OBJECT_HANDLE_SET_PROPERTY(PROPERTY, HANDLER) \
	{this->handle<ldraw::Property::PROPERTY>(result, pair, \
		[&](const ldraw::PropertyType_t<ldraw::Property::PROPERTY>& value) HANDLER);}

class ldraw::Object
{
public:
	enum class SetPropertyResult
	{
		Success = 0,
		PropertyNotHandled
	};
	friend bool handled(SetPropertyResult result)
	{
		return result == SetPropertyResult::Success;
	}
	class BadPointIndex : public std::exception
	{
	};
	Object();
	Object(const Object&) = delete;
	virtual ~Object();
	const id_t id;
	virtual bool hasColor() const;
	virtual QVariant getProperty(Property id) const;
	template<ldraw::Property property>
	SetPropertyResult setProperty(const PropertyType_t<property>& value);
	SetPropertyResult setProperty(const PropertyKeyValue& pair);
	virtual QString textRepresentation() const = 0;
	virtual QBrush textRepresentationForeground() const;
	virtual QBrush textRepresentationBackground() const;
	virtual QFont textRepresentationFont() const;
	virtual void getPolygons(std::vector<gl::Polygon>& polygons, GetPolygonsContext* context) const;
	virtual void invert() {}
	virtual int numPoints() const { return 0; }
	virtual const glm::vec3& getPoint(int index) const;
protected:
	template<Property property, typename Function>
	void handle(SetPropertyResult* result, const PropertyKeyValue& pair, Function function);
	virtual void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair);
};

template<ldraw::Property property>
ldraw::Object::SetPropertyResult ldraw::Object::setProperty(const PropertyType_t<property>& value)
{
	SetPropertyResult result = SetPropertyResult::PropertyNotHandled;
	this->setProperty(&result, PropertyKeyValue{property, QVariant::fromValue(value)});
	return result;
}

template<ldraw::Property property, typename Function>
void ldraw::Object::handle(SetPropertyResult* result, const PropertyKeyValue& pair, Function function)
{
	if (pair.key == property)
	{
		function(pair.value.value<ldraw::PropertyType_t<property>>());
		*result = SetPropertyResult::Success;
	}
}

class ldraw::ColoredObject : public Object
{
public:
	ColoredObject(const Color colorIndex = ldraw::mainColor);
	bool hasColor() const override final;
	QVariant getProperty(Property id) const override;
	Color colorIndex = ldraw::mainColor;
protected:
	void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair) override;
};

template<int N>
class ldraw::PolygonObject : public ColoredObject
{
public:
	PolygonObject(const std::array<glm::vec3, N>& points, const Color color) :
		ColoredObject{color},
		points{points} {}
	int numPoints() const override
	{
		return N;
	}
	const glm::vec3& getPoint(int index) const override
	{
		Q_ASSERT(index >= 0 and index < N);
		return this->points[index];
	}
	QVariant getProperty(const Property id) const override
	{
		switch (id)
		{
		case Property::Point0:
			return QVariant::fromValue(points[0]);
		case Property::Point1:
			return QVariant::fromValue(points[1]);
		case Property::Point2:
			if (N >= 3)
			{
				return QVariant::fromValue(points[2]);
			}
			break;
		case Property::Point3:
			if (N >= 4)
			{
				return QVariant::fromValue(points[3]);
			}
			break;
		default:
			break;
		}
		return ColoredObject::getProperty(id);
	}
	void setProperty(SetPropertyResult* result, const PropertyKeyValue& pair)
	{
		LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point0, {points[0] = value;})
		LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point1, {points[1] = value;})
		if constexpr (N >= 3)
		{
			LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point2, {points[2] = value;})
		}
		if constexpr (N >= 4)
		{
			LDRAW_OBJECT_HANDLE_SET_PROPERTY(Point3, {points[2] = value;})
		}
		ColoredObject::setProperty(result, pair);
	}
	std::array<std::enable_if_t<(N > 0 and N <= 4), glm::vec3>, N> points;
};

/**
 * @brief Represents an empty line.
 */
class ldraw::Empty : public Object
{
	QString textRepresentation() const override;
};

mercurial