001/*
002 * Units of Measurement Systems
003 * Copyright (c) 2005-2017, 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 tec.uom.se.unit.MetricPrefix.MICRO;
033import static tec.uom.se.unit.Units.*;
034
035import javax.measure.Unit;
036import javax.measure.quantity.Acceleration;
037import javax.measure.quantity.Area;
038import javax.measure.quantity.Force;
039import javax.measure.quantity.Length;
040import javax.measure.quantity.Mass;
041import javax.measure.quantity.Temperature;
042import javax.measure.quantity.Time;
043import javax.measure.quantity.Volume;
044import javax.measure.spi.SystemOfUnits;
045
046import tec.uom.se.AbstractSystemOfUnits;
047import tec.uom.se.AbstractUnit;
048import tec.uom.se.format.SimpleUnitFormat;
049import tec.uom.se.unit.ProductUnit;
050
051/**
052 * <p>
053 * This class contains units from the Imperial system.
054 * </p>
055 * <p>
056 * 
057 * @noextend This class is not intended to be extended by clients.
058 * 
059 * @author <a href="mailto:units@catmedia.us">Werner Keil</a>
060 * @version 1.0.4, $Date: 2018-05-02 $
061 * @see <a href=
062 *      "http://en.wikipedia.org/wiki/http://en.wikipedia.org/wiki/Imperial_unit">
063 *      Wikipedia: Imperial Units</a>
064 * @see <a href=
065 *      "https://en.wikipedia.org/wiki/Imperial_and_US_customary_measurement_systems">
066 * @since 0.2
067 */
068public final class Imperial extends AbstractSystemOfUnits {
069    /**
070     * Holds the avoirdupois pound: 0.45359237 kg exact
071     */
072    static final int AVOIRDUPOIS_POUND_DIVIDEND = 45359237;
073
074    static final int AVOIRDUPOIS_POUND_DIVISOR = 100000000;
075    
076    /**
077     * Holds the standard gravity constant: 9.80665 m/s² exact.
078     */
079    private static final int STANDARD_GRAVITY_DIVIDEND = 980665;
080
081    private static final int STANDARD_GRAVITY_DIVISOR = 100000;
082
083    /**
084     * Default constructor (prevents this class from being instantiated).
085     */
086    private Imperial() {
087    }
088
089    /**
090     * Returns the unique instance of this class.
091     * 
092     * @return the Imperial instance.
093     */
094    public static SystemOfUnits getInstance() {
095        return INSTANCE;
096    }
097
098    private static final Imperial INSTANCE = new Imperial();
099
100    ////////////
101    // Length //
102    ////////////
103
104    /**
105     * A unit of length equal to <code>0.0254 m</code> (standard name
106     * <code>in</code>).
107     */
108    public static final Unit<Length> INCH = addUnit(USCustomary.INCH, "Inch", "in");
109
110    //////////
111    // Mass //
112    //////////
113
114    /**
115     * A unit of mass equal to <code>453.59237 grams</code> (avoirdupois pound,
116     * standard name <code>lb</code>).
117     */
118    public static final Unit<Mass> POUND = addUnit(
119            KILOGRAM.multiply(AVOIRDUPOIS_POUND_DIVIDEND).divide(AVOIRDUPOIS_POUND_DIVISOR), "Pound", "lb", true);
120    /**
121     * An English and imperial unit of weight or mass now equal to 14
122     * avoirdupois pounds or 6.35029318 kg (<code>st</code>).
123     */
124    public static final Unit<Mass> STONE = addUnit(KILOGRAM.multiply(6.35029318), "st", true);
125
126    /**
127     * A unit of mass equal to <code>1 / 16 {@link #POUND}</code> (standard name
128     * <code>oz</code>).
129     */
130    public static final Unit<Mass> OUNCE = addUnit(POUND.divide(16), "oz");
131
132    /**
133     * A unit of mass equal to <code>2240 {@link #POUND}</code> (long ton,
134     * standard name <code>ton_uk</code>).
135     */
136    public static final Unit<Mass> TON_UK = addUnit(POUND.multiply(2240), "ton_uk");
137
138    /**
139     * A unit of mass equal to <code>1000 kg</code> (metric ton, standard name
140     * <code>t</code>).
141     */
142    public static final Unit<Mass> METRIC_TON = addUnit(KILOGRAM.multiply(1000), "t");
143
144    /////////////////
145    // Temperature //
146    /////////////////
147
148    /**
149     * A unit of temperature equal to <code>5/9 °K</code> (standard name
150     * <code>°R</code>).
151     */
152    static final Unit<Temperature> RANKINE = addUnit(KELVIN.multiply(5).divide(9), "°R", true);
153
154    /**
155     * A unit of temperature equal to degree Rankine minus
156     * <code>459.67 °R</code> (standard name <code>°F</code>).
157     * 
158     * @see #RANKINE
159     */
160    static final Unit<Temperature> FAHRENHEIT = addUnit(RANKINE.shift(459.67), "°F", true);
161
162    //////////////
163    // Time //
164    //////////////
165    /**
166     * A unit of time equal to <code>60 s</code> (standard name <code>min</code>
167     * ).
168     */
169    static final Unit<Time> MINUTE = addUnit(SECOND.multiply(60));
170
171    /**
172     * A unit of duration equal to <code>60 {@link #MINUTE}</code> (standard
173     * name <code>h</code>).
174     */
175    static final Unit<Time> HOUR = addUnit(MINUTE.multiply(60));
176    
177    // ////////////////
178    // Acceleration //
179    // ////////////////
180    /**
181     * A unit of acceleration equal to the gravity at the earth's surface
182     * (standard name <code>grav</code>).
183     */
184    static final Unit<Acceleration> G = addUnit(
185            METRE_PER_SQUARE_SECOND.multiply(STANDARD_GRAVITY_DIVIDEND).divide(STANDARD_GRAVITY_DIVISOR));
186
187    //////////
188    // Area //
189    //////////
190
191    /**
192     * A unit of area (standard name <code>sft</code> ).
193     */
194    public static final Unit<Area> SQUARE_FOOT = addUnit(USCustomary.SQUARE_FOOT, "sft", true);
195
196    /**
197     * One acre is 43,560 <code>square feet</code> (standard name <code>a</code>
198     * ).
199     */
200    public static final Unit<Area> ACRE = addUnit(USCustomary.SQUARE_FOOT.multiply(43560), "Acre", "ac", true);
201
202    ////////////
203    // Volume //
204    ////////////
205    /**
206     * A unit of volume equal to one cubic decimeter (default label
207     * <code>L</code>, also recognized <code>µL, mL, cL, dL</code>).
208     */
209    static final Unit<Volume> LITRE = addUnit(CUBIC_METRE.divide(1000), "L", true);
210
211    /**
212     * A unit of volume equal to one cubic inch (<code>in³</code>).
213     */
214    static final Unit<Volume> CUBIC_INCH = addUnit(new ProductUnit<Volume>(USCustomary.INCH.pow(3)), "Cubic Inch",
215            "in³");
216
217    /**
218     * A unit of volume equal to <code>4.546 09 {@link #LITRE}</code> (standard
219     * name <code>gal_uk</code>).
220     */
221    public static final Unit<Volume> GALLON_UK = addUnit(LITRE.multiply(454609).divide(100000), "gal_uk");
222
223    /**
224     * A unit of volume equal to one UK gallon, Liquid Unit.
225     */
226    // public static final Unit<Volume> GALLON_LIQUID =
227    // addUnit(CUBIC_INCH.multiply(277.42));
228
229    /**
230     * A unit of volume equal to <code>1 / 160 {@link #GALLON_UK}</code>
231     * (standard name <code>fl_oz_uk</code>).
232     */
233    static final Unit<Volume> FLUID_OUNCE_UK = GALLON_UK.divide(160); // ,
234                                                                       // "fl_oz_uk",
235                                                                       // true);
236
237    /**
238     * A unit of volume equal to <code>1 / 160 {@link #GALLON_LIQUID}</code>
239     * (standard name <code>fl_oz</code>).
240     * @deprecated use FLUID_OUNCE
241     */
242    public static final Unit<Volume> OUNCE_LIQUID = FLUID_OUNCE_UK;
243
244    /**
245     * A unit of volume equal to <code>1 / 160 {@link #GALLON_LIQUID}</code>
246     * (standard name <code>fl_oz</code>).
247     */
248    public static final Unit<Volume> FLUID_OUNCE = addUnit(FLUID_OUNCE_UK, "fl_oz", true);
249
250    /**
251     * A unit of volume equal to <code>5 {@link #FLUID_OUNCE}</code> (standard
252     * name <code>gi</code>).
253     */
254    public static final Unit<Volume> GILL = addUnit(FLUID_OUNCE.multiply(5), "Gill", "gi");
255
256    /**
257     * A unit of volume equal to <code>20 {@link #FLUID_OUNCE}</code> (standard
258     * name <code>pt</code>).
259     */
260    public static final Unit<Volume> PINT = addUnit(FLUID_OUNCE.multiply(20), "Pint", "pt", true);
261
262    /**
263     * A unit of volume equal to <code>40 {@link #FLUID_OUNCE}</code> (standard
264     * name <code>qt</code>).
265     */
266    public static final Unit<Volume> QUART = addUnit(FLUID_OUNCE.multiply(40), "Quart", "qt");
267
268    /**
269     * A unit of volume <code>~ 1 drop or 0.95 grain of water </code> (standard
270     * name <code>min</code>).
271     */
272    public static final Unit<Volume> MINIM = addUnit(MICRO(LITRE).multiply(59.1938802d), "Minim", "min_br");
273
274    /**
275     * A unit of volume equal to <code>20 {@link #MINIM}</code> (standard name
276     * <code>fl scr</code>).
277     */
278    public static final Unit<Volume> FLUID_SCRUPLE = addUnit(MINIM.multiply(60), "fl scr", true);
279
280    /**
281     * A unit of volume equal to <code>3 {@link #FLUID_SCRUPLE}</code> (standard
282     * name <code>fl drc</code>).
283     */
284    public static final Unit<Volume> FLUID_DRACHM = addUnit(FLUID_SCRUPLE.multiply(3), "fl drc", true);
285    
286    /**
287     * A unit of force equal to <code>{@link #POUND}·{@link #G}</code>
288     * (standard name <code>lbf</code>).
289     */
290    public static final Unit<Force> POUND_FORCE = addUnit(
291            NEWTON.multiply(1L * AVOIRDUPOIS_POUND_DIVIDEND * STANDARD_GRAVITY_DIVIDEND)
292                    .divide(1L * AVOIRDUPOIS_POUND_DIVISOR * STANDARD_GRAVITY_DIVISOR), "lbf");
293    /**
294     * A unit of force equal to <code>9.80665 N</code> (standard name
295     * <code>kgf</code>).
296     */
297    static final Unit<Force> KILOGRAM_FORCE = addUnit(
298            NEWTON.multiply(STANDARD_GRAVITY_DIVIDEND).divide(STANDARD_GRAVITY_DIVISOR));
299
300
301    /**
302     * Adds a new unit not mapped to any specified quantity type.
303     *
304     * @param unit
305     *            the unit being added.
306     * @return <code>unit</code>.
307     */
308    private static <U extends Unit<?>> U addUnit(U unit) {
309        INSTANCE.units.add(unit);
310        return unit;
311    }
312
313    /**
314     * Adds a new unit not mapped to any specified quantity type and puts a text
315     * as symbol or label.
316     *
317     * @param unit
318     *            the unit being added.
319     * @param name
320     *            the string to use as name
321     * @param text
322     *            the string to use as label or symbol
323     * @param isLabel
324     *            if the string should be used as a label or not
325     * @return <code>unit</code>.
326     */
327    private static <U extends Unit<?>> U addUnit(U unit, String name, String text, boolean isLabel) {
328        if (isLabel) {
329            SimpleUnitFormat.getInstance().label(unit, text);
330        }
331        if (name != null && unit instanceof AbstractUnit) {
332            return Helper.addUnit(INSTANCE.units, unit, name);
333        } else {
334            INSTANCE.units.add(unit);
335        }
336        return unit;
337    }
338
339    /**
340     * Adds a new unit not mapped to any specified quantity type and puts a text
341     * as symbol or label.
342     *
343     * @param unit
344     *            the unit being added.
345     * @param name
346     *            the string to use as name
347     * @param label
348     *            the string to use as label
349     * @return <code>unit</code>.
350     */
351    private static <U extends Unit<?>> U addUnit(U unit, String name, String label) {
352        return addUnit(unit, name, label, true);
353    }
354
355    /**
356     * Adds a new unit not mapped to any specified quantity type and puts a text
357     * as symbol or label.
358     *
359     * @param unit
360     *            the unit being added.
361     * @param text
362     *            the string to use as label or symbol
363     * @param isLabel
364     *            if the string should be used as a label or not
365     * @return <code>unit</code>.
366     */
367    private static <U extends Unit<?>> U addUnit(U unit, String text, boolean isLabel) {
368        return addUnit(unit, null, text, isLabel);
369    }
370
371    /**
372     * Adds a new unit not mapped to any specified quantity type and puts a text
373     * as label.
374     *
375     * @param unit
376     *            the unit being added.
377     * @param text
378     *            the string to use as label or symbol
379     * @return <code>unit</code>.
380     */
381    private static <U extends Unit<?>> U addUnit(U unit, String text) {
382        return addUnit(unit, null, text, true);
383    }
384
385    // //////////////////////////////////////////////////////////////////////////
386    // Label adjustments for Imperial system
387    static {
388        SimpleUnitFormat.getInstance().label(FLUID_DRACHM, "fl drc");
389        SimpleUnitFormat.getInstance().label(FLUID_SCRUPLE, "fl scr");
390    }
391
392    // ///////////////////
393    // Collection View //
394    // ///////////////////
395
396    @Override
397    public String getName() {
398        return getClass().getSimpleName();
399    }
400}