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