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.collections.LongToObjectHashMap; 008import java.util.Objects; 009 010/** 011 * Unit of velocity dimension that is a combination of a distance unit (numerator) and a time unit 012 * (denominator). 013 * 014 * <p>This is the base type for units of velocity dimension. It is also used in combination with a 015 * distance dimension to specify the dimension for {@link Measure}. For example: <code> 016 * Measure<Velocity<Distance>></code>. 017 * 018 * <p>Actual units (such as {@link Units#MetersPerSecond} and {@link Units#RPM}) can be found in the 019 * {@link Units} class. 020 * 021 * @param <D> the distance unit, such as {@link Angle} or {@link Distance} 022 */ 023public class Velocity<D extends Unit<D>> extends Unit<Velocity<D>> { 024 private final D m_unit; 025 private final Time m_period; 026 027 /** 028 * Stores velocity units that were created ad-hoc using {@link #combine(Unit, Time, String, 029 * String)}. Does not store objects created directly by constructors. 030 */ 031 @SuppressWarnings("rawtypes") 032 private static final LongToObjectHashMap<Velocity> cache = new LongToObjectHashMap<>(); 033 034 /** Generates a cache key used for cache lookups. */ 035 private static long cacheKey(Unit<?> numerator, Unit<?> denominator) { 036 return ((long) numerator.hashCode()) << 32L | (((long) denominator.hashCode()) & 0xFFFFFFFFL); 037 } 038 039 /** 040 * Creates a new velocity unit derived from an arbitrary numerator and time period units. 041 * 042 * <p>Results of this method are cached so future invocations with the same arguments will return 043 * the pre-existing units instead of generating new identical ones. 044 * 045 * <pre> 046 * Velocity.combine(Kilograms, Second) // mass flow 047 * Velocity.combine(Feet, Millisecond) // linear speed 048 * Velocity.combine(Radians, Second) // angular speed 049 * 050 * Velocity.combine(Feet.per(Second), Second) // linear acceleration in ft/s/s 051 * Velocity.combine(Radians.per(Second), Second) // angular acceleration 052 * </pre> 053 * 054 * <p>It's recommended to use the convenience function {@link Unit#per(Time)} instead of calling 055 * this factory directly. 056 * 057 * @param <D> the type of the numerator unit 058 * @param numerator the numerator unit 059 * @param period the period for unit time 060 * @param name the name of the new velocity unit 061 * @param symbol the symbol of the new velocity unit 062 * @return the new unit 063 */ 064 @SuppressWarnings("unchecked") 065 public static <D extends Unit<D>> Velocity<D> combine( 066 Unit<D> numerator, Time period, String name, String symbol) { 067 long key = cacheKey(numerator, period); 068 if (cache.containsKey(key)) { 069 return cache.get(key); 070 } 071 072 Velocity<D> velocity = new Velocity<>((D) numerator, period, name, symbol); 073 cache.put(key, velocity); 074 return velocity; 075 } 076 077 /** 078 * Creates a new velocity unit derived from an arbitrary numerator and time period units. 079 * 080 * <p>Results of this method are cached so future invocations with the same arguments will return 081 * the pre-existing units instead of generating new identical ones. 082 * 083 * <p>This method automatically generates a new name and symbol for the new velocity unit. 084 * 085 * <pre> 086 * Velocity.combine(Kilograms, Second) // mass flow 087 * Velocity.combine(Feet, Millisecond) // linear speed 088 * Velocity.combine(Radians, Second) // angular speed 089 * 090 * Velocity.combine(Feet.per(Second), Second) // linear acceleration in ft/s/s 091 * Velocity.combine(Radians.per(Second), Second) // angular acceleration 092 * </pre> 093 * 094 * <p>It's recommended to use the convenience function {@link Unit#per(Time)} instead of calling 095 * this factory directly. 096 * 097 * @param <D> the type of the numerator unit 098 * @param numerator the numerator unit 099 * @param period the period for unit time 100 * @return the new unit 101 */ 102 @SuppressWarnings("unchecked") 103 public static <D extends Unit<D>> Velocity<D> combine(Unit<D> numerator, Time period) { 104 long key = cacheKey(numerator, period); 105 if (cache.containsKey(key)) { 106 return cache.get(key); 107 } 108 109 var name = numerator.name() + " per " + period.name(); 110 var symbol = numerator.symbol() + "/" + period.symbol(); 111 112 Velocity<D> velocity = new Velocity<>((D) numerator, period, name, symbol); 113 cache.put(key, velocity); 114 return velocity; 115 } 116 117 @SuppressWarnings({"unchecked", "rawtypes"}) 118 Velocity(D unit, Time period, String name, String symbol) { 119 super( 120 unit.isBaseUnit() && period.isBaseUnit() 121 ? null 122 : combine(unit.getBaseUnit(), period.getBaseUnit()), 123 unit.toBaseUnits(1) / period.toBaseUnits(1), 124 name, 125 symbol); 126 this.m_unit = unit; 127 this.m_period = period; 128 } 129 130 @SuppressWarnings({"unchecked", "rawtypes"}) 131 Velocity( 132 Velocity<D> baseUnit, 133 UnaryFunction toBaseConverter, 134 UnaryFunction fromBaseConverter, 135 String name, 136 String symbol) { 137 super(baseUnit, toBaseConverter, fromBaseConverter, name, symbol); 138 this.m_unit = baseUnit.getUnit(); 139 this.m_period = baseUnit.getPeriod(); 140 } 141 142 /** 143 * Gets the major unit being measured (eg Meters for Meters per Second). 144 * 145 * @return the major unit 146 */ 147 public D getUnit() { 148 return m_unit; 149 } 150 151 /** 152 * Gets the period unit of the velocity, eg Seconds or Milliseconds. 153 * 154 * @return the period unit 155 */ 156 public Time getPeriod() { 157 return m_period; 158 } 159 160 /** 161 * Returns the reciprocal of this velocity. 162 * 163 * @return the reciprocal 164 */ 165 public Per<Time, D> reciprocal() { 166 return m_period.per(m_unit); 167 } 168 169 @Override 170 public boolean equals(Object o) { 171 if (this == o) { 172 return true; 173 } 174 if (o == null || getClass() != o.getClass()) { 175 return false; 176 } 177 if (!super.equals(o)) { 178 return false; 179 } 180 Velocity<?> velocity = (Velocity<?>) o; 181 return m_unit.equals(velocity.m_unit) && m_period.equals(velocity.m_period); 182 } 183 184 @Override 185 public int hashCode() { 186 return Objects.hash(super.hashCode(), m_unit, m_period); 187 } 188}