001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.units; 006 007import static edu.wpi.first.units.Units.Seconds; 008 009/** 010 * A measure holds the magnitude and unit of some dimension, such as distance, time, or speed. Two 011 * measures with the same <i>unit</i> and <i>magnitude</i> are effectively equivalent objects. 012 * 013 * @param <U> the unit type of the measure 014 */ 015public interface Measure<U extends Unit<U>> extends Comparable<Measure<U>> { 016 /** 017 * The threshold for two measures to be considered equivalent if converted to the same unit. This 018 * is only needed due to floating-point error. 019 */ 020 double EQUIVALENCE_THRESHOLD = 1e-12; 021 022 /** 023 * Gets the unitless magnitude of this measure. 024 * 025 * @return the magnitude in terms of {@link #unit() the unit}. 026 */ 027 double magnitude(); 028 029 /** 030 * Gets the magnitude of this measure in terms of the base unit. If the unit is the base unit for 031 * its system of measure, then the value will be equivalent to {@link #magnitude()}. 032 * 033 * @return the magnitude in terms of the base unit 034 */ 035 double baseUnitMagnitude(); 036 037 /** 038 * Gets the units of this measure. 039 * 040 * @return the unit 041 */ 042 U unit(); 043 044 /** 045 * Converts this measure to a measure with a different unit of the same type, eg minutes to 046 * seconds. Converting to the same unit is equivalent to calling {@link #magnitude()}. 047 * 048 * <pre> 049 * Meters.of(12).in(Feet) // 39.3701 050 * Seconds.of(15).in(Minutes) // 0.25 051 * </pre> 052 * 053 * @param unit the unit to convert this measure to 054 * @return the value of this measure in the given unit 055 */ 056 default double in(Unit<U> unit) { 057 if (this.unit().equals(unit)) { 058 return magnitude(); 059 } else { 060 return unit.fromBaseUnits(baseUnitMagnitude()); 061 } 062 } 063 064 /** 065 * Multiplies this measurement by some constant multiplier and returns the result. The magnitude 066 * of the result will be the <i>base</i> magnitude multiplied by the scalar value. If the measure 067 * uses a unit with a non-linear relation to its base unit (such as Fahrenheit for temperature), 068 * then the result will only be a multiple <i>in terms of the base unit</i>. 069 * 070 * @param multiplier the constant to multiply by 071 * @return the resulting measure 072 */ 073 default Measure<U> times(double multiplier) { 074 return ImmutableMeasure.ofBaseUnits(baseUnitMagnitude() * multiplier, unit()); 075 } 076 077 /** 078 * Generates a new measure that is equal to this measure multiplied by another. Some dimensional 079 * analysis is performed to reduce the units down somewhat; for example, multiplying a {@code 080 * Measure<Time>} by a {@code Measure<Velocity<Distance>>} will return just a {@code 081 * Measure<Distance>} instead of the naive {@code Measure<Mult<Time, Velocity<Distance>>}. This is 082 * not guaranteed to perform perfect dimensional analysis. 083 * 084 * @param <U2> the type of the other measure to multiply by 085 * @param other the unit to multiply by 086 * @return the multiplicative unit 087 */ 088 default <U2 extends Unit<U2>> Measure<?> times(Measure<U2> other) { 089 if (other.unit() instanceof Dimensionless) { 090 // scalar multiplication 091 return times(other.baseUnitMagnitude()); 092 } 093 094 if (unit() instanceof Per<?, ?> per 095 && other.unit().getBaseUnit().equals(per.denominator().getBaseUnit())) { 096 // denominator of the Per cancels out, return with just the units of the numerator 097 Unit<?> numerator = per.numerator(); 098 return numerator.ofBaseUnits(baseUnitMagnitude() * other.baseUnitMagnitude()); 099 } else if (unit() instanceof Velocity<?> v && other.unit().getBaseUnit().equals(Seconds)) { 100 // Multiplying a velocity by a time, return the scalar unit (eg Distance) 101 Unit<?> numerator = v.getUnit(); 102 return numerator.ofBaseUnits(baseUnitMagnitude() * other.baseUnitMagnitude()); 103 } else if (other.unit() instanceof Per<?, ?> per 104 && unit().getBaseUnit().equals(per.denominator().getBaseUnit())) { 105 Unit<?> numerator = per.numerator(); 106 return numerator.ofBaseUnits(baseUnitMagnitude() * other.baseUnitMagnitude()); 107 } else if (unit() instanceof Per<?, ?> per 108 && other.unit() instanceof Per<?, ?> otherPer 109 && per.denominator().getBaseUnit().equals(otherPer.numerator().getBaseUnit()) 110 && per.numerator().getBaseUnit().equals(otherPer.denominator().getBaseUnit())) { 111 // multiplying eg meters per second * milliseconds per foot 112 // return a scalar 113 return Units.Value.of(baseUnitMagnitude() * other.baseUnitMagnitude()); 114 } 115 116 // Dimensional analysis fallthrough, do a basic unit multiplication 117 return unit().mult(other.unit()).ofBaseUnits(baseUnitMagnitude() * other.baseUnitMagnitude()); 118 } 119 120 /** 121 * Divides this measurement by some constant divisor and returns the result. This is equivalent to 122 * {@code times(1 / divisor)} 123 * 124 * @param divisor the constant to divide by 125 * @return the resulting measure 126 * @see #times(double) 127 */ 128 default Measure<U> divide(double divisor) { 129 return times(1 / divisor); 130 } 131 132 /** 133 * Divides this measurement by another measure and performs some dimensional analysis to reduce 134 * the units. 135 * 136 * @param <U2> the type of the other measure to multiply by 137 * @param other the unit to multiply by 138 * @return the resulting measure 139 */ 140 default <U2 extends Unit<U2>> Measure<?> divide(Measure<U2> other) { 141 if (unit().getBaseUnit().equals(other.unit().getBaseUnit())) { 142 return Units.Value.ofBaseUnits(baseUnitMagnitude() / other.baseUnitMagnitude()); 143 } 144 if (other.unit() instanceof Dimensionless) { 145 return divide(other.baseUnitMagnitude()); 146 } 147 if (other.unit() instanceof Velocity<?> velocity 148 && velocity.getUnit().getBaseUnit().equals(unit().getBaseUnit())) { 149 return times(velocity.reciprocal().ofBaseUnits(1 / other.baseUnitMagnitude())); 150 } 151 if (other.unit() instanceof Per<?, ?> per 152 && per.numerator().getBaseUnit().equals(unit().getBaseUnit())) { 153 return times(per.reciprocal().ofBaseUnits(1 / other.baseUnitMagnitude())); 154 } 155 return unit().per(other.unit()).ofBaseUnits(baseUnitMagnitude() / other.baseUnitMagnitude()); 156 } 157 158 /** 159 * Creates a velocity measure by dividing this one by a time period measure. 160 * 161 * <pre> 162 * Meters.of(1).per(Second) // Measure<Velocity<Distance>> 163 * </pre> 164 * 165 * @param period the time period to divide by. 166 * @return the velocity result 167 */ 168 default Measure<Velocity<U>> per(Measure<Time> period) { 169 var newUnit = unit().per(period.unit()); 170 return ImmutableMeasure.ofBaseUnits(baseUnitMagnitude() / period.baseUnitMagnitude(), newUnit); 171 } 172 173 /** 174 * Creates a relational measure equivalent to this one per some other unit. 175 * 176 * <pre> 177 * Volts.of(1.05).per(Meter) // V/m, potential PID constant 178 * </pre> 179 * 180 * @param <U2> the type of the denominator unit 181 * @param denominator the denominator unit being divided by 182 * @return the relational measure 183 */ 184 default <U2 extends Unit<U2>> Measure<Per<U, U2>> per(U2 denominator) { 185 var newUnit = unit().per(denominator); 186 return newUnit.of(magnitude()); 187 } 188 189 /** 190 * Creates a velocity measure equivalent to this one per a unit of time. 191 * 192 * <pre> 193 * Radians.of(3.14).per(Second) // Velocity<Angle> equivalent to RadiansPerSecond.of(3.14) 194 * </pre> 195 * 196 * @param time the unit of time 197 * @return the velocity measure 198 */ 199 default Measure<Velocity<U>> per(Time time) { 200 var newUnit = unit().per(time); 201 return newUnit.of(magnitude()); 202 } 203 204 /** 205 * Adds another measure to this one. The resulting measure has the same unit as this one. 206 * 207 * @param other the measure to add to this one 208 * @return a new measure containing the result 209 */ 210 default Measure<U> plus(Measure<U> other) { 211 return unit().ofBaseUnits(baseUnitMagnitude() + other.baseUnitMagnitude()); 212 } 213 214 /** 215 * Subtracts another measure from this one. The resulting measure has the same unit as this one. 216 * 217 * @param other the measure to subtract from this one 218 * @return a new measure containing the result 219 */ 220 default Measure<U> minus(Measure<U> other) { 221 return unit().ofBaseUnits(baseUnitMagnitude() - other.baseUnitMagnitude()); 222 } 223 224 /** 225 * Negates this measure and returns the result. 226 * 227 * @return the resulting measure 228 */ 229 default Measure<U> negate() { 230 return times(-1); 231 } 232 233 /** 234 * Returns an immutable copy of this measure. The copy can be used freely and is guaranteed never 235 * to change. 236 * 237 * @return the copied measure 238 */ 239 Measure<U> copy(); 240 241 /** 242 * Creates a new mutable copy of this measure. 243 * 244 * @return a mutable measure initialized to be identical to this measure 245 */ 246 default MutableMeasure<U> mutableCopy() { 247 return MutableMeasure.mutable(this); 248 } 249 250 /** 251 * Checks if this measure is near another measure of the same unit. Provide a variance threshold 252 * for use for a +/- scalar, such as 0.05 for +/- 5%. 253 * 254 * <pre> 255 * Inches.of(11).isNear(Inches.of(10), 0.1) // true 256 * Inches.of(12).isNear(Inches.of(10), 0.1) // false 257 * </pre> 258 * 259 * @param other the other measurement to compare against 260 * @param varianceThreshold the acceptable variance threshold, in terms of an acceptable +/- error 261 * range multiplier. Checking if a value is within 10% means a value of 0.1 should be passed; 262 * checking if a value is within 1% means a value of 0.01 should be passed, and so on. 263 * @return true if this unit is near the other measure, otherwise false 264 */ 265 default boolean isNear(Measure<?> other, double varianceThreshold) { 266 if (!this.unit().getBaseUnit().equivalent(other.unit().getBaseUnit())) { 267 return false; // Disjoint units, not compatible 268 } 269 270 // abs so negative inputs are calculated correctly 271 var tolerance = Math.abs(other.baseUnitMagnitude() * varianceThreshold); 272 273 return Math.abs(this.baseUnitMagnitude() - other.baseUnitMagnitude()) <= tolerance; 274 } 275 276 /** 277 * Checks if this measure is near another measure of the same unit, with a specified tolerance of 278 * the same unit. 279 * 280 * <pre> 281 * Meters.of(1).isNear(Meters.of(1.2), Millimeters.of(300)) // true 282 * Degrees.of(90).isNear(Rotations.of(0.5), Degrees.of(45)) // false 283 * </pre> 284 * 285 * @param other the other measure to compare against. 286 * @param tolerance the tolerance allowed in which the two measures are defined as near each 287 * other. 288 * @return true if this unit is near the other measure, otherwise false. 289 */ 290 default boolean isNear(Measure<U> other, Measure<U> tolerance) { 291 return Math.abs(this.baseUnitMagnitude() - other.baseUnitMagnitude()) 292 <= Math.abs(tolerance.baseUnitMagnitude()); 293 } 294 295 /** 296 * Checks if this measure is equivalent to another measure of the same unit. 297 * 298 * @param other the measure to compare to 299 * @return true if this measure is equivalent, false otherwise 300 */ 301 default boolean isEquivalent(Measure<?> other) { 302 // Return false for disjoint units that aren't compatible 303 return this.unit().getBaseUnit().equals(other.unit().getBaseUnit()) 304 && Math.abs(baseUnitMagnitude() - other.baseUnitMagnitude()) <= EQUIVALENCE_THRESHOLD; 305 } 306 307 /** {@inheritDoc} */ 308 @Override 309 default int compareTo(Measure<U> o) { 310 return Double.compare(this.baseUnitMagnitude(), o.baseUnitMagnitude()); 311 } 312 313 /** 314 * Checks if this measure is greater than another measure of the same unit. 315 * 316 * @param o the other measure to compare to 317 * @return true if this measure has a greater equivalent magnitude, false otherwise 318 */ 319 default boolean gt(Measure<U> o) { 320 return compareTo(o) > 0; 321 } 322 323 /** 324 * Checks if this measure is greater than or equivalent to another measure of the same unit. 325 * 326 * @param o the other measure to compare to 327 * @return true if this measure has an equal or greater equivalent magnitude, false otherwise 328 */ 329 default boolean gte(Measure<U> o) { 330 return compareTo(o) > 0 || isEquivalent(o); 331 } 332 333 /** 334 * Checks if this measure is less than another measure of the same unit. 335 * 336 * @param o the other measure to compare to 337 * @return true if this measure has a lesser equivalent magnitude, false otherwise 338 */ 339 default boolean lt(Measure<U> o) { 340 return compareTo(o) < 0; 341 } 342 343 /** 344 * Checks if this measure is less than or equivalent to another measure of the same unit. 345 * 346 * @param o the other measure to compare to 347 * @return true if this measure has an equal or lesser equivalent magnitude, false otherwise 348 */ 349 default boolean lte(Measure<U> o) { 350 return compareTo(o) < 0 || isEquivalent(o); 351 } 352 353 /** 354 * Returns the measure with the absolute value closest to positive infinity. 355 * 356 * @param <U> the type of the units of the measures 357 * @param measures the set of measures to compare 358 * @return the measure with the greatest positive magnitude, or null if no measures were provided 359 */ 360 @SafeVarargs 361 static <U extends Unit<U>> Measure<U> max(Measure<U>... measures) { 362 if (measures.length == 0) { 363 return null; // nothing to compare 364 } 365 366 Measure<U> max = null; 367 for (Measure<U> measure : measures) { 368 if (max == null || measure.gt(max)) { 369 max = measure; 370 } 371 } 372 373 return max; 374 } 375 376 /** 377 * Returns the measure with the absolute value closest to negative infinity. 378 * 379 * @param <U> the type of the units of the measures 380 * @param measures the set of measures to compare 381 * @return the measure with the greatest negative magnitude 382 */ 383 @SafeVarargs 384 static <U extends Unit<U>> Measure<U> min(Measure<U>... measures) { 385 if (measures.length == 0) { 386 return null; // nothing to compare 387 } 388 389 Measure<U> max = null; 390 for (Measure<U> measure : measures) { 391 if (max == null || measure.lt(max)) { 392 max = measure; 393 } 394 } 395 396 return max; 397 } 398 399 /** 400 * Returns a string representation of this measurement in a shorthand form. The symbol of the 401 * backing unit is used, rather than the full name, and the magnitude is represented in scientific 402 * notation. 403 * 404 * @return the short form representation of this measurement 405 */ 406 default String toShortString() { 407 // eg 1.234e+04 V/m (1234 Volt per Meter in long form) 408 return String.format("%.3e %s", magnitude(), unit().symbol()); 409 } 410 411 /** 412 * Returns a string representation of this measurement in a longhand form. The name of the backing 413 * unit is used, rather than its symbol, and the magnitude is represented in a full string, not 414 * scientific notation. (Very large values may be represented in scientific notation, however) 415 * 416 * @return the long form representation of this measurement 417 */ 418 default String toLongString() { 419 // eg 1234 Volt per Meter (1.234e+04 V/m in short form) 420 return String.format("%s %s", magnitude(), unit().name()); 421 } 422}