/* * © Copyright 2014 – Urheberrechtshinweis * Alle Rechte vorbehalten / All Rights Reserved * * Programmcode ist urheberrechtlich geschuetzt. * Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner. * Keine Verwendung ohne explizite Genehmigung. * (vgl. § 106 ff UrhG / § 97 UrhG) */ #ifndef HEADING_H #define HEADING_H #include #include #include "Angle.h" struct Heading { #define _2PI (2*(float)M_PI) private: /** heading in radians. 0 = to-the-right */ float rad; public: /** ctor with radians */ Heading(const float rad) : rad(rad) { Assert::isBetween(rad, 0.0f, (float)_2PI, "radians out of bounds"); } /** ctor from(x1,y1) to(x2,y2) */ Heading(const float x1, const float y1, const float x2, const float y2) : rad(Angle::getRAD_2PI(x1,y1,x2,y2)) { Assert::isBetween(rad, 0.0f, (float)_2PI, "radians out of bounds"); } /** ctor from(x,y) -> to(x,y) */ Heading(const Point2 from, const Point2 to) : Heading(from.x, from.y, to.x, to.y) { ; } /** POSITIVE angular difference [0:PI] */ float getDiffHalfRAD(const Heading other) const { return Angle::getDiffRAD_2PI_PI(rad, other.rad); } /** signled angular difference [-PI:+PI] */ // float getSignedDiff(const Heading other) const { // return Angle::getSignedDiffRAD_2PI(other.rad, rad); // } static float getSignedDiff(const Heading from, const Heading to) { return Angle::getSignedDiffRAD_2PI(from.rad, to.rad); } /** update the angle but ensure we stay within [0:2PI] */ Heading& operator += (const float _rad) { // Assert::isBetween(_rad, float(-_2PI*0.999), float(+_2PI*0.999), "radians out of bounds"); // Assert::isBetween(_rad, float(-_2PI), float(+_2PI), "radians out of bounds"); rad += _rad; while (rad >= _2PI) {rad -= _2PI;} while (rad < 0) {rad += _2PI;} return *this; } /** update the angle but ensure we stay within [0:2PI] */ Heading& operator -= (const float _rad) { return *this += (-_rad); } /** update the angle but ensure we stay within [0:2PI] */ Heading operator + (const float _rad) const { return (Heading(*this) += _rad); } /** update the angle but ensure we stay within [0:2PI] */ Heading operator - (const float _rad) const { return (Heading(*this) -= _rad); } /** update the angle but ensure we stay within [0:2PI] */ Heading operator - (const Heading head) const { return *this - head.rad; } /** update the angle but ensure we stay within [0:2PI] */ Heading operator + (const Heading head) const { return *this + head.rad; } Heading& operator = (const float _rad) { rad = _rad; return *this; } /** compare two headings */ bool operator == (const Heading other) const {return rad == other.rad;} bool operator != (const Heading other) const {return rad != other.rad;} /** get an inverted version of this heading (upwards -> downwards, left -> right, ...) */ Heading getInverted() const { Heading out(rad); out += M_PI; return out; } float getRAD() const {return rad;} /** convert heading into a direction-vector */ Point2 asVector() const { return Point2(std::cos(rad), std::sin(rad)); } // /** get a random heading */ // static Heading rnd() { // static std::minstd_rand gen(1234); // static std::uniform_real_distribution dist(0, _2PI); // const float rnd = dist(gen); // return Heading(rnd); // } #undef _2PI }; namespace Headings { static const Heading RIGHT = Heading((float)M_PI*0.0f/2.0f); static const Heading UP = Heading((float)M_PI*1.0f/2.0f); static const Heading LEFT = Heading((float)M_PI*2.0f/2.0f); static const Heading DOWN = Heading((float)M_PI*3.0f/2.0f); } #endif // HEADING_H