src/geometry.h

Tue, 11 Apr 2023 20:27:04 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Tue, 11 Apr 2023 20:27:04 +0300
changeset 375
21a5ecbe34e4
parent 374
75efc3ba5a56
permissions
-rw-r--r--

Simplify signature of updateRenderPreferences

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

enum class winding_e
{
	none,
	anticlockwise,
	clockwise
};

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

/**
 * @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 calculate_matrix_scaling(const glm::mat4 matrix);
LineSegment2D top(const QRectF& rectangle);
LineSegment2D bottom(const QRectF& rectangle);
LineSegment2D left(const QRectF& rectangle);
LineSegment2D right(const QRectF& rectangle);
enum class convexity_e { concave, convex };
convexity_e quadrilateral_convexity(const Quadrilateral& quad);
convexity_e polygon_convexity(const std::vector<glm::vec3>& polygon);
winding_e calculate_polygon_winding(const QPolygonF& polygon);
struct unscaled_matrix
{
	glm::vec3 scaling;
	glm::mat4 unscaled;
};
unscaled_matrix unscale_matrix(const glm::mat4& matrix);

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

template<typename Iter>
std::optional<glm::mat3> calculateNormal(Iter&& begin, Iter&& end)
{
	const long int n = end - begin;
	std::optional<glm::mat3> result;
	for (long int i = 0; i < n; ++i) {
		const glm::vec3& v1 = *(begin + (i + n - 1) % n);
		const glm::vec3& v2 = *(begin + i);
		const glm::vec3& v3 = *(begin + (i + 1) % n);
		const glm::vec3 xvec = v1 - v2;
		const glm::vec3 yvec = v3 - v2;
		constexpr float threshold = 1e-6f;
		if (glm::length(xvec) > threshold and glm::length(yvec) > threshold) {
			const glm::vec3 zvec = glm::cross(glm::normalize(xvec), glm::normalize(yvec));
			if (glm::length(zvec) > threshold) {
				result = {xvec, yvec, zvec};
				break;
			}
		}
	}
	return result;
}

constexpr QPointF vecToQPoint(const glm::vec2& a)
{
	return {a.x, a.y};
}

mercurial