Browse Source

Math: add castInto() variants for Double<->integer.

Because yes of course dealing with a JSON just isn't possible
without having to make decisions between insufficiently imprecise
integers and unnecessarly overprecise doubles.
sceneconverter
Vladimír Vondruš 4 years ago
parent
commit
e0909fedfe
  1. 4
      doc/changelog.dox
  2. 48
      src/Magnum/Math/PackingBatch.cpp
  3. 100
      src/Magnum/Math/PackingBatch.h
  4. 96
      src/Magnum/Math/Test/PackingBatchTest.cpp

4
doc/changelog.dox

@ -379,8 +379,8 @@ See also:
- Added @ref Math::castInto() overloads for casting between @ref UnsignedByte
and @ref UnsignedShort or @ref Byte and @ref Short, from and to
@ref UnsignedLong / @ref Long, and for casting between @ref Float and
@ref Double
@ref UnsignedLong / @ref Long, between integral types and @ref Double and
for casting between @ref Float and @ref Double
- @ref Math::RectangularMatrix is now explicitly convertible from matrices of
different sizes, with a possibility to specify whether to fill the diagonal
or leave it as zeros. This was originally available only on (square)

48
src/Magnum/Math/PackingBatch.cpp

@ -216,6 +216,30 @@ void castInto(const Corrade::Containers::StridedArrayView2D<const Int>& src, con
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const UnsignedByte>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const Byte>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const UnsignedShort>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const Short>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const UnsignedInt>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const Int>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const Float>& src, const Corrade::Containers::StridedArrayView2D<UnsignedByte>& dst) {
castIntoImplementation(src, dst);
}
@ -240,6 +264,30 @@ void castInto(const Corrade::Containers::StridedArrayView2D<const Float>& src, c
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<UnsignedByte>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<Byte>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<UnsignedShort>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<Short>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<UnsignedInt>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<Int>& dst) {
castIntoImplementation(src, dst);
}
void castInto(const Corrade::Containers::StridedArrayView2D<const UnsignedByte>& src, const Corrade::Containers::StridedArrayView2D<UnsignedShort>& dst) {
castIntoImplementation(src, dst);
}

100
src/Magnum/Math/PackingBatch.h

