Browse Source

GCC 4.4 compatibility: better solution for explicit conversion of Unit.

Having implicit conversion on Unit class causes much more harm than
doing the conversion some other way -- mainly for multiplication and
division, which is done with builtin operators and thus the result is
unitless. Also it is possible to do wrong "retyping" between degrees and
radians:

    Rad a = Constants::pi();
    Deg b(a*2);

On GCC >4.5 b is `180`, but on GCC 4.4 it is `2pi`, which is obviously
wrong and not wanted.

The conversion is done using Unit::toUnderlyingType() which is now used
everywhere instead of conversion operator. The conversion operator is
made available only for GCC 4.5, where it can be marked as explicit.
This might cause incompatibilites with `master` branch, where no
Unit::toUnderlyingType() exists, but users should have no need to
convert it to underlying type anyway as all required functions are
available through the library.

This reverts commit 36ac4de5c4 and
partially also 0db3a183ae (UnitTest.cpp).
Vladimír Vondruš 13 years ago
parent
commit
f91f464ec8
  1. 6
      src/Color.h
  2. 8
      src/Math/Angle.h
  3. 2
      src/Math/Complex.h
  4. 6
      src/Math/Functions.h
  5. 4
      src/Math/Matrix3.h
  6. 18
      src/Math/Matrix4.h
  7. 2
      src/Math/Quaternion.h
  8. 22
      src/Math/Test/AngleTest.cpp
  9. 16
      src/Math/Test/FunctionsTest.cpp
  10. 19
      src/Math/Test/UnitTest.cpp
  11. 12
      src/Math/Unit.h
  12. 8
      src/Primitives/Capsule.cpp
  13. 2
      src/Primitives/Cylinder.cpp
  14. 2
      src/Primitives/UVSphere.cpp

6
src/Color.h

@ -46,11 +46,11 @@ template<class T> inline typename std::enable_if<std::is_floating_point<T>::valu
std::tie(hue, saturation, value) = hsv;
/* Remove repeats */
hue -= Math::Deg<T>(int(T(hue)/T(360))*T(360));
hue -= int(hue.toUnderlyingType()/T(360))*Math::Deg<T>(360);
if(hue < Math::Deg<T>(0)) hue += Math::Deg<T>(360);
int h = int(T(hue)/T(60)) % 6;
T f = T(hue)/T(60) - h;
int h = int(hue.toUnderlyingType()/T(60)) % 6;
T f = hue.toUnderlyingType()/T(60) - h;
T p = value * (T(1) - saturation);
T q = value * (T(1) - f*saturation);

8
src/Math/Angle.h

