From 8a35299636b4b6464ba6b067ed2e7dfd7a6395b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 13 Aug 2018 20:47:10 +0200 Subject: [PATCH] Math: added Math::Range::contains() with Range as a parameter. --- doc/changelog.dox | 2 ++ src/Magnum/Math/Range.h | 38 +++++++++++++++++++++-- src/Magnum/Math/Test/RangeTest.cpp | 48 ++++++++++++++++++++++++++++-- 3 files changed, 82 insertions(+), 6 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index fa6ff7716..13ffe7190 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -71,6 +71,8 @@ See also: and @ref Math::Range3D::y() for slicing ranges into lower dimensions - Added @ref Math::intersect() and @ref Math::intersects() as a counterpart to @ref Math::join() for operating with @ref Math::Range instances +- Added @ref Math::Range::contains() overloading taking a range, in addition + to vector - Added @ref Math::Constants::piQuarter() - Added a convenience function @ref Math::select() as a constant interpolation counterpart to @ref Math::lerp() diff --git a/src/Magnum/Math/Range.h b/src/Magnum/Math/Range.h index 329c53ce2..6ba1a3702 100644 --- a/src/Magnum/Math/Range.h +++ b/src/Magnum/Math/Range.h @@ -190,9 +190,41 @@ template class Range { */ Range scaled(const VectorType& scaling) const; - /** @brief Whether given point is contained inside the range */ - constexpr bool contains(const VectorType& a) const { - return (a >= _min).all() && (a < _max).all(); + /** + * @brief Whether given point is contained inside the range + * + * Returns @cpp true @ce if the following holds for all dimensions + * @f$ i @f$, @cpp false @ce otherwise. @f[ + * \bigwedge_i + * (b_i \ge \operatorname{min}(A)_i) \land + * (b_i < \operatorname{max}(A)_i) + * @f] + * + * The range minimum is interpreted as inclusive, maximum as exclusive. + * Results are undefined if the range has negative size. + * @see @ref intersects(), @ref contains(const Range&) const, + * @ref min(), @ref max() + */ + bool contains(const VectorType& b) const { + return (b >= _min).all() && (b < _max).all(); + } + + /** + * @brief Whether another range is fully contained inside this range + * + * Returns @cpp true @ce if the following holds for all dimensions + * @f$ i @f$, @cpp false @ce otherwise. @f[ + * \bigwedge_i + * (\operatorname{min}(B)_i \ge \operatorname{min}(A)_i) \land + * (\operatorname{max}(B)_i \le \operatorname{max}(A)_i) + * @f] + * + * Results are undefined if the range has negative size. + * @see @ref intersects(), @ref contains(const VectorType&) const, + * @ref min(), @ref max() + */ + bool contains(const Range& b) const { + return (b._min >= _min).all() && (b._max <= _max).all(); } private: diff --git a/src/Magnum/Math/Test/RangeTest.cpp b/src/Magnum/Math/Test/RangeTest.cpp index 35dfb9e0d..9d9de731b 100644 --- a/src/Magnum/Math/Test/RangeTest.cpp +++ b/src/Magnum/Math/Test/RangeTest.cpp @@ -115,7 +115,8 @@ struct RangeTest: Corrade::TestSuite::Tester { void padded(); void scaled(); - void contains(); + void containsVector(); + void containsRange(); void intersectIntersects(); void join(); @@ -154,7 +155,8 @@ RangeTest::RangeTest() { &RangeTest::padded, &RangeTest::scaled, - &RangeTest::contains, + &RangeTest::containsVector, + &RangeTest::containsRange, &RangeTest::intersectIntersects, &RangeTest::join, @@ -500,12 +502,52 @@ void RangeTest::scaled() { CORRADE_COMPARE(a.scaled({2, -3}), b); } -void RangeTest::contains() { +void RangeTest::containsVector() { Range2Di a({34, 23}, {47, 30}); CORRADE_VERIFY(a.contains({40, 23})); CORRADE_VERIFY(!a.contains({33, 23})); CORRADE_VERIFY(!a.contains({40, 30})); + + /* Contains a point at min, but not at max */ + CORRADE_VERIFY(a.contains({34, 23})); + CORRADE_VERIFY(!a.contains({47, 30})); +} + +void RangeTest::containsRange() { + Range2Di a({34, 23}, {47, 30}); + + /* Contains whole range with a gap, not the other way around */ + Range2Di b{{35, 25}, {40, 28}}; + CORRADE_VERIFY(a.contains(b)); + CORRADE_VERIFY(!b.contains(a)); + + /* Contains itself, empty range contains itself as well */ + Range2Di c; + CORRADE_VERIFY(a.contains(a)); + CORRADE_VERIFY(b.contains(b)); + CORRADE_VERIFY(c.contains(c)); + + /* Contains zero-sized range inside but not outside */ + Range2Di d{{34, 23}, {34, 23}}; + Range2Di e{{33, 23}, {33, 23}}; + Range2Di f{{47, 30}, {47, 30}}; + Range2Di g{{47, 31}, {47, 31}}; + CORRADE_VERIFY(a.contains(d)); + CORRADE_VERIFY(!a.contains(e)); + CORRADE_VERIFY(a.contains(f)); + CORRADE_VERIFY(!a.contains(g)); + + /* Doesn't contain a range that overlaps */ + Range2Di h{{30, 25}, {35, 105}}; + CORRADE_VERIFY(!a.contains(h)); + CORRADE_VERIFY(!h.contains(a)); + + /* Doesn't contain a range touching the edges from the outside */ + Range2Di i{{20, 30}, {34, 40}}; + Range2Di j{{47, 20}, {60, 23}}; + CORRADE_VERIFY(!a.contains(i)); + CORRADE_VERIFY(!a.contains(j)); } void RangeTest::intersectIntersects() {