Browse Source

Math: make one-dimensional range just from scalar types.

Since Range1D is now used all over Animation, the vector made it very
annoying to use. That's fixed now. This is a backwards-incompatible
change, but I don't expect the 1D range to be used much, mainly because
it was so shitty to use. Generic code that needs a vector can always
cast to it, like this:

    Math::Vector<dimensions, T>{range.min()}

Test for the constructor from pair is no longer accepting pairs of 1D
vectors. I have no idea what I meant by that test case (it's testing the
same thing twice), so I removed one of these.
pull/297/head
Vladimír Vondruš 8 years ago
parent
commit
0226ab26c4
  1. 6
      doc/changelog.dox
  2. 13
      doc/snippets/MagnumMath.cpp
  3. 6
      src/Magnum/Animation/Player.hpp
  4. 2
      src/Magnum/Animation/Test/PlayerCustomTest.cpp
  5. 4
      src/Magnum/Animation/Test/PlayerTest.cpp
  6. 8
      src/Magnum/GL/AbstractTexture.cpp
  7. 4
      src/Magnum/GL/Renderer.cpp
  8. 2
      src/Magnum/GL/Test/RendererGLTest.cpp
  9. 76
      src/Magnum/Math/Range.h
  10. 177
      src/Magnum/Math/Test/RangeTest.cpp

6
doc/changelog.dox

@ -528,6 +528,12 @@ See also:
working to fail with an assertion. See the new
@ref Math::Matrix3::rotationShear() and @ref Math::Matrix4::rotationShear()
accessors for a possible solution.
- Since one-dimensional @ref Math::Range is now used on many new places such
as the @ref Animation library, its underlying type is just @cpp T @ce
instead of @ref Math::Vector "Math::Vector<1, T>" to make it easier to use.
This may break rare existing code that was using one-dimensional ranges or
generic code that's always expecting a vector type. See
@ref Math-Range-generic for possible solutions.
- @ref SceneGraph::Camera::setViewport() and @ref SceneGraph::Camera::draw()
are no longer @cpp virtual @ce functions. If you need to override their
functionality, simply call the subclass implementation directly instead of

13
doc/snippets/MagnumMath.cpp

