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  @SuppressWarnings("unchecked")
089  default <U2 extends Unit<U2>> Measure<?> times(Measure<U2> other) {
090    if (other.unit() instanceof Dimensionless) {
091      // scalar multiplication
092      return times(other.baseUnitMagnitude());
093    }
094
095    if (unit() instanceof Per
096        && other.unit().getBaseUnit().equals(((Per<?, ?>) unit()).denominator().getBaseUnit())) {
097      // denominator of the Per cancels out, return with just the units of the numerator
098      Unit<?> numerator = ((Per<?, ?>) unit()).numerator();
099      return numerator.ofBaseUnits(baseUnitMagnitude() * other.baseUnitMagnitude());
100    } else if (unit() instanceof Velocity && other.unit().getBaseUnit().equals(Seconds)) {
101      // Multiplying a velocity by a time, return the scalar unit (eg Distance)
102      Unit<?> numerator = ((Velocity<?>) unit()).getUnit();
103      return numerator.ofBaseUnits(baseUnitMagnitude() * other.baseUnitMagnitude());
104    } else if (other.unit() instanceof Per
105        && unit().getBaseUnit().equals(((Per<?, ?>) other.unit()).denominator().getBaseUnit())) {
106      Unit<?> numerator = ((Per<?, ?>) other.unit()).numerator();
107      return numerator.ofBaseUnits(baseUnitMagnitude() * other.baseUnitMagnitude());
108    } else if (unit() instanceof Per
109        && other.unit() instanceof Per
110        && ((Per<?, ?>) unit())
111            .denominator()
112            .getBaseUnit()
113            .equals(((Per<?, U>) other.unit()).numerator().getBaseUnit())
114        && ((Per<?, ?>) unit())
115            .numerator()
116            .getBaseUnit()
117            .equals(((Per<?, ?>) other.unit()).denominator().getBaseUnit())) {
118      // multiplying eg meters per second * milliseconds per foot
119      // return a scalar
120      return Units.Value.of(baseUnitMagnitude() * other.baseUnitMagnitude());
121    }
122
123    // Dimensional analysis fallthrough, do a basic unit multiplication
124    return unit().mult(other.unit()).ofBaseUnits(baseUnitMagnitude() * other.baseUnitMagnitude());
125  }
126
127  /**
128   * Divides this measurement by some constant divisor and returns the result. This is equivalent to
129   * {@code times(1 / divisor)}
130   *
131   * @param divisor the constant to divide by
132   * @return the resulting measure
133   * @see #times(double)
134   */
135  default Measure<U> divide(double divisor) {
136    return times(1 / divisor);
137  }
138
139  /**
140   * Divides this measurement by another measure and performs some dimensional analysis to reduce
141   * the units.
142   *
143   * @param <U2> the type of the other measure to multiply by
144   * @param other the unit to multiply by
145   * @return the resulting measure
146   */
147  default <U2 extends Unit<U2>> Measure<?> divide(Measure<U2> other) {
148    if (unit().getBaseUnit().equals(other.unit().getBaseUnit())) {
149      return Units.Value.ofBaseUnits(baseUnitMagnitude() / other.baseUnitMagnitude());
150    }
151    if (other.unit() instanceof Dimensionless) {
152      return divide(other.baseUnitMagnitude());
153    }
154    if (other.unit() instanceof Velocity<?> velocity
155        && velocity.getUnit().getBaseUnit().equals(unit().getBaseUnit())) {
156      return times(velocity.reciprocal().ofBaseUnits(1 / other.baseUnitMagnitude()));
157    }
158    if (other.unit() instanceof Per<?, ?> per
159        && per.numerator().getBaseUnit().equals(unit().getBaseUnit())) {
160      return times(per.reciprocal().ofBaseUnits(1 / other.baseUnitMagnitude()));
161    }
162    return unit().per(other.unit()).ofBaseUnits(baseUnitMagnitude() / other.baseUnitMagnitude());
163  }
164
165  /**
166   * Creates a velocity measure by dividing this one by a time period measure.
167   *
168   * <pre>
169   *   Meters.of(1).per(Second) // Measure&lt;Velocity&lt;Distance&gt;&gt;
170   * </pre>
171   *
172   * @param period the time period to divide by.
173   * @return the velocity result
174   */
175  default Measure<Velocity<U>> per(Measure<Time> period) {
176    var newUnit = unit().per(period.unit());
177    return ImmutableMeasure.ofBaseUnits(baseUnitMagnitude() / period.baseUnitMagnitude(), newUnit);
178  }
179
180  /**
181   * Creates a relational measure equivalent to this one per some other unit.
182   *
183   * <pre>
184   *   Volts.of(1.05).per(Meter) // V/m, potential PID constant
185   * </pre>
186   *
187   * @param <U2> the type of the denominator unit
188   * @param denominator the denominator unit being divided by
189   * @return the relational measure
190   */
191  default <U2 extends Unit<U2>> Measure<Per<U, U2>> per(U2 denominator) {
192    var newUnit = unit().per(denominator);
193    return newUnit.of(magnitude());
194  }
195
196  /**
197   * Creates a velocity measure equivalent to this one per a unit of time.
198   *
199   * <pre>
200   *   Radians.of(3.14).per(Second) // Velocity&lt;Angle&gt; equivalent to RadiansPerSecond.of(3.14)
201   * </pre>
202   *
203   * @param time the unit of time
204   * @return the velocity measure
205   */
206  default Measure<Velocity<U>> per(Time time) {
207    var newUnit = unit().per(time);
208    return newUnit.of(magnitude());
209  }
210
211  /**
212   * Adds another measure to this one. The resulting measure has the same unit as this one.
213   *
214   * @param other the measure to add to this one
215   * @return a new measure containing the result
216   */
217  default Measure<U> plus(Measure<U> other) {
218    return unit().ofBaseUnits(baseUnitMagnitude() + other.baseUnitMagnitude());
219  }
220
221  /**
222   * Subtracts another measure from this one. The resulting measure has the same unit as this one.
223   *
224   * @param other the measure to subtract from this one
225   * @return a new measure containing the result
226   */
227  default Measure<U> minus(Measure<U> other) {
228    return unit().ofBaseUnits(baseUnitMagnitude() - other.baseUnitMagnitude());
229  }
230
231  /**
232   * Negates this measure and returns the result.
233   *
234   * @return the resulting measure
235   */
236  default Measure<U> negate() {
237    return times(-1);
238  }
239
240  /**
241   * Returns an immutable copy of this measure. The copy can be used freely and is guaranteed never
242   * to change.
243   *
244   * @return the copied measure
245   */
246  Measure<U> copy();
247
248  /**
249   * Creates a new mutable copy of this measure.
250   *
251   * @return a mutable measure initialized to be identical to this measure
252   */
253  default MutableMeasure<U> mutableCopy() {
254    return MutableMeasure.mutable(this);
255  }
256
257  /**
258   * Checks if this measure is near another measure of the same unit. Provide a variance threshold
259   * for use for a +/- scalar, such as 0.05 for +/- 5%.
260   *
261   * <pre>
262   *   Inches.of(11).isNear(Inches.of(10), 0.1) // true
263   *   Inches.of(12).isNear(Inches.of(10), 0.1) // false
264   * </pre>
265   *
266   * @param other the other measurement to compare against
267   * @param varianceThreshold the acceptable variance threshold, in terms of an acceptable +/- error
268   *     range multiplier. Checking if a value is within 10% means a value of 0.1 should be passed;
269   *     checking if a value is within 1% means a value of 0.01 should be passed, and so on.
270   * @return true if this unit is near the other measure, otherwise false
271   */
272  default boolean isNear(Measure<?> other, double varianceThreshold) {
273    if (!this.unit().getBaseUnit().equivalent(other.unit().getBaseUnit())) {
274      return false; // Disjoint units, not compatible
275    }
276
277    // abs so negative inputs are calculated correctly
278    var tolerance = Math.abs(other.baseUnitMagnitude() * varianceThreshold);
279
280    return Math.abs(this.baseUnitMagnitude() - other.baseUnitMagnitude()) <= tolerance;
281  }
282
283  /**
284   * Checks if this measure is near another measure of the same unit, with a specified tolerance of
285   * the same unit.
286   *
287   * <pre>
288   *     Meters.of(1).isNear(Meters.of(1.2), Millimeters.of(300)) // true
289   *     Degrees.of(90).isNear(Rotations.of(0.5), Degrees.of(45)) // false
290   * </pre>
291   *
292   * @param other the other measure to compare against.
293   * @param tolerance the tolerance allowed in which the two measures are defined as near each
294   *     other.
295   * @return true if this unit is near the other measure, otherwise false.
296   */
297  default boolean isNear(Measure<U> other, Measure<U> tolerance) {
298    return Math.abs(this.baseUnitMagnitude() - other.baseUnitMagnitude())
299        <= Math.abs(tolerance.baseUnitMagnitude());
300  }
301
302  /**
303   * Checks if this measure is equivalent to another measure of the same unit.
304   *
305   * @param other the measure to compare to
306   * @return true if this measure is equivalent, false otherwise
307   */
308  default boolean isEquivalent(Measure<?> other) {
309    if (!this.unit().getBaseUnit().equals(other.unit().getBaseUnit())) {
310      return false; // Disjoint units, not compatible
311    }
312
313    return Math.abs(baseUnitMagnitude() - other.baseUnitMagnitude()) <= EQUIVALENCE_THRESHOLD;
314  }
315
316  /** {@inheritDoc} */
317  @Override
318  default int compareTo(Measure<U> o) {
319    return Double.compare(this.baseUnitMagnitude(), o.baseUnitMagnitude());
320  }
321
322  /**
323   * Checks if this measure is greater than another measure of the same unit.
324   *
325   * @param o the other measure to compare to
326   * @return true if this measure has a greater equivalent magnitude, false otherwise
327   */
328  default boolean gt(Measure<U> o) {
329    return compareTo(o) > 0;
330  }
331
332  /**
333   * Checks if this measure is greater than or equivalent to another measure of the same unit.
334   *
335   * @param o the other measure to compare to
336   * @return true if this measure has an equal or greater equivalent magnitude, false otherwise
337   */
338  default boolean gte(Measure<U> o) {
339    return compareTo(o) > 0 || isEquivalent(o);
340  }
341
342  /**
343   * Checks if this measure is less than another measure of the same unit.
344   *
345   * @param o the other measure to compare to
346   * @return true if this measure has a lesser equivalent magnitude, false otherwise
347   */
348  default boolean lt(Measure<U> o) {
349    return compareTo(o) < 0;
350  }
351
352  /**
353   * Checks if this measure is less than or equivalent to another measure of the same unit.
354   *
355   * @param o the other measure to compare to
356   * @return true if this measure has an equal or lesser equivalent magnitude, false otherwise
357   */
358  default boolean lte(Measure<U> o) {
359    return compareTo(o) < 0 || isEquivalent(o);
360  }
361
362  /**
363   * Returns the measure with the absolute value closest to positive infinity.
364   *
365   * @param <U> the type of the units of the measures
366   * @param measures the set of measures to compare
367   * @return the measure with the greatest positive magnitude, or null if no measures were provided
368   */
369  @SafeVarargs
370  static <U extends Unit<U>> Measure<U> max(Measure<U>... measures) {
371    if (measures.length == 0) {
372      return null; // nothing to compare
373    }
374
375    Measure<U> max = null;
376    for (Measure<U> measure : measures) {
377      if (max == null || measure.gt(max)) {
378        max = measure;
379      }
380    }
381
382    return max;
383  }
384
385  /**
386   * Returns the measure with the absolute value closest to negative infinity.
387   *
388   * @param <U> the type of the units of the measures
389   * @param measures the set of measures to compare
390   * @return the measure with the greatest negative magnitude
391   */
392  @SafeVarargs
393  static <U extends Unit<U>> Measure<U> min(Measure<U>... measures) {
394    if (measures.length == 0) {
395      return null; // nothing to compare
396    }
397
398    Measure<U> max = null;
399    for (Measure<U> measure : measures) {
400      if (max == null || measure.lt(max)) {
401        max = measure;
402      }
403    }
404
405    return max;
406  }
407
408  /**
409   * Returns a string representation of this measurement in a shorthand form. The symbol of the
410   * backing unit is used, rather than the full name, and the magnitude is represented in scientific
411   * notation.
412   *
413   * @return the short form representation of this measurement
414   */
415  default String toShortString() {
416    // eg 1.234e+04 V/m (1234 Volt per Meter in long form)
417    return String.format("%.3e %s", magnitude(), unit().symbol());
418  }
419
420  /**
421   * Returns a string representation of this measurement in a longhand form. The name of the backing
422   * unit is used, rather than its symbol, and the magnitude is represented in a full string, not
423   * scientific notation. (Very large values may be represented in scientific notation, however)
424   *
425   * @return the long form representation of this measurement
426   */
427  default String toLongString() {
428    // eg 1234 Volt per Meter (1.234e+04 V/m in short form)
429    return String.format("%s %s", magnitude(), unit().name());
430  }
431}