@ -231,14 +231,14 @@ See operator""_degf() for more information.
inline constexpr Rad<Float> operator "" _radf(long double value) { return Rad<Float>(value); }
#endif
template<class T> inline constexpr Deg<T>::Deg(Unit<Rad, T> value): Unit<Math::Deg, T>(T(180)*T(value)/Math::Constants<T>::pi()) {}
template<class T> inline constexpr Rad<T>::Rad(Unit<Deg, T> value): Unit<Math::Rad, T>(T(value)*Math::Constants<T>::pi()/T(180)) {}
template<class T> inline constexpr Deg<T>::Deg(Unit<Rad, T> value): Unit<Math::Deg, T>(T(180)*value.toUnderlyingType()/Math::Constants<T>::pi()) {}
template<class T> inline constexpr Rad<T>::Rad(Unit<Deg, T> value): Unit<Math::Rad, T>(value.toUnderlyingType()*Math::Constants<T>::pi()/T(180)) {}
/** @debugoperator{Magnum::Math::Rad} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Unit<Rad, T>& value) {
debug << "Rad(";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false);
debug << T(value) << ")";
debug << value.toUnderlyingType() << ")";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true);
return debug;
}
@ -247,7 +247,7 @@ template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug deb
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Unit<Deg, T>& value) {
debug << "Deg(";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false);
debug << T(value) << ")";
debug << value.toUnderlyingType() << ")";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true);
return debug;
}

2
src/Math/Complex.h

@ -93,7 +93,7 @@ template<class T> class Complex {
* @see angle(), Matrix3::rotation(), Quaternion::rotation()
*/
inline static Complex<T> rotation(Rad<T> angle) {
return {std::cos(T(angle)), std::sin(T(angle))};
return {std::cos(angle.toUnderlyingType()), std::sin(angle.toUnderlyingType())};
}
/**

6
src/Math/Functions.h

@ -86,7 +86,7 @@ UnsignedInt MAGNUM_EXPORT log(UnsignedInt base, UnsignedInt number);
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class T> inline T sin(Rad<T> angle) { return std::sin(T(angle)); }
#else
template<class T> inline T sin(Unit<Rad, T> angle) { return std::sin(T(angle)); }
template<class T> inline T sin(Unit<Rad, T> angle) { return std::sin(angle.toUnderlyingType()); }
template<class T> inline T sin(Unit<Deg, T> angle) { return sin(Rad<T>(angle)); }
#endif
@ -94,7 +94,7 @@ template<class T> inline T sin(Unit<Deg, T> angle) { return sin(Rad<T>(angle));
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class T> inline T cos(Rad<T> angle) { return std::cos(T(angle)); }
#else
template<class T> inline T cos(Unit<Rad, T> angle) { return std::cos(T(angle)); }
template<class T> inline T cos(Unit<Rad, T> angle) { return std::cos(angle.toUnderlyingType()); }
template<class T> inline T cos(Unit<Deg, T> angle) { return cos(Rad<T>(angle)); }
#endif
@ -102,7 +102,7 @@ template<class T> inline T cos(Unit<Deg, T> angle) { return cos(Rad<T>(angle));
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class T> inline T tan(Rad<T> angle) { return std::tan(T(angle)); }
#else
template<class T> inline T tan(Unit<Rad, T> angle) { return std::tan(T(angle)); }
template<class T> inline T tan(Unit<Rad, T> angle) { return std::tan(angle.toUnderlyingType()); }
template<class T> inline T tan(Unit<Deg, T> angle) { return tan(Rad<T>(angle)); }
#endif

4
src/Math/Matrix3.h

@ -80,8 +80,8 @@ template<class T> class Matrix3: public Matrix<3, T> {
* Matrix4::rotation(Rad, const Vector3&)
*/
static Matrix3<T> rotation(Rad<T> angle) {
T sine = std::sin(T(angle));
T cosine = std::cos(T(angle));
T sine = std::sin(angle.toUnderlyingType());
T cosine = std::cos(angle.toUnderlyingType());
return {{ cosine, sine, T(0)},
{ -sine, cosine, T(0)},

18
src/Math/Matrix4.h

@ -94,8 +94,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
CORRADE_ASSERT(normalizedAxis.isNormalized(),
"Math::Matrix4::rotation(): axis must be normalized", {});
T sine = std::sin(T(angle));
T cosine = std::cos(T(angle));
T sine = std::sin(angle.toUnderlyingType());
T cosine = std::cos(angle.toUnderlyingType());
T oneMinusCosine = T(1) - cosine;
T xx = normalizedAxis.x()*normalizedAxis.x();
@ -131,8 +131,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad)
*/
static Matrix4<T> rotationX(Rad<T> angle) {
T sine = std::sin(T(angle));
T cosine = std::cos(T(angle));
T sine = std::sin(angle.toUnderlyingType());
T cosine = std::cos(angle.toUnderlyingType());
return {{T(1), T(0), T(0), T(0)},
{T(0), cosine, sine, T(0)},
@ -149,8 +149,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad)
*/
static Matrix4<T> rotationY(Rad<T> angle) {
T sine = std::sin(T(angle));
T cosine = std::cos(T(angle));
T sine = std::sin(angle.toUnderlyingType());
T cosine = std::cos(angle.toUnderlyingType());
return {{cosine, T(0), -sine, T(0)},
{ T(0), T(1), T(0), T(0)},
@ -167,8 +167,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad)
*/
static Matrix4<T> rotationZ(Rad<T> angle) {
T sine = std::sin(T(angle));
T cosine = std::cos(T(angle));
T sine = std::sin(angle.toUnderlyingType());
T cosine = std::cos(angle.toUnderlyingType());
return {{cosine, sine, T(0), T(0)},
{ -sine, cosine, T(0), T(0)},
@ -235,7 +235,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see orthographicProjection(), Matrix3::projection()
*/
static Matrix4<T> perspectiveProjection(Rad<T> fov, T aspectRatio, T near, T far) {
T xyScale = 2*std::tan(T(fov)/2)*near;
T xyScale = 2*std::tan(fov.toUnderlyingType()/2)*near;
return perspectiveProjection(Vector2<T>(xyScale, xyScale/aspectRatio), near, far);
}

2
src/Math/Quaternion.h

@ -170,7 +170,7 @@ template<class T> class Quaternion {
CORRADE_ASSERT(normalizedAxis.isNormalized(),
"Math::Quaternion::rotation(): axis must be normalized", {});
return {normalizedAxis*std::sin(T(angle)/2), std::cos(T(angle)/2)};
return {normalizedAxis*std::sin(angle.toUnderlyingType()/2), std::cos(angle.toUnderlyingType()/2)};
}
/**

22
src/Math/Test/AngleTest.cpp

@ -60,24 +60,24 @@ AngleTest::AngleTest() {
void AngleTest::construct() {
/* Default constructor */
constexpr Deg m;
CORRADE_COMPARE(Float(m), 0.0f);
CORRADE_COMPARE(m.toUnderlyingType(), 0.0f);
#ifndef MAGNUM_TARGET_GLES
constexpr Degd a;
CORRADE_COMPARE(Double(a), 0.0);
CORRADE_COMPARE(a.toUnderlyingType(), 0.0);
#else
constexpr Deg a;
CORRADE_COMPARE(Float(a), 0.0f);
CORRADE_COMPARE(a.toUnderlyingType(), 0.0f);
#endif
/* Value constructor */
constexpr Deg b(25.0);
CORRADE_COMPARE(Float(b), 25.0f);
CORRADE_COMPARE(b.toUnderlyingType(), 25.0f);
#ifndef MAGNUM_TARGET_GLES
constexpr Radd n(3.14);
CORRADE_COMPARE(Double(n), 3.14);
CORRADE_COMPARE(n.toUnderlyingType(), 3.14);
#else
constexpr Rad n(3.14);
CORRADE_COMPARE(Float(n), 3.14f);
CORRADE_COMPARE(n.toUnderlyingType(), 3.14f);
#endif
/* Copy constructor */
@ -93,13 +93,13 @@ void AngleTest::construct() {
/* Conversion operator */
constexpr Rad p(n);
CORRADE_COMPARE(Float(p), 3.14f);
CORRADE_COMPARE(p.toUnderlyingType(), 3.14f);
#ifndef MAGNUM_TARGET_GLES
constexpr Degd d(b);
CORRADE_COMPARE(Double(d), 25.0);
CORRADE_COMPARE(d.toUnderlyingType(), 25.0);
#else
constexpr Deg d(b);
CORRADE_COMPARE(Float(d), 25.0f);
CORRADE_COMPARE(d.toUnderlyingType(), 25.0f);
#endif
}
@ -130,10 +130,10 @@ void AngleTest::literals() {
void AngleTest::conversion() {
/* Implicit conversion should be allowed */
constexpr Deg a = Rad(1.57079633f);
CORRADE_COMPARE(Float(a), 90.0f);
CORRADE_COMPARE(a.toUnderlyingType(), 90.0f);
constexpr Rad b = Deg(90.0f);
CORRADE_COMPARE(Float(b), 1.57079633f);
CORRADE_COMPARE(b.toUnderlyingType(), 1.57079633f);
}
void AngleTest::debugDeg() {

16
src/Math/Test/FunctionsTest.cpp

@ -300,17 +300,17 @@ void FunctionsTest::trigonometric() {
void FunctionsTest::trigonometricWithBase() {
/* Verify that the functions can be called with Unit<Deg, T> and Unit<Rad, T> */
CORRADE_VERIFY((std::is_same<decltype(Deg(15.0f)+Deg(15.0f)), Unit<Math::Deg, Float>>::value));
CORRADE_VERIFY((std::is_same<decltype(Rad(Constants::pi()/12)+Rad(Constants::pi()/12)), Unit<Math::Rad, Float>>::value));
CORRADE_VERIFY((std::is_same<decltype(2*Deg(15.0f)), Unit<Math::Deg, Float>>::value));
CORRADE_VERIFY((std::is_same<decltype(2*Rad(Constants::pi()/12)), Unit<Math::Rad, Float>>::value));
CORRADE_COMPARE(Math::sin(Deg(15.0f)+Deg(15.0f)), 0.5f);
CORRADE_COMPARE(Math::sin(Rad(Constants::pi()/12)+Rad(Constants::pi()/12)), 0.5f);
CORRADE_COMPARE(Math::sin(2*Deg(15.0f)), 0.5f);
CORRADE_COMPARE(Math::sin(2*Rad(Constants::pi()/12)), 0.5f);
CORRADE_COMPARE(Math::cos(Deg(30.0f)+Deg(30.0f)), 0.5f);
CORRADE_COMPARE(Math::cos(Rad(Constants::pi()/6)+Rad(Constants::pi()/6)), 0.5f);
CORRADE_COMPARE(Math::cos(2*Deg(30.0f)), 0.5f);
CORRADE_COMPARE(Math::cos(2*Rad(Constants::pi()/6)), 0.5f);
CORRADE_COMPARE(Math::tan(Deg(22.5f)+Deg(22.5f)), 1.0f);
CORRADE_COMPARE(Math::tan(Rad(Constants::pi()/8)+Rad(Constants::pi()/8)), 1.0f);
CORRADE_COMPARE(Math::tan(2*Deg(22.5f)), 1.0f);
CORRADE_COMPARE(Math::tan(2*Rad(Constants::pi()/8)), 1.0f);
}
}}}

19
src/Math/Test/UnitTest.cpp

@ -58,21 +58,16 @@ typedef Unit<Sec_, Float> Sec;
typedef Unit<Sec_, Int> Seci;
inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, Sec value) {
return debug << Float(value);
return debug << value.toUnderlyingType();
}
void UnitTest::construct() {
constexpr Sec a(25.0f);
CORRADE_COMPARE(Float(a), 25.0f);
CORRADE_COMPARE(a.toUnderlyingType(), 25.0f);
/* Implicit conversion is not allowed */
CORRADE_VERIFY(!(std::is_convertible<Float, Sec>::value));
{
#ifdef CORRADE_GCC44_COMPATIBILITY
CORRADE_EXPECT_FAIL("GCC 4.4 doesn't have explicit conversion operators");
#endif
CORRADE_VERIFY(!(std::is_convertible<Sec, Float>::value));
}
CORRADE_VERIFY(!(std::is_convertible<Sec, Float>::value));
}
void UnitTest::constructDefault() {
@ -143,17 +138,9 @@ void UnitTest::multiplyDivide() {
constexpr Sec b(-4.5f);
constexpr Sec c(5.0f);
/* The operation returns underlying type on GCC 4.4 because of non-explicit
conversion operators and conflicts with builtin operators */
#ifndef CORRADE_GCC44_COMPATIBILITY
constexpr Sec d = a*-1.5f;
constexpr Sec e = -1.5f*a;
constexpr Sec f = b/-1.5f;
#else
constexpr Sec d(a*-1.5f);
constexpr Sec e(-1.5f*a);
constexpr Sec f(b/-1.5f);
#endif
CORRADE_COMPARE(d, b);
CORRADE_COMPARE(e, b);
CORRADE_COMPARE(f, a);

12
src/Math/Unit.h

@ -53,11 +53,12 @@ template<template<class> class Derived, class T> class Unit {
/** @brief Construct from another underlying type */
template<class U> inline constexpr explicit Unit(Unit<Derived, U> value): value(value.value) {}
/** @brief Explicit conversion to underlying type */
inline constexpr T toUnderlyingType() const { return value; }
/** @brief Explicit conversion to underlying type */
#ifndef CORRADE_GCC44_COMPATIBILITY
inline constexpr explicit operator T() const { return value; }
#else
inline constexpr operator T() const { return value; }
#endif
/** @brief Equality comparison */
@ -117,9 +118,6 @@ template<template<class> class Derived, class T> class Unit {
return Unit<Derived, T>(value - other.value);
}
/* These are conflicting with builtin operators because of non-explicit
conversion to T */
#ifndef CORRADE_GCC44_COMPATIBILITY
/** @brief Multiply with number and assign */
inline Unit<Derived, T>& operator*=(T number) {
value *= number;
@ -146,21 +144,17 @@ template<template<class> class Derived, class T> class Unit {
inline constexpr T operator/(Unit<Derived, T> other) const {
return value/other.value;
}
#endif
private:
T value;
};
/* This is conflicting with builtin operator because of non-explicit conversion to T */
#ifndef CORRADE_GCC44_COMPATIBILITY
/** @relates Unit
@brief Multiply number with value
*/
template<template<class> class Derived, class T> inline constexpr Unit<Derived, T> operator*(typename std::common_type<T>::type number, const Unit<Derived, T>& value) {
return value*number;
}
#endif
}}

8
src/Primitives/Capsule.cpp

@ -40,7 +40,7 @@ Capsule::Capsule(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, Unsigne
capVertex(-height/2, -1.0f, 0.0f);
/* Rings of bottom hemisphere */
hemisphereVertexRings(hemisphereRings-1, -length/2, -Rad(Constants::pi()/2)+hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement);
hemisphereVertexRings(hemisphereRings-1, -length/2, -Rad(Constants::pi())/2+hemisphereRingAngleIncrement, hemisphereRingAngleIncrement, hemisphereTextureCoordsVIncrement, hemisphereTextureCoordsVIncrement);
/* Rings of cylinder */
cylinderVertexRings(cylinderRings+1, -length/2, length/cylinderRings, 1.0f/height, length/(cylinderRings*height));
@ -71,12 +71,12 @@ void Capsule::hemisphereVertexRings(UnsignedInt count, Float centerY, Rad startR
Rad segmentAngleIncrement(2*Constants::pi()/segments);
Float x, y, z;
for(UnsignedInt i = 0; i != count; ++i) {
Rad ringAngle = startRingAngle + Rad(i*ringAngleIncrement);
Rad ringAngle = startRingAngle + i*ringAngleIncrement;
x = z = Math::cos(ringAngle);
y = Math::sin(ringAngle);
for(UnsignedInt j = 0; j != segments; ++j) {
Rad segmentAngle(j*segmentAngleIncrement);
Rad segmentAngle = j*segmentAngleIncrement;
positions(0)->push_back({x*Math::sin(segmentAngle), centerY+y, z*Math::cos(segmentAngle)});
normals(0)->push_back({x*Math::sin(segmentAngle), y, z*Math::cos(segmentAngle)});
@ -97,7 +97,7 @@ void Capsule::cylinderVertexRings(UnsignedInt count, Float startY, Float yIncrem
Rad segmentAngleIncrement(2*Constants::pi()/segments);
for(UnsignedInt i = 0; i != count; ++i) {
for(UnsignedInt j = 0; j != segments; ++j) {
Rad segmentAngle(j*segmentAngleIncrement);
Rad segmentAngle = j*segmentAngleIncrement;
positions(0)->push_back({Math::sin(segmentAngle), startY, Math::cos(segmentAngle)});
normals(0)->push_back({Math::sin(segmentAngle), 0.0f, Math::cos(segmentAngle)});

2
src/Primitives/Cylinder.cpp

@ -60,7 +60,7 @@ void Cylinder::capVertexRing(Float y, Float textureCoordsV, const Vector3& norma
Rad segmentAngleIncrement(2*Constants::pi()/segments);
for(UnsignedInt i = 0; i != segments; ++i) {
Rad segmentAngle(i*segmentAngleIncrement);
Rad segmentAngle = i*segmentAngleIncrement;
positions(0)->push_back({Math::sin(segmentAngle), y, Math::cos(segmentAngle)});
normals(0)->push_back(normal);

2
src/Primitives/UVSphere.cpp

@ -38,7 +38,7 @@ UVSphere::UVSphere(UnsignedInt rings, UnsignedInt segments, TextureCoords textur
capVertex(-1.0f, -1.0f, 0.0f);
/* Vertex rings */
hemisphereVertexRings(rings-1, 0.0f, -Rad(Constants::pi()/2)+ringAngleIncrement, ringAngleIncrement, textureCoordsVIncrement, textureCoordsVIncrement);
hemisphereVertexRings(rings-1, 0.0f, -Rad(Constants::pi())/2+ringAngleIncrement, ringAngleIncrement, textureCoordsVIncrement, textureCoordsVIncrement);
/* Top cap vertex */
capVertex(1.0f, 1.0f, 1.0f);

Loading…
Cancel
Save