@ -873,6 +873,19 @@ Debug{} << Math::Vector3<UnsignedShort>{a}; // prints {16968, 48552, 15993}
/* [Half-usage-vector] */
}
{
Range1D range, a, b;
constexpr UnsignedInt dimensions = 1;
typedef Float T;
/* [Range-generic] */
Math::Vector<dimensions, T> min = range.min(); // works for 1D, 2D and 3D
T c = Math::max<dimensions, T>(a.size(), b.size()).product(); // vector max()
/* [Range-generic] */
static_cast<void>(min);
static_cast<void>(c);
}
{
/* [Range-construct-minmax] */
Vector3 a, b, c;

6
src/Magnum/Animation/Player.hpp

@ -250,7 +250,7 @@ template<class T, class K> std::pair<UnsignedInt, K> Player<T, K>::elapsed(const
T startTime = _startTime;
T pauseTime = _stopPauseTime;
State state = _state;
const K duration = _duration.size()[0];
const K duration = _duration.size();
const Containers::Optional<std::pair<UnsignedInt, K>> elapsed = Implementation::playerElapsed(duration, _playCount, _scaler, time, startTime, pauseTime, state);
if(elapsed) return *elapsed;
@ -282,12 +282,12 @@ template<class T, class K> std::pair<UnsignedInt, K> Player<T, K>::elapsed(const
template<class T, class K> Player<T, K>& Player<T, K>::advance(const T time) {
/* Get the elapsed time. If we shouldn't advance anything (player already
stopped / not yet playing, quit */
Containers::Optional<std::pair<UnsignedInt, K>> elapsed = Implementation::playerElapsed(_duration.size()[0], _playCount, _scaler, time, _startTime, _stopPauseTime, _state);
Containers::Optional<std::pair<UnsignedInt, K>> elapsed = Implementation::playerElapsed(_duration.size(), _playCount, _scaler, time, _startTime, _stopPauseTime, _state);
if(!elapsed) return *this;
/* Advance all tracks. Properly handle durations that don't start at 0. */
for(Track& t: _tracks)
t.advancer(t.track, _duration.min()[0] + elapsed->second, t.hint, t.destination, t.userCallback, t.userCallbackData);
t.advancer(t.track, _duration.min() + elapsed->second, t.hint, t.destination, t.userCallback, t.userCallbackData);
return *this;
}

2
src/Magnum/Animation/Test/PlayerCustomTest.cpp

@ -67,7 +67,7 @@ void PlayerCustomTest::test() {
player.add(Track, value)
.play(2000000ull);
CORRADE_COMPARE(player.duration().size()[0], 24*3);
CORRADE_COMPARE(player.duration().size(), 24*3);
/* 1.75 secs in */
player.advance(3750000ull);

4
src/Magnum/Animation/Test/PlayerTest.cpp

@ -1230,7 +1230,7 @@ void PlayerTest::runFor100YearsFloat() {
/* The track must fit an integer number of times into the day for this test
to work (3 seconds do fit) */
CORRADE_COMPARE(player.duration().size()[0], 3.0f);
CORRADE_COMPARE(player.duration().size(), 3.0f);
CORRADE_COMPARE(player.state(), State::Playing);
CORRADE_COMPARE(value, -1.0f);
@ -1277,7 +1277,7 @@ void PlayerTest::runFor100YearsChrono() {
/* The track must fit an integer number of times into the day for this test
to work (3 seconds do fit) */
CORRADE_COMPARE(player.duration().size()[0], 3.0f);
CORRADE_COMPARE(player.duration().size(), 3.0f);
CORRADE_COMPARE(player.state(), State::Playing);
CORRADE_COMPARE(value, -1.0f);

8
src/Magnum/GL/AbstractTexture.cpp

@ -1795,7 +1795,7 @@ template<UnsignedInt dimensions> void AbstractTexture::subImage(const GLint leve
const Math::Vector<dimensions, Int> size = range.size();
const std::size_t dataSize = Magnum::Implementation::imageDataSizeFor(image, size);
const Vector3i paddedOffset = Vector3i::pad(range.min());
const Vector3i paddedOffset = Vector3i::pad<dimensions>(range.min());
const Vector3i paddedSize = Vector3i::pad(size, 1);
/* Reallocate only if needed */
@ -1818,7 +1818,7 @@ template<UnsignedInt dimensions> void AbstractTexture::subImage(const GLint leve
const Math::Vector<dimensions, Int> size = range.size();
const std::size_t dataSize = Magnum::Implementation::imageDataSizeFor(image, size);
const Vector3i paddedOffset = Vector3i::pad(range.min());
const Vector3i paddedOffset = Vector3i::pad<dimensions>(range.min());
const Vector3i paddedSize = Vector3i::pad(size, 1);
/* Reallocate only if needed */
@ -1848,7 +1848,7 @@ template<UnsignedInt dimensions> void AbstractTexture::compressedSubImage(const
createIfNotAlready();
const Math::Vector<dimensions, Int> size = range.size();
const Vector3i paddedOffset = Vector3i::pad(range.min());
const Vector3i paddedOffset = Vector3i::pad<dimensions>(range.min());
const Vector3i paddedSize = Vector3i::pad(size, 1);
/* Internal texture format */
@ -1882,7 +1882,7 @@ template<UnsignedInt dimensions> void AbstractTexture::compressedSubImage(const
createIfNotAlready();
const Math::Vector<dimensions, Int> size = range.size();
const Vector3i paddedOffset = Vector3i::pad(range.min());
const Vector3i paddedOffset = Vector3i::pad<dimensions>(range.min());
const Vector3i paddedSize = Vector3i::pad(size, 1);
/* Internal texture format */

4
src/Magnum/GL/Renderer.cpp

@ -40,7 +40,7 @@ Range1D Renderer::lineWidthRange() {
Range1D& value = state.lineWidthRange;
/* Get the value, if not already cached */
if(value.max().isZero())
if(!value.max())
value = state.lineWidthRangeImplementation();
return value;
@ -55,7 +55,7 @@ Range1D Renderer::lineWidthRangeImplementationDefault() {
#ifndef MAGNUM_TARGET_GLES
Range1D Renderer::lineWidthRangeImplementationMesaForwardCompatible() {
Range1D value = lineWidthRangeImplementationDefault();
value.max() = Math::min(1.0f, value.max()[0]);
value.max() = Math::min(1.0f, value.max());
return value;
}
#endif

2
src/Magnum/GL/Test/RendererGLTest.cpp

@ -55,7 +55,7 @@ void RendererGLTest::maxLineWidth() {
MAGNUM_VERIFY_NO_GL_ERROR();
Renderer::setLineWidth(lineWidthRange.max()[0]);
Renderer::setLineWidth(lineWidthRange.max());
MAGNUM_VERIFY_NO_GL_ERROR();
}

76
src/Magnum/Math/Range.h

@ -37,7 +37,7 @@ namespace Magnum { namespace Math {
namespace Implementation {
template<UnsignedInt, class> struct RangeTraits;
template<class T> struct RangeTraits<1, T> { typedef Vector<1, T> Type; };
template<class T> struct RangeTraits<1, T> { typedef T Type; };
template<class T> struct RangeTraits<2, T> { typedef Vector2<T> Type; };
template<class T> struct RangeTraits<3, T> { typedef Vector3<T> Type; };
@ -47,9 +47,19 @@ namespace Implementation {
/**
@brief N-dimensional range
Axis-aligned line (in 1D), rectangle (in 2D) or cube (in 3D). Minimal
Axis-aligned line (in 1D), rectangle (in 2D) or cube (in 3D). The minimal
coordinate is inclusive, maximal exclusive. See @ref Range1D, @ref Range2D and
@ref Range3D specializations for given dimension count.
@section Math-Range-generic Use in generic code
While @ref Range2D and @ref Range3D have a vector underlying type, @ref Range1D
is just a scalar. This makes common usage simpler, but may break in generic
code that expects a vector type for any dimension. Solution is to
unconditionally cast the value to a vector type or explicitly specify template
parameters to choose a vector function overload. For example:
@snippet MagnumMath.cpp Range-generic
*/
template<UnsignedInt dimensions, class T> class Range {
template<UnsignedInt, class> friend class Range;
@ -58,8 +68,8 @@ template<UnsignedInt dimensions, class T> class Range {
/**
* @brief Underlying vector type
*
* @ref Math::Vector "Vector<1, T>" in 1D, @ref Math::Vector2 "Vector2<T>"
* in 2D, @ref Math::Vector3 "Vector3<T>" in 3D.
* @cpp T @ce in 1D, @ref Math::Vector2 "Vector2<T>" in 2D,
* @ref Math::Vector3 "Vector3<T>" in 3D.
*/
typedef typename Implementation::RangeTraits<dimensions, T>::Type VectorType;
@ -91,10 +101,10 @@ template<UnsignedInt dimensions, class T> class Range {
*
* Construct zero-size range positioned at origin.
*/
constexpr /*implicit*/ Range(ZeroInitT = ZeroInit) noexcept: _min{ZeroInit}, _max{ZeroInit} {}
constexpr /*implicit*/ Range(ZeroInitT = ZeroInit) noexcept: Range<dimensions, T>{ZeroInit, typename std::conditional<dimensions == 1, void*, ZeroInitT*>::type{}} {}
/** @brief Construct without initializing the contents */
explicit Range(NoInitT) noexcept: _min{NoInit}, _max{NoInit} {}
explicit Range(NoInitT) noexcept: Range<dimensions, T>{NoInit, typename std::conditional<dimensions == 1, void*, NoInitT*>::type{}} {}
/** @brief Construct a range from minimal and maximal coordinates */
constexpr /*implicit*/ Range(const VectorType& min, const VectorType& max) noexcept: _min{min}, _max{max} {}
@ -143,12 +153,10 @@ template<UnsignedInt dimensions, class T> class Range {
}
/** @brief Equality comparison */
constexpr bool operator==(const Range<dimensions, T>& other) const {
return _min == other._min && _max == other._max;
}
bool operator==(const Range<dimensions, T>& other) const;
/** @brief Non-equality comparison */
constexpr bool operator!=(const Range<dimensions, T>& other) const {
bool operator!=(const Range<dimensions, T>& other) const {
return !operator==(other);
}
@ -156,8 +164,12 @@ template<UnsignedInt dimensions, class T> class Range {
* @brief Raw data
* @return One-dimensional array of `dimensions`*2 length.
*/
T* data() { return _min.data(); }
constexpr const T* data() const { return _min.data(); } /**< @overload */
T* data() {
return dataInternal(typename std::conditional<dimensions == 1, void*, T*>::type{});
}
constexpr const T* data() const {
return dataInternal(typename std::conditional<dimensions == 1, void*, T*>::type{});
} /**< @overload */
/**
* @brief Minimal coordinates (inclusive)
@ -258,7 +270,8 @@ template<UnsignedInt dimensions, class T> class Range {
* @ref min(), @ref max()
*/
bool contains(const VectorType& b) const {
return (b >= _min).all() && (b < _max).all();
return (Vector<dimensions, T>{b} >= _min).all() &&
(Vector<dimensions, T>{b} < _max).all();
}
/**
@ -276,10 +289,27 @@ template<UnsignedInt dimensions, class T> class Range {
* @ref min(), @ref max()
*/
bool contains(const Range<dimensions, T>& b) const {
return (b._min >= _min).all() && (b._max <= _max).all();
return (Vector<dimensions, T>{b._min} >= _min).all() &&
(Vector<dimensions, T>{b._max} <= _max).all();
}
private:
/* Called from Range(ZeroInit), either using the ZeroInit constructor
(if available) or passing zero directly (for scalar types) */
constexpr explicit Range(ZeroInitT, ZeroInitT*) noexcept: _min{ZeroInit}, _max{ZeroInit} {}
constexpr explicit Range(ZeroInitT, void*) noexcept: _min{T(0)}, _max{T(0)} {}
/* Called from Range(NoInit), either using the NoInit constructor (if
available) or not doing anything */
explicit Range(NoInitT, NoInitT*) noexcept: _min{NoInit}, _max{NoInit} {}
explicit Range(NoInitT, void*) noexcept {}
/* Called from data(), always returning a T* */
constexpr const VectorType* dataInternal(void*) const { return &_min; }
VectorType* dataInternal(void*) { return &_min; }
constexpr const T* dataInternal(T*) const { return _min.data(); }
T* dataInternal(T*) { return _min.data(); }
VectorType _min, _max;
};
@ -693,21 +723,29 @@ are undefined if any range has a negative size.
@ref Range::max()
*/
template<UnsignedInt dimensions, class T> inline bool intersects(const Range<dimensions, T>& a, const Range<dimensions, T>& b) {
return (a.max() > b.min()).all() && (a.min() < b.max()).all();
return (Vector<dimensions, T>{a.max()} > b.min()).all() &&
(Vector<dimensions, T>{a.min()} < b.max()).all();
}
/** @debugoperator{Range} */
template<UnsignedInt dimensions, class T> Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug& debug, const Range<dimensions, T>& value) {
debug << "Range({" << Corrade::Utility::Debug::nospace << value.min()[0];
debug << "Range({" << Corrade::Utility::Debug::nospace << Vector<dimensions, T>{value.min()}[0];
for(UnsignedInt i = 1; i != dimensions; ++i)
debug << Corrade::Utility::Debug::nospace << "," << value.min()[i];
debug << Corrade::Utility::Debug::nospace << "," << Vector<dimensions, T>{value.min()}[i];
debug << Corrade::Utility::Debug::nospace << "}, {"
<< Corrade::Utility::Debug::nospace << value.max()[0];
<< Corrade::Utility::Debug::nospace << Vector<dimensions, T>{value.max()}[0];
for(UnsignedInt i = 1; i != dimensions; ++i)
debug << Corrade::Utility::Debug::nospace << "," << value.max()[i];
debug << Corrade::Utility::Debug::nospace << "," << Vector<dimensions, T>{value.max()}[i];
return debug << Corrade::Utility::Debug::nospace << "})";
}
template<UnsignedInt dimensions, class T> inline bool Range<dimensions, T>::operator==(const Range<dimensions, T>& other) const {
/* For non-scalar types default implementation of TypeTraits would be used,
which is just operator== */
return TypeTraits<VectorType>::equals(_min, other._min) &&
TypeTraits<VectorType>::equals(_max, other._max);
}
/* Explicit instantiation for commonly used types */
#ifndef DOXYGEN_GENERATING_OUTPUT
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const Range<1, Float>&);

177
src/Magnum/Math/Test/RangeTest.cpp

@ -52,9 +52,9 @@ template<> struct RangeConverter<1, Float, Dim> {
}
constexpr static Dim to(const Range<1, Float>& other) {
return {other.min()[0],
return {other.min(),
/* Doing it this way to preserve constexpr */
other.max()[0] - other.min()[0]};
other.max() - other.min()};
}
};
@ -113,15 +113,26 @@ struct RangeTest: Corrade::TestSuite::Tester {
void size();
void center();
/* Testing 1D separately because it's a scalar, not vector. The above
functions test all dimensions explicitly. */
void translated();
void translated1D();
void padded();
void padded1D();
void scaled();
void scaled1D();
void scaledFromCenter();
void scaledFromCenter1D();
void containsVector();
void containsPoint();
void containsPoint1D();
void containsRange();
void containsRange1D();
void intersectIntersects();
void intersectIntersects1D();
void join();
void join1D();
void subclassTypes();
void subclass();
@ -157,14 +168,22 @@ RangeTest::RangeTest() {
&RangeTest::center,
&RangeTest::translated,
&RangeTest::translated1D,
&RangeTest::padded,
&RangeTest::padded1D,
&RangeTest::scaled,
&RangeTest::scaled1D,
&RangeTest::scaledFromCenter,
&RangeTest::scaledFromCenter1D,
&RangeTest::containsVector,
&RangeTest::containsPoint,
&RangeTest::containsPoint1D,
&RangeTest::containsRange,
&RangeTest::containsRange1D,
&RangeTest::intersectIntersects,
&RangeTest::intersectIntersects1D,
&RangeTest::join,
&RangeTest::join1D,
&RangeTest::subclassTypes,
&RangeTest::subclass,
@ -255,11 +274,9 @@ void RangeTest::constructPair() {
Vector2i b{30, 18};
Vector2i c{20, 25};
Range1Di bounds1a{Math::minmax<Math::Vector<1, Int>>({a.x(), b.x(), c.x()})};
Range1Di bounds1b{std::pair<Math::Vector<1, Int>, Math::Vector<1, Int>>{10, 30}};
Range1Di bounds1a{Math::minmax({a.x(), b.x(), c.x()})};
Range1Di bounds1c{10, 30};
CORRADE_COMPARE(bounds1a, bounds1c);
CORRADE_COMPARE(bounds1b, bounds1c);
Range2Di bounds2a{Math::minmax({a, b, c})};
Range2Di bounds2b{std::pair<Math::Vector<2, Int>, Math::Vector<2, Int>>{{10, 18}, {30, 25}}};
@ -372,6 +389,16 @@ void RangeTest::access() {
constexpr Range2Di crect({34, 23}, {47, 30});
constexpr Range3Di ccube({34, 23, -17}, {47, 30, 12});
CORRADE_COMPARE(line.data(), static_cast<void*>(&line));
CORRADE_COMPARE(rect.data(), static_cast<void*>(&rect));
CORRADE_COMPARE(cube.data(), static_cast<void*>(&cube));
constexpr Int lineData = *cline.data();
constexpr Int rectData = *crect.data();
constexpr Int cubeData = *ccube.data();
CORRADE_COMPARE(lineData, 34);
CORRADE_COMPARE(rectData, 34);
CORRADE_COMPARE(cubeData, 34);
CORRADE_COMPARE(line.min(), 34);
CORRADE_COMPARE(cline.min(), 34);
CORRADE_COMPARE(line.max(), 47);
@ -520,6 +547,14 @@ void RangeTest::translated() {
CORRADE_COMPARE(a.size(), b.size());
}
void RangeTest::translated1D() {
Range1Di a(34, 47);
Range1Di b(17, 30);
CORRADE_COMPARE(a.translated(-17), b);
CORRADE_COMPARE(a.size(), b.size());
}
void RangeTest::padded() {
Range2Di a({34, 23}, {47, 30});
Range2Di b({31, 28}, {50, 25});
@ -528,6 +563,14 @@ void RangeTest::padded() {
CORRADE_COMPARE(a.center(), b.center());
}
void RangeTest::padded1D() {
Range1Di a{34, 47};
Range1Di b{31, 50};
CORRADE_COMPARE(a.padded(3), b);
CORRADE_COMPARE(a.center(), b.center());
}
void RangeTest::scaled() {
Range2Di a({34, 23}, {47, 30});
Range2Di b({68, -69}, {94, -90});
@ -536,6 +579,14 @@ void RangeTest::scaled() {
CORRADE_COMPARE((a.size()*Vector2i{2, -3}), b.size());
}
void RangeTest::scaled1D() {
Range1Di a{34, 47};
Range1Di b{68, 94};
CORRADE_COMPARE(a.scaled(2), b);
CORRADE_COMPARE(a.size()*2, b.size());
}
void RangeTest::scaledFromCenter() {
Range2Di a{{34, 22}, {48, 30}};
Range2Di b{{27, 38}, {55, 14}};
@ -545,7 +596,16 @@ void RangeTest::scaledFromCenter() {
CORRADE_COMPARE((a.size()*Vector2i{2, -3}), b.size());
}
void RangeTest::containsVector() {
void RangeTest::scaledFromCenter1D() {
Range1Di a{34, 48};
Range1Di b{27, 55};
CORRADE_COMPARE(a.scaledFromCenter(2), b);
CORRADE_COMPARE(a.center(), b.center());
CORRADE_COMPARE(a.size()*2, b.size());
}
void RangeTest::containsPoint() {
Range2Di a({34, 23}, {47, 30});
CORRADE_VERIFY(a.contains({40, 23}));
@ -557,6 +617,17 @@ void RangeTest::containsVector() {
CORRADE_VERIFY(!a.contains({47, 30}));
}
void RangeTest::containsPoint1D() {
Range1Di a{34, 47};
CORRADE_VERIFY(a.contains(40));
CORRADE_VERIFY(!a.contains(33));
/* Contains a point at min, but not at max */
CORRADE_VERIFY(a.contains(34));
CORRADE_VERIFY(!a.contains(47));
}
void RangeTest::containsRange() {
Range2Di a({34, 23}, {47, 30});
@ -593,6 +664,42 @@ void RangeTest::containsRange() {
CORRADE_VERIFY(!a.contains(j));
}
void RangeTest::containsRange1D() {
Range1Di a{34, 47};
/* Contains whole range with a gap, not the other way around */
Range1Di b{35, 40};
CORRADE_VERIFY(a.contains(b));
CORRADE_VERIFY(!b.contains(a));
/* Contains itself, empty range contains itself as well */
Range1Di c;
CORRADE_VERIFY(a.contains(a));
CORRADE_VERIFY(b.contains(b));
CORRADE_VERIFY(c.contains(c));
/* Contains zero-sized range inside but not outside */
Range1Di d{34, 34};
Range1Di e{33, 33};
Range1Di f{47, 47};
Range1Di g{48, 48};
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 */
Range1Di h{30, 35};
CORRADE_VERIFY(!a.contains(h));
CORRADE_VERIFY(!h.contains(a));
/* Doesn't contain a range touching the edges from the outside */
Range1Di i{20, 34};
Range1Di j{47, 60};
CORRADE_VERIFY(!a.contains(i));
CORRADE_VERIFY(!a.contains(j));
}
void RangeTest::intersectIntersects() {
Range2Di a({34, 23}, {47, 30});
@ -645,6 +752,48 @@ void RangeTest::intersectIntersects() {
CORRADE_COMPARE(Math::intersect(l, a), Range2Di{});
}
void RangeTest::intersectIntersects1D() {
Range1Di a(34, 47);
/* Intersects itself */
CORRADE_VERIFY(Math::intersects(a, a));
CORRADE_COMPARE(Math::intersect(a, a), a);
/* Non-empty intersection */
Range1Di b{30, 35};
Range1Di c{34, 35};
CORRADE_VERIFY(Math::intersects(a, b));
CORRADE_VERIFY(Math::intersects(b, a));
CORRADE_COMPARE(Math::intersect(a, b), c);
CORRADE_COMPARE(Math::intersect(b, a), c);
/* Intersecting with an empty range outside produces a default-constructed range */
Range1Di d{130, 130};
CORRADE_VERIFY(!Math::intersects(a, d));
CORRADE_VERIFY(!Math::intersects(d, a));
CORRADE_COMPARE(Math::intersect(a, d), Range1Di{});
CORRADE_COMPARE(Math::intersect(d, a), Range1Di{});
/* Intersecting with an empty range inside produces an empty range */
Range1Di e{40, 40};
CORRADE_VERIFY(Math::intersects(a, e));
CORRADE_VERIFY(Math::intersects(e, a));
CORRADE_COMPARE(Math::intersect(a, e), e);
CORRADE_COMPARE(Math::intersect(e, a), e);
/* Doesn't intersect a range touching the edges from the outside */
Range1Di i{20, 34};
Range1Di j{47, 60};
CORRADE_VERIFY(!Math::intersects(a, i));
CORRADE_VERIFY(!Math::intersects(a, j));
CORRADE_VERIFY(!Math::intersects(i, a));
CORRADE_VERIFY(!Math::intersects(j, a));
CORRADE_COMPARE(Math::intersect(a, i), Range1Di{});
CORRADE_COMPARE(Math::intersect(a, j), Range1Di{});
CORRADE_COMPARE(Math::intersect(i, a), Range1Di{});
CORRADE_COMPARE(Math::intersect(j, a), Range1Di{});
}
void RangeTest::join() {
Range2Di a{{12, 20}, {15, 35}};
Range2Di b{{10, 25}, {17, 105}};
@ -657,6 +806,18 @@ void RangeTest::join() {
CORRADE_COMPARE(Math::join(c, a), a);
}
void RangeTest::join1D() {
Range1Di a{12, 15};
Range1Di b{10, 17};
Range1Di c{130, 130};
Range1Di d{10, 17};
CORRADE_COMPARE(Math::join(a, b), d);
CORRADE_COMPARE(Math::join(b, a), d);
CORRADE_COMPARE(Math::join(a, c), a);
CORRADE_COMPARE(Math::join(c, a), a);
}
template<class T> class BasicRect: public Math::Range<2, T> {
public:
template<class ...U> constexpr BasicRect(U&&... args): Math::Range<2, T>{args...} {}

Loading…
Cancel
Save