test_geometry_3d.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /**************************************************************************/
  2. /* test_geometry_3d.h */
  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. #pragma once
  31. #include "core/math/geometry_3d.h"
  32. #include "tests/test_macros.h"
  33. namespace TestGeometry3D {
  34. TEST_CASE("[Geometry3D] Closest Points Between Segments") {
  35. Vector3 ps, qt;
  36. Geometry3D::get_closest_points_between_segments(Vector3(1, -1, 1), Vector3(1, 1, -1), Vector3(-1, -2, -1), Vector3(-1, 1, 1), ps, qt);
  37. CHECK(ps.is_equal_approx(Vector3(1, -0.2, 0.2)));
  38. CHECK(qt.is_equal_approx(Vector3(-1, -0.2, 0.2)));
  39. }
  40. TEST_CASE("[Geometry3D] Closest Distance Between Segments") {
  41. 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);
  42. }
  43. TEST_CASE("[Geometry3D] Build Box Planes") {
  44. constexpr Vector3 extents = Vector3(5, 5, 20);
  45. Vector<Plane> box = Geometry3D::build_box_planes(extents);
  46. CHECK(box.size() == 6);
  47. CHECK(extents.x == box[0].d);
  48. CHECK(box[0].normal == Vector3(1, 0, 0));
  49. CHECK(extents.x == box[1].d);
  50. CHECK(box[1].normal == Vector3(-1, 0, 0));
  51. CHECK(extents.y == box[2].d);
  52. CHECK(box[2].normal == Vector3(0, 1, 0));
  53. CHECK(extents.y == box[3].d);
  54. CHECK(box[3].normal == Vector3(0, -1, 0));
  55. CHECK(extents.z == box[4].d);
  56. CHECK(box[4].normal == Vector3(0, 0, 1));
  57. CHECK(extents.z == box[5].d);
  58. CHECK(box[5].normal == Vector3(0, 0, -1));
  59. }
  60. TEST_CASE("[Geometry3D] Build Capsule Planes") {
  61. Vector<Plane> capsule = Geometry3D::build_capsule_planes(10, 20, 6, 10);
  62. CHECK(capsule.size() == 126);
  63. }
  64. TEST_CASE("[Geometry3D] Build Cylinder Planes") {
  65. Vector<Plane> planes = Geometry3D::build_cylinder_planes(3.0f, 10.0f, 10);
  66. CHECK(planes.size() == 12);
  67. }
  68. TEST_CASE("[Geometry3D] Build Sphere Planes") {
  69. Vector<Plane> planes = Geometry3D::build_sphere_planes(10.0f, 10, 3);
  70. CHECK(planes.size() == 63);
  71. }
  72. #if false
  73. // This test has been temporarily disabled because it's really fragile and
  74. // breaks if calculations change very slightly. For example, it breaks when
  75. // using doubles, and it breaks when making Plane calculations more accurate.
  76. TEST_CASE("[Geometry3D] Build Convex Mesh") {
  77. struct Case {
  78. Vector<Plane> object;
  79. int want_faces, want_edges, want_vertices;
  80. Case(){};
  81. Case(Vector<Plane> p_object, int p_want_faces, int p_want_edges, int p_want_vertices) :
  82. object(p_object), want_faces(p_want_faces), want_edges(p_want_edges), want_vertices(p_want_vertices){};
  83. };
  84. Vector<Case> tt;
  85. tt.push_back(Case(Geometry3D::build_box_planes(Vector3(5, 10, 5)), 6, 12, 8));
  86. tt.push_back(Case(Geometry3D::build_capsule_planes(5, 5, 20, 20, Vector3::Axis()), 820, 7603, 6243));
  87. tt.push_back(Case(Geometry3D::build_cylinder_planes(5, 5, 20, Vector3::Axis()), 22, 100, 80));
  88. tt.push_back(Case(Geometry3D::build_sphere_planes(5, 5, 20), 220, 1011, 522));
  89. for (int i = 0; i < tt.size(); ++i) {
  90. Case current_case = tt[i];
  91. Geometry3D::MeshData mesh = Geometry3D::build_convex_mesh(current_case.object);
  92. CHECK(mesh.faces.size() == current_case.want_faces);
  93. CHECK(mesh.edges.size() == current_case.want_edges);
  94. CHECK(mesh.vertices.size() == current_case.want_vertices);
  95. }
  96. }
  97. #endif
  98. TEST_CASE("[Geometry3D] Clip Polygon") {
  99. Vector<Plane> box_planes = Geometry3D::build_box_planes(Vector3(5, 10, 5));
  100. Vector<Vector3> box = Geometry3D::compute_convex_mesh_points(&box_planes[0], box_planes.size());
  101. Vector<Vector3> output = Geometry3D::clip_polygon(box, Plane());
  102. CHECK(output == box);
  103. output = Geometry3D::clip_polygon(box, Plane(Vector3(0, 1, 0), Vector3(0, 3, 0)));
  104. CHECK(output != box);
  105. }
  106. TEST_CASE("[Geometry3D] Compute Convex Mesh Points") {
  107. Vector<Vector3> cube;
  108. cube.push_back(Vector3(-5, -5, -5));
  109. cube.push_back(Vector3(5, -5, -5));
  110. cube.push_back(Vector3(-5, 5, -5));
  111. cube.push_back(Vector3(5, 5, -5));
  112. cube.push_back(Vector3(-5, -5, 5));
  113. cube.push_back(Vector3(5, -5, 5));
  114. cube.push_back(Vector3(-5, 5, 5));
  115. cube.push_back(Vector3(5, 5, 5));
  116. Vector<Plane> box_planes = Geometry3D::build_box_planes(Vector3(5, 5, 5));
  117. CHECK(Geometry3D::compute_convex_mesh_points(&box_planes[0], box_planes.size()) == cube);
  118. }
  119. TEST_CASE("[Geometry3D] Get Closest Point To Segment") {
  120. constexpr Vector3 a = Vector3(1, 1, 1);
  121. constexpr Vector3 b = Vector3(5, 5, 5);
  122. Vector3 output = Geometry3D::get_closest_point_to_segment(Vector3(2, 1, 4), a, b);
  123. CHECK(output.is_equal_approx(Vector3(2.33333, 2.33333, 2.33333)));
  124. }
  125. TEST_CASE("[Geometry3D] Plane and Box Overlap") {
  126. CHECK(Geometry3D::planeBoxOverlap(Vector3(3, 4, 2), 5.0f, Vector3(5, 5, 5)) == true);
  127. CHECK(Geometry3D::planeBoxOverlap(Vector3(0, 1, 0), -10.0f, Vector3(5, 5, 5)) == false);
  128. CHECK(Geometry3D::planeBoxOverlap(Vector3(1, 0, 0), -6.0f, Vector3(5, 5, 5)) == false);
  129. }
  130. TEST_CASE("[Geometry3D] Is Point in Projected Triangle") {
  131. CHECK(Geometry3D::point_in_projected_triangle(Vector3(1, 1, 0), Vector3(3, 0, 0), Vector3(0, 3, 0), Vector3(-3, 0, 0)) == true);
  132. CHECK(Geometry3D::point_in_projected_triangle(Vector3(5, 1, 0), Vector3(3, 0, 0), Vector3(0, 3, 0), Vector3(-3, 0, 0)) == false);
  133. CHECK(Geometry3D::point_in_projected_triangle(Vector3(3, 0, 0), Vector3(3, 0, 0), Vector3(0, 3, 0), Vector3(-3, 0, 0)) == true);
  134. }
  135. TEST_CASE("[Geometry3D] Does Ray Intersect Triangle") {
  136. Vector3 result;
  137. 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);
  138. 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);
  139. 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);
  140. }
  141. TEST_CASE("[Geometry3D] Does Segment Intersect Convex") {
  142. Vector<Plane> box_planes = Geometry3D::build_box_planes(Vector3(5, 5, 5));
  143. Vector3 result, normal;
  144. CHECK(Geometry3D::segment_intersects_convex(Vector3(10, 10, 10), Vector3(0, 0, 0), &box_planes[0], box_planes.size(), &result, &normal) == true);
  145. CHECK(Geometry3D::segment_intersects_convex(Vector3(10, 10, 10), Vector3(5, 5, 5), &box_planes[0], box_planes.size(), &result, &normal) == true);
  146. CHECK(Geometry3D::segment_intersects_convex(Vector3(10, 10, 10), Vector3(6, 5, 5), &box_planes[0], box_planes.size(), &result, &normal) == false);
  147. }
  148. TEST_CASE("[Geometry3D] Segment Intersects Cylinder") {
  149. Vector3 result, normal;
  150. CHECK(Geometry3D::segment_intersects_cylinder(Vector3(10, 10, 10), Vector3(0, 0, 0), 5, 5, &result, &normal) == true);
  151. CHECK(Geometry3D::segment_intersects_cylinder(Vector3(10, 10, 10), Vector3(6, 6, 6), 5, 5, &result, &normal) == false);
  152. }
  153. TEST_CASE("[Geometry3D] Segment Intersects Cylinder") {
  154. Vector3 result, normal;
  155. CHECK(Geometry3D::segment_intersects_sphere(Vector3(10, 10, 10), Vector3(0, 0, 0), Vector3(0, 0, 0), 5, &result, &normal) == true);
  156. CHECK(Geometry3D::segment_intersects_sphere(Vector3(10, 10, 10), Vector3(0, 0, 2.5), Vector3(0, 0, 0), 5, &result, &normal) == true);
  157. CHECK(Geometry3D::segment_intersects_sphere(Vector3(10, 10, 10), Vector3(5, 5, 5), Vector3(0, 0, 0), 5, &result, &normal) == false);
  158. }
  159. TEST_CASE("[Geometry3D] Segment Intersects Triangle") {
  160. Vector3 result;
  161. 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);
  162. 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);
  163. 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);
  164. }
  165. TEST_CASE("[Geometry3D] Triangle and Box Overlap") {
  166. constexpr Vector3 good_triangle[3] = { Vector3(3, 2, 3), Vector3(2, 2, 1), Vector3(2, 1, 1) };
  167. CHECK(Geometry3D::triangle_box_overlap(Vector3(0, 0, 0), Vector3(5, 5, 5), good_triangle) == true);
  168. constexpr Vector3 bad_triangle[3] = { Vector3(100, 100, 100), Vector3(-100, -100, -100), Vector3(10, 10, 10) };
  169. CHECK(Geometry3D::triangle_box_overlap(Vector3(1000, 1000, 1000), Vector3(1, 1, 1), bad_triangle) == false);
  170. }
  171. TEST_CASE("[Geometry3D] Triangle and Sphere Intersect") {
  172. constexpr Vector3 triangle_a = Vector3(3, 0, 0);
  173. constexpr Vector3 triangle_b = Vector3(-3, 0, 0);
  174. constexpr Vector3 triangle_c = Vector3(0, 3, 0);
  175. Vector3 triangle_contact, sphere_contact;
  176. 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);
  177. 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);
  178. 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);
  179. }
  180. } // namespace TestGeometry3D