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 edu.wpi.first.units.measure.Velocity;
008
009/**
010 * Unit of velocity dimension that is a combination of a distance unit (numerator) and a time unit
011 * (denominator).
012 *
013 * <p>This is a generic velocity type for units that do not have discrete velocity units (eg {@link
014 * DistanceUnit} has {@link LinearVelocityUnit}, and so would not use this class).
015 *
016 * @param <D> the unit of the changing quantity, such as {@link VoltageUnit} or {@link
017 *     TemperatureUnit}
018 */
019public final class VelocityUnit<D extends Unit> extends PerUnit<D, TimeUnit> {
020  @SuppressWarnings("rawtypes")
021  private static final CombinatoryUnitCache<Unit, TimeUnit, VelocityUnit> cache =
022      new CombinatoryUnitCache<>(VelocityUnit::new);
023
024  @SuppressWarnings("unchecked")
025  VelocityUnit(D numerator, TimeUnit denominator) {
026    super(
027        numerator.isBaseUnit() && denominator.isBaseUnit()
028            ? null
029            : combine((D) numerator.getBaseUnit(), denominator.getBaseUnit()),
030        numerator,
031        denominator);
032  }
033
034  VelocityUnit(
035      VelocityUnit<D> baseUnit,
036      UnaryFunction toBaseConverter,
037      UnaryFunction fromBaseConverter,
038      String name,
039      String symbol) {
040    super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
041  }
042
043  /**
044   * Combines a dimension unit and a unit of the period of change to create a unit of velocity.
045   *
046   * @param unit the unit of the changing dimension
047   * @param period the unit of the period of change in the velocity
048   * @param <D> the unit of the changing dimension
049   * @return the combined velocity unit
050   */
051  @SuppressWarnings("unchecked")
052  public static <D extends Unit> VelocityUnit<D> combine(D unit, TimeUnit period) {
053    return cache.combine(unit, period);
054  }
055
056  @Override
057  public VelocityUnit<D> getBaseUnit() {
058    return (VelocityUnit<D>) super.getBaseUnit();
059  }
060
061  /**
062   * Gets the major unit being measured (eg Meters for Meters per Second).
063   *
064   * @return the major unit
065   */
066  public D getUnit() {
067    return numerator();
068  }
069
070  /**
071   * Gets the period unit of the velocity, eg Seconds or Milliseconds.
072   *
073   * @return the period unit
074   */
075  public TimeUnit getPeriod() {
076    return denominator();
077  }
078
079  @Override
080  public Velocity<D> of(double magnitude) {
081    return new Velocity<>(magnitude, toBaseUnits(magnitude), this);
082  }
083
084  @Override
085  public Velocity<D> ofBaseUnits(double baseUnitMagnitude) {
086    return new Velocity<>(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
087  }
088
089  @Override
090  @SuppressWarnings("unchecked")
091  public Velocity<D> zero() {
092    return (Velocity<D>) super.zero();
093  }
094
095  @Override
096  @SuppressWarnings("unchecked")
097  public Velocity<D> one() {
098    return (Velocity<D>) super.one();
099  }
100
101  /**
102   * Combines this velocity unit with a unit of a period of change to create an acceleration unit.
103   *
104   * @param period the unit of the period of change
105   * @return the acceleration unit
106   */
107  @Override
108  public AccelerationUnit<D> per(TimeUnit period) {
109    return AccelerationUnit.combine(this, period);
110  }
111
112  /**
113   * Creates a ratio unit between this unit and an arbitrary other unit.
114   *
115   * @param other the other unit
116   * @param <U> the type of the other unit
117   * @return the ratio unit
118   */
119  public <U extends Unit> PerUnit<VelocityUnit<D>, U> per(U other) {
120    return PerUnit.combine(this, other);
121  }
122
123  /**
124   * Converts a measurement value in terms of another velocity unit to this unit.
125   *
126   * @param magnitude the magnitude of the measurement in terms of the other velocity unit
127   * @param otherUnit the other velocity unit
128   * @return the value of the measurement in terms of this unit
129   */
130  public double convertFrom(double magnitude, VelocityUnit<? extends D> otherUnit) {
131    return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
132  }
133}