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