Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/tests/core/math/test_geometry_3d.cpp
23450 views
1
/**************************************************************************/
2
/* test_geometry_3d.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "tests/test_macros.h"
32
33
TEST_FORCE_LINK(test_geometry_3d)
34
35
#include "core/math/geometry_3d.h"
36
37
namespace TestGeometry3D {
38
39
TEST_CASE("[Geometry3D] Closest Points Between Segments") {
40
Vector3 ps, qt;
41
Geometry3D::get_closest_points_between_segments(Vector3(1, -1, 1), Vector3(1, 1, -1), Vector3(-1, -2, -1), Vector3(-1, 1, 1), ps, qt);
42
CHECK(ps.is_equal_approx(Vector3(1, -0.2, 0.2)));
43
CHECK(qt.is_equal_approx(Vector3(-1, -0.2, 0.2)));
44
}
45
46
TEST_CASE("[Geometry3D] Closest Distance Between Segments") {
47
CHECK(Geometry3D::get_closest_distance_between_segments(Vector3(1, -2, 0), Vector3(1, 2, 0), Vector3(-1, 2, 0), Vector3(-1, -2, 0)) == 2.0f);
48
}
49
50
TEST_CASE("[Geometry3D] Build Box Planes") {
51
constexpr Vector3 extents = Vector3(5, 5, 20);
52
Vector<Plane> box = Geometry3D::build_box_planes(extents);
53
CHECK(box.size() == 6);
54
CHECK(extents.x == box[0].d);
55
CHECK(box[0].normal == Vector3(1, 0, 0));
56
CHECK(extents.x == box[1].d);
57
CHECK(box[1].normal == Vector3(-1, 0, 0));
58
CHECK(extents.y == box[2].d);
59
CHECK(box[2].normal == Vector3(0, 1, 0));
60
CHECK(extents.y == box[3].d);
61
CHECK(box[3].normal == Vector3(0, -1, 0));
62
CHECK(extents.z == box[4].d);
63
CHECK(box[4].normal == Vector3(0, 0, 1));
64
CHECK(extents.z == box[5].d);
65
CHECK(box[5].normal == Vector3(0, 0, -1));
66
}
67
68
TEST_CASE("[Geometry3D] Build Capsule Planes") {
69
Vector<Plane> capsule = Geometry3D::build_capsule_planes(10, 20, 6, 10);
70
CHECK(capsule.size() == 126);
71
}
72
73
TEST_CASE("[Geometry3D] Build Cylinder Planes") {
74
Vector<Plane> planes = Geometry3D::build_cylinder_planes(3.0f, 10.0f, 10);
75
CHECK(planes.size() == 12);
76
}
77
78
TEST_CASE("[Geometry3D] Build Sphere Planes") {
79
Vector<Plane> planes = Geometry3D::build_sphere_planes(10.0f, 10, 3);
80
CHECK(planes.size() == 63);
81
}
82
83
#if false
84
// This test has been temporarily disabled because it's really fragile and
85
// breaks if calculations change very slightly. For example, it breaks when
86
// using doubles, and it breaks when making Plane calculations more accurate.
87
TEST_CASE("[Geometry3D] Build Convex Mesh") {
88
struct Case {
89
Vector<Plane> object;
90
int want_faces, want_edges, want_vertices;
91
Case(){};
92
Case(Vector<Plane> p_object, int p_want_faces, int p_want_edges, int p_want_vertices) :
93
object(p_object), want_faces(p_want_faces), want_edges(p_want_edges), want_vertices(p_want_vertices){};
94
};
95
Vector<Case> tt;
96
tt.push_back(Case(Geometry3D::build_box_planes(Vector3(5, 10, 5)), 6, 12, 8));
97
tt.push_back(Case(Geometry3D::build_capsule_planes(5, 5, 20, 20, Vector3::Axis()), 820, 7603, 6243));
98
tt.push_back(Case(Geometry3D::build_cylinder_planes(5, 5, 20, Vector3::Axis()), 22, 100, 80));
99
tt.push_back(Case(Geometry3D::build_sphere_planes(5, 5, 20), 220, 1011, 522));
100
for (int i = 0; i < tt.size(); ++i) {
101
Case current_case = tt[i];
102
Geometry3D::MeshData mesh = Geometry3D::build_convex_mesh(current_case.object);
103
CHECK(mesh.faces.size() == current_case.want_faces);
104
CHECK(mesh.edges.size() == current_case.want_edges);
105
CHECK(mesh.vertices.size() == current_case.want_vertices);
106
}
107
}
108
#endif
109
110
TEST_CASE("[Geometry3D] Clip Polygon") {
111
Vector<Plane> box_planes = Geometry3D::build_box_planes(Vector3(5, 10, 5));
112
Vector<Vector3> box = Geometry3D::compute_convex_mesh_points(&box_planes[0], box_planes.size());
113
Vector<Vector3> output = Geometry3D::clip_polygon(box, Plane());
114
CHECK(output == box);
115
output = Geometry3D::clip_polygon(box, Plane(Vector3(0, 1, 0), Vector3(0, 3, 0)));
116
CHECK(output != box);
117
}
118
119
TEST_CASE("[Geometry3D] Compute Convex Mesh Points") {
120
Vector<Vector3> cube;
121
cube.push_back(Vector3(-5, -5, -5));
122
cube.push_back(Vector3(5, -5, -5));
123
cube.push_back(Vector3(-5, 5, -5));
124
cube.push_back(Vector3(5, 5, -5));
125
cube.push_back(Vector3(-5, -5, 5));
126
cube.push_back(Vector3(5, -5, 5));
127
cube.push_back(Vector3(-5, 5, 5));
128
cube.push_back(Vector3(5, 5, 5));
129
Vector<Plane> box_planes = Geometry3D::build_box_planes(Vector3(5, 5, 5));
130
CHECK(Geometry3D::compute_convex_mesh_points(&box_planes[0], box_planes.size()) == cube);
131
}
132
133
TEST_CASE("[Geometry3D] Get Closest Point To Segment") {
134
constexpr Vector3 a = Vector3(1, 1, 1);
135
constexpr Vector3 b = Vector3(5, 5, 5);
136
Vector3 output = Geometry3D::get_closest_point_to_segment(Vector3(2, 1, 4), a, b);
137
CHECK(output.is_equal_approx(Vector3(2.33333, 2.33333, 2.33333)));
138
}
139
140
TEST_CASE("[Geometry3D] Plane and Box Overlap") {
141
CHECK(Geometry3D::planeBoxOverlap(Vector3(3, 4, 2), 5.0f, Vector3(5, 5, 5)) == true);
142
CHECK(Geometry3D::planeBoxOverlap(Vector3(0, 1, 0), -10.0f, Vector3(5, 5, 5)) == false);
143
CHECK(Geometry3D::planeBoxOverlap(Vector3(1, 0, 0), -6.0f, Vector3(5, 5, 5)) == false);
144
}
145
146
TEST_CASE("[Geometry3D] Is Point in Projected Triangle") {
147
CHECK(Geometry3D::point_in_projected_triangle(Vector3(1, 1, 0), Vector3(3, 0, 0), Vector3(0, 3, 0), Vector3(-3, 0, 0)) == true);
148
CHECK(Geometry3D::point_in_projected_triangle(Vector3(5, 1, 0), Vector3(3, 0, 0), Vector3(0, 3, 0), Vector3(-3, 0, 0)) == false);
149
CHECK(Geometry3D::point_in_projected_triangle(Vector3(3, 0, 0), Vector3(3, 0, 0), Vector3(0, 3, 0), Vector3(-3, 0, 0)) == true);
150
}
151
152
TEST_CASE("[Geometry3D] Does Ray Intersect Triangle") {
153
Vector3 result;
154
CHECK(Geometry3D::ray_intersects_triangle(Vector3(0, 1, 1), Vector3(0, 0, -10), Vector3(0, 3, 0), Vector3(-3, 0, 0), Vector3(3, 0, 0), &result) == true);
155
CHECK(Geometry3D::ray_intersects_triangle(Vector3(5, 10, 1), Vector3(0, 0, -10), Vector3(0, 3, 0), Vector3(-3, 0, 0), Vector3(3, 0, 0), &result) == false);
156
CHECK(Geometry3D::ray_intersects_triangle(Vector3(0, 1, 1), Vector3(0, 0, 10), Vector3(0, 3, 0), Vector3(-3, 0, 0), Vector3(3, 0, 0), &result) == false);
157
}
158
159
TEST_CASE("[Geometry3D] Does Segment Intersect Convex") {
160
Vector<Plane> box_planes = Geometry3D::build_box_planes(Vector3(5, 5, 5));
161
Vector3 result, normal;
162
CHECK(Geometry3D::segment_intersects_convex(Vector3(10, 10, 10), Vector3(0, 0, 0), &box_planes[0], box_planes.size(), &result, &normal) == true);
163
CHECK(Geometry3D::segment_intersects_convex(Vector3(10, 10, 10), Vector3(5, 5, 5), &box_planes[0], box_planes.size(), &result, &normal) == true);
164
CHECK(Geometry3D::segment_intersects_convex(Vector3(10, 10, 10), Vector3(6, 5, 5), &box_planes[0], box_planes.size(), &result, &normal) == false);
165
CHECK(Geometry3D::segment_intersects_convex(Vector3(10, 10, 0), Vector3(10, 0, 0), &box_planes[0], box_planes.size(), &result, &normal) == false);
166
}
167
168
TEST_CASE("[Geometry3D] Segment Intersects Cylinder") {
169
Vector3 result, normal;
170
CHECK(Geometry3D::segment_intersects_cylinder(Vector3(10, 10, 10), Vector3(0, 0, 0), 5, 5, &result, &normal) == true);
171
CHECK(Geometry3D::segment_intersects_cylinder(Vector3(10, 10, 10), Vector3(6, 6, 6), 5, 5, &result, &normal) == false);
172
}
173
174
TEST_CASE("[Geometry3D] Segment Intersects Cylinder") {
175
Vector3 result, normal;
176
CHECK(Geometry3D::segment_intersects_sphere(Vector3(10, 10, 10), Vector3(0, 0, 0), Vector3(0, 0, 0), 5, &result, &normal) == true);
177
CHECK(Geometry3D::segment_intersects_sphere(Vector3(10, 10, 10), Vector3(0, 0, 2.5), Vector3(0, 0, 0), 5, &result, &normal) == true);
178
CHECK(Geometry3D::segment_intersects_sphere(Vector3(10, 10, 10), Vector3(5, 5, 5), Vector3(0, 0, 0), 5, &result, &normal) == false);
179
}
180
181
TEST_CASE("[Geometry3D] Segment Intersects Triangle") {
182
Vector3 result;
183
CHECK(Geometry3D::segment_intersects_triangle(Vector3(1, 1, 1), Vector3(-1, -1, -1), Vector3(-3, 0, 0), Vector3(0, 3, 0), Vector3(3, 0, 0), &result) == true);
184
CHECK(Geometry3D::segment_intersects_triangle(Vector3(1, 1, 1), Vector3(3, 0, 0), Vector3(-3, 0, 0), Vector3(0, 3, 0), Vector3(3, 0, 0), &result) == true);
185
CHECK(Geometry3D::segment_intersects_triangle(Vector3(1, 1, 1), Vector3(10, -1, -1), Vector3(-3, 0, 0), Vector3(0, 3, 0), Vector3(3, 0, 0), &result) == false);
186
}
187
188
TEST_CASE("[Geometry3D] Triangle and Box Overlap") {
189
constexpr Vector3 good_triangle[3] = { Vector3(3, 2, 3), Vector3(2, 2, 1), Vector3(2, 1, 1) };
190
CHECK(Geometry3D::triangle_box_overlap(Vector3(0, 0, 0), Vector3(5, 5, 5), good_triangle) == true);
191
constexpr Vector3 bad_triangle[3] = { Vector3(100, 100, 100), Vector3(-100, -100, -100), Vector3(10, 10, 10) };
192
CHECK(Geometry3D::triangle_box_overlap(Vector3(1000, 1000, 1000), Vector3(1, 1, 1), bad_triangle) == false);
193
}
194
195
TEST_CASE("[Geometry3D] Triangle and Sphere Intersect") {
196
constexpr Vector3 triangle_a = Vector3(3, 0, 0);
197
constexpr Vector3 triangle_b = Vector3(-3, 0, 0);
198
constexpr Vector3 triangle_c = Vector3(0, 3, 0);
199
Vector3 triangle_contact, sphere_contact;
200
CHECK(Geometry3D::triangle_sphere_intersection_test(triangle_a, triangle_b, triangle_c, Vector3(0, -1, 0), Vector3(0, 0, 0), 5, triangle_contact, sphere_contact) == true);
201
CHECK(Geometry3D::triangle_sphere_intersection_test(triangle_a, triangle_b, triangle_c, Vector3(0, 1, 0), Vector3(0, 0, 0), 5, triangle_contact, sphere_contact) == true);
202
CHECK(Geometry3D::triangle_sphere_intersection_test(triangle_a, triangle_b, triangle_c, Vector3(0, 1, 0), Vector3(20, 0, 0), 5, triangle_contact, sphere_contact) == false);
203
}
204
205
} // namespace TestGeometry3D
206
207