summaryrefslogtreecommitdiff
path: root/game/geoDataMesh.h
blob: 72b069e3fa0aeee14f8d0de8f68c53105937ba72 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#pragma once

#include "config/types.h"
#include "triangle.h"
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <set>
#include <source_location>
#include <thirdparty/openmesh/glmcompat.h>
#include <thirdparty/openmesh/helpers.h>

struct GeoDataTraits : public OpenMesh::DefaultTraits {
	FaceAttributes(OpenMesh::Attributes::Status);
	EdgeAttributes(OpenMesh::Attributes::Status);
	VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Status);
	HalfedgeAttributes(OpenMesh::Attributes::Status);
	using Point = GlobalPosition3D;
	using Normal = Normal3D;
};

class GeoDataMesh : public OpenMesh::TriMesh_ArrayKernelT<GeoDataTraits> {
public:
	struct PointFace {
		// NOLINTNEXTLINE(hicpp-explicit-conversions)
		PointFace(GlobalPosition2D coord) : point {coord} { }

		PointFace(GlobalPosition2D coord, FaceHandle face) : point {coord}, faceCache {face} { }

		PointFace(GlobalPosition2D coord, const GeoDataMesh *);
		PointFace(GlobalPosition2D coord, GeoDataMesh const *, FaceHandle start);

		const GlobalPosition2D point;
		[[nodiscard]] FaceHandle face(const GeoDataMesh *) const;
		[[nodiscard]] FaceHandle face(const GeoDataMesh *, FaceHandle start) const;

		[[nodiscard]] bool
		isLocated() const
		{
			return faceCache.is_valid();
		}

	private:
		mutable FaceHandle faceCache;
	};

	template<glm::length_t Dim> using Triangle = ::Triangle<Dim, GlobalDistance>;

	[[nodiscard]] FaceHandle findPoint(GlobalPosition2D) const;
	[[nodiscard]] FaceHandle findPoint(GlobalPosition2D, FaceHandle) const;

	[[nodiscard]] GlobalPosition3D positionAt(const PointFace &) const;

protected:
#ifndef NDEBUG
	void sanityCheck(const std::source_location & = std::source_location::current()) const;
#endif

	[[nodiscard]] bool faceContainsPoint(GlobalPosition2D, FaceHandle) const;
	[[nodiscard]] HalfedgeHandle findBoundaryStart() const;
	[[nodiscard]] RelativePosition3D difference(HalfedgeHandle) const;
	using HalfEdgeVertices = std::pair<VertexHandle, VertexHandle>;
	[[nodiscard]] HalfEdgeVertices toVertexHandles(HalfedgeHandle) const;
	using HalfEdgePoints = std::pair<GlobalPosition3D, GlobalPosition3D>;
	[[nodiscard]] HalfEdgePoints points(HalfEdgeVertices) const;

	template<glm::length_t D>
	[[nodiscard]] auto
	vertexDistanceFunction(GlobalPosition<D> point) const
	{
		struct DistanceCalculator {
			[[nodiscard]] std::pair<VertexHandle, float>
			operator()(VertexHandle compVertex) const
			{
				return std::make_pair(
						compVertex, ::distance<D, GlobalDistance, glm::defaultp>(point, mesh->point(compVertex)));
			}

			[[nodiscard]]
			std::pair<HalfedgeHandle, float>
			operator()(const HalfedgeHandle compHalfedge) const
			{
				const auto edgePoints = mesh->points(mesh->toVertexHandles(compHalfedge));
				return std::make_pair(compHalfedge, Triangle<2> {edgePoints.second, edgePoints.first, point}.height());
			};

			const GeoDataMesh * mesh;
			GlobalPosition<D> point;
		};

		return DistanceCalculator {this, point};
	}

	[[nodiscard]] bool canFlip(HalfedgeHandle edge) const;
	[[nodiscard]] std::optional<EdgeHandle> shouldFlip(HalfedgeHandle next, GlobalPosition2D startPoint) const;
	void expandVerts(std::set<VertexHandle> & verts) const;

	template<glm::length_t D>
	[[nodiscard]] RelativeDistance
	length(HalfedgeHandle heh) const
	{
		return ::distance<D, GlobalDistance, glm::defaultp>(
				point(to_vertex_handle(heh)), point(from_vertex_handle(heh)));
	}

	[[nodiscard]] GlobalPosition3D centre(HalfedgeHandle) const;

	template<glm::length_t Dim>
	[[nodiscard]] Triangle<Dim>
	triangle(FaceHandle face) const
	{
		Triangle<Dim> triangle;
		std::ranges::transform(fv_range(face), triangle.begin(), [this](auto vertex) {
			return point(vertex);
		});
		return triangle;
	}
};