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((Class) Velocity.class, unit.toBaseUnits(1) / period.toBaseUnits(1), name, symbol); 120 this.m_unit = unit; 121 this.m_period = period; 122 } 123 124 @SuppressWarnings({"unchecked", "rawtypes"}) 125 Velocity( 126 UnaryFunction toBaseConverter, UnaryFunction fromBaseConverter, String name, String symbol) { 127 super((Class) Velocity.class, toBaseConverter, fromBaseConverter, name, symbol); 128 this.m_unit = Units.anonymous(); 129 this.m_period = Units.Seconds; 130 } 131 132 /** 133 * Gets the major unit being measured (eg Meters for Meters per Second). 134 * 135 * @return the major unit 136 */ 137 public D getUnit() { 138 return m_unit; 139 } 140 141 /** 142 * Gets the period unit of the velocity, eg Seconds or Milliseconds. 143 * 144 * @return the period unit 145 */ 146 public Time getPeriod() { 147 return m_period; 148 } 149 150 @Override 151 public boolean equals(Object o) { 152 if (this == o) { 153 return true; 154 } 155 if (o == null || getClass() != o.getClass()) { 156 return false; 157 } 158 if (!super.equals(o)) { 159 return false; 160 } 161 Velocity<?> velocity = (Velocity<?>) o; 162 return m_unit.equals(velocity.m_unit) && m_period.equals(velocity.m_period); 163 } 164 165 @Override 166 public int hashCode() { 167 return Objects.hash(super.hashCode(), m_unit, m_period); 168 } 169}