diff --git a/AABB_tree/benchmark/AABB_tree/tree_creation.cpp b/AABB_tree/benchmark/AABB_tree/tree_creation.cpp index deb999c6b27..aa58d5545f2 100644 --- a/AABB_tree/benchmark/AABB_tree/tree_creation.cpp +++ b/AABB_tree/benchmark/AABB_tree/tree_creation.cpp @@ -36,14 +36,12 @@ static void BM_Intersections(benchmark::State& state) Point_3 q(-0.5, 0.04, 0.06); Tree tree{mesh.faces_begin(), mesh.faces_end(), mesh}; - tree.build(); + tree.accelerate_distance_queries(); Segment segment_query(p, q); - for (auto _ : state) { benchmark::DoNotOptimize([&]() { - tree.accelerate_distance_queries(); tree.number_of_intersected_primitives(segment_query); Point_3 point_query(2.0, 2.0, 2.0); Point_3 closest = tree.closest_point(point_query); diff --git a/AABB_tree/include/CGAL/AABB_tree.h b/AABB_tree/include/CGAL/AABB_tree.h index 95933a614c3..6ac023ecbb6 100644 --- a/AABB_tree/include/CGAL/AABB_tree.h +++ b/AABB_tree/include/CGAL/AABB_tree.h @@ -632,13 +632,14 @@ public: template typename AABB_tree::Self& AABB_tree::operator=(Self&& tree) noexcept { - m_traits = std::move(tree.traits); + m_traits = std::move(tree.m_traits); m_primitives = std::move(tree.m_primitives); m_p_nodes = std::move(tree.m_p_nodes); m_p_search_tree = std::move(tree.m_p_search_tree); m_search_tree_constructed = std::exchange(tree.m_search_tree_constructed, false); m_default_search_tree_constructed = std::exchange(tree.m_default_search_tree_constructed, true); m_need_build = std::exchange(tree.m_need_build, false); + return *this; } template diff --git a/AABB_tree/test/AABB_tree/aabb_test_move_constructor.cpp b/AABB_tree/test/AABB_tree/aabb_test_move_constructor.cpp new file mode 100644 index 00000000000..da175f7bb63 --- /dev/null +++ b/AABB_tree/test/AABB_tree/aabb_test_move_constructor.cpp @@ -0,0 +1,193 @@ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template auto create_tree(); +template void init_tree(T &tree) {} +template bool test_tree(T &tree); +template class TestUtils; + +// test 0 is from "aabb_test_singleton_tree" +template <> struct TestUtils<0> { + typedef CGAL::Simple_cartesian K; + typedef K::FT FT; + typedef K::Point_3 Point; + typedef K::Plane_3 Plane; + typedef K::Segment_3 Segment; + typedef K::Triangle_3 Triangle; + typedef std::vector::iterator Iterator; + typedef CGAL::AABB_segment_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Tree; + + Point a = {1.0, 0.0, 0.0}; + Point b = {0.0, 1.0, 0.0}; + Point c = {0.0, 0.0, 1.0}; + Point d = {0.0, 0.0, 0.0}; + std::vector segments = {Segment(Point(0, 0, 0), Point(2, 2, 2))}; +}; + +template <> auto create_tree<0>() { + using T = TestUtils<0>; + T utils; + return T::Tree(utils.segments.begin(), utils.segments.end()); +} +using Test0Param = decltype(create_tree<0>()); +template <> bool test_tree<0, Test0Param>(Test0Param &tree) { + using T = TestUtils<0>; + T utils; + + T::Plane plane_query(utils.a, utils.b, utils.d); + T::Triangle triangle_query(utils.a, utils.b, utils.c); + + // Test calls to all functions + CGAL::Emptyset_iterator devnull; + tree.all_intersections(triangle_query, devnull); + tree.all_intersected_primitives(triangle_query, devnull); + assert(tree.any_intersected_primitive(triangle_query)); + assert(tree.any_intersection(triangle_query)); + const CGAL::Bbox_3 bbox = tree.bbox(); + assert(bbox == CGAL::Bbox_3(0, 0, 0, 2, 2, 2)); + tree.clear(); + tree.insert(utils.segments.begin(), utils.segments.end()); + tree.build(); + assert(tree.closest_point(T::Point(-0.1, -0.1, -0.1)) == T::Point(0, 0, 0)); + assert(tree.closest_point(T::Point(-0.1, -0.1, -0.1), T::Point(0, 0, 0)) == + T::Point(0, 0, 0)); + assert(tree.closest_point_and_primitive(T::Point(-0.1, -0.1, -0.1)).second == + utils.segments.begin()); + assert(tree.do_intersect(plane_query) == true); + assert(tree.do_intersect(triangle_query) == true); + assert(!tree.empty()); + assert(tree.size() == 1); + tree.clear(); + assert(tree.size() == 0); + tree.insert(utils.segments.begin(), utils.segments.end()); + assert(tree.size() == 1); + assert(tree.number_of_intersected_primitives(plane_query) == 1); + tree.rebuild(utils.segments.begin(), utils.segments.end()); + assert(tree.size() == 1); + assert(tree.number_of_intersected_primitives(triangle_query) == 1); + assert(tree.squared_distance(T::Point(0, 0, 0)) == 0); + return true; +} + +// test 1 is from "aabb_test_all_intersected_primitives" +template <> struct TestUtils<1> { + typedef CGAL::Epick K; + typedef K::FT FT; + typedef K::Point_3 Point; + typedef K::Vector_3 Vector; + typedef K::Segment_3 Segment; + typedef K::Ray_3 Ray; + typedef CGAL::Surface_mesh> Mesh; + typedef CGAL::AABB_halfedge_graph_segment_primitive + S_Primitive; + typedef CGAL::AABB_face_graph_triangle_primitive + T_Primitive; + typedef CGAL::AABB_traits T_Traits; + typedef CGAL::AABB_traits S_Traits; + typedef CGAL::AABB_tree T_Tree; + typedef CGAL::AABB_tree S_Tree; + typedef T_Tree::Primitive_id T_Primitive_id; + typedef S_Tree::Primitive_id S_Primitive_id; +}; + +template <> auto create_tree<1>() { + using T = TestUtils<1>; + + static CGAL::Surface_mesh> m1 = {}; + static CGAL::Surface_mesh> m2 = {}; + static bool mesh_loaded = false; + if (!mesh_loaded) { + std::ifstream in("data/cube.off"); + assert(in); + in >> m1; + in.close(); + in.open("data/tetrahedron.off"); + assert(in); + in >> m2; + in.close(); + mesh_loaded = true; + } + return std::make_pair(T::T_Tree{faces(m1).first, faces(m1).second, m1}, + T::S_Tree{edges(m2).first, edges(m2).second, m2}); +} +using Test1Param = decltype(create_tree<1>()); +template <> void init_tree<1, Test1Param>(Test1Param &trees) { + trees.first.build(); + trees.second.build(); +} +template <> bool test_tree<1, Test1Param>(Test1Param &trees) { + using T = TestUtils<1>; + + auto &cube_tree = trees.first; + auto &tet_tree = trees.second; + + std::list t_primitives; + std::list s_primitives; + cube_tree.all_intersected_primitives(tet_tree, + std::back_inserter(t_primitives)); + CGAL_assertion(t_primitives.size() == 6); + tet_tree.all_intersected_primitives(cube_tree, + std::back_inserter(s_primitives)); + CGAL_assertion(s_primitives.size() == 6); + CGAL_assertion(tet_tree.do_intersect(cube_tree)); + CGAL_assertion(cube_tree.do_intersect(tet_tree)); + + std::vector all_primitives; + cube_tree.all_intersected_primitives(tet_tree, + std::back_inserter(all_primitives)); + bool found_f5 = false; + for (auto prim : all_primitives) { + if ((int)prim.first == 5) + found_f5 = true; + } + CGAL_assertion(found_f5); + CGAL_USE(found_f5); + return true; +} + +template bool run_test() { + // create_tree should return prvalue for guaranteed copy elision + auto tree_1 = create_tree(); + init_tree(tree_1); + auto tree_2 = create_tree(); + init_tree(tree_2); + auto tree_3 = create_tree(); + init_tree(tree_3); + + decltype(tree_1) tree_ctor{std::move(tree_2)}; + decltype(tree_1) tree_assig{}; + tree_assig = std::move(tree_3); + + bool normal = test_tree(tree_1); + bool move_ctor = test_tree(tree_ctor); + bool move_ass = + test_tree(tree_assig); // test move assignment operator + + if (!normal) + std::cout << "Test " << test_number << "failed on the original tree\n"; + if (!move_ctor) + std::cout << "Test " << test_number << "failed on move constructed tree\n"; + if (!move_ass) + std::cout << "Test " << test_number << "failed on move assigned tree\n"; + return normal && move_ctor && move_ass; +} + +int main() { return (run_test<0>() && run_test<1>()) ? 0 : 1; }