001/*
002 * Units of Measurement Systems
003 * Copyright (c) 2005-2019, Jean-Marie Dautelle, Werner Keil and others.
004 *
005 * All rights reserved.
006 *
007 * Redistribution and use in source and binary forms, with or without modification,
008 * are permitted provided that the following conditions are met:
009 *
010 * 1. Redistributions of source code must retain the above copyright notice,
011 *    this list of conditions and the following disclaimer.
012 *
013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
014 *    and the following disclaimer in the documentation and/or other materials provided with the distribution.
015 *
016 * 3. Neither the name of JSR-363, Units of Measurement nor the names of their contributors may be used to
017 *    endorse or promote products derived from this software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package systems.uom.common;
031
032import static tech.units.indriya.unit.MetricPrefix.MICRO;
033import static tech.units.indriya.unit.Units.*;
034
035import java.util.Objects;
036
037import tech.units.indriya.AbstractSystemOfUnits;
038import tech.units.indriya.AbstractUnit;
039import tech.units.indriya.format.SimpleUnitFormat;
040import tech.units.indriya.function.RationalConverter;
041import tech.units.indriya.unit.ProductUnit;
042import tech.units.indriya.unit.TransformedUnit;
043
044import javax.measure.Unit;
045import javax.measure.quantity.Angle;
046import javax.measure.quantity.Area;
047
048import javax.measure.quantity.Energy;
049import javax.measure.quantity.Length;
050import javax.measure.quantity.Mass;
051import javax.measure.quantity.Power;
052import javax.measure.quantity.Temperature;
053import javax.measure.quantity.Time;
054import javax.measure.quantity.Speed;
055import javax.measure.quantity.Volume;
056import javax.measure.spi.SystemOfUnits;
057
058/**
059 * <p>
060 * This class contains units from the United States customary system.
061 * </p>
062 * <p>
063 * 
064 * @noextend This class is not intended to be extended by clients.
065 * 
066 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
067 * @author <a href="mailto:units@catmedia.us">Werner Keil</a>
068 * @version 1.28, January 21, 2019
069 * @see <a href="http://en.wikipedia.org/wiki/United_States_customary_units"> Wikipedia: United State Customary Units</a>
070 * @see <a href="https://en.wikipedia.org/wiki/Imperial_and_US_customary_measurement_systems"> Wikipedia: United State Customary Units</a>
071 * @since 0.3
072 */
073public final class USCustomary extends AbstractSystemOfUnits {
074    private static final String SYSTEM_NAME = "United States Customary Units";
075
076    /**
077     * Default constructor (prevents this class from being instantiated).
078     */
079    private USCustomary() {
080    }
081
082    /**
083     * Returns the unique instance of this class.
084     * 
085     * @return the USCustomary instance.
086     */
087    public static SystemOfUnits getInstance() {
088        return INSTANCE;
089    }
090
091    private static final USCustomary INSTANCE = new USCustomary();
092
093    ////////////
094    // Length //
095    ////////////
096    /**
097     * US name for {@link SI#METRE}.
098     */
099    public static final Unit<Length> METER = addUnit(METRE);
100
101    /**
102     * A unit of length equal to <code>0.3048 m</code> (standard name <code>ft</code>).
103     */
104    public static final Unit<Length> FOOT = addUnit(METER.multiply(3048).divide(10000), "Foot", "ft");
105
106    /**
107     * A unit of length equal to <code>1200/3937 m</code> (standard name <code>foot_survey_us</code>). See also:
108     * <a href="http://www.sizes.com/units/foot.htm">foot</a>
109     */
110    public static final Unit<Length> FOOT_SURVEY = addUnit(METER.multiply(1200).divide(3937), "US Survey foot", "ft_survey_us");
111
112    /**
113     * A unit of length equal to <code>0.9144 m</code> (standard name <code>yd</code>).
114     */
115    public static final Unit<Length> YARD = addUnit(FOOT.multiply(3), "Yard", "yd");
116
117    /**
118     * A unit of length equal to <code>0.0254 m</code> (standard name <code>in</code>).
119     */
120    public static final Unit<Length> INCH = addUnit(FOOT.divide(12), "in");
121
122    /**
123     * A unit of length equal to <code>1609.344 m</code> (standard name <code>mi</code>).
124     */
125    public static final Unit<Length> MILE = addUnit(METER.multiply(1609344).divide(1000), "Mile", "mi");
126
127    /**
128     * A unit of length equal to the distance that light travels in one year through a vacuum (standard name <code>ly</code>).
129     */
130    public static final Unit<Length> LIGHT_YEAR = addUnit(METRE.multiply(9.460528405e15), "Light year", "ly");
131
132    /**
133     * A unit of length equal to <code>1852.0 m</code> (standard name <code>nmi</code>).
134     */
135    public static final Unit<Length> NAUTICAL_MILE = addUnit(METER.multiply(1852), "Nautical mile", "nmi");
136
137    //////////
138    // Mass //
139    //////////
140
141    /**
142     * A unit of mass equal to <code>453.59237 grams</code> (avoirdupois pound, standard name <code>lb</code>).
143     */
144    public static final Unit<Mass> POUND = addUnit(KILOGRAM.multiply(45359237).divide(100000000), "Pound", "lb"); // ,
145    // Messages.US_lb_name);
146
147    /**
148     * A unit of mass equal to <code>1 / 16 {@link #POUND}</code> (standard name <code>oz</code>).
149     */
150    public static final Unit<Mass> OUNCE = addUnit(POUND.divide(16), "oz");
151
152    /**
153     * A unit of mass equal to <code>2000 {@link #POUND}</code> (short ton, standard name <code>ton</code>).
154     */
155    public static final Unit<Mass> TON = addUnit(POUND.multiply(2000), "ton_us");
156
157    /////////////////
158    // Temperature //
159    /////////////////
160
161    /**
162     * A unit of temperature equal to <code>5/9 °K</code> (standard name <code>°R</code>).
163     */
164    public static final Unit<Temperature> RANKINE = addUnit(KELVIN.multiply(5).divide(9));
165
166    /**
167     * A unit of temperature equal to degree Rankine minus <code>459.67 °R</code> (standard name <code>°F</code>).
168     * 
169     * @see #RANKINE
170     */
171    public static final Unit<Temperature> FAHRENHEIT = addUnit(RANKINE.shift(459.67), "°F");
172
173    ///////////
174    // Angle //
175    ///////////
176
177    /**
178     * A unit of angle equal to a full circle or <code>2<i>&pi;</i>
179     * {@link SI#RADIAN}</code> (standard name <code>rev</code>).
180     */
181    public static final Unit<Angle> REVOLUTION = addUnit(RADIAN.multiply(2).multiply(Math.PI).asType(Angle.class), "rev");
182
183    /**
184     * A unit of angle equal to <code>1/360 {@link #REVOLUTION}</code> (standard name <code>deg</code>).
185     */
186    public static final Unit<Angle> DEGREE_ANGLE = addUnit(REVOLUTION.divide(360));
187
188    /**
189     * A unit of angle equal to <code>1/60 {@link #DEGREE_ANGLE}</code> (standard name <code>'</code>).
190     */
191    public static final Unit<Angle> MINUTE_ANGLE = addUnit(DEGREE_ANGLE.divide(60));
192
193    /**
194     * A unit of angle equal to <code>1/60 {@link #MINUTE_ANGLE}</code> (standard name <code>"</code>).
195     */
196    public static final Unit<Angle> SECOND_ANGLE = addUnit(MINUTE_ANGLE.divide(60));
197
198    /**
199     * A unit of angle equal to <code>0.01 {@link SI#RADIAN}</code> (standard name <code>centiradian</code>).
200     */
201    public static final Unit<Angle> CENTIRADIAN = addUnit(RADIAN.divide(100));
202
203    /**
204     * A unit of angle measure equal to <code>1/400 {@link #REVOLUTION}</code> (standard name <code>grade</code> ).
205     */
206    public static final Unit<Angle> GRADE = addUnit(REVOLUTION.divide(400));
207
208    // ////////////
209    // Time //
210    // ////////////
211    /**
212     * A unit of time equal to <code>60 s</code> (standard name <code>min</code> ).
213     */
214    public static final Unit<Time> MINUTE = addUnit(SECOND.multiply(60));
215
216    /**
217     * A unit of duration equal to <code>60 {@link #MINUTE}</code> (standard name <code>h</code>).
218     */
219    public static final Unit<Time> HOUR = addUnit(MINUTE.multiply(60));
220
221    // ////////////
222    // Speed //
223    // ////////////
224    /**
225     * A unit of velocity expressing the number of {@link #FOOT feet} per {@link SI#SECOND second}.
226     * 
227     * @since 0.5.1
228     */
229    public static final Unit<Speed> FOOT_PER_SECOND = addUnit(FOOT.divide(SECOND)).asType(Speed.class);
230
231    /**
232     * Alias for {@link FOOT_PER_SECOND}
233     * 
234     * @deprecated use FOOT_PER_SECOND.
235     */
236    public static final Unit<Speed> FEET_PER_SECOND = FOOT_PER_SECOND;
237
238    /**
239     * A unit of velocity expressing the number of international {@link #MILE miles} per {@link #HOUR hour} (abbreviation <code>mph</code>).
240     */
241    public static final Unit<Speed> MILE_PER_HOUR = addUnit(MILE.divide(HOUR).asType(Speed.class), "Mile per hour", "mph");
242
243    /**
244     * Alias for {@link MILE_PER_HOUR}
245     * 
246     * @deprecated use MILE_PER_HOUR.
247     */
248    public static final Unit<Speed> MILES_PER_HOUR = MILE_PER_HOUR;
249
250    /**
251     * A unit of velocity expressing the number of {@link #NAUTICAL_MILE nautical miles} per {@link #HOUR hour} (abbreviation <code>kn</code>).
252     */
253    public static final Unit<Speed> KNOT = addUnit(NAUTICAL_MILE.divide(HOUR).asType(Speed.class), "Knot", "kn");
254
255    //////////
256    // Area //
257    //////////
258
259    /**
260     * A unit of area (standard name <code>sft</code> ).
261     */
262    public static final Unit<Area> SQUARE_FOOT = addUnit(new ProductUnit<Area>((AbstractUnit<?>) FOOT.multiply(FOOT)), "sft");
263
264    /**
265     * A unit of area equal to <code>100 m²</code> (standard name <code>a</code> ).
266     */
267    public static final Unit<Area> ARE = addUnit(SQUARE_METRE.multiply(100), "Are", "a");
268
269    /**
270     * A unit of area equal to <code>100 {@link #ARE}</code> (standard name <code>ha</code>).
271     */
272    public static final Unit<Area> HECTARE = addUnit(ARE.multiply(100), "Hectare", "ha"); // Exact.
273
274    /**
275     * The acre is a unit of area used in the imperial and U.S. customary systems. It is equivalent to <code>43,560 square feet</code>. An acre is
276     * about 40% of a <code>HECTARE</code> – slightly smaller than an American football field. (standard name <code>ac</code> ).
277     * 
278     * @see <a href="http://en.wikipedia.org/wiki/Acre">Wikipedia: Acre</a>
279     */
280    public static final Unit<Area> ACRE = addUnit(SQUARE_FOOT.multiply(43560), "Acre", "ac");
281
282    ////////////
283    // Energy //
284    ////////////
285
286    /**
287     * A unit of energy equal to one electron-volt (standard name <code>eV</code>, also recognized <code>keV, MeV, GeV</code>).
288     */
289    public static final Unit<Energy> ELECTRON_VOLT = addUnit(JOULE.multiply(1.602176462e-19), "Electron Volt", "eV");
290
291    ////////////
292    // Power //
293    ////////////
294
295    /**
296     * Horsepower (HP) is the name of several units of measurement of power. The most common definitions equal between 735.5 and 750 watts. Horsepower
297     * was originally defined to compare the output of steam engines with the power of draft horses. The unit was widely adopted to measure the output
298     * of piston engines, turbines, electric motors, and other machinery. The definition of the unit varied between geographical regions. Most
299     * countries now use the SI unit watt for measurement of power. With the implementation of the EU Directive 80/181/EEC on January 1, 2010, the use
300     * of horsepower in the EU is only permitted as supplementary unit.
301     */
302    public static final Unit<Power> HORSEPOWER = addUnit(WATT.multiply(735.499), "Horsepower", "HP");
303
304    // //////////
305    // Volume //
306    // //////////
307    /**
308     * A unit of volume equal to one cubic decimeter (default label <code>L</code>, also recognized <code>µL, mL, cL, dL</code>).
309     */
310    public static final Unit<Volume> LITER = addUnit(new TransformedUnit<Volume>(CUBIC_METRE, new RationalConverter(1, 1000)), "Liter", "L");
311
312    /**
313     * A unit of volume equal to one cubic inch (<code>in³</code>).
314     */
315    public static final Unit<Volume> CUBIC_INCH = addUnit(INCH.pow(3).asType(Volume.class), "in³");
316
317    /**
318     * The cubic foot is an imperial and US customary (non-metric) unit of volume, used in the United States, Canada, and the United Kingdom. It is
319     * defined as the volume of a cube with sides of one foot (0.3048 m) in length. Its volume is 28.3168 liters or about 1⁄35 of a cubic meter. (
320     * <code>ft³</code>).
321     */
322    public static final Unit<Volume> CUBIC_FOOT = addUnit(CUBIC_INCH.multiply(1728), "ft³");
323
324    /**
325     * An acre-foot is a unit of volume commonly used in the United States in reference to large-scale water resources, such as reservoirs, aqueducts,
326     * canals, sewer flow capacity, irrigation water, and river flows.
327     */
328    public static final Unit<Volume> ACRE_FOOT = addUnit(CUBIC_FOOT.multiply(43560), "Acre-foot", "ac ft");
329
330    /**
331     * A unit of volume equal to one US dry gallon. (standard name <code>gallon_dry_us</code>).
332     */
333    public static final Unit<Volume> GALLON_DRY = addUnit(CUBIC_INCH.multiply(2688025).divide(10000), "US dry gallon", "gal_dry_us");
334
335    /**
336     * A unit of volume equal to one US gallon, Liquid Unit. The U.S. liquid gallon is based on the Queen Anne or Wine gallon occupying 231 cubic
337     * inches (standard name <code>gal</code>).
338     */
339    public static final Unit<Volume> GALLON_LIQUID = addUnit(CUBIC_INCH.multiply(231), "US gallon", "gal");
340
341    /**
342     * A unit of volume equal to <code>1 / 128 {@link #GALLON_LIQUID}</code> (standard name <code>oz_fl</code>).
343     */
344    public static final Unit<Volume> FLUID_OUNCE = addUnit(GALLON_LIQUID.divide(128), "Fluid Ounze", "fl oz");
345
346    /**
347     * A unit of volume equal to 4 US oz_fl (standard name <code>liq.gi</code>).
348     */
349    public static final Unit<Volume> GILL_LIQUID = addUnit(FLUID_OUNCE.multiply(4), "Liquid Gill", "liq.gi");
350
351    /**
352     * A unit of volume <code>~ 1 drop or 0.95 grain of water </code> (standard name <code>min</code>).
353     */
354    public static final Unit<Volume> MINIM = addUnit(MICRO(LITER).multiply(61.61152d), "Minim", "min_us");
355
356    /**
357     * A unit of volume equal to <code>60 {@link #MINIM}</code> (standard name <code>fl dr</code>).
358     */
359    public static final Unit<Volume> FLUID_DRAM = addUnit(MINIM.multiply(60), "Fluid dram", "fl dr");
360
361    /**
362     * The cup is a unit of measurement for volume, used in cooking to measure liquids (fluid measurement) and bulk foods such as granulated sugar
363     * (dry measurement). A cup is equal to <code>8 {@link #FLUID_OUNCE}</code> (standard name <code>cup</code>).
364     */
365    public static final Unit<Volume> CUP = addUnit(FLUID_OUNCE.multiply(8), "Cup", "cup");
366
367    /**
368     * A unit of volume equal to <code>80 {@link #MINIM}</code> (standard name <code>tsp</code>).
369     */
370    public static final Unit<Volume> TEASPOON = addUnit(MINIM.multiply(80), "Teaspoon", "tsp");
371
372    /**
373     * A unit of volume equal to <code>3 {@link #TEASPOON}</code> (standard name <code>Tbsp</code>).
374     */
375    public static final Unit<Volume> TABLESPOON = addUnit(TEASPOON.multiply(3), "Tablespoon", "Tbsp");
376
377    /**
378     * A unit of volume equal to <code>238.4810 {@link #LITER}</code> (standard name <code>bbl</code>).
379     */
380    public static final Unit<Volume> BARREL = addUnit(LITER.multiply(238.4810d), "Barrel", "bbl");
381
382    /**
383     * A unit of volume equal to <code>4 {@link #GILL_LIQUID}</code> (standard name <code>pt</code>).
384     */
385    public static final Unit<Volume> PINT = addUnit(GILL_LIQUID.multiply(4), "Pint", "pt");
386
387    @Override
388    public String getName() {
389        return SYSTEM_NAME;
390    }
391
392    @Override
393    public Unit<?> getUnit(String string) {
394        Objects.requireNonNull(string);
395        return this.getUnits().stream().filter((u) -> string.equals(u.toString())).findAny().orElse(null);
396    }
397
398    /**
399     * Holds the international foot: 0.3048 m exact.
400     */
401    // private static final int INTERNATIONAL_FOOT_DIVIDEND = 3048;
402
403    // private static final int INTERNATIONAL_FOOT_DIViSOR = 10000;
404
405    /**
406     * Adds a new unit not mapped to any specified quantity type.
407     *
408     * @param unit
409     *            the unit being added.
410     * @return <code>unit</code>.
411     */
412    private static <U extends Unit<?>> U addUnit(U unit) {
413        INSTANCE.units.add(unit);
414        return unit;
415    }
416
417    /**
418     * Adds a new unit not mapped to any specified quantity type and puts a text as symbol or label.
419     *
420     * @param unit
421     *            the unit being added.
422     * @param name
423     *            the string to use as name
424     * @param text
425     *            the string to use as label or symbol
426     * @param isLabel
427     *            if the string should be used as a label or not
428     * @return <code>unit</code>.
429     */
430    private static <U extends Unit<?>> U addUnit(U unit, String name, String text, boolean isLabel) {
431        if (isLabel) {
432            SimpleUnitFormat.getInstance().label(unit, text);
433        }
434        if (name != null && unit instanceof AbstractUnit) {
435            return Helper.addUnit(INSTANCE.units, unit, name);
436        } else {
437            INSTANCE.units.add(unit);
438        }
439        return unit;
440    }
441
442    /**
443     * Adds a new unit not mapped to any specified quantity type and puts a text as symbol or label.
444     *
445     * @param unit
446     *            the unit being added.
447     * @param name
448     *            the string to use as name
449     * @param label
450     *            the string to use as label
451     * @return <code>unit</code>.
452     */
453    private static <U extends Unit<?>> U addUnit(U unit, String name, String label) {
454        return addUnit(unit, name, label, true);
455    }
456
457    /**
458     * Adds a new unit not mapped to any specified quantity type and puts a text as label.
459     *
460     * @param unit
461     *            the unit being added.
462     * @param text
463     *            the string to use as label or symbol
464     * @return <code>unit</code>.
465     */
466    private static <U extends Unit<?>> U addUnit(U unit, String text) {
467        return addUnit(unit, null, text, true);
468    }
469}