Wed, 12 Apr 2023 01:53:42 +0300
Circular primitive type is now an enum class
#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}; }