summaryrefslogtreecommitdiff
path: root/game/geoDataMesh.cpp
blob: aaa8c9cc328fe20fa2b98080152010dd863c13b6 (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
117
118
#include "geoDataMesh.h"
#include <format>
#ifndef NDEBUG
#	include <stream_support.h>
#endif

OpenMesh::FaceHandle
GeoDataMesh::findPoint(GlobalPosition2D coord) const
{
	return findPoint(coord, *faces_sbegin());
}

GeoDataMesh::PointFace::PointFace(const GlobalPosition2D coord, const GeoDataMesh * mesh) :
	PointFace {coord, mesh, *mesh->faces_sbegin()}
{
}

GeoDataMesh::PointFace::PointFace(const GlobalPosition2D coord, const GeoDataMesh * mesh, FaceHandle start) :
	PointFace {coord, mesh->findPoint(coord, start)}
{
}

OpenMesh::FaceHandle
GeoDataMesh::PointFace::face(const GeoDataMesh * mesh, FaceHandle start) const
{
	if (faceCache.is_valid() && mesh->faceContainsPoint(point, faceCache)) {
		return faceCache;
	}
	return (faceCache = mesh->findPoint(point, start));
}

OpenMesh::FaceHandle
GeoDataMesh::PointFace::face(const GeoDataMesh * mesh) const
{
	return face(mesh, *mesh->faces_sbegin());
}

GeoDataMesh::HalfEdgeVertices
GeoDataMesh::toVertexHandles(HalfedgeHandle halfEdge) const
{
	return {from_vertex_handle(halfEdge), to_vertex_handle(halfEdge)};
}

GeoDataMesh::HalfEdgePoints
GeoDataMesh::points(HalfEdgeVertices vertices) const
{
	return {point(vertices.first), point(vertices.second)};
}

OpenMesh::FaceHandle
GeoDataMesh::findPoint(const GlobalPosition2D coord, OpenMesh::FaceHandle face) const
{
	while (face.is_valid() && !triangle<2>(face).containsPoint(coord)) {
		for (auto next = cfh_iter(face); next.is_valid(); ++next) {
			face = opposite_face_handle(*next);
			if (face.is_valid()) {
				const auto nextPoints = points(toVertexHandles(*next));
				if (pointLeftOfLine(coord, nextPoints.second, nextPoints.first)) {
					break;
				}
			}
			face.reset();
		}
	}
	return face;
}

GlobalPosition3D
GeoDataMesh::positionAt(const PointFace & coord) const
{
	return triangle<3>(coord.face(this)).positionOnPlane(coord.point);
}

bool
GeoDataMesh::faceContainsPoint(const GlobalPosition2D coord, FaceHandle face) const
{
	return triangle<2>(face).containsPoint(coord);
}

OpenMesh::HalfedgeHandle
GeoDataMesh::findBoundaryStart() const
{
	return *std::find_if(halfedges_sbegin(), halfedges_end(), [this](const auto heh) {
		return is_boundary(heh);
	});
}

[[nodiscard]] RelativePosition3D
GeoDataMesh::difference(const HalfedgeHandle heh) const
{
	return ::difference(point(to_vertex_handle(heh)), point(from_vertex_handle(heh)));
}

[[nodiscard]] GlobalPosition3D
GeoDataMesh::centre(const HalfedgeHandle heh) const
{
	const auto hehPoints = points(toVertexHandles(heh));
	return midpoint(hehPoints.first, hehPoints.second);
}

void
GeoDataMesh::sanityCheck(const std::source_location & loc) const
{
	if (const auto upSideDown = std::ranges::count_if(faces(), [this](const auto face) {
			if (!triangle<2>(face).isUp()) {
#ifndef NDEBUG
				for (const auto vertex : fv_range(face)) {
					CLOG(point(vertex));
				}
#endif
				return true;
			}
			return false;
		}) > 0) {
		throw std::logic_error(std::format(
				"{} upside down faces detected - checked from {}:{}", upSideDown, loc.function_name(), loc.line()));
	}
}