001/*
002 * Units of Measurement Systems
003 * Copyright (c) 2005-2021, 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-385, 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 javax.measure.MetricPrefix.MICRO;
033import static tech.units.indriya.unit.Units.*;
034
035import tech.units.indriya.AbstractSystemOfUnits;
036import tech.units.indriya.AbstractUnit;
037import tech.units.indriya.format.SimpleUnitFormat;
038import tech.units.indriya.function.MultiplyConverter;
039import tech.units.indriya.unit.ProductUnit;
040import tech.units.indriya.unit.TransformedUnit;
041
042import javax.measure.Unit;
043import javax.measure.quantity.Angle;
044import javax.measure.quantity.Area;
045
046import javax.measure.quantity.Energy;
047import javax.measure.quantity.Frequency;
048import javax.measure.quantity.Length;
049import javax.measure.quantity.Mass;
050import javax.measure.quantity.Power;
051import javax.measure.quantity.Temperature;
052import javax.measure.quantity.Time;
053import javax.measure.quantity.Speed;
054import javax.measure.quantity.Volume;
055import javax.measure.spi.SystemOfUnits;
056
057import si.uom.quantity.AngularSpeed;
058
059/**
060 * <p>
061 * This class contains units from the United States customary system.
062 * </p>
063 * <p>
064 * 
065 * @noextend This class is not intended to be extended by clients.
066 * 
067 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
068 * @author <a href="mailto:werner@uom.systems">Werner Keil</a>
069 * @version 2.2, May 21, 2021
070 * @see <a href="http://en.wikipedia.org/wiki/United_States_customary_units"> Wikipedia: United State Customary Units</a>
071 * @see <a href="https://en.wikipedia.org/wiki/Imperial_and_US_customary_measurement_systems"> Wikipedia: United State Customary Units</a>
072 * @since 0.3
073 */
074public final class USCustomary extends AbstractSystemOfUnits {
075    private static final String SYSTEM_NAME = "United States Customary Units";
076    
077    private static final USCustomary INSTANCE = new USCustomary();
078    
079    /**
080     * Default constructor (prevents this class from being instantiated).
081     */
082    private USCustomary() {
083    }
084
085    /**
086     * Returns the unique instance of this class.
087     * 
088     * @return the USCustomary instance.
089     */
090    public static SystemOfUnits getInstance() {
091        return INSTANCE;
092    }    
093
094    ////////////
095    // Length //
096    ////////////
097    /**
098     * US name for {@link SI#METRE}.
099     */
100    public static final Unit<Length> METER = addUnit(METRE);
101
102    /**
103     * A unit of length equal to <code>0.3048 m</code> (standard name <code>ft</code>).
104     */
105    public static final Unit<Length> FOOT = addUnit(METER.multiply(3048).divide(10000), "Foot", "ft");
106
107    /**
108     * A unit of length equal to <code>1200/3937 m</code> (standard name <code>foot_survey_us</code>). See also:
109     * <a href="http://www.sizes.com/units/foot.htm">foot</a>
110     */
111    public static final Unit<Length> FOOT_SURVEY = addUnit(METER.multiply(1200).divide(3937), "US Survey foot", "ft_survey_us");
112
113    /**
114     * A unit of length equal to <code>0.9144 m</code> (standard name <code>yd</code>).
115     */
116    public static final Unit<Length> YARD = addUnit(FOOT.multiply(3), "Yard", "yd");
117
118    /**
119     * A unit of length equal to <code>0.0254 m</code> (standard name <code>in</code>).
120     */
121    public static final Unit<Length> INCH = addUnit(FOOT.divide(12), "in");
122
123    /**
124     * A unit of length equal to <code>1609.344 m</code> (standard name <code>mi</code>).
125     */
126    public static final Unit<Length> MILE = addUnit(METER.multiply(1609344).divide(1000), "Mile", "mi");
127
128    /**
129     * A unit of length equal to the distance that light travels in one year through a vacuum (standard name <code>ly</code>).
130     */
131    public static final Unit<Length> LIGHT_YEAR = addUnit(METRE.multiply(9.460528405e15), "Light year", "ly");
132
133    /**
134     * A unit of length equal to <code>1852.0 m</code> (standard name <code>nmi</code>).
135     */
136    public static final Unit<Length> NAUTICAL_MILE = addUnit(METER.multiply(1852), "Nautical mile", "nmi");
137
138    //////////
139    // Mass //
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     * A unit of temperature equal to <code>5/9 °K</code> (standard name <code>°R</code>).
162     */
163    public static final Unit<Temperature> RANKINE = addUnit(KELVIN.multiply(5).divide(9));
164
165    /**
166     * A unit of temperature equal to degree Rankine minus <code>459.67 °R</code> (standard name <code>°F</code>).
167     * 
168     * @see #RANKINE
169     */
170    public static final Unit<Temperature> FAHRENHEIT = addUnit(RANKINE.shift(459.67), "°F");
171
172    ///////////
173    // Angle //
174    ///////////
175    /**
176     * A unit of angle equal to a full circle or <code>2<i>&pi;</i>
177     * {@link SI#RADIAN}</code> (standard name <code>rev</code>).
178     */
179    public static final Unit<Angle> REVOLUTION = addUnit(RADIAN.multiply(2).multiply(Math.PI).asType(Angle.class), "rev");
180
181    /**
182     * A unit of angle equal to <code>1/360 {@link #REVOLUTION}</code> (standard name <code>deg</code>).
183     */
184    public static final Unit<Angle> DEGREE_ANGLE = addUnit(REVOLUTION.divide(360));
185
186    /**
187     * A unit of angle equal to <code>1/60 {@link #DEGREE_ANGLE}</code> (standard name <code>'</code>).
188     */
189    public static final Unit<Angle> MINUTE_ANGLE = addUnit(DEGREE_ANGLE.divide(60));
190
191    /**
192     * A unit of angle equal to <code>1/60 {@link #MINUTE_ANGLE}</code> (standard name <code>"</code>).
193     */
194    public static final Unit<Angle> SECOND_ANGLE = addUnit(MINUTE_ANGLE.divide(60));
195
196    /**
197     * A unit of angle equal to <code>0.01 {@link SI#RADIAN}</code> (standard name <code>centiradian</code>).
198     */
199    public static final Unit<Angle> CENTIRADIAN = addUnit(RADIAN.divide(100));
200
201    /**
202     * A unit of angle measure equal to <code>1/400 {@link #REVOLUTION}</code> (standard name <code>grade</code> ).
203     */
204    public static final Unit<Angle> GRADE = addUnit(REVOLUTION.divide(400));
205
206    //////////////
207    //Time      //
208    //////////////
209    /**
210     * A unit of time equal to <code>60 s</code> (standard name <code>min</code> ).
211     */
212    public static final Unit<Time> MINUTE = addUnit(SECOND.multiply(60));
213
214    /**
215     * A unit of duration equal to <code>60 {@link #MINUTE}</code> (standard name <code>h</code>).
216     */
217    public static final Unit<Time> HOUR = addUnit(MINUTE.multiply(60));
218
219    //////////////
220    // Speed    //
221    //////////////
222    /**
223     * A unit of velocity expressing the number of {@link #FOOT feet} per {@link SI#SECOND second}.
224     * 
225     * @since 0.5.1
226     */
227    public static final Unit<Speed> FOOT_PER_SECOND = addUnit(FOOT.divide(SECOND).asType(Speed.class));
228
229    /**
230     * A unit of velocity expressing the number of international {@link #MILE miles} per {@link #HOUR hour} (abbreviation <code>mph</code>).
231     */
232    public static final Unit<Speed> MILE_PER_HOUR = addUnit(MILE.divide(HOUR).asType(Speed.class), "Mile per hour", "mph");
233
234    /**
235     * A unit of velocity expressing the number of {@link #NAUTICAL_MILE nautical miles} per {@link #HOUR hour} (abbreviation <code>kn</code>).
236     */
237    public static final Unit<Speed> KNOT = addUnit(NAUTICAL_MILE.divide(HOUR).asType(Speed.class), "Knot", "kn");
238
239    //////////
240    // Area //
241    //////////
242    /**
243     * A unit of area (standard name <code>sft</code> ).
244     */
245    public static final Unit<Area> SQUARE_FOOT = addUnit(new ProductUnit<Area>((AbstractUnit<?>) FOOT.multiply(FOOT)), "sft");
246
247    /**
248     * A unit of area equal to <code>100 m²</code> (standard name <code>a</code> ).
249     */
250    public static final Unit<Area> ARE = addUnit(SQUARE_METRE.multiply(100), "Are", "a");
251
252    /**
253     * A unit of area equal to <code>100 {@link #ARE}</code> (standard name <code>ha</code>).
254     */
255    public static final Unit<Area> HECTARE = addUnit(ARE.multiply(100), "Hectare", "ha"); // Exact.
256
257    /**
258     * 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
259     * about 40% of a <code>HECTARE</code> – slightly smaller than an American football field. (standard name <code>ac</code> ).
260     * 
261     * @see <a href="http://en.wikipedia.org/wiki/Acre">Wikipedia: Acre</a>
262     */
263    public static final Unit<Area> ACRE = addUnit(SQUARE_FOOT.multiply(43560), "Acre", "ac");
264
265    ////////////
266    // Energy //
267    ////////////
268    /**
269     * A unit of energy equal to one electron-volt (standard name <code>eV</code>, also recognized <code>keV, MeV, GeV</code>).
270     */
271    public static final Unit<Energy> ELECTRON_VOLT = addUnit(JOULE.multiply(1.602176462e-19), "Electron Volt", "eV");
272
273    ////////////
274    // Power  //
275    ////////////
276    /**
277     * Horsepower (hp) is the name of several units of measurement of power. The most common definitions equal between 735.5 and 750 watts. Horsepower
278     * 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
279     * of piston engines, turbines, electric motors, and other machinery. The definition of the unit varied between geographical regions. Most
280     * 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
281     * of horsepower in the EU is only permitted as supplementary unit.
282     */
283    public static final Unit<Power> HORSEPOWER = addUnit(WATT.multiply(745.69987158227), "Horsepower", "hp");
284
285    /**
286     * Nameplates on electrical motors show their power output, not the power input (the power delivered at the shaft, not the power consumed to drive the motor). <br>
287     * This power output is ordinarily stated in watts or kilowatts. In the United States, the power output is stated in horsepower, which for this purpose is defined as exactly 746 W.
288     */
289    public static final Unit<Power> ELECTRICAL_HORSEPOWER = addUnit(WATT.multiply(746), "Horsepower (Electrical)", "hp(E)");
290    
291    ////////////
292    // Volume //
293    ////////////
294    /**
295     * A unit of volume equal to one cubic decimeter (default label <code>L</code>, also recognized <code>µL, mL, cL, dL</code>).
296     */
297    public static final Unit<Volume> LITER = addUnit(new TransformedUnit<Volume>(CUBIC_METRE, MultiplyConverter.ofRational(1, 1000)), "Liter", "L");
298
299    /**
300     * A unit of volume equal to one cubic inch (<code>in³</code>).
301     */
302    public static final Unit<Volume> CUBIC_INCH = addUnit(INCH.pow(3).asType(Volume.class), "in³");
303
304    /**
305     * 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
306     * 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. (
307     * <code>ft³</code>).
308     */
309    public static final Unit<Volume> CUBIC_FOOT = addUnit(CUBIC_INCH.multiply(1728), "ft³");
310
311    /**
312     * 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,
313     * canals, sewer flow capacity, irrigation water, and river flows.
314     */
315    public static final Unit<Volume> ACRE_FOOT = addUnit(CUBIC_FOOT.multiply(43560), "Acre-foot", "ac ft");
316
317    /**
318     * A unit of volume equal to one US dry gallon. (standard name <code>gallon_dry_us</code>).
319     */
320    public static final Unit<Volume> GALLON_DRY = addUnit(CUBIC_INCH.multiply(2688025).divide(10000), "US dry gallon", "gal_dry_us");
321
322    /**
323     * 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
324     * inches (standard name <code>gal</code>).
325     */
326    public static final Unit<Volume> GALLON_LIQUID = addUnit(CUBIC_INCH.multiply(231), "US gallon", "gal");
327
328    /**
329     * A unit of volume equal to <code>1 / 128 {@link #GALLON_LIQUID}</code> (standard name <code>oz_fl</code>).
330     */
331    public static final Unit<Volume> FLUID_OUNCE = addUnit(GALLON_LIQUID.divide(128), "Fluid Ounze", "fl oz");
332
333    /**
334     * A unit of volume equal to 4 US oz_fl (standard name <code>liq.gi</code>).
335     */
336    public static final Unit<Volume> GILL_LIQUID = addUnit(FLUID_OUNCE.multiply(4), "Liquid Gill", "liq.gi");
337
338    /**
339     * A unit of volume <code>~ 1 drop or 0.95 grain of water </code> (standard name <code>min</code>).
340     */
341    public static final Unit<Volume> MINIM = addUnit(MICRO(LITER).multiply(61.61152d), "Minim", "min_us");
342
343    /**
344     * A unit of volume equal to <code>60 {@link #MINIM}</code> (standard name <code>fl dr</code>).
345     */
346    public static final Unit<Volume> FLUID_DRAM = addUnit(MINIM.multiply(60), "Fluid dram", "fl dr");
347
348    /**
349     * The cup is a unit of measurement for volume, used in cooking to measure liquids (fluid measurement) and bulk foods such as granulated sugar
350     * (dry measurement). A cup is equal to <code>8 {@link #FLUID_OUNCE}</code> (standard name <code>cup</code>).
351     */
352    public static final Unit<Volume> CUP = addUnit(FLUID_OUNCE.multiply(8), "Cup", "cup");
353
354    /**
355     * A unit of volume equal to <code>80 {@link #MINIM}</code> (standard name <code>tsp</code>).
356     */
357    public static final Unit<Volume> TEASPOON = addUnit(MINIM.multiply(80), "Teaspoon", "tsp");
358
359    /**
360     * A unit of volume equal to <code>3 {@link #TEASPOON}</code> (standard name <code>Tbsp</code>).
361     */
362    public static final Unit<Volume> TABLESPOON = addUnit(TEASPOON.multiply(3), "Tablespoon", "Tbsp");
363
364    /**
365     * A unit of volume equal to <code>238.4810 {@link #LITER}</code> (standard name <code>bbl</code>).
366     */
367    public static final Unit<Volume> BARREL = addUnit(LITER.multiply(238.4810d), "Barrel", "bbl");
368
369    /**
370     * A unit of volume equal to <code>4 {@link #GILL_LIQUID}</code> (standard name <code>pt</code>).
371     */
372    public static final Unit<Volume> PINT = addUnit(GILL_LIQUID.multiply(4), "Pint", "pt");
373
374    
375        ///////////////////
376        // Angular Speed //
377        //////////////////
378    
379    /**
380     * Revolutions per minute (abbreviated <code>rpm</code>, RPM, rev/min, r/min, or with the notation min−1) is the number of turns in one minute. It is a unit of rotational speed or the frequency of rotation around a fixed axis.
381     * 
382         * @see <a href="https://en.wikipedia.org/wiki/Revolutions_per_minute"> Wikipedia: Revolutions per minute</a>
383     * @since 2.1
384     */
385    public static final Unit<AngularSpeed> REVOLUTION_PER_MINUTE = addUnit(REVOLUTION.divide(MINUTE), "Pint", "rpm")
386                .asType(AngularSpeed.class);
387    
388    @Override
389    public String getName() {
390        return SYSTEM_NAME;
391    }
392
393    /**
394     * Adds a new unit not mapped to any specified quantity type.
395     *
396     * @param unit
397     *            the unit being added.
398     * @return <code>unit</code>.
399     */
400    private static <U extends Unit<?>> U addUnit(U unit) {
401        INSTANCE.units.add(unit);
402        return unit;
403    }
404
405    /**
406     * Adds a new unit not mapped to any specified quantity type and puts a text as symbol or label.
407     *
408     * @param unit
409     *            the unit being added.
410     * @param name
411     *            the string to use as name
412     * @param text
413     *            the string to use as label or symbol
414     * @param isLabel
415     *            if the string should be used as a label or not
416     * @return <code>unit</code>.
417     */
418    private static <U extends Unit<?>> U addUnit(U unit, String name, String text, boolean isLabel) {
419        if (isLabel) {
420            SimpleUnitFormat.getInstance().label(unit, text);
421        }
422        if (name != null && unit instanceof AbstractUnit) {
423            return Helper.addUnit(INSTANCE.units, unit, name);
424        } else {
425            INSTANCE.units.add(unit);
426        }
427        return unit;
428    }
429
430    /**
431     * Adds a new unit not mapped to any specified quantity type and puts a text as symbol or label.
432     *
433     * @param unit
434     *            the unit being added.
435     * @param name
436     *            the string to use as name
437     * @param label
438     *            the string to use as label
439     * @return <code>unit</code>.
440     */
441    private static <U extends Unit<?>> U addUnit(U unit, String name, String label) {
442        return addUnit(unit, name, label, true);
443    }
444
445    /**
446     * Adds a new unit not mapped to any specified quantity type and puts a text as label.
447     *
448     * @param unit
449     *            the unit being added.
450     * @param text
451     *            the string to use as label or symbol
452     * @return <code>unit</code>.
453     */
454    private static <U extends Unit<?>> U addUnit(U unit, String text) {
455        return addUnit(unit, null, text, true);
456    }
457}