diff --git a/src/Magnum/Math/Range.h b/src/Magnum/Math/Range.h index 529ce08159..37c08acc04 100644 --- a/src/Magnum/Math/Range.h +++ b/src/Magnum/Math/Range.h @@ -50,6 +50,13 @@ namespace Implementation { Axis-aligned line (in 1D), rectangle (in 2D) or cube (in 3D). Minimal coordinate is inclusive, maximal exclusive. See @ref Range1D, @ref Range2D and @ref Range3D specializations for given dimension count. + +@section Math-Range-inverted Inverted ranges + +It is valid to create ranges where a maximal coordinate is less than the +matching minimal coordinate in some dimension. The range is then interpreted as +inverted in given dimension, affecting result of @ref contains(), @ref intersect(), +@ref intersects() and @ref join(). */ template class Range { template friend class Range; @@ -234,7 +241,6 @@ template class Range { * @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() */ @@ -252,7 +258,6 @@ template class Range { * (\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() */ @@ -646,8 +651,7 @@ template inline Range join(const Returns a range that covers the intersection of both ranges. If the intersection is empty, a default-constructed range is returned. The range -minimum is interpreted as inclusive, maximum as exclusive. Results are -undefined if any range has a negative size. +minimum is interpreted as inclusive, maximum as exclusive. @see @ref intersects() */ template inline Range intersect(const Range& a, const Range& b) { @@ -664,13 +668,13 @@ Returns @cpp true @ce if the following holds for all dimensions @f$ i @f$, (\operatorname{max}(A)_i > \operatorname{min}(B)_i) \land (\operatorname{min}(A)_i < \operatorname{max}(B)_i) @f] -The range minimum is interpreted as inclusive, maximum as exclusive. Results -are undefined if any range has a negative size. +The range minimum is interpreted as inclusive, maximum as exclusive. @see @ref Range::contains(), @ref intersect(), @ref join(), @ref Range::min(), @ref Range::max() */ template inline bool intersects(const Range& a, const Range& b) { - return (a.max() > b.min()).all() && (a.min() < b.max()).all(); + return ((a.min() > b.min()) & (a.min() < b.max())).all() || + ((b.min() > a.min()) & (b.min() < a.max())).all(); } /** @debugoperator{Range} */ diff --git a/src/Magnum/Math/Test/RangeTest.cpp b/src/Magnum/Math/Test/RangeTest.cpp index c7114a0b97..f69bdc9663 100644 --- a/src/Magnum/Math/Test/RangeTest.cpp +++ b/src/Magnum/Math/Test/RangeTest.cpp @@ -119,6 +119,7 @@ struct RangeTest: Corrade::TestSuite::Tester { void containsVector(); void containsRange(); + void containsRangeInverted(); void intersectIntersects(); void join(); @@ -161,6 +162,7 @@ RangeTest::RangeTest() { &RangeTest::containsVector, &RangeTest::containsRange, + &RangeTest::containsRangeInverted, &RangeTest::intersectIntersects, &RangeTest::join, @@ -581,6 +583,16 @@ void RangeTest::containsRange() { CORRADE_VERIFY(!a.contains(j)); } +void RangeTest::containsRangeInverted() { + /* Inverse range contains things that are only outside */ + Range2Di b({40, 50}, {10, 30}); + CORRADE_VERIFY( b.contains({{45, 55}, { 5, 25}})); + CORRADE_VERIFY(!b.contains({{35, 45}, {15, 35}})); /* B contains A */ + CORRADE_VERIFY(!b.contains({{15, 35}, {35, 45}})); /* Fully inside */ + CORRADE_VERIFY(!b.contains({{45, 55}, {15, 25}})); /* "Leaks" on max X */ + CORRADE_VERIFY(!b.contains({{45, 45}, { 5, 25}})); /* "Leaks" on min Y */ +} + void RangeTest::intersectIntersects() { Range2Di a({34, 23}, {47, 30});