Skip to content

Commit

Permalink
feat(Geometry): fixing angle range and adding common PI for calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
zsmn committed Sep 29, 2023
1 parent 6063a36 commit 38535ef
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 72 deletions.
5 changes: 4 additions & 1 deletion include/Armorial/Geometry/Angle/Angle.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef ARMORIAL_GEOMETRY_ANGLE_H
#define ARMORIAL_GEOMETRY_ANGLE_H

#include <math.h>

namespace Geometry {
/*!
* \brief The Geometry::Angle class is a class that stores angles on the interval [-π, π) and allows
Expand All @@ -9,6 +11,7 @@ namespace Geometry {
class Angle
{
public:
static constexpr float PI = M_PI;
/*!
* \brief The Direction enum contains the possible directions which we can use
* to rotate our angle to achieve some target angle value.
Expand All @@ -22,7 +25,7 @@ namespace Geometry {
* \brief Constructor of the Angle class, receiving a float value that represents the angle
* value in radians and normalize it.
* \param angle The given float value of the angle. As it is normalized after you can give it
* outside the range [-π, π).
* outside the range [-π, π].
*/
Angle(const float &angle = 0.0);

Expand Down
4 changes: 2 additions & 2 deletions include/Armorial/Utils/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ namespace Utils {
*/
template<typename T>
inline static constexpr std::enable_if_t<std::is_floating_point_v<T>, T> radToDeg(const T& radians) {
return (radians * (180.0 / M_PI));
return (radians * (180.0f / Geometry::Angle::PI));
}

/*!
Expand All @@ -52,7 +52,7 @@ namespace Utils {
*/
template<typename T>
inline static constexpr std::enable_if_t<std::is_floating_point_v<T>, T> degToRad(const T& degrees) {
return (degrees * (M_PI / 180.0));
return (degrees * (Geometry::Angle::PI / 180.0f));
}

}
Expand Down
26 changes: 13 additions & 13 deletions src/Armorial/Common/Widgets/FieldView/FieldView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ void FieldView::setupRobotDisplayList() {
else glColor3d(0.5882,0.5882,0.5882);

// Drawing triangle (robot front)
float theta1 = 40.0*(M_PI/180.0);
float theta2 = 2.0*M_PI - theta1;
float theta1 = 40.0*(Geometry::Angle::PI/180.0);
float theta2 = 2.0*Geometry::Angle::PI - theta1;
drawTriangle(QVector2D(0, 0), QVector2D(90.0*cos(theta1), 90.0*sin(theta1)),
QVector2D(90.0*cos(theta2), 90.0*sin(theta2)), _robotZ);
drawArc(QVector2D(0, 0), 0, 90, theta1, theta2, _robotZ);
Expand All @@ -136,26 +136,26 @@ void FieldView::setupRobotDisplayList() {
// Draw robot wheels
drawRect(QVector2D(90.0*cos(theta1), 90.0*sin(theta1)),
QVector2D(90.0*cos(theta1) + 3.5, 90.0*sin(theta1) + 3.5),
QVector2D(90.0*cos(theta1 + (M_PI/6)) + 3.5, 90.0*sin(theta1 + (M_PI/6)) + 3.5),
QVector2D(90.0*cos(theta1 + (M_PI/6)), 90.0*sin(theta1 + (M_PI/6))),
QVector2D(90.0*cos(theta1 + (Geometry::Angle::PI/6)) + 3.5, 90.0*sin(theta1 + (Geometry::Angle::PI/6)) + 3.5),
QVector2D(90.0*cos(theta1 + (Geometry::Angle::PI/6)), 90.0*sin(theta1 + (Geometry::Angle::PI/6))),
_robotZ + 0.02);

drawRect(QVector2D(-90.0*cos(theta1), 90.0*sin(theta1)),
QVector2D(-90.0*cos(theta1) - 3.5, 90.0*sin(theta1) + 3.5),
QVector2D(-90.0*cos(theta1 + (M_PI/6)) - 3.5, 90.0*sin(theta1 + (M_PI/6)) + 3.5),
QVector2D(-90.0*cos(theta1 + (M_PI/6)), 90.0*sin(theta1 + (M_PI/6))),
QVector2D(-90.0*cos(theta1 + (Geometry::Angle::PI/6)) - 3.5, 90.0*sin(theta1 + (Geometry::Angle::PI/6)) + 3.5),
QVector2D(-90.0*cos(theta1 + (Geometry::Angle::PI/6)), 90.0*sin(theta1 + (Geometry::Angle::PI/6))),
_robotZ + 0.02);

drawRect(QVector2D(90.0*cos(theta2), 90.0*sin(theta2)),
QVector2D(90.0*cos(theta2) + 3.5, 90.0*sin(theta2) - 3.5),
QVector2D(90.0*cos(theta2 - (M_PI/6)) + 3.5, 90.0*sin(theta2 - (M_PI/6)) - 3.5),
QVector2D(90.0*cos(theta2 - (M_PI/6)), 90.0*sin(theta2 - (M_PI/6))),
QVector2D(90.0*cos(theta2 - (Geometry::Angle::PI/6)) + 3.5, 90.0*sin(theta2 - (Geometry::Angle::PI/6)) - 3.5),
QVector2D(90.0*cos(theta2 - (Geometry::Angle::PI/6)), 90.0*sin(theta2 - (Geometry::Angle::PI/6))),
_robotZ + 0.02);

drawRect(QVector2D(-90.0*cos(theta2), 90.0*sin(theta2)),
QVector2D(-90.0*cos(theta2) - 3.5, 90.0*sin(theta2) - 3.5),
QVector2D(-90.0*cos(theta2 - (M_PI/6)) - 3.5, 90.0*sin(theta2 - (M_PI/6)) - 3.5),
QVector2D(-90.0*cos(theta2 - (M_PI/6)), 90.0*sin(theta2 - (M_PI/6))),
QVector2D(-90.0*cos(theta2 - (Geometry::Angle::PI/6)) - 3.5, 90.0*sin(theta2 - (Geometry::Angle::PI/6)) - 3.5),
QVector2D(-90.0*cos(theta2 - (Geometry::Angle::PI/6)), 90.0*sin(theta2 - (Geometry::Angle::PI/6))),
_robotZ + 0.02);

glEndList();
Expand All @@ -178,9 +178,9 @@ void FieldView::setupBallDisplayList() {
glNewList(_ballShape, GL_COMPILE);

glColor3d(1.0, 0.5059, 0.0);
drawArc(QVector2D(0, 0), 0, 16, -M_PI, M_PI, _ballZ);
drawArc(QVector2D(0, 0), 0, 16, -Geometry::Angle::PI, Geometry::Angle::PI, _ballZ);
glColor3d(0.8706, 0.3490, 0.0);
drawArc(QVector2D(0, 0), 15, 21, -M_PI, M_PI, _ballZ);
drawArc(QVector2D(0, 0), 15, 21, -Geometry::Angle::PI, Geometry::Angle::PI, _ballZ);

glEndList();
}
Expand Down Expand Up @@ -254,7 +254,7 @@ void FieldView::drawFieldLines() {

for (auto &c : _fieldCircles) {
const float half_thickness = 0.5 * getLineThickness();
drawArc(c.center(), c.radius() - half_thickness, c.radius() + half_thickness, 0.0, 2.0 * M_PI, _fieldZ);
drawArc(c.center(), c.radius() - half_thickness, c.radius() + half_thickness, 0.0, 2.0 * Geometry::Angle::PI, _fieldZ);
}

for (auto &a : _fieldArcs) {
Expand Down
10 changes: 7 additions & 3 deletions src/Armorial/Geometry/Angle/Angle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,20 @@ float Angle::value() const {
}

Angle Angle::normalize() {
_angle = fmod(value() + M_PI, 2.0 * M_PI);
_angle = (value() <= 0.0) ? value() + M_PI : value() - M_PI;
while (_angle > Geometry::Angle::PI) {
_angle -= 2*Geometry::Angle::PI;
}
while (_angle < -Geometry::Angle::PI) {
_angle += 2*Geometry::Angle::PI;
}

return *this;
}

Angle::Direction Angle::rotateDirection(const Angle &target) const {
float angleDiff = target.value() - this->value();
bool positive = (angleDiff >= 0.0);
bool large = fabs(angleDiff) >= M_PI;
bool large = fabs(angleDiff) >= Geometry::Angle::PI;

return Angle::Direction(positive ^ large);
}
Expand Down
24 changes: 14 additions & 10 deletions src/Armorial/Geometry/Arc/Arc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ using namespace Geometry;
Arc::Arc() {
_center = Vector2D();
_radius = 1.0;
_startAngle = Geometry::Angle(-M_PI);
_endAngle = Geometry::Angle(M_PI);
_startAngle = Geometry::Angle(-Geometry::Angle::PI);
_endAngle = Geometry::Angle(Geometry::Angle::PI);
_reversed = false;
}

Arc::Arc(const Vector2D &center, const float &radius) {
_center = center;
_radius = radius;
_startAngle = Geometry::Angle(-M_PI);
_endAngle = Geometry::Angle(M_PI);
_startAngle = Geometry::Angle(-Geometry::Angle::PI);
_endAngle = Geometry::Angle(Geometry::Angle::PI);
_reversed = false;
}

Expand Down Expand Up @@ -58,12 +58,13 @@ Geometry::Angle Arc::endAngle() const {
}

bool Arc::isCircle() const {
return (startAngle() == -M_PI && endAngle() == M_PI);
return (startAngle() == -Geometry::Angle::PI && endAngle() == Geometry::Angle::PI);
}

bool Arc::angleWithinArc(const Geometry::Angle &angle) const {
if (_reversed) {
return !(angle.value() >= _startAngle.value() && angle.value() <= _endAngle.value());
// include start and final angle in calculations
return !(angle.value() > _startAngle.value() && angle.value() < _endAngle.value());
} else {
return (angle.value() >= _startAngle.value() && angle.value() <= _endAngle.value());
}
Expand Down Expand Up @@ -93,10 +94,13 @@ std::vector<Vector2D> Arc::intersectionWithLine(const LineSegment &lineSegment)
}

QString Arc::toQString() {
QString arcStr = "";
arcStr.append("Center: (%1, %2)\nRadius: %3\n").arg(_center.x()).arg(_center.y()).arg(_radius);
arcStr.append("Start: %1; End: %2\n").arg(_startAngle.value()).arg(_endAngle.value());
arcStr.append(_reversed ? "Reversed" : "Not Reversed");
QString arcStr = QString("Center: (%1, %2)\nRadius: %3\nStart: %4; End: %5\n%6")
.arg(_center.x())
.arg(_center.y())
.arg(_radius)
.arg(_startAngle.value())
.arg(_endAngle.value())
.arg(_reversed ? "Reversed" : "Not Reversed");
return arcStr;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Armorial/Geometry/Polygon/Polygon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ bool Polygon::isSimple() const {

QString Polygon::toQString() {
QString polygonStr = "";
for (int i = 0; i < _vertices.size(); i++) {
for (size_t i = 0; i < _vertices.size(); i++) {
if ((i + 1) == _vertices.size()) {
polygonStr.append(QString("Vertice %1: (%2, %3)").arg(i).arg(_vertices.at(i).x()).arg(_vertices.at(i).y()));
} else {
Expand Down
18 changes: 9 additions & 9 deletions test/src/Geometry/Angle/Angle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ TEST(Geometry_Angle_Tests, GivenAnAngle_AngleLimitsChecker_ShouldWork) {

spdlog::info("{}", angleBase.value());

ASSERT_GE(angleBase.value(), -M_PI) << "Angle under minimum angle limit";
ASSERT_LE(angleBase.value(), M_PI) << "Angle over maximum angle limit";
ASSERT_GE(angleBase.value(), -Geometry::Angle::PI) << "Angle under minimum angle limit";
ASSERT_LE(angleBase.value(), Geometry::Angle::PI) << "Angle over maximum angle limit";
ASSERT_LE(angleBase.value(), std::numeric_limits<float>::epsilon()) << "Angle value does not match";
}

TEST(Geometry_Angle_Tests, GivenAnAngle_Normalization_ShouldWork) {
Geometry::Angle angleBase(M_PI_4);
Geometry::Angle referenceAngle1(17 * M_PI_4);
Geometry::Angle referenceAngle2(-7 * M_PI_4);
Geometry::Angle angleBase(Geometry::Angle::PI / 4.0f);
Geometry::Angle referenceAngle1(17 * Geometry::Angle::PI / 4.0f);
Geometry::Angle referenceAngle2(-7 * Geometry::Angle::PI / 4.0f);

EXPECT_EQ(angleBase, referenceAngle1) << "Normalization does not work";
EXPECT_EQ(angleBase, referenceAngle2) << "Normalization does not work";
Expand All @@ -30,14 +30,14 @@ TEST(Geometry_Angle_Tests, GivenAnAngle_Normalization_ShouldWork) {
TEST(Geometry_Angle_Tests, GivenAnAngle_RotationDirectionGetter_ShouldWork) {
Geometry::Angle angleBase(0.0f);

EXPECT_EQ(angleBase.rotateDirection(M_PI - 0.1f), Geometry::Angle::COUNTER_CLOCKWISE) << "Rot. direction does not match";
EXPECT_EQ(angleBase.rotateDirection(Geometry::Angle::PI - 0.1f), Geometry::Angle::COUNTER_CLOCKWISE) << "Rot. direction does not match";
EXPECT_EQ(angleBase.rotateDirection(-sqrtf(3)), Geometry::Angle::CLOCKWISE) << "Rot. direction does not match";
}

TEST(Geometry_Angle_Tests, GivenAnAngle_ShotestAngleGetter_ShouldWork) {
Geometry::Angle angleBase(M_PI);
EXPECT_FLOAT_EQ(angleBase.shortestAngleDiff(sqrtf(3)), M_PI - sqrtf(3)) << "Angle difference does not match";
EXPECT_FLOAT_EQ(angleBase.shortestAngleDiff(3*M_PI_2), M_PI_2) << "Angle difference does not match";
Geometry::Angle angleBase(Geometry::Angle::PI);
EXPECT_FLOAT_EQ(angleBase.shortestAngleDiff(sqrtf(3)), Geometry::Angle::PI - sqrtf(3)) << "Angle difference does not match";
EXPECT_FLOAT_EQ(angleBase.shortestAngleDiff(3*Geometry::Angle::PI/2.0f), Geometry::Angle::PI/2.0f) << "Angle difference does not match";
}

TEST(Geometry_Angle_Tests, GivenAnAngle_Operators_ShouldWork) {
Expand Down
34 changes: 17 additions & 17 deletions test/src/Geometry/Arc/Arc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,55 +18,55 @@ TEST(Geometry_Arc_Tests, GivenAnArc_RadiusGetter_ShouldWork) {

TEST(Geometry_Arc_Tests, GivenAnArc_AngleGetters_ShouldWork) {
Geometry::Arc arcBase1(Geometry::Vector2D(1.0f, -1.0f), 1.0f);
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(M_PI_4), Geometry::Angle(-M_PI_4));
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(Geometry::Angle::PI/4.0f), Geometry::Angle(-Geometry::Angle::PI/4.0f));

{
SCOPED_TRACE("Start angles");
EXPECT_EQ(arcBase1.startAngle(), Geometry::Angle(-M_PI)) << "Start angle does not match";
EXPECT_EQ(arcBase2.startAngle(), Geometry::Angle(M_PI_4)) << "Start angle does not match";
EXPECT_EQ(arcBase1.startAngle(), Geometry::Angle(-Geometry::Angle::PI)) << "Start angle does not match";
EXPECT_EQ(arcBase2.startAngle(), Geometry::Angle(Geometry::Angle::PI/4.0f)) << "Start angle does not match";
}
{
SCOPED_TRACE("End angles");
EXPECT_EQ(arcBase1.endAngle(), Geometry::Angle(M_PI)) << "End angle does not match";
EXPECT_EQ(arcBase2.endAngle(), Geometry::Angle(-M_PI_4)) << "End angle does not match";
EXPECT_EQ(arcBase1.endAngle(), Geometry::Angle(Geometry::Angle::PI)) << "End angle does not match";
EXPECT_EQ(arcBase2.endAngle(), Geometry::Angle(-Geometry::Angle::PI/4.0f)) << "End angle does not match";
}
}

TEST(Geometry_Arc_Tests, GivenAnArc_CircleChecker_ShouldWork) {
Geometry::Arc arcBase1(Geometry::Vector2D(1.0f, -1.0f), 1.0f);
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(M_PI_4), Geometry::Angle(-M_PI_4));
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(Geometry::Angle::PI/4.0f), Geometry::Angle(-Geometry::Angle::PI/4.0f));

EXPECT_EQ(arcBase1.isCircle(), true) << "Arc is not a circle";
EXPECT_EQ(arcBase2.isCircle(), false) << "Arc is a circle";
}

TEST(Geometry_Arc_Tests, GivenAnArc_AngleWithinArcChecker_ShouldWork) {
Geometry::Arc arcBase1(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(M_PI_2), Geometry::Angle(-M_PI_2));
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(-M_PI_2), Geometry::Angle(M_PI_2));
Geometry::Arc arcBase1(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(Geometry::Angle::PI/2.0f), Geometry::Angle(-Geometry::Angle::PI/2.0f));
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(-Geometry::Angle::PI/2.0f), Geometry::Angle(Geometry::Angle::PI/2.0f));

EXPECT_EQ(arcBase1.angleWithinArc(Geometry::Angle(M_PI)), true);
EXPECT_EQ(arcBase1.angleWithinArc(Geometry::Angle(Geometry::Angle::PI)), true);
EXPECT_EQ(arcBase2.angleWithinArc(Geometry::Angle(0.0f)), true) << "Angle outside arc";
}

TEST(Geometry_Arc_Tests, GivenAnArc_AngleOutsideArcChecker_ShouldWork) {
Geometry::Arc arcBase1(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(M_PI_2), Geometry::Angle(-M_PI_2));
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(-M_PI_2), Geometry::Angle(M_PI_2));
Geometry::Arc arcBase1(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(Geometry::Angle::PI/2.0f), Geometry::Angle(-Geometry::Angle::PI/2.0f));
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(-Geometry::Angle::PI/2.0f), Geometry::Angle(Geometry::Angle::PI/2.0f));

EXPECT_EQ(arcBase1.angleWithinArc(Geometry::Angle(0.0f)), false) << "Angle within arc";
EXPECT_EQ(arcBase2.angleWithinArc(Geometry::Angle(M_PI)), false) << "Angle within arc";
EXPECT_EQ(arcBase2.angleWithinArc(Geometry::Angle(Geometry::Angle::PI)), false) << "Angle within arc";
}

TEST(Geometry_Arc_Tests, GivenAnArc_PointInArcChecker_ShouldWork) {
Geometry::Arc arcBase1(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(M_PI_2), Geometry::Angle(-M_PI_2));
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(-M_PI_2), Geometry::Angle(M_PI_2));
Geometry::Arc arcBase1(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(Geometry::Angle::PI/2.0f), Geometry::Angle(-Geometry::Angle::PI/2.0f));
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(-Geometry::Angle::PI/2.0f), Geometry::Angle(Geometry::Angle::PI/2.0f));

EXPECT_EQ(arcBase1.pointInArc(Geometry::Vector2D(-1.0f, 0.0f)), true) << "Point not in arc";
EXPECT_EQ(arcBase2.pointInArc(Geometry::Vector2D(1.0f, 0.0f)), true) << "Point not in arc";
}

TEST(Geometry_Arc_Tests, GivenAnArc_PointNotInArcChecker_ShouldWork) {
Geometry::Arc arcBase1(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(M_PI_2), Geometry::Angle(-M_PI_2));
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(-M_PI_2), Geometry::Angle(M_PI_2));
Geometry::Arc arcBase1(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(Geometry::Angle::PI/2.0f), Geometry::Angle(-Geometry::Angle::PI/2.0f));
Geometry::Arc arcBase2(Geometry::Vector2D(0.0f, 0.0f), 1.0f, Geometry::Angle(-Geometry::Angle::PI/2.0f), Geometry::Angle(Geometry::Angle::PI/2.0f));

EXPECT_EQ(arcBase1.pointInArc(Geometry::Vector2D(1.0f, 0.0f)), false) << "Point in arc";
EXPECT_EQ(arcBase2.pointInArc(Geometry::Vector2D(-1.0f, 0.0f)), false) << "Point in arc";
Expand All @@ -76,7 +76,7 @@ TEST(Geometry_Arc_Tests, GivenAnArc_IntersectionGetter_ShouldWork) {
Geometry::LineSegment intersectionLine(Geometry::Vector2D(5.0f, 2.0f), Geometry::Vector2D(0.5f, -1.0f));
std::vector<Geometry::Vector2D> arcIntersections({Geometry::Vector2D(2.0f, 0.0f),
Geometry::Vector2D(3.384615f, 0.923077f)});
Geometry::Arc arcBase(Geometry::Vector2D(3.0f, 0.0f), 1.0f, Geometry::Angle(M_PI), Geometry::Angle(M_PI_2));
Geometry::Arc arcBase(Geometry::Vector2D(3.0f, 0.0f), 1.0f, Geometry::Angle::PI, Geometry::Angle::PI/2.0f);
std::vector<Geometry::Vector2D> intersections = arcBase.intersectionWithLine(intersectionLine);

ASSERT_EQ(arcIntersections.size(), intersections.size()) << "Wrong arc intersections quantity";
Expand Down
Loading

0 comments on commit 38535ef

Please sign in to comment.