@ -215,6 +215,56 @@ MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const Int>& src, const Corrade::Containers::StridedArrayView2D<Float>& dst);
/**
@brief Cast integer values into a 64-bit floating-point representation
@param[in] src Source integral values
@param[out] dst Destination float values
@m_since_latest
Unlike @ref packInto(), this function performs only an equivalent of
@cpp Double(a) @ce over the range, so e.g. @cpp 135 @ce becomes @cpp 135.0 @ce.
Second dimension is meant to contain vector/matrix components, or have a size
of 1 for scalars. Expects that @p src and @p dst have the same size and that
the second dimension in both is contiguous.
@attention Numbers with more than 52 bits of precision will not be represented
accurately when cast into a @relativeref{Magnum,Double}.
@see @ref castInto(const Corrade::Containers::StridedArrayView2D<const Double>&, const Corrade::Containers::StridedArrayView2D<UnsignedByte>&),
@ref Corrade::Containers::StridedArrayView::isContiguous()
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const UnsignedByte>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst);
/**
* @overload
* @m_since_latest
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const Byte>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst);
/**
* @overload
* @m_since_latest
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const UnsignedShort>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst);
/**
* @overload
* @m_since_latest
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const Short>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst);
/**
* @overload
* @m_since_latest
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const UnsignedInt>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst);
/**
* @overload
* @m_since_latest
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const Int>& src, const Corrade::Containers::StridedArrayView2D<Double>& dst);
/**
@brief Cast 32-bit floating-point values into an integer representation
@param[in] src Source float values
@ -265,6 +315,56 @@ MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const Float>& src, const Corrade::Containers::StridedArrayView2D<Int>& dst);
/**
@brief Cast 64-bit floating-point values into an integer representation
@param[in] src Source double values
@param[out] dst Destination integral values
@m_since_latest
Unlike @ref packInto(), this function performs only an equivalent of
@cpp T(a) @ce over the range, so e.g. @cpp 135.0 @ce becomes @cpp 135 @ce.
Second dimension is meant to contain vector/matrix components, or have a size
of 1 for scalars. Expects that @p src and @p dst have the same size and that
the second dimension in both is contiguous.
@attention Fractional part of the @relativeref{Magnum,Double} input will be
silently discarded when cast into an integer type.
@see @ref castInto(const Corrade::Containers::StridedArrayView2D<const UnsignedByte>&, const Corrade::Containers::StridedArrayView2D<Double>&),
@ref Corrade::Containers::StridedArrayView::isContiguous()
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<UnsignedByte>& dst);
/**
* @overload
* @m_since_latest
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<Byte>& dst);
/**
* @overload
* @m_since_latest
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<UnsignedShort>& dst);
/**
* @overload
* @m_since_latest
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<Short>& dst);
/**
* @overload
* @m_since_latest
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<UnsignedInt>& dst);
/**
* @overload
* @m_since_latest
*/
MAGNUM_EXPORT void castInto(const Corrade::Containers::StridedArrayView2D<const Double>& src, const Corrade::Containers::StridedArrayView2D<Int>& dst);
/**
@brief Cast integer values into a differently sized type
@param[in] src Source values

96
src/Magnum/Math/Test/PackingBatchTest.cpp

@ -51,8 +51,8 @@ struct PackingBatchTest: Corrade::TestSuite::Tester {
void unpackHalf();
void packHalf();
template<class T> void castUnsignedFloat();
template<class T> void castSignedFloat();
template<class FloatingPoint, class Integral> void castUnsignedFloatingPoint();
template<class FloatingPoint, class Integral> void castSignedFloatingPoint();
template<class T, class U> void castUnsignedInteger();
template<class T, class U> void castSignedInteger();
@ -77,12 +77,18 @@ PackingBatchTest::PackingBatchTest() {
&PackingBatchTest::unpackHalf,
&PackingBatchTest::packHalf,
&PackingBatchTest::castUnsignedFloat<UnsignedByte>,
&PackingBatchTest::castUnsignedFloat<UnsignedShort>,
&PackingBatchTest::castUnsignedFloat<UnsignedInt>,
&PackingBatchTest::castSignedFloat<Byte>,
&PackingBatchTest::castSignedFloat<Short>,
&PackingBatchTest::castSignedFloat<Int>,
&PackingBatchTest::castUnsignedFloatingPoint<Float, UnsignedByte>,
&PackingBatchTest::castUnsignedFloatingPoint<Float, UnsignedShort>,
&PackingBatchTest::castUnsignedFloatingPoint<Float, UnsignedInt>,
&PackingBatchTest::castUnsignedFloatingPoint<Double, UnsignedByte>,
&PackingBatchTest::castUnsignedFloatingPoint<Double, UnsignedShort>,
&PackingBatchTest::castUnsignedFloatingPoint<Double, UnsignedInt>,
&PackingBatchTest::castSignedFloatingPoint<Float, Byte>,
&PackingBatchTest::castSignedFloatingPoint<Float, Short>,
&PackingBatchTest::castSignedFloatingPoint<Float, Int>,
&PackingBatchTest::castSignedFloatingPoint<Double, Byte>,
&PackingBatchTest::castSignedFloatingPoint<Double, Short>,
&PackingBatchTest::castSignedFloatingPoint<Double, Int>,
&PackingBatchTest::castUnsignedInteger<UnsignedByte, UnsignedShort>,
&PackingBatchTest::castUnsignedInteger<UnsignedByte, UnsignedInt>,
@ -109,6 +115,12 @@ PackingBatchTest::PackingBatchTest() {
&PackingBatchTest::assertionsCast<Float, Short>,
&PackingBatchTest::assertionsCast<Float, UnsignedInt>,
&PackingBatchTest::assertionsCast<Float, Int>,
&PackingBatchTest::assertionsCast<Double, UnsignedByte>,
&PackingBatchTest::assertionsCast<Double, Byte>,
&PackingBatchTest::assertionsCast<Double, UnsignedShort>,
&PackingBatchTest::assertionsCast<Double, Short>,
&PackingBatchTest::assertionsCast<Double, UnsignedInt>,
&PackingBatchTest::assertionsCast<Double, Int>,
&PackingBatchTest::assertionsCast<UnsignedShort, UnsignedByte>,
&PackingBatchTest::assertionsCast<UnsignedInt, UnsignedByte>,
&PackingBatchTest::assertionsCast<UnsignedInt, UnsignedShort>,
@ -433,12 +445,12 @@ void PackingBatchTest::packHalf() {
CORRADE_COMPARE(Math::packHalf(data[i].src), data[i].dst);
}
template<class T> void PackingBatchTest::castUnsignedFloat() {
setTestCaseTemplateName(TypeTraits<T>::name());
template<class FloatingPoint, class Integral> void PackingBatchTest::castUnsignedFloatingPoint() {
setTestCaseTemplateName({TypeTraits<FloatingPoint>::name(), TypeTraits<Integral>::name()});
struct Data {
Math::Vector2<T> src;
Vector2 dst;
Math::Vector2<Integral> src;
Math::Vector2<FloatingPoint> dst;
} data[]{
{{0, 89}, {}},
{{149, 22}, {}},
@ -447,38 +459,38 @@ template<class T> void PackingBatchTest::castUnsignedFloat() {
/* GCC 4.8 doesn't like constexpr here (cannot initialize aggregate of type
const Vector2 [3] with a compound literal), wtf */
const Vector2 expectedFloat[] {
{0.0f, 89.0f},
{149.0f, 22.0f},
{13.0f, 255.0f}
const Math::Vector2<FloatingPoint> expectedFloatingPoint[] {
{FloatingPoint(0.0), FloatingPoint(89.0)},
{FloatingPoint(149.0), FloatingPoint(22.0)},
{FloatingPoint(13.0), FloatingPoint(255.0)}
};
constexpr Math::Vector2<T> expectedInteger[] {
constexpr Math::Vector2<Integral> expectedIntegral[] {
{0, 89},
{149, 22},
{13, 255}
};
Corrade::Containers::StridedArrayView1D<Math::Vector2<T>> src{data, &data[0].src, 3, sizeof(Data)};
Corrade::Containers::StridedArrayView1D<Vector2> dst{data, &data[0].dst, 3, sizeof(Data)};
castInto(Corrade::Containers::arrayCast<2, T>(src),
Corrade::Containers::arrayCast<2, Float>(dst));
CORRADE_COMPARE_AS(dst, Corrade::Containers::stridedArrayView(expectedFloat),
Corrade::Containers::StridedArrayView1D<Math::Vector2<Integral>> src{data, &data[0].src, 3, sizeof(Data)};
Corrade::Containers::StridedArrayView1D<Math::Vector2<FloatingPoint>> dst{data, &data[0].dst, 3, sizeof(Data)};
castInto(Corrade::Containers::arrayCast<2, Integral>(src),
Corrade::Containers::arrayCast<2, FloatingPoint>(dst));
CORRADE_COMPARE_AS(dst, Corrade::Containers::stridedArrayView(expectedFloatingPoint),
Corrade::TestSuite::Compare::Container);
/* Test the other way around as well */
castInto(Corrade::Containers::arrayCast<2, Float>(dst),
Corrade::Containers::arrayCast<2, T>(src));
CORRADE_COMPARE_AS(src, Corrade::Containers::stridedArrayView(expectedInteger),
castInto(Corrade::Containers::arrayCast<2, FloatingPoint>(dst),
Corrade::Containers::arrayCast<2, Integral>(src));
CORRADE_COMPARE_AS(src, Corrade::Containers::stridedArrayView(expectedIntegral),
Corrade::TestSuite::Compare::Container);
}
template<class T> void PackingBatchTest::castSignedFloat() {
setTestCaseTemplateName(TypeTraits<T>::name());
template<class FloatingPoint, class Integral> void PackingBatchTest::castSignedFloatingPoint() {
setTestCaseTemplateName({TypeTraits<FloatingPoint>::name(), TypeTraits<Integral>::name()});
struct Data {
Math::Vector2<T> src;
Vector2 dst;
Math::Vector2<Integral> src;
Math::Vector2<FloatingPoint> dst;
} data[]{
{{0, -89}, {}},
{{-119, 22}, {}},
@ -487,29 +499,29 @@ template<class T> void PackingBatchTest::castSignedFloat() {
/* GCC 4.8 doesn't like constexpr here (cannot initialize aggregate of type
const Vector2 [3] with a compound literal), wtf */
const Vector2 expectedFloat[] {
{0.0f, -89.0f},
{-119.0f, 22.0f},
{13.0f, 127.0f}
const Math::Vector2<FloatingPoint> expectedFloatingPoint[] {
{FloatingPoint(0.0), FloatingPoint(-89.0)},
{FloatingPoint(-119.0), FloatingPoint(22.0)},
{FloatingPoint(13.0), FloatingPoint(127.0)}
};
constexpr Math::Vector2<T> expectedInteger[] {
constexpr Math::Vector2<Integral> expectedIntegral[] {
{0, -89},
{-119, 22},
{13, 127}
};
Corrade::Containers::StridedArrayView1D<Math::Vector2<T>> src{data, &data[0].src, 3, sizeof(Data)};
Corrade::Containers::StridedArrayView1D<Vector2> dst{data, &data[0].dst, 3, sizeof(Data)};
castInto(Corrade::Containers::arrayCast<2, T>(src),
Corrade::Containers::arrayCast<2, Float>(dst));
CORRADE_COMPARE_AS(dst, Corrade::Containers::stridedArrayView(expectedFloat),
Corrade::Containers::StridedArrayView1D<Math::Vector2<Integral>> src{data, &data[0].src, 3, sizeof(Data)};
Corrade::Containers::StridedArrayView1D<Math::Vector2<FloatingPoint>> dst{data, &data[0].dst, 3, sizeof(Data)};
castInto(Corrade::Containers::arrayCast<2, Integral>(src),
Corrade::Containers::arrayCast<2, FloatingPoint>(dst));
CORRADE_COMPARE_AS(dst, Corrade::Containers::stridedArrayView(expectedFloatingPoint),
Corrade::TestSuite::Compare::Container);
/* Test the other way around as well */
castInto(Corrade::Containers::arrayCast<2, Float>(dst),
Corrade::Containers::arrayCast<2, T>(src));
CORRADE_COMPARE_AS(src, Corrade::Containers::stridedArrayView(expectedInteger),
castInto(Corrade::Containers::arrayCast<2, FloatingPoint>(dst),
Corrade::Containers::arrayCast<2, Integral>(src));
CORRADE_COMPARE_AS(src, Corrade::Containers::stridedArrayView(expectedIntegral),
Corrade::TestSuite::Compare::Container);
}

Loading…
Cancel
Save