Merge branch 'main' into 2027

This commit is contained in:
Peter Johnson
2025-10-11 23:54:41 -07:00
14 changed files with 546 additions and 125 deletions

View File

@@ -56,7 +56,7 @@ the consequences for any action they deem in violation of this Code of Conduct:
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
**Consequence**: A warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

View File

@@ -53,12 +53,16 @@ doxygen {
// See below maven and https://doxygen.nl/download.html for provided binaries
// Ensure theme.css (from https://github.com/jothepro/doxygen-awesome-css) is compatible with
// doxygen version when updating
executables {
doxygen {
// Note: has no effect if not on an x86_64 platform - you need to have a global install available on your
// PATH for the doxygen plugin to run
executableByVersion('1.12.0')
String arch = System.getProperty("os.arch");
if (arch.equals("x86_64") || arch.equals("amd64")) {
executables {
doxygen {
executableByVersion('1.12.0')
String arch = System.getProperty("os.arch");
if (!(arch.equals("x86_64") || arch.equals("amd64"))) {
// Search for a local doxygen install
executableBySearchPath('doxygen')
}
}
}

View File

@@ -154,8 +154,7 @@ def copy_upstream_src(wpilib_root: Path):
def main():
name = "eigen"
url = "https://gitlab.com/libeigen/eigen.git"
# 5.0.0 release as of 2025-09-23
tag = "d65cda87c1a673047b59b20a9f9e165a452f91e9"
tag = "5.0.0"
eigen = Lib(name, url, tag, copy_upstream_src)
eigen.main()

View File

@@ -112,8 +112,8 @@ DifferentialDrive::WheelSpeeds DifferentialDrive::ArcadeDriveIK(
// Square the inputs (while preserving the sign) to increase fine control
// while permitting full power.
if (squareInputs) {
xSpeed = CopySignPow(xSpeed, 2);
zRotation = CopySignPow(zRotation, 2);
xSpeed = CopyDirectionPow(xSpeed, 2);
zRotation = CopyDirectionPow(zRotation, 2);
}
double leftSpeed = xSpeed - zRotation;
@@ -167,8 +167,8 @@ DifferentialDrive::WheelSpeeds DifferentialDrive::TankDriveIK(
// Square the inputs (while preserving the sign) to increase fine control
// while permitting full power.
if (squareInputs) {
leftSpeed = CopySignPow(leftSpeed, 2);
rightSpeed = CopySignPow(rightSpeed, 2);
leftSpeed = CopyDirectionPow(leftSpeed, 2);
rightSpeed = CopyDirectionPow(rightSpeed, 2);
}
return {leftSpeed, rightSpeed};

View File

@@ -260,8 +260,8 @@ public class DifferentialDrive extends RobotDriveBase implements Sendable, AutoC
// Square the inputs (while preserving the sign) to increase fine control
// while permitting full power.
if (squareInputs) {
xSpeed = MathUtil.copySignPow(xSpeed, 2);
zRotation = MathUtil.copySignPow(zRotation, 2);
xSpeed = MathUtil.copyDirectionPow(xSpeed, 2);
zRotation = MathUtil.copyDirectionPow(zRotation, 2);
}
double leftSpeed = xSpeed - zRotation;
@@ -335,8 +335,8 @@ public class DifferentialDrive extends RobotDriveBase implements Sendable, AutoC
// Square the inputs (while preserving the sign) to increase fine control
// while permitting full power.
if (squareInputs) {
leftSpeed = MathUtil.copySignPow(leftSpeed, 2);
rightSpeed = MathUtil.copySignPow(rightSpeed, 2);
leftSpeed = MathUtil.copyDirectionPow(leftSpeed, 2);
rightSpeed = MathUtil.copyDirectionPow(rightSpeed, 2);
}
return new WheelSpeeds(leftSpeed, rightSpeed);

View File

@@ -116,6 +116,39 @@ public final class MathUtil {
return applyDeadband(value, deadband, 1);
}
/**
* Returns a zero vector if the given vector is within the specified distance from the origin. The
* remaining distance between the deadband and the maximum distance is scaled from the origin to
* the maximum distance.
*
* @param value Value to clip.
* @param deadband Distance from origin.
* @param maxMagnitude The maximum distance from the origin of the input. Can be infinite.
* @param <R> The number of rows in the vector.
* @return The value after the deadband is applied.
*/
public static <R extends Num> Vector<R> applyDeadband(
Vector<R> value, double deadband, double maxMagnitude) {
if (value.norm() < 1e-9) {
return value.times(0);
}
return value.unit().times(applyDeadband(value.norm(), deadband, maxMagnitude));
}
/**
* Returns a zero vector if the given vector is within the specified distance from the origin. The
* remaining distance between the deadband and a distance of 1.0 is scaled from the origin to a
* distance of 1.0.
*
* @param value Value to clip.
* @param deadband Distance from origin.
* @param <R> The number of rows in the vector.
* @return The value after the deadband is applied.
*/
public static <R extends Num> Vector<R> applyDeadband(Vector<R> value, double deadband) {
return applyDeadband(value, deadband, 1);
}
/**
* Raises the input to the power of the given exponent while preserving its sign.
*
@@ -133,7 +166,7 @@ public final class MathUtil {
* @param maxMagnitude The maximum expected absolute value of input. Must be positive.
* @return The transformed value with the same sign and scaled to the input range.
*/
public static double copySignPow(double value, double exponent, double maxMagnitude) {
public static double copyDirectionPow(double value, double exponent, double maxMagnitude) {
return Math.copySign(Math.pow(Math.abs(value) / maxMagnitude, exponent), value) * maxMagnitude;
}
@@ -148,8 +181,44 @@ public final class MathUtil {
* positive.
* @return The transformed value with the same sign.
*/
public static double copySignPow(double value, double exponent) {
return copySignPow(value, exponent, 1);
public static double copyDirectionPow(double value, double exponent) {
return copyDirectionPow(value, exponent, 1);
}
/**
* Raises the norm of the input to the power of the given exponent while preserving its direction.
*
* <p>The function normalizes the norm of the input to the range [0, 1] based on the maximum
* distance, raises it to the power of the exponent, then scales the result back to the original
* range. This keeps the value in the original max distance and gives consistent curve behavior
* regardless of the input norm's scale.
*
* @param value The input vector to transform.
* @param exponent The exponent to apply (e.g. 1.0 = linear, 2.0 = squared curve). Must be
* positive.
* @param maxMagnitude The maximum expected distance from origin of input. Must be positive.
* @param <R> The number of rows in the vector.
* @return The transformed value with the same direction and norm scaled to the input range.
*/
public static <R extends Num> Vector<R> copyDirectionPow(
Vector<R> value, double exponent, double maxMagnitude) {
if (value.norm() < 1e-9) {
return value.times(0);
}
return value.unit().times(copyDirectionPow(value.norm(), exponent, maxMagnitude));
}
/**
* Raises the norm of the input to the power of the given exponent while preserving its direction.
*
* @param value The input vector to transform.
* @param exponent The exponent to apply (e.g. 1.0 = linear, 2.0 = squared curve). Must be
* positive.
* @param <R> The number of rows in the vector.
* @return The transformed value with the same direction.
*/
public static <R extends Num> Vector<R> copyDirectionPow(Vector<R> value, double exponent) {
return copyDirectionPow(value, exponent, 1);
}
/**

View File

@@ -94,15 +94,41 @@ constexpr T ApplyDeadband(T value, T deadband, T maxMagnitude = T{1.0}) {
}
}
/**
* Returns a zero vector if the given vector is within the specified
* distance from the origin. The remaining distance between the deadband and the
* maximum distance is scaled from the origin to the maximum distance.
*
* @param value Value to clip.
* @param deadband Distance from origin.
* @param maxMagnitude The maximum distance from the origin of the input
* (defaults to 1). Can be infinite.
* @return The value after the deadband is applied.
*/
template <typename T, int N>
requires std::is_arithmetic_v<T> || units::traits::is_unit_t_v<T>
Eigen::Vector<T, N> ApplyDeadband(const Eigen::Vector<T, N>& value, T deadband,
T maxMagnitude = T{1.0}) {
if constexpr (std::is_arithmetic_v<T>) {
if (value.norm() < T{1e-9}) {
return Eigen::Vector<T, N>::Zero();
}
return value.normalized() *
ApplyDeadband(value.norm(), deadband, maxMagnitude);
} else {
const Eigen::Vector<double, N> asDouble = value.template cast<double>();
const Eigen::Vector<double, N> processed =
ApplyDeadband(asDouble, deadband.value(), maxMagnitude.value());
return processed.template cast<T>();
}
}
/**
* Raises the input to the power of the given exponent while preserving its
* sign.
*
* The function normalizes the input value to the range [0, 1] based on the
* maximum magnitude, raises it to the power of the exponent, then scales the
* result back to the original range and copying the sign. This keeps the value
* in the original range and gives consistent curve behavior regardless of the
* input value's scale.
* maximum magnitude so that the output stays in the range.
*
* This is useful for applying smoother or more aggressive control response
* curves (e.g. joystick input shaping).
@@ -110,14 +136,15 @@ constexpr T ApplyDeadband(T value, T deadband, T maxMagnitude = T{1.0}) {
* @param value The input value to transform.
* @param exponent The exponent to apply (e.g. 1.0 = linear, 2.0 = squared
* curve). Must be positive.
* @param maxMagnitude The maximum expected absolute value of input. Must be
* positive.
* @param maxMagnitude The maximum expected absolute value of input (defaults to
* 1). Must be positive.
* @return The transformed value with the same sign and scaled to the input
* range.
*/
template <typename T>
requires std::is_arithmetic_v<T> || units::traits::is_unit_t_v<T>
constexpr T CopySignPow(T value, double exponent, T maxMagnitude = T{1.0}) {
constexpr T CopyDirectionPow(T value, double exponent,
T maxMagnitude = T{1.0}) {
if constexpr (std::is_arithmetic_v<T>) {
return gcem::copysign(
gcem::pow(gcem::abs(value) / maxMagnitude, exponent) * maxMagnitude,
@@ -130,6 +157,42 @@ constexpr T CopySignPow(T value, double exponent, T maxMagnitude = T{1.0}) {
}
}
/**
* Raises the norm of the input to the power of the given exponent while
* preserving its direction.
*
* The function normalizes the input value to the range [0, 1] based on the
* maximum magnitude so that the output stays in the range.
*
* This is useful for applying smoother or more aggressive control response
* curves (e.g. joystick input shaping).
*
* @param value The input vector to transform.
* @param exponent The exponent to apply (e.g. 1.0 = linear, 2.0 = squared
* curve). Must be positive.
* @param maxMagnitude The maximum expected distance from origin of input
* (defaults to 1). Must be positive.
* @return The transformed value with the same direction and norm scaled to
* the input range.
*/
template <typename T, int N>
requires std::is_arithmetic_v<T> || units::traits::is_unit_t_v<T>
Eigen::Vector<T, N> CopyDirectionPow(const Eigen::Vector<T, N>& value,
double exponent, T maxMagnitude = T{1.0}) {
if constexpr (std::is_arithmetic_v<T>) {
if (value.norm() < T{1e-9}) {
return Eigen::Vector<T, N>::Zero();
}
return value.normalized() *
CopyDirectionPow(value.norm(), exponent, maxMagnitude);
} else {
const Eigen::Vector<double, N> asDouble = value.template cast<double>();
const Eigen::Vector<double, N> processed =
CopyDirectionPow(asDouble, exponent, maxMagnitude.value());
return processed.template cast<T>();
}
}
/**
* Returns modulus of input.
*
@@ -279,6 +342,7 @@ constexpr Translation2d SlewRateLimit(const Translation2d& current,
}
if (dist > maxVelocity * dt) {
// Move maximum allowed amount in direction of the difference
// NOLINTNEXTLINE(bugprone-integer-division)
return current + diff * (maxVelocity * dt / dist);
}
return next;
@@ -309,6 +373,7 @@ constexpr Translation3d SlewRateLimit(const Translation3d& current,
}
if (dist > maxVelocity * dt) {
// Move maximum allowed amount in direction of the difference
// NOLINTNEXTLINE(bugprone-integer-division)
return current + diff * (maxVelocity * dt / dist);
}
return next;

View File

@@ -7,8 +7,8 @@
#define EIGEN_MAJOR_VERSION 5
#define EIGEN_MINOR_VERSION 0
#define EIGEN_PATCH_VERSION 0
#define EIGEN_PRERELEASE_VERSION
#define EIGEN_BUILD_VERSION
#define EIGEN_PRERELEASE_VERSION ""
#define EIGEN_BUILD_VERSION ""
#define EIGEN_VERSION_STRING "5.0.0"
#endif // EIGEN_VERSION_H

View File

@@ -1048,22 +1048,33 @@ struct ternary_evaluator<CwiseTernaryOp<TernaryOp, Arg1, Arg2, Arg3>, IndexBased
Data m_d;
};
// specialization for expressions like (a < b).select(c, d) to enable full vectorization
template <typename Arg1, typename Arg2, typename Scalar, typename CmpLhsType, typename CmpRhsType, ComparisonName cmp>
struct evaluator<CwiseTernaryOp<scalar_boolean_select_op<Scalar, Scalar, bool>, Arg1, Arg2,
CwiseBinaryOp<scalar_cmp_op<Scalar, Scalar, cmp, false>, CmpLhsType, CmpRhsType>>>
: public ternary_evaluator<
CwiseTernaryOp<scalar_boolean_select_op<Scalar, Scalar, Scalar>, Arg1, Arg2,
CwiseBinaryOp<scalar_cmp_op<Scalar, Scalar, cmp, true>, CmpLhsType, CmpRhsType>>> {
struct scalar_boolean_select_spec {
using DummyTernaryOp = scalar_boolean_select_op<Scalar, Scalar, bool>;
using DummyArg3 = CwiseBinaryOp<scalar_cmp_op<Scalar, Scalar, cmp, false>, CmpLhsType, CmpRhsType>;
using DummyXprType = CwiseTernaryOp<DummyTernaryOp, Arg1, Arg2, DummyArg3>;
using TernaryOp = scalar_boolean_select_op<Scalar, Scalar, Scalar>;
using Arg3 = CwiseBinaryOp<scalar_cmp_op<Scalar, Scalar, cmp, true>, CmpLhsType, CmpRhsType>;
// only use the typed comparison if it is vectorized
static constexpr bool UseTyped = functor_traits<scalar_cmp_op<Scalar, Scalar, cmp, true>>::PacketAccess;
using CondScalar = std::conditional_t<UseTyped, Scalar, bool>;
using TernaryOp = scalar_boolean_select_op<Scalar, Scalar, CondScalar>;
using Arg3 = CwiseBinaryOp<scalar_cmp_op<Scalar, Scalar, cmp, UseTyped>, CmpLhsType, CmpRhsType>;
using XprType = CwiseTernaryOp<TernaryOp, Arg1, Arg2, Arg3>;
using Base = ternary_evaluator<XprType>;
};
// specialization for expressions like (a < b).select(c, d) to enable full vectorization
template <typename Arg1, typename Arg2, typename Scalar, typename CmpLhsType, typename CmpRhsType, ComparisonName cmp>
struct evaluator<CwiseTernaryOp<scalar_boolean_select_op<Scalar, Scalar, bool>, Arg1, Arg2,
CwiseBinaryOp<scalar_cmp_op<Scalar, Scalar, cmp, false>, CmpLhsType, CmpRhsType>>>
: public scalar_boolean_select_spec<Arg1, Arg2, Scalar, CmpLhsType, CmpRhsType, cmp>::Base {
using Helper = scalar_boolean_select_spec<Arg1, Arg2, Scalar, CmpLhsType, CmpRhsType, cmp>;
using Base = typename Helper::Base;
using DummyXprType = typename Helper::DummyXprType;
using Arg3 = typename Helper::Arg3;
using XprType = typename Helper::XprType;
EIGEN_DEVICE_FUNC explicit evaluator(const DummyXprType& xpr)
: Base(XprType(xpr.arg1(), xpr.arg2(), Arg3(xpr.arg3().lhs(), xpr.arg3().rhs()))) {}

View File

@@ -1272,6 +1272,14 @@ template <typename Lhs, typename Rhs, int ProductTag, typename MatrixShape>
struct generic_product_impl<Lhs, Rhs, HomogeneousShape, MatrixShape, ProductTag>
: generic_product_impl<typename Lhs::PlainObject, Rhs, DenseShape, MatrixShape, ProductTag> {};
template <typename Lhs, typename Rhs, int ProductTag>
struct generic_product_impl<Lhs, Rhs, PermutationShape, HomogeneousShape, ProductTag>
: generic_product_impl<Lhs, Rhs, PermutationShape, DenseShape, ProductTag> {};
template <typename Lhs, typename Rhs, int ProductTag>
struct generic_product_impl<Lhs, Rhs, HomogeneousShape, PermutationShape, ProductTag>
: generic_product_impl<Lhs, Rhs, DenseShape, PermutationShape, ProductTag> {};
} // end namespace internal
} // end namespace Eigen

View File

@@ -207,20 +207,9 @@ struct functor_traits<scalar_cmp_op<LhsScalar, RhsScalar, cmp, UseTypedComparato
};
};
template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
struct typed_cmp_helper {
static constexpr bool SameType = is_same<LhsScalar, RhsScalar>::value;
static constexpr bool IsNumeric = is_arithmetic<typename NumTraits<LhsScalar>::Real>::value;
static constexpr bool UseTyped = UseTypedComparators && SameType && IsNumeric;
using type = typename conditional<UseTyped, LhsScalar, bool>::type;
};
template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
using cmp_return_t = typename typed_cmp_helper<LhsScalar, RhsScalar, UseTypedComparators>::type;
template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_EQ, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
return a == b ? result_type(1) : result_type(0);
}
@@ -233,7 +222,7 @@ struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_EQ, UseTypedComparators> : binary
template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LT, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
return a < b ? result_type(1) : result_type(0);
}
@@ -246,7 +235,7 @@ struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LT, UseTypedComparators> : binary
template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LE, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
return a <= b ? result_type(1) : result_type(0);
}
@@ -259,7 +248,7 @@ struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_LE, UseTypedComparators> : binary
template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GT, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
return a > b ? result_type(1) : result_type(0);
}
@@ -272,7 +261,7 @@ struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GT, UseTypedComparators> : binary
template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GE, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
return a >= b ? result_type(1) : result_type(0);
}
@@ -285,7 +274,7 @@ struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_GE, UseTypedComparators> : binary
template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_UNORD, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
return !(a <= b || b <= a) ? result_type(1) : result_type(0);
}
@@ -298,7 +287,7 @@ struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_UNORD, UseTypedComparators> : bin
template <typename LhsScalar, typename RhsScalar, bool UseTypedComparators>
struct scalar_cmp_op<LhsScalar, RhsScalar, cmp_NEQ, UseTypedComparators> : binary_op_base<LhsScalar, RhsScalar> {
using result_type = cmp_return_t<LhsScalar, RhsScalar, UseTypedComparators>;
using result_type = std::conditional_t<UseTypedComparators, LhsScalar, bool>;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator()(const LhsScalar& a, const RhsScalar& b) const {
return a != b ? result_type(1) : result_type(0);
}

View File

@@ -227,9 +227,6 @@ class SparseMatrixBase : public EigenBase<Derived> {
using Nested = typename Derived::Nested;
using NestedCleaned = typename internal::remove_all<Nested>::type;
/// For converting `0's` to the matrices numerical type
using Scalar = typename Derived::Scalar;
if (Flags & RowMajorBit) {
Nested nm(m.derived());
internal::evaluator<NestedCleaned> thisEval(nm);

View File

@@ -89,41 +89,166 @@ class MathUtilTest extends UtilityClassTest<MathUtil> {
}
@Test
void testCopySignPow() {
assertEquals(0.5, MathUtil.copySignPow(0.5, 1.0));
assertEquals(-0.5, MathUtil.copySignPow(-0.5, 1.0));
void testApplyDeadband2dUnityScale() {
assertEquals(
VecBuilder.fill(0.0, 1.0), MathUtil.applyDeadband(VecBuilder.fill(0.0, 1.0), 0.02));
assertEquals(
VecBuilder.fill(0.0, -1.0), MathUtil.applyDeadband(VecBuilder.fill(0.0, -1.0), 0.02));
assertEquals(
VecBuilder.fill(-1.0, 0.0), MathUtil.applyDeadband(VecBuilder.fill(-1.0, 0.0), 0.02));
assertEquals(0.5 * 0.5, MathUtil.copySignPow(0.5, 2.0));
assertEquals(-(0.5 * 0.5), MathUtil.copySignPow(-0.5, 2.0));
// == 0
assertEquals(
VecBuilder.fill(0.0, 0.0), MathUtil.applyDeadband(VecBuilder.fill(0.0, 0.0), 0.02));
assertEquals(Math.sqrt(0.5), MathUtil.copySignPow(0.5, 0.5));
assertEquals(-Math.sqrt(0.5), MathUtil.copySignPow(-0.5, 0.5));
assertEquals(0.0, MathUtil.copySignPow(0.0, 2.0));
assertEquals(1.0, MathUtil.copySignPow(1.0, 2.0));
assertEquals(-1.0, MathUtil.copySignPow(-1.0, 2.0));
assertEquals(Math.pow(0.8, 0.3), MathUtil.copySignPow(0.8, 0.3));
assertEquals(-Math.pow(0.8, 0.3), MathUtil.copySignPow(-0.8, 0.3));
// > 0
assertEquals(
VecBuilder.fill(0.0, 0.0), MathUtil.applyDeadband(VecBuilder.fill(0.01, 0.0), 0.02));
assertEquals(
VecBuilder.fill(0.0, 0.0), MathUtil.applyDeadband(VecBuilder.fill(0.02, 0.0), 0.02));
assertEquals(
VecBuilder.fill((0.03 - 0.02) / (1.0 - 0.02), 0.0),
MathUtil.applyDeadband(VecBuilder.fill(0.03, 0.0), 0.02));
assertEquals(
VecBuilder.fill(1.0, 0.0), MathUtil.applyDeadband(VecBuilder.fill(1.0, 0.0), 0.02));
}
@Test
void testCopySignPowMaxMagnitude() {
assertEquals(5, MathUtil.copySignPow(5.0, 1.0, 10.0));
assertEquals(-5, MathUtil.copySignPow(-5.0, 1.0, 10.0));
void testApplyDeadband2dArbitraryScale() {
assertEquals(
VecBuilder.fill(0.0, 2.5), MathUtil.applyDeadband(VecBuilder.fill(0.0, 2.5), 0.02, 2.5));
assertEquals(
VecBuilder.fill(0.0, -2.5), MathUtil.applyDeadband(VecBuilder.fill(0.0, -2.5), 0.02, 2.5));
assertEquals(
VecBuilder.fill(-2.5, 0.0), MathUtil.applyDeadband(VecBuilder.fill(-2.5, 0.0), 0.02, 2.5));
assertEquals(0.5 * 0.5 * 10, MathUtil.copySignPow(5.0, 2.0, 10.0));
assertEquals(-0.5 * 0.5 * 10, MathUtil.copySignPow(-5.0, 2.0, 10.0));
// == 0
assertEquals(
VecBuilder.fill(0.0, 0.0), MathUtil.applyDeadband(VecBuilder.fill(0.0, 0.0), 0.02, 2.5));
assertEquals(Math.sqrt(0.5) * 10, MathUtil.copySignPow(5.0, 0.5, 10.0));
assertEquals(-Math.sqrt(0.5) * 10, MathUtil.copySignPow(-5.0, 0.5, 10.0));
// > 0
assertEquals(
VecBuilder.fill(0.0, 0.0), MathUtil.applyDeadband(VecBuilder.fill(0.01, 0.0), 0.02, 2.5));
assertEquals(
VecBuilder.fill(0.0, 0.0), MathUtil.applyDeadband(VecBuilder.fill(0.02, 0.0), 0.02, 2.5));
assertEquals(
VecBuilder.fill(2.5, 0.0), MathUtil.applyDeadband(VecBuilder.fill(2.5, 0.0), 0.02, 2.5));
}
assertEquals(0.0, MathUtil.copySignPow(0.0, 2.0, 5.0));
assertEquals(5.0, MathUtil.copySignPow(5.0, 2.0, 5.0));
assertEquals(-5.0, MathUtil.copySignPow(-5.0, 2.0, 5.0));
@Test
void testApplyDeadband2dLargeMaxMagnitude() {
assertEquals(
VecBuilder.fill(80.0, 0.0),
MathUtil.applyDeadband(VecBuilder.fill(100.0, 0.0), 20, Double.POSITIVE_INFINITY));
}
assertEquals(Math.pow(0.8, 0.3) * 100, MathUtil.copySignPow(80, 0.3, 100.0));
assertEquals(-Math.pow(0.8, 0.3) * 100, MathUtil.copySignPow(-80, 0.3, 100.0));
@Test
void testCopyDirectionPow() {
assertEquals(0.5, MathUtil.copyDirectionPow(0.5, 1.0));
assertEquals(-0.5, MathUtil.copyDirectionPow(-0.5, 1.0));
assertEquals(0.5 * 0.5, MathUtil.copyDirectionPow(0.5, 2.0));
assertEquals(-(0.5 * 0.5), MathUtil.copyDirectionPow(-0.5, 2.0));
assertEquals(Math.sqrt(0.5), MathUtil.copyDirectionPow(0.5, 0.5));
assertEquals(-Math.sqrt(0.5), MathUtil.copyDirectionPow(-0.5, 0.5));
assertEquals(0.0, MathUtil.copyDirectionPow(0.0, 2.0));
assertEquals(1.0, MathUtil.copyDirectionPow(1.0, 2.0));
assertEquals(-1.0, MathUtil.copyDirectionPow(-1.0, 2.0));
assertEquals(Math.pow(0.8, 0.3), MathUtil.copyDirectionPow(0.8, 0.3));
assertEquals(-Math.pow(0.8, 0.3), MathUtil.copyDirectionPow(-0.8, 0.3));
}
@Test
void testCopyDirectionPowMaxMagnitude() {
assertEquals(5, MathUtil.copyDirectionPow(5.0, 1.0, 10.0));
assertEquals(-5, MathUtil.copyDirectionPow(-5.0, 1.0, 10.0));
assertEquals(0.5 * 0.5 * 10, MathUtil.copyDirectionPow(5.0, 2.0, 10.0));
assertEquals(-0.5 * 0.5 * 10, MathUtil.copyDirectionPow(-5.0, 2.0, 10.0));
assertEquals(Math.sqrt(0.5) * 10, MathUtil.copyDirectionPow(5.0, 0.5, 10.0));
assertEquals(-Math.sqrt(0.5) * 10, MathUtil.copyDirectionPow(-5.0, 0.5, 10.0));
assertEquals(0.0, MathUtil.copyDirectionPow(0.0, 2.0, 5.0));
assertEquals(5.0, MathUtil.copyDirectionPow(5.0, 2.0, 5.0));
assertEquals(-5.0, MathUtil.copyDirectionPow(-5.0, 2.0, 5.0));
assertEquals(Math.pow(0.8, 0.3) * 100, MathUtil.copyDirectionPow(80, 0.3, 100.0));
assertEquals(-Math.pow(0.8, 0.3) * 100, MathUtil.copyDirectionPow(-80, 0.3, 100.0));
}
@Test
void testCopyDirectionPow2d() {
assertEquals(
VecBuilder.fill(0.5, 0.0), MathUtil.copyDirectionPow(VecBuilder.fill(0.5, 0.0), 1.0));
assertEquals(
VecBuilder.fill(-0.5, 0.0), MathUtil.copyDirectionPow(VecBuilder.fill(-0.5, 0.0), 1.0));
assertEquals(
VecBuilder.fill(0.25, 0.0), MathUtil.copyDirectionPow(VecBuilder.fill(0.5, 0.0), 2.0));
assertEquals(
VecBuilder.fill(-0.25, 0.0), MathUtil.copyDirectionPow(VecBuilder.fill(-0.5, 0.0), 2.0));
assertEquals(
VecBuilder.fill(Math.sqrt(0.5), 0.0),
MathUtil.copyDirectionPow(VecBuilder.fill(0.5, 0.0), 0.5));
assertEquals(
VecBuilder.fill(-Math.sqrt(0.5), 0.0),
MathUtil.copyDirectionPow(VecBuilder.fill(-0.5, 0.0), 0.5));
assertEquals(
VecBuilder.fill(0.0, 0.0), MathUtil.copyDirectionPow(VecBuilder.fill(0.0, 0.0), 2.0));
assertEquals(
VecBuilder.fill(1.0, 0.0), MathUtil.copyDirectionPow(VecBuilder.fill(1.0, 0.0), 2.0));
assertEquals(
VecBuilder.fill(-1.0, 0.0), MathUtil.copyDirectionPow(VecBuilder.fill(-1.0, 0.0), 2.0));
assertEquals(
VecBuilder.fill(0.0, Math.pow(0.8, 0.3)),
MathUtil.copyDirectionPow(VecBuilder.fill(0.0, 0.8), 0.3));
assertEquals(
VecBuilder.fill(0.0, -Math.pow(0.8, 0.3)),
MathUtil.copyDirectionPow(VecBuilder.fill(0.0, -0.8), 0.3));
}
@Test
void testCopyDirectionPow2dMaxDistance() {
assertEquals(
VecBuilder.fill(5.0, 0.0), MathUtil.copyDirectionPow(VecBuilder.fill(5.0, 0.0), 1.0, 10.0));
assertEquals(
VecBuilder.fill(-5.0, 0.0),
MathUtil.copyDirectionPow(VecBuilder.fill(-5.0, 0.0), 1.0, 10.0));
assertEquals(
VecBuilder.fill(2.5, 0.0), MathUtil.copyDirectionPow(VecBuilder.fill(5.0, 0.0), 2.0, 10.0));
assertEquals(
VecBuilder.fill(-2.5, 0.0),
MathUtil.copyDirectionPow(VecBuilder.fill(-5.0, 0.0), 2.0, 10.0));
assertEquals(
VecBuilder.fill(Math.sqrt(0.5) * 10, 0.0),
MathUtil.copyDirectionPow(VecBuilder.fill(5.0, 0.0), 0.5, 10.0));
assertEquals(
VecBuilder.fill(-Math.sqrt(0.5) * 10, 0.0),
MathUtil.copyDirectionPow(VecBuilder.fill(-5.0, 0.0), 0.5, 10.0));
assertEquals(
VecBuilder.fill(0.0, 0.0), MathUtil.copyDirectionPow(VecBuilder.fill(0.0, 0.0), 2.0, 5.0));
assertEquals(
VecBuilder.fill(5.0, 0.0), MathUtil.copyDirectionPow(VecBuilder.fill(5.0, 0.0), 2.0, 5.0));
assertEquals(
VecBuilder.fill(-5.0, 0.0),
MathUtil.copyDirectionPow(VecBuilder.fill(-5.0, 0.0), 2.0, 5.0));
assertEquals(
VecBuilder.fill(0.0, Math.pow(0.8, 0.3) * 100),
MathUtil.copyDirectionPow(VecBuilder.fill(0.0, 80.0), 0.3, 100.0));
assertEquals(
VecBuilder.fill(0.0, -Math.pow(0.8, 0.3) * 100),
MathUtil.copyDirectionPow(VecBuilder.fill(0.0, -80.0), 0.3, 100.0));
}
@Test

View File

@@ -55,8 +55,8 @@ TEST(MathUtilTest, ApplyDeadbandArbitraryScale) {
TEST(MathUtilTest, ApplyDeadbandUnits) {
// < 0
EXPECT_DOUBLE_EQ(
-20, frc::ApplyDeadband<units::radian_t>(-20_rad, 1_rad, 20_rad).value());
EXPECT_UNITS_EQ(-20_rad,
frc::ApplyDeadband<units::radian_t>(-20_rad, 1_rad, 20_rad));
}
TEST(MathUtilTest, ApplyDeadbandLargeMaxMagnitude) {
@@ -65,59 +65,213 @@ TEST(MathUtilTest, ApplyDeadbandLargeMaxMagnitude) {
frc::ApplyDeadband(100.0, 20.0, std::numeric_limits<double>::infinity()));
}
TEST(MathUtilTest, CopySignPow) {
EXPECT_DOUBLE_EQ(0.5, frc::CopySignPow(0.5, 1.0));
EXPECT_DOUBLE_EQ(-0.5, frc::CopySignPow(-0.5, 1.0));
TEST(MathUtilTest, ApplyDeadband2dUnityScale) {
EXPECT_EQ((Eigen::Vector2d{{0.0}, {1.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{0.0}, {1.0}}, 0.02));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {-1.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{0.0}, {-1.0}}, 0.02));
EXPECT_EQ((Eigen::Vector2d{{-1.0}, {0.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{-1.0}, {0.0}}, 0.02));
EXPECT_DOUBLE_EQ(0.5 * 0.5, frc::CopySignPow(0.5, 2.0));
EXPECT_DOUBLE_EQ(-(0.5 * 0.5), frc::CopySignPow(-0.5, 2.0));
// == 0
EXPECT_EQ((Eigen::Vector2d{{0.0}, {0.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{0.0}, {0.0}}, 0.02));
EXPECT_DOUBLE_EQ(std::sqrt(0.5), frc::CopySignPow(0.5, 0.5));
EXPECT_DOUBLE_EQ(-std::sqrt(0.5), frc::CopySignPow(-0.5, 0.5));
EXPECT_DOUBLE_EQ(0.0, frc::CopySignPow(0.0, 2.0));
EXPECT_DOUBLE_EQ(1.0, frc::CopySignPow(1.0, 2.0));
EXPECT_DOUBLE_EQ(-1.0, frc::CopySignPow(-1.0, 2.0));
EXPECT_DOUBLE_EQ(std::pow(0.8, 0.3), frc::CopySignPow(0.8, 0.3));
EXPECT_DOUBLE_EQ(-std::pow(0.8, 0.3), frc::CopySignPow(-0.8, 0.3));
// > 0
EXPECT_EQ((Eigen::Vector2d{{0.0}, {0.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{0.01}, {0.0}}, 0.02));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {0.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{0.02}, {0.0}}, 0.02));
EXPECT_EQ((Eigen::Vector2d{{(0.03 - 0.02) / (1.0 - 0.02)}, {0.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{0.03}, {0.0}}, 0.02));
EXPECT_EQ((Eigen::Vector2d{{1.0}, {0.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{1.0}, {0.0}}, 0.02));
}
TEST(MathUtilTest, CopySignPowWithMaxMagnitude) {
EXPECT_DOUBLE_EQ(5.0, frc::CopySignPow(5.0, 1.0, 10.0));
EXPECT_DOUBLE_EQ(-5.0, frc::CopySignPow(-5.0, 1.0, 10.0));
TEST(MathUtilTest, ApplyDeadband2dArbitraryScale) {
EXPECT_EQ((Eigen::Vector2d{{0.0}, {2.5}}),
frc::ApplyDeadband(Eigen::Vector2d{{0.0}, {2.5}}, 0.02, 2.5));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {-2.5}}),
frc::ApplyDeadband(Eigen::Vector2d{{0.0}, {-2.5}}, 0.02, 2.5));
EXPECT_EQ((Eigen::Vector2d{{-2.5}, {0.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{-2.5}, {0.0}}, 0.02, 2.5));
EXPECT_DOUBLE_EQ(0.5 * 0.5 * 10, frc::CopySignPow(5.0, 2.0, 10.0));
EXPECT_DOUBLE_EQ(-0.5 * 0.5 * 10, frc::CopySignPow(-5.0, 2.0, 10.0));
// == 0
EXPECT_EQ((Eigen::Vector2d{{0.0}, {0.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{0.0}, {0.0}}, 0.02, 2.5));
EXPECT_DOUBLE_EQ(std::sqrt(0.5) * 10, frc::CopySignPow(5.0, 0.5, 10.0));
EXPECT_DOUBLE_EQ(-std::sqrt(0.5) * 10, frc::CopySignPow(-5.0, 0.5, 10.0));
// > 0
EXPECT_EQ((Eigen::Vector2d{{0.0}, {0.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{0.01}, {0.0}}, 0.02, 2.5));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {0.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{0.02}, {0.0}}, 0.02, 2.5));
EXPECT_EQ((Eigen::Vector2d{{2.5}, {0.0}}),
frc::ApplyDeadband(Eigen::Vector2d{{2.5}, {0.0}}, 0.02, 2.5));
}
EXPECT_DOUBLE_EQ(0.0, frc::CopySignPow(0.0, 2.0, 5.0));
EXPECT_DOUBLE_EQ(5.0, frc::CopySignPow(5.0, 2.0, 5.0));
EXPECT_DOUBLE_EQ(-5.0, frc::CopySignPow(-5.0, 2.0, 5.0));
TEST(MathUtilTest, ApplyDeadband2dLargeMaxMagnitude) {
EXPECT_EQ((Eigen::Vector2d{{80.0}, {0.0}}),
(frc::ApplyDeadband(Eigen::Vector2d{{100.0}, {0.0}}, 20.0,
std::numeric_limits<double>::infinity())));
}
TEST(MathUtilTest, ApplyDeadband2dUnits) {
EXPECT_EQ((Eigen::Vector<units::meters_per_second_t, 2>{0_mps, 2.5_mps}),
frc::ApplyDeadband(
Eigen::Vector<units::meters_per_second_t, 2>{0_mps, 2.5_mps},
0.02_mps, 2.5_mps));
EXPECT_EQ((Eigen::Vector<units::meters_per_second_t, 2>{1_mps, 0_mps}),
frc::ApplyDeadband(
Eigen::Vector<units::meters_per_second_t, 2>{1_mps, 0_mps},
0.02_mps));
EXPECT_EQ((Eigen::Vector<units::meters_per_second_t, 2>{0_mps, 0_mps}),
frc::ApplyDeadband(
Eigen::Vector<units::meters_per_second_t, 2>{0_mps, 0_mps},
0.02_mps, 2.5_mps));
}
TEST(MathUtilTest, CopyDirectionPow) {
EXPECT_DOUBLE_EQ(0.5, frc::CopyDirectionPow(0.5, 1.0));
EXPECT_DOUBLE_EQ(-0.5, frc::CopyDirectionPow(-0.5, 1.0));
EXPECT_DOUBLE_EQ(0.5 * 0.5, frc::CopyDirectionPow(0.5, 2.0));
EXPECT_DOUBLE_EQ(-(0.5 * 0.5), frc::CopyDirectionPow(-0.5, 2.0));
EXPECT_DOUBLE_EQ(std::sqrt(0.5), frc::CopyDirectionPow(0.5, 0.5));
EXPECT_DOUBLE_EQ(-std::sqrt(0.5), frc::CopyDirectionPow(-0.5, 0.5));
EXPECT_DOUBLE_EQ(0.0, frc::CopyDirectionPow(0.0, 2.0));
EXPECT_DOUBLE_EQ(1.0, frc::CopyDirectionPow(1.0, 2.0));
EXPECT_DOUBLE_EQ(-1.0, frc::CopyDirectionPow(-1.0, 2.0));
EXPECT_DOUBLE_EQ(std::pow(0.8, 0.3), frc::CopyDirectionPow(0.8, 0.3));
EXPECT_DOUBLE_EQ(-std::pow(0.8, 0.3), frc::CopyDirectionPow(-0.8, 0.3));
}
TEST(MathUtilTest, CopyDirectionPowWithMaxMagnitude) {
EXPECT_DOUBLE_EQ(5.0, frc::CopyDirectionPow(5.0, 1.0, 10.0));
EXPECT_DOUBLE_EQ(-5.0, frc::CopyDirectionPow(-5.0, 1.0, 10.0));
EXPECT_DOUBLE_EQ(0.5 * 0.5 * 10, frc::CopyDirectionPow(5.0, 2.0, 10.0));
EXPECT_DOUBLE_EQ(-0.5 * 0.5 * 10, frc::CopyDirectionPow(-5.0, 2.0, 10.0));
EXPECT_DOUBLE_EQ(std::sqrt(0.5) * 10, frc::CopyDirectionPow(5.0, 0.5, 10.0));
EXPECT_DOUBLE_EQ(-std::sqrt(0.5) * 10,
frc::CopyDirectionPow(-5.0, 0.5, 10.0));
EXPECT_DOUBLE_EQ(0.0, frc::CopyDirectionPow(0.0, 2.0, 5.0));
EXPECT_DOUBLE_EQ(5.0, frc::CopyDirectionPow(5.0, 2.0, 5.0));
EXPECT_DOUBLE_EQ(-5.0, frc::CopyDirectionPow(-5.0, 2.0, 5.0));
EXPECT_DOUBLE_EQ(std::pow(0.8, 0.3) * 100,
frc::CopySignPow(80.0, 0.3, 100.0));
frc::CopyDirectionPow(80.0, 0.3, 100.0));
EXPECT_DOUBLE_EQ(-std::pow(0.8, 0.3) * 100,
frc::CopySignPow(-80.0, 0.3, 100.0));
frc::CopyDirectionPow(-80.0, 0.3, 100.0));
}
TEST(MathUtilTest, CopySignPowWithUnits) {
EXPECT_DOUBLE_EQ(
0, frc::CopySignPow<units::meters_per_second_t>(0_mps, 2.0).value());
EXPECT_DOUBLE_EQ(
1, frc::CopySignPow<units::meters_per_second_t>(1_mps, 2.0).value());
EXPECT_DOUBLE_EQ(
-1, frc::CopySignPow<units::meters_per_second_t>(-1_mps, 2.0).value());
TEST(MathUtilTest, CopyDirectionPowWithUnits) {
EXPECT_UNITS_EQ(
0_mps, frc::CopyDirectionPow<units::meters_per_second_t>(0_mps, 2.0));
EXPECT_UNITS_EQ(
1_mps, frc::CopyDirectionPow<units::meters_per_second_t>(1_mps, 2.0));
EXPECT_UNITS_EQ(
-1_mps, frc::CopyDirectionPow<units::meters_per_second_t>(-1_mps, 2.0));
EXPECT_DOUBLE_EQ(
0.5 * 0.5 * 10,
frc::CopySignPow<units::meters_per_second_t>(5_mps, 2.0, 10_mps).value());
EXPECT_DOUBLE_EQ(
-0.5 * 0.5 * 10,
frc::CopySignPow<units::meters_per_second_t>(-5_mps, 2.0, 10_mps)
.value());
EXPECT_UNITS_EQ(
units::meters_per_second_t{0.5 * 0.5 * 10},
frc::CopyDirectionPow<units::meters_per_second_t>(5_mps, 2.0, 10_mps));
EXPECT_UNITS_EQ(
units::meters_per_second_t{-0.5 * 0.5 * 10},
frc::CopyDirectionPow<units::meters_per_second_t>(-5_mps, 2.0, 10_mps));
}
TEST(MathUtilTest, CopyDirectionPow2d) {
EXPECT_EQ((Eigen::Vector2d{{0.5}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{0.5}, {0.0}}, 1.0));
EXPECT_EQ((Eigen::Vector2d{{-0.5}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{-0.5}, {0.0}}, 1.0));
EXPECT_EQ((Eigen::Vector2d{{0.25}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{0.5}, {0.0}}, 2.0));
EXPECT_EQ((Eigen::Vector2d{{-0.25}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{-0.5}, {0.0}}, 2.0));
EXPECT_EQ((Eigen::Vector2d{{std::sqrt(0.5)}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{0.5}, {0.0}}, 0.5));
EXPECT_EQ((Eigen::Vector2d{{-std::sqrt(0.5)}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{-0.5}, {0.0}}, 0.5));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{0.0}, {0.0}}, 2.0));
EXPECT_EQ((Eigen::Vector2d{{1.0}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{1.0}, {0.0}}, 2.0));
EXPECT_EQ((Eigen::Vector2d{{-1.0}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{-1.0}, {0.0}}, 2.0));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {1.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{0.0}, {1.0}}, 2.0));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {-1.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{0.0}, {-1.0}}, 2.0));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {std::pow(0.8, 0.3)}}),
frc::CopyDirectionPow(Eigen::Vector2d{{0.0}, {0.8}}, 0.3));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {-std::pow(0.8, 0.3)}}),
frc::CopyDirectionPow(Eigen::Vector2d{{0.0}, {-0.8}}, 0.3));
}
TEST(MathUtilTest, CopyDirectionPow2dMaxDistance) {
EXPECT_EQ((Eigen::Vector2d{{5.0}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{5.0}, {0.0}}, 1.0, 10.0));
EXPECT_EQ((Eigen::Vector2d{{-5.0}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{-5.0}, {0.0}}, 1.0, 10.0));
EXPECT_EQ((Eigen::Vector2d{{2.5}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{5.0}, {0.0}}, 2.0, 10.0));
EXPECT_EQ((Eigen::Vector2d{{-2.5}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{-5.0}, {0.0}}, 2.0, 10.0));
EXPECT_EQ((Eigen::Vector2d{{std::sqrt(0.5) * 10.0}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{5.0}, {0.0}}, 0.5, 10.0));
EXPECT_EQ((Eigen::Vector2d{{-std::sqrt(0.5) * 10.0}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{-5.0}, {0.0}}, 0.5, 10.0));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{0.0}, {0.0}}, 2.0, 5.0));
EXPECT_EQ((Eigen::Vector2d{{5.0}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{5.0}, {0.0}}, 2.0, 5.0));
EXPECT_EQ((Eigen::Vector2d{{-5.0}, {0.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{-5.0}, {0.0}}, 2.0, 5.0));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {std::pow(0.8, 0.3) * 100.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{0.0}, {80.0}}, 0.3, 100.0));
EXPECT_EQ((Eigen::Vector2d{{0.0}, {-std::pow(0.8, 0.3) * 100.0}}),
frc::CopyDirectionPow(Eigen::Vector2d{{0.0}, {-80.0}}, 0.3, 100.0));
}
TEST(MathUtilTest, CopyDirectionPow2dUnits) {
EXPECT_EQ(
(Eigen::Vector<units::meters_per_second_t, 2>{1_mps, 0_mps}),
frc::CopyDirectionPow(
Eigen::Vector<units::meters_per_second_t, 2>{1_mps, 0_mps}, 2.0));
EXPECT_EQ(
(Eigen::Vector<units::meters_per_second_t, 2>{-1_mps, 0_mps}),
frc::CopyDirectionPow(
Eigen::Vector<units::meters_per_second_t, 2>{-1_mps, 0_mps}, 2.0));
EXPECT_EQ((Eigen::Vector<units::meters_per_second_t, 2>{0_mps, 0_mps}),
frc::CopyDirectionPow(
Eigen::Vector<units::meters_per_second_t, 2>{0_mps, 0_mps}, 2.0,
5_mps));
EXPECT_EQ((Eigen::Vector<units::meters_per_second_t, 2>{5_mps, 0_mps}),
frc::CopyDirectionPow(
Eigen::Vector<units::meters_per_second_t, 2>{5_mps, 0_mps}, 2.0,
5_mps));
EXPECT_EQ((Eigen::Vector<units::meters_per_second_t, 2>{-5_mps, 0_mps}),
frc::CopyDirectionPow(
Eigen::Vector<units::meters_per_second_t, 2>{-5_mps, 0_mps},
2.0, 5_mps));
}
TEST(MathUtilTest, InputModulus) {