Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wpiunits] Add absolute value and copy sign functionality #7358

Merged
merged 15 commits into from
Nov 19, 2024

Conversation

viggy96
Copy link
Contributor

@viggy96 viggy96 commented Nov 7, 2024

Absolute value and copy sign are some common methods that I use, its kinda annoying to need to unwrap the object to do these common operations.

@viggy96 viggy96 requested a review from a team as a code owner November 7, 2024 07:52
Copy link
Member

@calcmogul calcmogul left a comment

Choose a reason for hiding this comment

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

These operations do not make sense on an element of the SO(2) group. Rotation2d is a 2D unit vector, not an Euler angle. If you want an Euler angle, use a double or Angle.

The internal value field should be treated as if it doesn't exist, since it's a hack to prevent implicit wrapping in the constructor. Any operations on the Rotation2d don't preserve it. I’ve wanted to get rid of the value field, but I was told we couldn’t because it would break too much user code, but it will be removed for 2027. We originally took it from 254's geometry library, but they didn't intend the value field to be used in this way either; we just didn't realize that at the time: https://www.chiefdelphi.com/t/possible-bugs-in-rotation2d-and-rotation3d-java/474140/11

@viggy96
Copy link
Contributor Author

viggy96 commented Nov 8, 2024

Should the methods be removed then, or should I instead be operating using getRadians() and Rotation2d.fromRadians(double) instead of m_value?

@calcmogul
Copy link
Member

calcmogul commented Nov 8, 2024

The functions should be removed from Rotation2d. I have no opinion on them being in the measure class though. Rust takes that extension method approach as opposed to providing free functions.

* @param other measure from which to take sign
* @return a new measure with the sign from another measure
*/
default Measure<U> copySign(Measure<U> other) {
Copy link
Member

@calcmogul calcmogul Nov 8, 2024

Choose a reason for hiding this comment

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

This would ideally be called signum() and have the same semantics as the Java standard library.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is slightly different than signum(). Math.signum() simply returns +1, 0 or -1 based on the sign of the input. This method copies the sign of the input variable, but maintains the magnitude.
Its similar to Math.copySign().
https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#copySign-double-double-

Copy link
Member

@calcmogul calcmogul Nov 8, 2024

Choose a reason for hiding this comment

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

This function returns the wrong result if this is nonzero and other is zero. It inverts the sign when it shouldn't since the signum() return values don't match.

You should probably just use Math.copySign() on the base unit magnitude.

Copy link
Contributor Author

@viggy96 viggy96 Nov 8, 2024

Choose a reason for hiding this comment

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

Hmm, I get an error when I try to use Math.copySign().
Type mismatch: cannot convert from Measure<capture#1-of ?> to Measure<U>

/**
   * Take the sign of another measure.
   * @param other measure from which to take sign
   * @return a new measure with the sign from another measure
   */
  default Measure<U> copySign(Measure<U> other) {
    return baseUnit().of(Math.copySign(this.baseUnitMagnitude(), other.baseUnitMagnitude()));
  }

But if I do

if (other.isEquivalent(baseUnit().zero()) && baseUnitMagnitude() < 0.0) return times(-1);
else return times(other).baseUnitMagnitude() >= 0.0 ? this : times(-1);

its fine.

Copy link
Member

Choose a reason for hiding this comment

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

Unit.of returns a wildcarded Measure<?> because the self-type isn't known. You'd need to cast to Measure<U>.

Another issue is nonlinear units. What's the absolute value of -10°C? Using the base unit (Kelvin), it's still -10°C (263.15K); but using the relative unit Celsius it'd be 10°C, which would be treated as 283.15K in any math operations

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps abs() should also take in the desired Unit?
Also, how would I resolve an unchecked cast for the wildcard Measure<?> ?

@PeterJohnson PeterJohnson changed the title Add absolute value and copy sign functionality to units API and Rotation2d [wpiunits] Add absolute value and copy sign functionality Nov 8, 2024
@viggy96
Copy link
Contributor Author

viggy96 commented Nov 18, 2024

Is there anything else needed for this to be merged?

@PeterJohnson PeterJohnson merged commit ac1836e into wpilibsuite:main Nov 19, 2024
39 checks passed
katzuv pushed a commit to katzuv/allwpilib that referenced this pull request Feb 16, 2025
@viggy96 viggy96 deleted the measure-utils branch February 19, 2025 01:20
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.

5 participants