From 719e806d2fd5a2a2239f92577b47d4f64249a49e Mon Sep 17 00:00:00 2001 From: Quentin Khan <quentin.khan@inria.fr> Date: Mon, 25 Jan 2016 10:27:22 +0100 Subject: [PATCH] Add FBox and tests FBox is a class that represents a N dimensions interval. To do so, it keeps the maximum and minimum corners of the interval. --- Src/Adaptive/new/FBox.hpp | 199 +++++++++++++++++++++++++++ Tests/noDist/Adaptive/test_FBox.cpp | 204 ++++++++++++++++++++++++++++ 2 files changed, 403 insertions(+) create mode 100644 Src/Adaptive/new/FBox.hpp create mode 100644 Tests/noDist/Adaptive/test_FBox.cpp diff --git a/Src/Adaptive/new/FBox.hpp b/Src/Adaptive/new/FBox.hpp new file mode 100644 index 000000000..71146022a --- /dev/null +++ b/Src/Adaptive/new/FBox.hpp @@ -0,0 +1,199 @@ +#ifndef SCALFMM_BOX_HPP_ +#define SCALFMM_BOX_HPP_ + +#include <ostream> + +#include "FZCurve.hpp" + +/* Implements a N dimensions box + * + * \author Quentin Khan <quentin.khan@inria.fr> + * + * The box is described by two opposite corners : the maximum and + * the minimum one. All the class transformations maintain this + * predicate. + * + * \tparam Real Floating number representation. + * \tparam Dim Space dimension count. + * \tparam SpaceFillingCurve A templatize implementation of a space filling curve + * + */ +template<class _Position, template<std::size_t> class SpaceFillingCurve = FZCurve> +class FBox { +public: + /// Position type + using position_t = _Position; + /// Floating number representation + using Real = typename position_t::Real; + /// Space dimension + constexpr static const std::size_t Dim = position_t::Dim; + /// Space filling curve type + using space_filling_curve_t = SpaceFillingCurve<Dim>; + +private: + position_t _c1; ///< Minimum corner + position_t _c2; ///< Maximum corner + position_t _center; ///< Center + + /** Rearranges the corners to ensure the maximum-minimum predicate */ + void rearrange_corners () { + for(std::size_t i = 0; i < Dim; ++i){ + if(_c1[i] > _c2[i]) { + std::swap(_c1[i], _c2[i]); + } + } + _center = (_c1 + _c2) / 2; + } +public: + /// Accessor for the minimum corner + const position_t& c1 = _c1; + /// Accessor for the maximum corner + const position_t& c2 = _c2; + + /** Builds an empty box at the origin */ + FBox() = default; + /** Copies an existing box */ + FBox(const FBox& other) : _c1(other._c1), _c2(other._c2), _center(other._center) {} + + /** Copies an other box */ + FBox& operator=(const FBox& other) { + this->_c1 = other._c1; + this->_c2 = other._c2; + this->_center = other._center; + return *this; + } + + /** Builds a cube from the lower corner and its side length + * + * \param min_corner The lowest corner + * \param side_length The cube's side length + **/ + FBox(const position_t& min_corner, Real side_length) : + _c1(min_corner), + _c2(min_corner) + { + if(side_length < 0) { + side_length = - side_length; + } + + for(auto&& d : _c2) { + d += side_length; + } + + _center = (_c1 + _c2) / 2; + } + + /** Builds a box from two corners + * + * The maximum and minimum corners are deduced from the given corners. + * + * \param corner_1 The first corner. + * \param corner_2 The second corner. + */ + FBox(const position_t& corner_1, const position_t& corner_2) : _c1(corner_1), _c2(corner_2) { + rearrange_corners(); + } + + /** Changes the box corners + * + * The maximum and minimum corners are deduced from the given corners. + * + * \param corner_1 The first corner. + * \param corner_2 The second corner. + */ + void set(const position_t& corner_1, const position_t& corner_2) { + _c1 = corner_1; + _c2 = corner_2; + + rearrange_corners(); + } + + /** Checks whether a position is within the box bounds + * + * \param p The position to check. + */ + bool contains(const position_t& p) const { + for(std::size_t i = 0; i < Dim; i++) { + if(p[i] < _c1[i] || p[i] > _c2[i]) { + return false; + } + } + return true; + } + + /** Checks whether an object's position is within the box bounds + * + * The object must implement a `position_t position() const;` method. + * + * \tparam T The object type. + * \param obj The object which position to check. + */ + template<class T> + bool contains(const T& obj) const { + return contains(obj.position()); + } + + + /** Accessor for the box center */ + const position_t& center() const { + return _center; + } + + /** Accessor for the box corners + * + * The corners are numbered using a space filling curve. + * + * \param idx The corner index. + * \return The idx'th corner. + */ + position_t corner(std::size_t idx) const { + position_t c; + std::size_t i = 0; + for(bool choice : space_filling_curve_t::position(idx)) { + c[i] = choice ? _c2[i] : _c1[i]; + ++i; + } + return c; + } + + /** Setter for the corners + * + * Moves a corner to a new position and modifies the relevant other + * ones. The corners are numbered using a space filling curve. + * + * \param idx The moved corner index. + * \param pos The new corner position. + */ + void corner(std::size_t idx, const position_t& pos) { + std::size_t i = 0; + for(bool choice : space_filling_curve_t::position(idx)) { + if(choice) { + _c2[i] = pos[i]; + } else { + _c1[i] = pos[i]; + } + ++i; + } + rearrange_corners(); + } + + /** Sums the corners of two boxes */ + FBox operator+(const FBox& other) const { + return FBox(_c1 + other._c1, _c2 + other._c2); + } + + /** Tests two boxes equality */ + bool operator==(const FBox& other) const { + return c1 == other.c1 && c2 == other.c2; + } + /** Tests two boxes inequality */ + bool operator!=(const FBox& other) const { + return ! this->operator==(other); + } + + friend std::ostream& operator<<(std::ostream& os, const FBox& box) { + return os << "[" << box.c1 << "," << box.c2 << "]"; + } +}; + +#endif diff --git a/Tests/noDist/Adaptive/test_FBox.cpp b/Tests/noDist/Adaptive/test_FBox.cpp new file mode 100644 index 000000000..154995605 --- /dev/null +++ b/Tests/noDist/Adaptive/test_FBox.cpp @@ -0,0 +1,204 @@ +#include <cassert> +#include <cmath> +#include <iostream> + +#include "test_Abstract.hpp" + +#include "Utils/FPoint.hpp" +#include "Utils/FConstFuncs.hpp" +#include "Adaptive/new/FBox.hpp" + +namespace scalfmm { + namespace tests { + + + struct test_Box : public test_Abstract<test_Box> { + + constexpr static const std::size_t Dim = 3; + using position_t = FPoint<double, Dim>; + using box_t = FBox<position_t>; + + void run_all() { + RUN(test_constructor_1 ); + RUN(test_constructor_2 ); + RUN(test_constructor_3 ); + RUN(test_constructor_4 ); + RUN(test_constructor_5 ); + RUN(test_assign_copy_operator); + RUN(test_assign_move_operator); + RUN(test_center ); + RUN(test_corner ); + RUN(test_contains ); + } + + + /// Test default constructor + void test_constructor_1() { + box_t b; + position_t p {0,0,0}; + assert(b.c1 == p); + assert(b.c2 == p); + } + + /// Test constructor with minimum and maximum corners + void test_constructor_2() { + position_t p1 = {0,0,0}; + position_t p2 = {100,100,100}; + + box_t b(p1, p2); + assert(b.c1 == p1); + assert(b.c2 == p2); + } + + /// Test constructor with initializer lists + void test_constructor_3() { + position_t p {0,0,0}; + box_t d({0,0,0},{0,0,0}); + + assert(d.c1 == p); + assert(d.c2 == p); + } + + /// Test copy constructor + void test_constructor_4() { + position_t p1 = {0,0,0}; + position_t p2 = {100,100,100}; + box_t c(p1, p2); + + box_t e(c); + assert(c.c1 == e.c1); + assert(c.c2 == e.c2); + + // test deep copy + c.set(p2, p1 + position_t{-1,0,0}); + + assert(c.c1 != e.c1); + assert(c.c2 == e.c2); + } + + void test_constructor_5() { + position_t p1 = {0,100,0}; + position_t p2 = {100,0,100}; + box_t c(p1, p2); + + for(std::size_t i = 0; i < Dim; ++i) { + assert(Ffeq(c.c1[i], std::fmin(p1[i], p2[i]))); + assert(Ffeq(c.c2[i], std::fmax(p1[i], p2[i]))); + } + } + + void test_assign_copy_operator() { + position_t p1 = {0,0,0}; + position_t p2 = {100,100,100}; + box_t a(p1, p2); + + box_t b; + b = a; + assert(a.c1 == b.c1); + assert(a.c2 == b.c2); + assert(a.center() == b.center()); + } + + void test_assign_move_operator() { + position_t p1 = {0,0,0}; + position_t p2 = {100,100,100}; + box_t a(p1, p2); + + box_t b; + b = std::move(a); + assert(a.c1 == b.c1); + assert(a.c2 == b.c2); + } + + + void test_center() { + position_t p1 = {0,10,50}; + position_t p2 = {100,100,100}; + position_t p3 = {50,55,75}; + + box_t b{p1, p2}; + + assert(b.center() == p3); + + // Test center after copy + box_t c(b); + assert(c.center() == p3); + + b.set({20,30,40}, {120, 130, 140}); + assert(b.center() == position_t(70, 80, 90)); + } + + void test_corner() { + position_t p0 = { 0, 0, 0}; + position_t p1 = { 0, 0,100}; + position_t p2 = { 0,100, 0}; + position_t p3 = { 0,100,100}; + position_t p4 = {100, 0, 0}; + position_t p5 = {100, 0,100}; + position_t p6 = {100,100, 0}; + position_t p7 = {100,100,100}; + + box_t b = {p0, p7}; + + assert(b.corner(0) == p0); + assert(b.corner(1) == p1); + assert(b.corner(2) == p2); + assert(b.corner(3) == p3); + assert(b.corner(4) == p4); + assert(b.corner(5) == p5); + assert(b.corner(6) == p6); + assert(b.corner(7) == p7); + + b.corner(0, {1,1,1}); + assert(b.corner(0) == b.c1); + assert(b.corner(0) == position_t(1,1,1)); + b.corner(0, {0,0,0}); + + b.corner(2, {20, 80, 30}); + assert(b.c1 == position_t(20, 0, 30)); + assert(b.c2 == position_t(100, 80, 100)); + + b.corner(5, {0, 20, 25}); + assert(b.c1 == position_t(0, 20, 25)); + assert(b.c2 == position_t(20, 80, 30)); + } + + struct DummyObject { + position_t p; + position_t position() const {return p;} + }; + + void test_contains() { + box_t b = {{0,0,0}, {100,100,100}}; + + assert(b.contains(b.c1)); + assert(b.contains(b.c2)); + assert(b.contains({50,50,50})); + assert(! b.contains({150,50,50})); + assert(! b.contains({50,150,50})); + assert(! b.contains({50,50,150})); + assert(! b.contains({50,150,150})); + assert(! b.contains({150,150,50})); + assert(! b.contains({150,50,150})); + assert(! b.contains({150,150,150})); + + assert(b.contains(DummyObject {{ 50, 50, 50}})); + assert(! b.contains(DummyObject{{150, 50, 50}})); + assert(! b.contains(DummyObject{{ 50,150, 50}})); + assert(! b.contains(DummyObject{{ 50, 50,150}})); + assert(! b.contains(DummyObject{{ 50,150,150}})); + assert(! b.contains(DummyObject{{150,150, 50}})); + assert(! b.contains(DummyObject{{150, 50,150}})); + assert(! b.contains(DummyObject{{150,150,150}})); + + + } + + }; + + } +} + +int main() { + scalfmm::tests::test_Box().run_all(); +} -- GitLab