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