src/geometry.h

Fri, 01 Jul 2022 16:46:43 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Fri, 01 Jul 2022 16:46:43 +0300
changeset 312
2637134bc37c
parent 223
ce81db996275
child 321
180072db4a83
permissions
-rw-r--r--

Fix right click to delete not really working properly
Instead of removing the point that had been added, it would remove
the point that is being drawn, which would cause it to overwrite the
previous point using the new point, causing a bit of a delay

#pragma once
#include <QPolygonF>
#include <glm/glm.hpp>
#include <optional>

enum Winding
{
	NoWinding,
	Anticlockwise,
	Clockwise,
};

//! \brief XOR operator for winding
constexpr Winding operator^(Winding one, Winding other)
{
	if (one == NoWinding or other == NoWinding) {
		return NoWinding;
	}
	else {
		const int xored = static_cast<int>(one) ^ static_cast<int>(other);
		return static_cast<Winding>(xored);
	}
}

constexpr Winding& operator^=(Winding& one, Winding other)
{
	one = one ^ other;
	return one;
}

struct Plane
{
	glm::vec3 normal;
	glm::vec3 anchor;
};

template<int N, typename T = float, glm::qualifier Q = glm::defaultp>
struct Line
{
	glm::vec<N, T, Q> direction;
	glm::vec<N, T, Q> anchor;
};

template<int N, typename T = float, glm::qualifier Q = glm::defaultp>
struct Ray
{
	glm::vec<N, T, Q> direction;
	glm::vec<N, T, Q> anchor;
};

inline const glm::vec3 origin = {0, 0, 0};
inline const Plane XY = {{0, 0, 1}, origin};
inline const Plane XZ = {{0, 1, 0}, origin};
inline const Plane YZ = {{1, 0, 0}, origin};

struct LineSegment
{
	glm::vec3 p1, p2;
};
struct Triangle
{
	glm::vec3 p1, p2, p3;
};
struct Quadrilateral
{
	glm::vec3 p1, p2, p3, p4;
};
struct ConditionalEdge
{
	glm::vec3 p1, p2;
	glm::vec3 c1, c2;
};
struct LineSegment2D
{
	glm::vec2 p1, p2;
};

// get polygon type from amount of points
template<int N>
struct PolygonType {};
template<>
struct PolygonType<2> { using type = LineSegment; };
template<>
struct PolygonType<3> { using type = Triangle; };
template<>
struct PolygonType<4> { using type = Quadrilateral; };
template<int N>
using Polygon = typename PolygonType<N>::type;

/**
 * @brief Computes a line from two points
 * @param point_1
 * @param point_2
 * @return line
 */
template<int N, typename T, glm::qualifier Q>
Line<N, T, Q> lineFromPoints(const glm::vec<N, T, Q>& point_1, const glm::vec<N, T, Q>& point_2)
{
	return {point_2 - point_1, point_1};
}

template<int N, typename T, glm::qualifier Q>
Ray<N, T, Q> rayFromPoints(const glm::vec<N, T, Q>& point_1, const glm::vec<N, T, Q>& point_2)
{
	return {point_2 - point_1, point_1};
}

template<int N, typename T, glm::qualifier Q>
Line<N, T, Q> rayToLine(const Ray<N, T, Q>& ray)
{
	return {ray.direction, ray.anchor};
}

enum class RectangleSide
{
	Top,
	Left,
	Bottom,
	Right
};

struct PointOnRectagle
{
	glm::vec2 position;
	RectangleSide side;
};

std::optional<glm::vec2> lineLineIntersection(const Line<2>& line_1, const Line<2>& line_2);
std::optional<glm::vec2> rayLineSegmentIntersection(const Ray<2>& ray, const LineSegment2D& line);
std::optional<PointOnRectagle> rayRectangleIntersection(const Ray<2>& ray, const QRectF& rectangle);
Plane planeFromTriangle(const Triangle& triangle);
glm::vec3 normalVector(const Triangle& triangle);
std::optional<glm::vec3> linePlaneIntersection(
	const Line<3>& line,
	const Plane& plane, const float epsilon = 1e-6f);
glm::vec3 scalingVector(const glm::mat4 matrix);
LineSegment2D top(const QRectF& rectangle);
LineSegment2D bottom(const QRectF& rectangle);
LineSegment2D left(const QRectF& rectangle);
LineSegment2D right(const QRectF& rectangle);
bool isConvex(const Quadrilateral& quad);
bool isConvex(const std::vector<glm::vec3>& polygon);
Winding winding(const QPolygonF& polygon);
struct ScalingExtract
{
	glm::vec3 scaling;
	glm::mat4 unscaled;
};
ScalingExtract extractScaling(const glm::mat4& matrix);

struct NPolygon
{
	std::vector<glm::vec3> points;
};

inline constexpr bool isclose(const glm::vec3& a, const glm::vec3& b)
{
	return qFuzzyCompare(a.x, b.x)
		and qFuzzyCompare(a.y, b.y)
		and qFuzzyCompare(a.z, b.z);
}

struct CircleF
{
	QPointF center;
	qreal radius;
};

/**
 * @brief Inscribes a circle
 * @param circle
 * @return a QRectF that inscribes the specified circle
 */
inline constexpr QRectF inscribe(const CircleF& circle)
{
	return {
		circle.center.x() - circle.radius,
		circle.center.y() - circle.radius,
		circle.radius * 2,
		circle.radius * 2
	};
}

struct BezierCurve
{
	glm::vec3 points[4];
	const glm::vec3& operator[](int x) const
	{
		Q_ASSERT(x >= 0 and x < 4);
		return this->points[x];
	}
	glm::vec3& operator[](int x)
	{
		Q_ASSERT(x >= 0 and x < 4);
		return this->points[x];
	}
};

glm::vec3 pointOnCurve(const BezierCurve& curve, float t);
glm::vec3 derivativeOnCurve(const BezierCurve& curve, float t);

mercurial