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.ImmutableMult; 008import edu.wpi.first.units.measure.Mult; 009import edu.wpi.first.units.measure.MutMult; 010import java.util.Objects; 011 012/** 013 * A combinatory unit type that is equivalent to the product of two other others. Note that 014 * algebraic reduction is not possible in Java's generic type system, so {@code MultUnit<A, B>} is 015 * not type-compatible with {@code MultUnit<B, A>}! 016 * 017 * @param <A> the type of the first unit in the result 018 * @param <B> the type of the second unit in the result 019 */ 020public class MultUnit<A extends Unit, B extends Unit> extends Unit { 021 private final A m_unitA; 022 private final B m_unitB; 023 024 @SuppressWarnings("rawtypes") 025 private static final CombinatoryUnitCache<Unit, Unit, MultUnit> cache = 026 new CombinatoryUnitCache<>(MultUnit::new); 027 028 /** 029 * Creates a new product unit. Consider using {@link #combine} instead of manually calling this 030 * constructor. 031 * 032 * @param a the first unit of the product 033 * @param b the second unit of the product 034 */ 035 private MultUnit(A a, B b) { 036 super( 037 a.isBaseUnit() && b.isBaseUnit() ? null : combine(a.getBaseUnit(), b.getBaseUnit()), 038 a.toBaseUnits(1) * b.toBaseUnits(1), 039 a.name() + "-" + b.name(), 040 a.symbol() + "*" + b.symbol()); 041 m_unitA = a; 042 m_unitB = b; 043 } 044 045 /** 046 * Creates a new product unit. Subclasses of {@code MultUnit} should use this constructor. 047 * 048 * @param baseUnit the base unit. Set this to null if the unit being constructed is its own base 049 * unit 050 * @param a the first unit of the product 051 * @param b the second unit of the product 052 */ 053 protected MultUnit(MultUnit<A, B> baseUnit, A a, B b) { 054 super( 055 baseUnit, 056 a.toBaseUnits(1) * b.toBaseUnits(1), 057 a.name() + "-" + b.name(), 058 a.symbol() + "*" + b.symbol()); 059 m_unitA = a; 060 m_unitB = b; 061 } 062 063 MultUnit( 064 MultUnit<A, B> baseUnit, 065 UnaryFunction toBaseConverter, 066 UnaryFunction fromBaseConverter, 067 String name, 068 String symbol) { 069 super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol); 070 m_unitA = getBaseUnit().unitA(); 071 m_unitB = getBaseUnit().unitB(); 072 } 073 074 /** 075 * Creates a new MultUnit unit derived from two arbitrary units multiplied together. 076 * 077 * <pre> 078 * MultUnit.combine(Volts, Meters) // Volt-Meters 079 * </pre> 080 * 081 * @param <A> the type of the first unit 082 * @param <B> the type of the second unit 083 * @param a the first unit 084 * @param b the second unit 085 * @return the combined unit 086 */ 087 @SuppressWarnings("unchecked") 088 public static <A extends Unit, B extends Unit> MultUnit<A, B> combine(A a, B b) { 089 return cache.combine(a, b); 090 } 091 092 /** 093 * {@inheritDoc} 094 * 095 * <p>Note: When called on an object of type {@code MultUnit} (and <i>not</i> a subclass!), this 096 * method will always return a {@link edu.wpi.first.units.measure.Mult} instance. If you want to 097 * avoid casting, use {@link #ofNativeBaseUnits(double)} that returns a {@code Per} instance 098 * directly. 099 * 100 * @param magnitude the magnitude of the measure in terms of its base units. 101 * @return the measurement object 102 */ 103 @Override 104 public Measure<? extends MultUnit<A, B>> of(double magnitude) { 105 return ofNative(magnitude); 106 } 107 108 /** 109 * {@inheritDoc} 110 * 111 * <p>Note: When called on an object of type {@code MultUnit} (and <i>not</i> a subclass!), this 112 * method will always return a {@link edu.wpi.first.units.measure.Mult} instance. If you want to 113 * avoid casting, use {@link #ofNativeBaseUnits(double)} that returns a {@code Per} instance 114 * directly. 115 * 116 * @param baseUnitMagnitude the magnitude of the measure in terms of its base units. 117 * @return the measurement object 118 */ 119 @Override 120 public Measure<? extends MultUnit<A, B>> ofBaseUnits(double baseUnitMagnitude) { 121 return ofNativeBaseUnits(baseUnitMagnitude); 122 } 123 124 /** 125 * Creates a new immutable measurement of the given magnitude in terms of this unit. This will 126 * always return a {@code Mult} object and cannot be overridden by subclasses. 127 * 128 * @param magnitude the magnitude of the measurement. 129 * @return the measurement object 130 * @see #of(double) 131 */ 132 public final Mult<A, B> ofNative(double magnitude) { 133 return new ImmutableMult<>(magnitude, toBaseUnits(magnitude), this); 134 } 135 136 /** 137 * Creates a new immutable measurement of the given magnitude in terms of the unit's base unit. 138 * This will always return a {@code Mult} object and cannot be overridden by subclasses. 139 * 140 * @param baseUnitMagnitude the magnitude of the measure in terms of its base units. 141 * @return the measurement object 142 * @see #ofBaseUnits(double) 143 */ 144 public final Mult<A, B> ofNativeBaseUnits(double baseUnitMagnitude) { 145 return new ImmutableMult<>(fromBaseUnits(baseUnitMagnitude), baseUnitMagnitude, this); 146 } 147 148 @Override 149 @SuppressWarnings("unchecked") 150 public Measure<? extends MultUnit<A, B>> zero() { 151 return (Measure<? extends MultUnit<A, B>>) super.zero(); 152 } 153 154 @Override 155 @SuppressWarnings("unchecked") 156 public Measure<? extends MultUnit<A, B>> one() { 157 return (Measure<? extends MultUnit<A, B>>) super.one(); 158 } 159 160 @Override 161 public MutableMeasure<? extends MultUnit<A, B>, ?, ?> mutable(double initialMagnitude) { 162 return new MutMult<>(initialMagnitude, toBaseUnits(initialMagnitude), this); 163 } 164 165 @Override 166 public Unit per(TimeUnit time) { 167 return VelocityUnit.combine(this, time); 168 } 169 170 /** 171 * Converts a measurement value in terms of another unit to this unit. 172 * 173 * @param magnitude the magnitude of the measurement in terms of the other unit 174 * @param otherUnit the other unit 175 * @return the value of the measurement in terms of this unit 176 */ 177 public double convertFrom(double magnitude, MultUnit<A, B> otherUnit) { 178 return fromBaseUnits(otherUnit.toBaseUnits(magnitude)); 179 } 180 181 @Override 182 @SuppressWarnings("unchecked") 183 public MultUnit<A, B> getBaseUnit() { 184 return (MultUnit<A, B>) super.getBaseUnit(); 185 } 186 187 /** 188 * Gets the first unit of the product. 189 * 190 * @return the first unit 191 */ 192 public A unitA() { 193 return m_unitA; 194 } 195 196 /** 197 * Gets the second unit of the product. 198 * 199 * @return the second unit 200 */ 201 public B unitB() { 202 return m_unitB; 203 } 204 205 @Override 206 public String toString() { 207 return "(" + m_unitA.toString() + " * " + m_unitB.toString() + ")"; 208 } 209 210 @Override 211 public boolean equals(Object o) { 212 if (this == o) { 213 return true; 214 } 215 if (o == null || getClass() != o.getClass()) { 216 return false; 217 } 218 if (!super.equals(o)) { 219 return false; 220 } 221 MultUnit<?, ?> multUnit = (MultUnit<?, ?>) o; 222 return Objects.equals(m_unitA, multUnit.m_unitA) && Objects.equals(m_unitB, multUnit.m_unitB); 223 } 224 225 @Override 226 public int hashCode() { 227 return Objects.hash(super.hashCode(), m_unitA, m_unitB); 228 } 229}