Skip to content

Commit 6a62037

Browse files
authored
Merge pull request #33 from LemLib/feat/unary-operator-overloads
✨ unary operator overloads
2 parents cfc47fc + 4ec716a commit 6a62037

File tree

3 files changed

+65
-92
lines changed

3 files changed

+65
-92
lines changed

include/units/Angle.hpp

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,50 @@ inline std::ostream& operator<<(std::ostream& os, const Angle& quantity) {
2626
return os;
2727
}
2828

29+
/**
30+
* @brief DO NOT USE
31+
*
32+
* this class prevents conversion errors from compass angles to angles in standard position.
33+
*
34+
* consider the following:
35+
* 0_cDeg gets converted to standard position angles internally, so it's converted to 90
36+
* -0_cDeg is converted to standard position angles internally, and only afterwards is the
37+
* negative applied, so now it equals -90 internally
38+
*
39+
* This class solves this problem by introducing the CAngle type. You can do things like
40+
* negate it, multiply it, etc. without messing up the angle. However, this class can
41+
* only be created through string literals, you can't do something like
42+
* CAngle angle = 2_cDeg;
43+
* because the constructor is private. However, you can do
44+
* Angle angle = 2_cDeg;
45+
*/
46+
class CAngle {
47+
// make string literals friends, so they have access to the constructor
48+
friend constexpr CAngle operator""_cRad(long double value);
49+
friend constexpr CAngle operator""_cRad(unsigned long long value);
50+
friend constexpr CAngle operator""_cDeg(long double value);
51+
friend constexpr CAngle operator""_cDeg(unsigned long long value);
52+
friend constexpr CAngle operator""_cRot(long double value);
53+
friend constexpr CAngle operator""_cRot(unsigned long long value);
54+
public:
55+
// we don't want CAngle to have move, copy, or assignment operators
56+
constexpr CAngle& operator=(const CAngle&) = delete;
57+
constexpr CAngle(const CAngle&) = delete;
58+
59+
// make CAngle able to be implicitly converted to Angle
60+
constexpr operator Angle() const { return Angle(M_PI_2 - this->value); }
61+
62+
constexpr CAngle operator-() const { return CAngle(-this->value); }
63+
64+
constexpr CAngle operator+() const { return CAngle(this->value); }
65+
private:
66+
const double value;
67+
68+
constexpr CAngle(double value) : value(value) {}
69+
};
70+
71+
constexpr bool operator==(Angle lhs, CAngle rhs) { return lhs == Angle(rhs); }
72+
2973
constexpr Angle rad = Angle(1.0);
3074
constexpr Angle deg = Angle(M_PI / 180);
3175
constexpr Angle rot = Angle(M_TWOPI);
@@ -59,17 +103,21 @@ constexpr Angle operator""_stRot(long double value) { return static_cast<double>
59103
constexpr Angle operator""_stRot(unsigned long long value) { return static_cast<double>(value) * rot; }
60104

61105
// Compass orientation
62-
constexpr Angle operator""_cRad(long double value) { return 90_stDeg - Angle(static_cast<double>(value)); }
106+
constexpr CAngle operator""_cRad(long double value) { return CAngle(static_cast<double>(value)); }
63107

64-
constexpr Angle operator""_cRad(unsigned long long value) { return 90_stDeg - Angle(static_cast<double>(value)); }
108+
constexpr CAngle operator""_cRad(unsigned long long value) { return CAngle(static_cast<double>(value)); }
65109

66-
constexpr Angle operator""_cDeg(long double value) { return 90_stDeg - static_cast<double>(value) * deg; }
110+
constexpr CAngle operator""_cDeg(long double value) { return CAngle(static_cast<double>(value) * deg.internal()); }
67111

68-
constexpr Angle operator""_cDeg(unsigned long long value) { return 90_stDeg - static_cast<double>(value) * deg; }
112+
constexpr CAngle operator""_cDeg(unsigned long long value) {
113+
return CAngle(static_cast<double>(value) * deg.internal());
114+
}
69115

70-
constexpr Angle operator""_cRot(long double value) { return 90_stDeg - static_cast<double>(value) * rot; }
116+
constexpr CAngle operator""_cRot(long double value) { return CAngle(static_cast<double>(value) * rot.internal()); }
71117

72-
constexpr Angle operator""_cRot(unsigned long long value) { return 90_stDeg - static_cast<double>(value) * rot; }
118+
constexpr CAngle operator""_cRot(unsigned long long value) {
119+
return CAngle(static_cast<double>(value) * rot.internal());
120+
}
73121

74122
// Angle functions
75123
namespace units {

include/units/units.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,16 @@ template <isQuantity Q> inline std::ostream& operator<<(std::ostream& os, const
199199
return os;
200200
}
201201

202+
template <isQuantity Q> constexpr Q operator+(Q rhs) { return rhs; }
203+
202204
template <isQuantity Q, isQuantity R> constexpr Q operator+(Q lhs, R rhs)
203205
requires Isomorphic<Q, R>
204206
{
205207
return Q(lhs.internal() + rhs.internal());
206208
}
207209

210+
template <isQuantity Q> constexpr Q operator-(Q rhs) { return Q(-rhs.internal()); }
211+
208212
template <isQuantity Q, isQuantity R> constexpr Q operator-(Q lhs, R rhs)
209213
requires Isomorphic<Q, R>
210214
{

src/main.cpp

Lines changed: 7 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,7 @@
44
#include "units/Vector2D.hpp"
55
#include "units/Vector3D.hpp"
66

7-
/**
8-
* A callback function for LLEMU's center button.
9-
*
10-
* When this callback is fired, it will toggle line 2 of the LCD text between
11-
* "I was pressed!" and nothing.
12-
*/
13-
void on_center_button() {
14-
static bool pressed = false;
15-
pressed = !pressed;
16-
if (pressed) {
17-
pros::lcd::set_text(2, "I was pressed!");
18-
} else {
19-
pros::lcd::clear_line(2);
20-
}
21-
}
7+
constexpr int r2i(double value) { return static_cast<int>(value >= 0.0 ? value + 0.5 : value - 0.5); }
228

239
/**
2410
* Runs initialization code. This occurs as soon as the program is started.
@@ -27,9 +13,6 @@ void on_center_button() {
2713
* to keep execution time for this mode under a few seconds.
2814
*/
2915
void initialize() {
30-
pros::lcd::initialize();
31-
pros::lcd::set_text(1, "Hello PROS User!");
32-
pros::lcd::register_btn1_cb(on_center_button);
3316
units::AccelerationPose a(1_mps2, 2_mps2);
3417
Number num = Number(1.0);
3518
num = Number(0.0);
@@ -38,9 +21,6 @@ void initialize() {
3821
std::ratio<0>, std::ratio<0>>(1.0);
3922
a.orientation += 2_rpm2;
4023
2_rpm2 -= a.orientation;
41-
to_cDeg(Quantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>,
42-
std::ratio<0>, std::ratio<0>>(5.0) -
43-
a.theta() + 5_cDeg);
4424
Quantity<std::ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>, std::ratio<1>, std::ratio<0>, std::ratio<0>,
4525
std::ratio<0>>
4626
c = Multiplied<Angle, Time>();
@@ -49,9 +29,6 @@ void initialize() {
4929
Length z = toLinear<Angle>(y, 2_cm);
5030
static_assert(Angle(5.1) >= Quantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>,
5131
std::ratio<0>, std::ratio<0>, std::ratio<0>>(5.0));
52-
units::clamp(2_cDeg, a.theta(),
53-
Quantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<1>, std::ratio<0>,
54-
std::ratio<0>, std::ratio<0>>(5.0));
5532
units::max(10_celsius, Quantity<std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>, std::ratio<0>,
5633
std::ratio<1>, std::ratio<0>, std::ratio<0>>(1.0));
5734
// check Vector3D overloads
@@ -68,66 +45,10 @@ void initialize() {
6845
units::Vector2D<Number> v2e = units::V2Position(2_in, 2_in) / 2_in;
6946
}
7047

71-
/**
72-
* Runs while the Probot is in the disabled state of Field Management System or
73-
* the VEX Competition Switch, following either autonomous or opcontrol. When
74-
* the robot is enabled, this task will exit.
75-
*/
76-
void disabled() {}
77-
78-
/**
79-
* Runs after initialize(), and before autonomous when connected to the Field
80-
* Management System or the VEX Competition Switch. This is intended for
81-
* competition-specific initialization routines, such as an autonomous selector
82-
* on the LCD.
83-
*
84-
* This task will exit when the robot is enabled and autonomous or opcontrol
85-
* starts.
86-
*/
87-
void competition_initialize() {}
88-
89-
/**
90-
* Runs the user autonomous code. This function will be started in its own task
91-
* with the default priority and stack size whenever the robot is enabled via
92-
* the Field Management System or the VEX Competition Switch in the autonomous
93-
* mode. Alternatively, this function may be called in initialize or opcontrol
94-
* for non-competition testing purposes.
95-
*
96-
* If the robot is disabled or communications is lost, the autonomous task
97-
* will be stopped. Re-enabling the robot will restart the task, not re-start it
98-
* from where it left off.
99-
*/
100-
void autonomous() {}
101-
102-
/**
103-
* Runs the operator control code. This function will be started in its own task
104-
* with the default priority and stack size whenever the robot is enabled via
105-
* the Field Management System or the VEX Competition Switch in the operator
106-
* control mode.
107-
*
108-
* If no competition control is connected, this function will run immediately
109-
* following initialize().
110-
*
111-
* If the robot is disabled or communications is lost, the
112-
* operator control task will be stopped. Re-enabling the robot will restart the
113-
* task, not resume it from where it left off.
114-
*/
115-
void opcontrol() {
116-
pros::Controller master(pros::E_CONTROLLER_MASTER);
117-
pros::MotorGroup left_mg({1, -2, 3}); // Creates a motor group with forwards ports 1 & 3 and reversed port 2
118-
pros::MotorGroup right_mg({-4, 5, -6}); // Creates a motor group with forwards port 4 and reversed ports 4 & 6
119-
120-
while (true) {
121-
pros::lcd::print(0, "%d %d %d", (pros::lcd::read_buttons() & LCD_BTN_LEFT) >> 2,
122-
(pros::lcd::read_buttons() & LCD_BTN_CENTER) >> 1,
123-
124-
(pros::lcd::read_buttons() & LCD_BTN_RIGHT) >> 0); // Prints status of the emulated screen LCDs
125-
126-
// Arcade control scheme
127-
int dir = master.get_analog(ANALOG_LEFT_Y); // Gets amount forward/backward from left joystick
128-
int turn = master.get_analog(ANALOG_RIGHT_X); // Gets the turn left/right from right joystick
129-
left_mg.move(dir - turn); // Sets left motor voltage
130-
right_mg.move(dir + turn); // Sets right motor voltage
131-
pros::delay(20); // Run for 20 ms then update
132-
}
48+
void angleTests() {
49+
static_assert(+15_cDeg == 75_stDeg);
50+
static_assert(to_stDeg(-+15_cDeg) == to_stDeg(105_stDeg));
51+
static_assert(r2i(to_stDeg(30_cDeg)) == r2i(to_stDeg(60_stDeg)));
52+
static_assert(r2i(to_stDeg(+0_cDeg)) == r2i(to_stDeg(90_stDeg)));
53+
Angle a = 2_cDeg;
13354
}

0 commit comments

Comments
 (0)