HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Strongly-typed angle measures in radians and degrees

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
anddegreesstronglytypedradiansanglemeasures

Problem

I often work with angles when writing code for 3D rendering and such. Personally, I prefer to measure angles in degrees, but many APIs (including the Standard Library) measure angles in radians. So more than once I have produced bugs by passing an angle in one measure when the function/library was expecting it in
another. These kinds of bugs are not hard to track down, but make you waste time nevertheless.

In account of that, I had the idea of defining two classes to represent each angle measure and disable implicit conversions (perhaps inspired by the time durations of std::chono). Following are the Radians and Degrees types (header only):

``
#ifndef ANGLES_HPP
#define ANGLES_HPP

#include
#include

constexpr float Pi = 3.1415926535897931f;
constexpr float TwoPi = 2.0f * Pi;
constexpr float DegToRad = Pi / 180.0f;
constexpr float RadToDeg = 180.0f / Pi;

//
// Implementation details:
//
namespace internal
{

// ========================================================
// template class AngleOps:
// ========================================================

// Operators and methods shared by both
Degrees and Radians` classes.
template
class AngleOps
{
public:

//
// Add, subtract and negate angles:
//

DERIVED operator - () const { return DERIVED(-angle); }

DERIVED operator + (const DERIVED & other) const { return DERIVED(angle + other.angle); }
DERIVED operator - (const DERIVED & other) const { return DERIVED(angle - other.angle); }

DERIVED & operator += (const DERIVED & other) { setFloatValue(angle + other.angle); return static_cast(*this); }
DERIVED & operator -= (const DERIVED & other) { setFloatValue(angle - other.angle); return static_cast(*this); }

//
// Multiply and divide angle by a scalar value:
//

DERIVED operator (const float scalar) const { return DERIVED(angle scalar); }
DERIVED operator / (const float scalar) const { return DERIVED(angle / scalar); }

DERIVED & operat

Solution

I think it's generally well written, but there are a few things that concern me. In particular:

Consider throwing exceptions rather than asserts

If we start with 360.0 degrees and add a degree, I'm not sure I'd be happy with an assert versus throwing an exception if I were using these classes. It seems to me that I'd more likely want to handle the condition myself, or even better, be able to set a flag as to whether it's an error condition or not.

Use M_PI rather than defining your own

Rather than defining Pi you could simply use M_PI which is defined in math.h (aliased to cmath which you already include).

Consider renaming namespace internal

While it might be descriptive for this one and only instance, internal is an awfully generic name to use for a namespace. Consider using something more descriptive.

Context

StackExchange Code Review Q#85029, answer score: 6

Revisions (0)

No revisions yet.