mirror of https://github.com/mosra/magnum.git
5 changed files with 418 additions and 0 deletions
@ -0,0 +1,79 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
Copyright © 2022 Pablo Escobar <mail@rvrs.in> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "BoundingVolume.h" |
||||||
|
|
||||||
|
#include <Corrade/Containers/StridedArrayView.h> |
||||||
|
|
||||||
|
#include "Magnum/Math/FunctionsBatch.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace MeshTools { |
||||||
|
|
||||||
|
Range3D boundingBoxAxisAligned(const Containers::StridedArrayView1D<const Vector3>& points) { |
||||||
|
return Math::minmax(points); |
||||||
|
} |
||||||
|
|
||||||
|
Containers::Pair<Vector3, Float> boundingSphereBouncingBubble(const Containers::StridedArrayView1D<const Vector3>& points) { |
||||||
|
/* See comment about radius below, this is done for consistency */ |
||||||
|
if(points.isEmpty()) return {{}, Math::TypeTraits<Float>::epsilon()}; |
||||||
|
|
||||||
|
/** @todo Skip NaNs here? To match behaviour of boundingBoxAxisAligned()
|
||||||
|
which uses minmax(). */ |
||||||
|
Vector3 center = points[0]; |
||||||
|
/* Radius ends up in the denominator in the first loop so we can't
|
||||||
|
initialize it to 0. Unfortunately this also means the returned radius is |
||||||
|
always above or equal to epsilon. */ |
||||||
|
Float radius = Math::TypeTraits<Float>::epsilon(); |
||||||
|
Float radiusSquared = radius*radius; |
||||||
|
|
||||||
|
for(int i = 0; i < 2; ++i) { |
||||||
|
for(const Vector3& p : points) { |
||||||
|
const Float ds = (p - center).dot(); |
||||||
|
if(ds > radiusSquared) { |
||||||
|
const Float alphaInv = radius/Math::sqrt(ds); |
||||||
|
const Float alphaSqInv = alphaInv*alphaInv; |
||||||
|
radius = (1.0f/alphaInv + alphaInv)*0.5f*radius; |
||||||
|
center = ((1.0f + alphaSqInv)*center + (1.0f - alphaSqInv)*p)*0.5f; |
||||||
|
radiusSquared = radius*radius; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for(const Vector3& p : points) { |
||||||
|
const Vector3 diff = p - center; |
||||||
|
const Float ds = diff.dot(); |
||||||
|
if(ds > radiusSquared) { |
||||||
|
const Float d = Math::sqrt(ds); |
||||||
|
radius = (radius + d)*0.5f; |
||||||
|
center = center + ((d - radius)/d*diff); |
||||||
|
radiusSquared = radius*radius; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return {center, radius}; |
||||||
|
} |
||||||
|
|
||||||
|
}} |
||||||
@ -0,0 +1,72 @@ |
|||||||
|
#ifndef Magnum_MeshTools_BoundingVolume_h |
||||||
|
#define Magnum_MeshTools_BoundingVolume_h |
||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
Copyright © 2022 Pablo Escobar <mail@rvrs.in> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** @file
|
||||||
|
* @brief Function @ref Magnum::MeshTools::boundingBoxAxisAligned(), @ref Magnum::MeshTools::boundingSphereBouncingBubble() |
||||||
|
* @m_since_latest |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <Corrade/Containers/Pair.h> |
||||||
|
|
||||||
|
#include "Magnum/Magnum.h" |
||||||
|
#include "Magnum/Math/Range.h" |
||||||
|
#include "Magnum/Math/Vector3.h" |
||||||
|
#include "Magnum/MeshTools/visibility.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace MeshTools { |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Calculate an axis-aligned bounding box |
||||||
|
@param positions Vertex positions |
||||||
|
@return Bounding box |
||||||
|
@m_since_latest |
||||||
|
|
||||||
|
Same as @ref Math::minmax(const Corrade::Containers::StridedArrayView1D<const T>&). |
||||||
|
*/ |
||||||
|
MAGNUM_MESHTOOLS_EXPORT Range3D boundingBoxAxisAligned(const Containers::StridedArrayView1D<const Vector3>& positions); |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Calculate an approximate bounding sphere using the Bouncing Bubble |
||||||
|
algorithm |
||||||
|
@param positions Vertex positions |
||||||
|
@return Sphere center and radius |
||||||
|
@m_since_latest |
||||||
|
|
||||||
|
The resulting bounding sphere is not usually minimal. According to the author, |
||||||
|
a 1% to 2% error can be expected. Due to the nature of the algorithm, the |
||||||
|
radius is never below @ref Math::TypeTraits::epsilon(), even for empty or |
||||||
|
entirely overlapping lists of points. <em>NaN</em>s are ignored, unless the |
||||||
|
first position is <em>NaN</em> in which case it is propagated. Algorithm used: |
||||||
|
* *Bo Tian --- Bouncing Bubble: A fast algorithm for Minimal Enclosing Ball |
||||||
|
problem, 2012, https://www.grin.com/document/204869*
|
||||||
|
*/ |
||||||
|
MAGNUM_MESHTOOLS_EXPORT Containers::Pair<Vector3, Float> boundingSphereBouncingBubble(const Containers::StridedArrayView1D<const Vector3>& positions); |
||||||
|
|
||||||
|
}} |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,264 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
Copyright © 2022 Pablo Escobar <mail@rvrs.in> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <Corrade/Containers/Array.h> |
||||||
|
#include <Corrade/Containers/StridedArrayView.h> |
||||||
|
#include <Corrade/TestSuite/Tester.h> |
||||||
|
#include <Corrade/TestSuite/Compare/Numeric.h> |
||||||
|
|
||||||
|
#include "Magnum/Math/FunctionsBatch.h" |
||||||
|
#include "Magnum/Math/TypeTraits.h" |
||||||
|
#include "Magnum/Math/Angle.h" |
||||||
|
#include "Magnum/Math/Vector3.h" |
||||||
|
#include "Magnum/MeshTools/BoundingVolume.h" |
||||||
|
#include "Magnum/MeshTools/Reference.h" |
||||||
|
#include "Magnum/MeshTools/Transform.h" |
||||||
|
#include "Magnum/Primitives/Capsule.h" |
||||||
|
#include "Magnum/Primitives/Cube.h" |
||||||
|
#include "Magnum/Primitives/Icosphere.h" |
||||||
|
#include "Magnum/Trade/MeshData.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace MeshTools { namespace Test { namespace { |
||||||
|
|
||||||
|
struct BoundingVolumeTest: TestSuite::Tester { |
||||||
|
explicit BoundingVolumeTest(); |
||||||
|
|
||||||
|
void boxAxisAligned(); |
||||||
|
void boxAxisAlignedNaN(); |
||||||
|
|
||||||
|
void sphereBouncingBubble(); |
||||||
|
void sphereBouncingBubbleNaN(); |
||||||
|
|
||||||
|
void benchmarkBoxAxisAligned(); |
||||||
|
void benchmarkSphereBouncingBubble(); |
||||||
|
}; |
||||||
|
|
||||||
|
BoundingVolumeTest::BoundingVolumeTest() { |
||||||
|
addTests({&BoundingVolumeTest::boxAxisAligned, |
||||||
|
&BoundingVolumeTest::boxAxisAlignedNaN, |
||||||
|
&BoundingVolumeTest::sphereBouncingBubble, |
||||||
|
&BoundingVolumeTest::sphereBouncingBubbleNaN}); |
||||||
|
|
||||||
|
addBenchmarks({&BoundingVolumeTest::benchmarkBoxAxisAligned, |
||||||
|
&BoundingVolumeTest::benchmarkSphereBouncingBubble}, 150); |
||||||
|
} |
||||||
|
|
||||||
|
void BoundingVolumeTest::boxAxisAligned() { |
||||||
|
/* boundingboxAxisAligned() is just a wrapper around minmax() so only test
|
||||||
|
that the input and output are forwarded correctly */ |
||||||
|
constexpr Float cylinderLength = 7.0f; |
||||||
|
const Trade::MeshData cylinderMesh = Primitives::capsule3DSolid(3, 1, 12, cylinderLength*0.5f); |
||||||
|
const Range3D box = MeshTools::boundingBoxAxisAligned( |
||||||
|
cylinderMesh.attribute<Vector3>(Trade::MeshAttribute::Position)); |
||||||
|
|
||||||
|
CORRADE_COMPARE(box.center(), (Vector3{})); |
||||||
|
CORRADE_COMPARE(box.size(), (Vector3{2.0f, cylinderLength + 2.0f, 2.0f})); |
||||||
|
} |
||||||
|
|
||||||
|
void BoundingVolumeTest::boxAxisAlignedNaN() { |
||||||
|
/* NaNs are skipped (unless it's all NaNs), matching minmax() behaviour */ |
||||||
|
{ |
||||||
|
const Range3D box = MeshTools::boundingBoxAxisAligned(Containers::stridedArrayView({ |
||||||
|
Vector3{Constants::nan()}, |
||||||
|
Vector3{1.0f, 1.0f, 1.0f}, |
||||||
|
Vector3{Constants::nan()}, |
||||||
|
Vector3{2.0f, 2.0f, 2.0f}, |
||||||
|
Vector3{Constants::nan()} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(box.min(), (Vector3{1.0f, 1.0f, 1.0f})); |
||||||
|
CORRADE_COMPARE(box.max(), (Vector3{2.0f, 2.0f, 2.0f})); |
||||||
|
} { |
||||||
|
const Range3D box = MeshTools::boundingBoxAxisAligned(Containers::stridedArrayView({ |
||||||
|
Vector3{Constants::nan()}, |
||||||
|
Vector3{Constants::nan()} |
||||||
|
})); |
||||||
|
CORRADE_VERIFY(Math::isNan(box.min())); |
||||||
|
CORRADE_VERIFY(Math::isNan(box.max())); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void BoundingVolumeTest::sphereBouncingBubble() { |
||||||
|
/* Empty positions -- produces radius epsilon for consistency with all
|
||||||
|
all identical positions */ |
||||||
|
{ |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(Containers::StridedArrayView1D<const Vector3>{}); |
||||||
|
CORRADE_COMPARE(sphere.first(), (Vector3{})); |
||||||
|
CORRADE_COMPARE(sphere.second(), Math::TypeTraits<Float>::epsilon()); |
||||||
|
|
||||||
|
/* Identical positions -- radius is always >= epsilon due to specifics of
|
||||||
|
the algorithm */ |
||||||
|
} { |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(Containers::stridedArrayView({ |
||||||
|
Vector3{1.0f, 2.0f, 3.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(sphere.first(), (Vector3{1.0f, 2.0f, 3.0f})); |
||||||
|
CORRADE_COMPARE(sphere.second(), Math::TypeTraits<Float>::epsilon()); |
||||||
|
} { |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(Containers::stridedArrayView({ |
||||||
|
Vector3{3.0f, 1.0f, 2.0f}, |
||||||
|
Vector3{3.0f, 1.0f, 2.0f}, |
||||||
|
Vector3{3.0f, 1.0f, 2.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(sphere.first(), (Vector3{3.0f, 1.0f, 2.0f})); |
||||||
|
CORRADE_COMPARE(sphere.second(), Math::TypeTraits<Float>::epsilon()); |
||||||
|
|
||||||
|
/* Simple cases */ |
||||||
|
} { |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(Containers::stridedArrayView({ |
||||||
|
Vector3{1.0f, 1.0f, 1.0f}, |
||||||
|
Vector3{2.0f, 2.0f, 2.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(sphere.first(), (Vector3{1.5f})); |
||||||
|
CORRADE_COMPARE(sphere.second(), Vector3{0.5f}.length()); |
||||||
|
} { |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(Containers::stridedArrayView({ |
||||||
|
Vector3{2.0f, 0.0f, 0.0f}, |
||||||
|
Vector3{-2.0f, 0.0f, 0.0f}, |
||||||
|
Vector3{0.0f, 2.0f, 0.0f}, |
||||||
|
Vector3{0.0f, -2.0f, 0.0f} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(sphere.first(), (Vector3{0.0f, 0.0f, 0.0f})); |
||||||
|
CORRADE_COMPARE(sphere.second(), 2.0f); |
||||||
|
|
||||||
|
/* Icosphere -- original/translated and scaled */ |
||||||
|
} { |
||||||
|
const Trade::MeshData sphereMesh = Primitives::icosphereSolid(1); |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(sphereMesh.attribute<Vector3>(Trade::MeshAttribute::Position)); |
||||||
|
/* No error */ |
||||||
|
CORRADE_COMPARE(sphere.first(), (Vector3{0.0f, 0.0f, 0.0f})); |
||||||
|
CORRADE_COMPARE(sphere.second(), 1.0f); |
||||||
|
} { |
||||||
|
Trade::MeshData sphereMesh = Primitives::icosphereSolid(1); |
||||||
|
constexpr Vector3 translation{1.0f, 2.0f, 3.0f}; |
||||||
|
constexpr Vector3 scale{0.5f, 1.2f, 2.8f}; |
||||||
|
MeshTools::transform3DInPlace(sphereMesh, Matrix4::translation(translation)*Matrix4::scaling(scale)); |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(sphereMesh.attribute<Vector3>(Trade::MeshAttribute::Position)); |
||||||
|
/* Noticeable error */ |
||||||
|
constexpr Float Delta = 0.04f; |
||||||
|
CORRADE_COMPARE_WITH(sphere.first(), translation, TestSuite::Compare::around(Vector3{Delta})); |
||||||
|
/* Radius should never be smaller than the ground truth */ |
||||||
|
CORRADE_COMPARE_WITH(sphere.second(), scale.max() + Delta, TestSuite::Compare::around(Delta)); |
||||||
|
|
||||||
|
/* Cube -- translated and scaled */ |
||||||
|
} { |
||||||
|
Trade::MeshData cubeMesh = MeshTools::owned(Primitives::cubeSolid()); |
||||||
|
constexpr Vector3 translation{1.0f, 2.0f, 3.0f}; |
||||||
|
constexpr Float scale = 13.2f; |
||||||
|
MeshTools::transform3DInPlace(cubeMesh, Matrix4::translation(translation)*Matrix4::scaling(Vector3{scale})); |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(cubeMesh.attribute<Vector3>(Trade::MeshAttribute::Position)); |
||||||
|
/* Noticeable error */ |
||||||
|
constexpr Float Delta = 0.04f; |
||||||
|
CORRADE_COMPARE_WITH(sphere.first(), translation, TestSuite::Compare::around(Vector3{Delta})); |
||||||
|
CORRADE_COMPARE_WITH(sphere.second(), Constants::sqrt3()*scale + Delta, |
||||||
|
TestSuite::Compare::around(Delta)); |
||||||
|
} |
||||||
|
|
||||||
|
/* Radius is rotationally invariant */ |
||||||
|
using namespace Math::Literals; |
||||||
|
|
||||||
|
for(Deg degrees = 0.0_degf; degrees < 360.0_degf; degrees += 60.0_degf) { |
||||||
|
CORRADE_ITERATION(degrees); |
||||||
|
Trade::MeshData cubeMesh = MeshTools::owned(Primitives::cubeSolid()); |
||||||
|
constexpr Vector3 translation{1.0f, 2.0f, 3.0f}; |
||||||
|
MeshTools::transform3DInPlace(cubeMesh, Matrix4::rotationY(degrees)*Matrix4::translation(translation)); |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(cubeMesh.attribute<Vector3>(Trade::MeshAttribute::Position)); |
||||||
|
CORRADE_COMPARE(sphere.second(), Constants::sqrt3()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void BoundingVolumeTest::sphereBouncingBubbleNaN() { |
||||||
|
/* NaN is ignored except for the first position element */ |
||||||
|
{ |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(Containers::stridedArrayView({ |
||||||
|
Vector3{1.0f, 1.0f, 1.0f}, |
||||||
|
Vector3{Constants::nan()}, |
||||||
|
Vector3{2.0f, 2.0f, 2.0f}, |
||||||
|
Vector3{Constants::nan()} |
||||||
|
})); |
||||||
|
CORRADE_COMPARE(sphere.first(), (Vector3{1.5f})); |
||||||
|
CORRADE_COMPARE(sphere.second(), Vector3{0.5f}.length()); |
||||||
|
|
||||||
|
} { |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(Containers::stridedArrayView({ |
||||||
|
Vector3{Constants::nan()}, |
||||||
|
Vector3{1.0f, 1.0f, 1.0f}, |
||||||
|
Vector3{2.0f, 2.0f, 2.0f} |
||||||
|
})); |
||||||
|
{ |
||||||
|
CORRADE_EXPECT_FAIL("NaN in the first position is not ignored."); |
||||||
|
CORRADE_COMPARE(sphere.first(), (Vector3{1.5f})); |
||||||
|
CORRADE_COMPARE(sphere.second(), Vector3{0.5f}.length()); |
||||||
|
} |
||||||
|
CORRADE_VERIFY(Math::isNan(sphere.first())); |
||||||
|
CORRADE_COMPARE(sphere.second(), Math::TypeTraits<Float>::epsilon()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void BoundingVolumeTest::benchmarkBoxAxisAligned() { |
||||||
|
Containers::Array<Vector3> points{NoInit, 500}; |
||||||
|
for(size_t i = 0; i < points.size(); ++i) { |
||||||
|
points[i] = Vector3{Float(i)*0.01f}; |
||||||
|
} |
||||||
|
|
||||||
|
Float r = 0.0f; |
||||||
|
CORRADE_BENCHMARK(50) { |
||||||
|
const Range3D box = MeshTools::boundingBoxAxisAligned(points); |
||||||
|
r += box.size().x(); |
||||||
|
} |
||||||
|
|
||||||
|
CORRADE_COMPARE_AS(r, 1.0f, TestSuite::Compare::Greater); |
||||||
|
} |
||||||
|
|
||||||
|
void BoundingVolumeTest::benchmarkSphereBouncingBubble() { |
||||||
|
Containers::Array<Vector3> points{NoInit, 500}; |
||||||
|
for(size_t i = 0; i < points.size(); ++i) { |
||||||
|
points[i] = Vector3{Float(i)*0.01f}; |
||||||
|
} |
||||||
|
|
||||||
|
Float r = 0.0f; |
||||||
|
CORRADE_BENCHMARK(50) { |
||||||
|
const Containers::Pair<Vector3, Float> sphere = |
||||||
|
MeshTools::boundingSphereBouncingBubble(points); |
||||||
|
r += sphere.second(); |
||||||
|
} |
||||||
|
|
||||||
|
CORRADE_COMPARE_AS(r, 1.0f, TestSuite::Compare::Greater); |
||||||
|
} |
||||||
|
|
||||||
|
}}}} |
||||||
|
|
||||||
|
CORRADE_TEST_MAIN(Magnum::MeshTools::Test::BoundingVolumeTest) |
||||||
Loading…
Reference in new issue