Skip to content

Conversation

@nycrat
Copy link
Member

@nycrat nycrat commented Dec 12, 2025

Description

Instead of the AngularVelocity and AngularAcceleration literally being an alias of Angle, this PR refactors them into child classes of Angle which has a few advantages:

  • As mentioned in the original issue, some methods of Angle do not make sense for AngularVelocity/Acceleration. So, we delete these methods in the child class to prevent their usage.
  • While debugging, I noticed there was a lot of incorrect usage of these three classes, for example, in er_force_simulator.cpp, there is a pair defined as std::pair<Vector, Angle> which is then passed to a function that uses std::pair<Vector, AngularVelocity>. These inaccuracies do not raise any error or warning with the original aliases, but now should enforce that there is a difference between the three classes.
  • In the future, we may want special functions for angle velocity or angle acceleration, so this should allow for that.

Line 7 of this code shows exactly the reason why original aliases were an issue.

IMG_9746

Testing Done

Ran thunderscope and the tests, everything seems to be fine.

Resolved Issues

resolves #3093

Length Justification and Key Files to Review

N/A

Review Checklist

It is the reviewers responsibility to also make sure every item here has been covered

  • Function & Class comments: All function definitions (usually in the .h file) should have a javadoc style comment at the start of them. For examples, see the functions defined in thunderbots/software/geom. Similarly, all classes should have an associated Javadoc comment explaining the purpose of the class.
  • Remove all commented out code
  • Remove extra print statements: for example, those just used for testing
  • Resolve all TODO's: All TODO (or similar) statements should either be completed or associated with a github issue

NOTE: I'm not sure if this is the best approach, it is possible to privately inherit from Angle and then avoid the delete statements so that may be cleaner instead. But it would be necessary to redefine inherited functions such as toRadians() that just calls the parent function. It is already necessary to redefine parent functions that return Angle, so for example, we need to redefine fromRadians(rad) since the original returns an Angle, and we need it to return AngularVelocity instead.

Also I'm not sure exactly which methods should be included or not used by the angular velocity/acceleration classes.

@nycrat nycrat marked this pull request as draft December 12, 2025 10:14
@nycrat nycrat marked this pull request as ready for review December 12, 2025 10:22
@nycrat nycrat marked this pull request as draft December 12, 2025 20:43
@nycrat nycrat marked this pull request as ready for review December 14, 2025 20:10
@nycrat nycrat force-pushed the avah/angular_velocity_acceleration_classes branch from 4fe3dc7 to 20c46a6 Compare December 21, 2025 17:18
*/
constexpr AngularVelocity minDiff(const AngularVelocity& other);

// Delete methods that do not apply to angular velocity
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better way to do this? I feel like this is a really clunky way to use classes. Ideally, there should be some abstract angle class that can implement all the common functions, and then we convert the current Angle, AngularVelocity, and AngularAcceleration classes to all inherit from this AngleAbstract class, each with their own set of other special functions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that part of the issue is that since some methods return an Angle or AngularVelocity, these methods have to be redefined anyways since c++ doesn't allow implicit casting from parent to child type. The one benefit would be that we can get rid of all the delete statements which I agree with

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea I'm not sure if adding an abstract Angle class will be much better, it can't even have the fromRadians and fromDegrees methods since they return the actual type which is not possible with an abstract class

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe consider not inheriting from Angle and just have AngularVelocity and AngularAcceleration be their own classes with their own implementation? They don't seem all that related to one another besides the fact that they all have "Angle" in their names; they each represent different units and have different semantics.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use a generic here? e.g. Angle<Velocity>, Angle<Acceleration>, and Angle<Angle>. This can be done with a few typedefs or simple structs and allows for default calls to Angle() to return something like Angle<Angle>.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try using generics since the other approach of implementing them all separately ignores that the classes do have many shared methods like toRadians, fromRadians, etc.

constexpr Angle minDiff(const Angle&) const = delete;
};

inline constexpr AngularVelocity::AngularVelocity() : Angle(0.0) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not certain, but I think our code style mandates that these should be moved to a separate cpp file unless it is required to have them in the header (e.g. for a template class)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just inlined the definitions cause thats what the Angle class did, but I agree that they probably should be in separate .cpp file

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I can tell the angle class was created and not changed for 5 something years, so probably the convention has changed to have separate header/source files since then, I'll make the change soon

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wait I'm pretty sure constexpr has to be inlined

@GrayHoang
Copy link
Contributor

These comments also apply to the angular acceleration files.

@Andrewyx Andrewyx requested review from GrayHoang and a-png129 January 9, 2026 05:31
@itsarune
Copy link
Contributor

itsarune commented Jan 9, 2026

drive-by review, another good and valid option that I'd argue is cleaner is to declare separate AngularVocity and AngularAcceleration classes that internally hold an Angle under the hood:

class AngularAcceleration {
     int abs() {
         return angle.abs();
     }
private:
Angle angle:
}

The benefits are that you get type-safety without duplicating a lot of code and you only need to specify the functions that are relevant for the class. Inheritance doesn't really make sense here because conceptually AngularAcceleration is kinda different from an Angle.

@nycrat
Copy link
Member Author

nycrat commented Jan 10, 2026

Yea maybe avoiding inheritance is the best solution, I'll see what I can do

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add new AngularVelocity / Acceleration classes that wrap Angle class

5 participants