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.Force;
008import edu.wpi.first.units.measure.ImmutableForce;
009import edu.wpi.first.units.measure.MutForce;
010
011/** A unit of force like {@link Units#Newtons}. */
012public final class ForceUnit extends MultUnit<MassUnit, LinearAccelerationUnit> {
013  private static final CombinatoryUnitCache<MassUnit, LinearAccelerationUnit, ForceUnit> cache =
014      new CombinatoryUnitCache<>(ForceUnit::new);
015
016  ForceUnit(MassUnit mass, LinearAccelerationUnit acceleration) {
017    super(
018        mass.isBaseUnit() && acceleration.isBaseUnit()
019            ? null
020            : combine(mass.getBaseUnit(), acceleration.getBaseUnit()),
021        mass,
022        acceleration);
023  }
024
025  ForceUnit(
026      ForceUnit baseUnit,
027      UnaryFunction toBaseConverter,
028      UnaryFunction fromBaseConverter,
029      String name,
030      String symbol) {
031    super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol);
032  }
033
034  /**
035   * Combines a mass and (linear) acceleration to form a unit of force.
036   *
037   * @param mass the unit of mass
038   * @param acceleration the unit of acceleration
039   * @return the combined unit of force
040   */
041  public static ForceUnit combine(MassUnit mass, LinearAccelerationUnit acceleration) {
042    return cache.combine(mass, acceleration);
043  }
044
045  @Override
046  public ForceUnit getBaseUnit() {
047    return (ForceUnit) super.getBaseUnit();
048  }
049
050  /**
051   * Multiplies this force unit by a unit of distance to create a unit of torque.
052   *
053   * @param distance the unit of distance
054   * @return the combined torque unit
055   */
056  public TorqueUnit multAsTorque(DistanceUnit distance) {
057    return TorqueUnit.combine(distance, this);
058  }
059
060  // TODO: Add a multAsEnergy equivalent
061
062  @Override
063  public Force of(double magnitude) {
064    return new ImmutableForce(magnitude, toBaseUnits(magnitude), this);
065  }
066
067  @Override
068  public Force ofBaseUnits(double baseUnitMagnitude) {
069    return new ImmutableForce(toBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this);
070  }
071
072  @Override
073  public Force zero() {
074    return (Force) super.zero();
075  }
076
077  @Override
078  public Force one() {
079    return (Force) super.one();
080  }
081
082  @Override
083  public MutForce mutable(double initialMagnitude) {
084    return new MutForce(initialMagnitude, toBaseUnits(initialMagnitude), this);
085  }
086
087  @Override
088  public VelocityUnit<ForceUnit> per(TimeUnit time) {
089    return VelocityUnit.combine(this, time);
090  }
091
092  /**
093   * Creates a ratio unit between this unit and an arbitrary other unit.
094   *
095   * @param other the other unit
096   * @param <U> the type of the other unit
097   * @return the ratio unit
098   */
099  public <U extends Unit> PerUnit<ForceUnit, U> per(U other) {
100    return PerUnit.combine(this, other);
101  }
102
103  /**
104   * Converts a measurement value in terms of another unit to this unit.
105   *
106   * @param magnitude the magnitude of the measurement in terms of the other unit
107   * @param otherUnit the other unit
108   * @return the value of the measurement in terms of this unit
109   */
110  public double convertFrom(double magnitude, ForceUnit otherUnit) {
111    return fromBaseUnits(otherUnit.toBaseUnits(magnitude));
112  }
113}