001/*
002 *  Units of Measurement Systems for Java
003 *  Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM.
004 *
005 * All rights reserved.
006 *
007 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
008 *
009 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
010 *
011 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
012 *
013 * 3. Neither the name of JSR-363, Units of Measurement nor the names of their contributors may be used to endorse or promote products derived from this software without specific prior written permission.
014 *
015 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
016 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
017 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
018 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
019 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
020 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
021 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
022 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
023 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
024 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
025 */
026package systems.uom.common;
027
028import static tec.uom.se.unit.MetricPrefix.MICRO;
029import static tec.uom.se.unit.Units.*;
030
031import javax.measure.Unit;
032import javax.measure.quantity.Acceleration;
033import javax.measure.quantity.Area;
034import javax.measure.quantity.Force;
035import javax.measure.quantity.Length;
036import javax.measure.quantity.Mass;
037import javax.measure.quantity.Temperature;
038import javax.measure.quantity.Time;
039import javax.measure.quantity.Volume;
040import javax.measure.spi.SystemOfUnits;
041
042import tec.uom.se.AbstractSystemOfUnits;
043import tec.uom.se.AbstractUnit;
044import tec.uom.se.format.SimpleUnitFormat;
045import tec.uom.se.unit.ProductUnit;
046
047/**
048 * <p>
049 * This class contains units from the Imperial system.
050 * </p>
051 * <p>
052 * 
053 * @noextend This class is not intended to be extended by clients.
054 * 
055 * @author <a href="mailto:units@catmedia.us">Werner Keil</a>
056 * @version 1.0.2, $Date: 2017-03-03 $
057 * @see <a href=
058 *      "http://en.wikipedia.org/wiki/http://en.wikipedia.org/wiki/Imperial_unit">
059 *      Wikipedia: Imperial Units</a>
060 * @see <a href=
061 *      "https://en.wikipedia.org/wiki/Imperial_and_US_customary_measurement_systems">
062 * @since 0.2
063 */
064public final class Imperial extends AbstractSystemOfUnits {
065    /**
066     * Holds the avoirdupois pound: 0.45359237 kg exact
067     */
068    static final int AVOIRDUPOIS_POUND_DIVIDEND = 45359237;
069
070    static final int AVOIRDUPOIS_POUND_DIVISOR = 100000000;
071    
072    /**
073     * Holds the standard gravity constant: 9.80665 m/s² exact.
074     */
075    private static final int STANDARD_GRAVITY_DIVIDEND = 980665;
076
077    private static final int STANDARD_GRAVITY_DIVISOR = 100000;
078
079    /**
080     * Default constructor (prevents this class from being instantiated).
081     */
082    private Imperial() {
083    }
084
085    /**
086     * Returns the unique instance of this class.
087     * 
088     * @return the Imperial instance.
089     */
090    public static SystemOfUnits getInstance() {
091        return INSTANCE;
092    }
093
094    private static final Imperial INSTANCE = new Imperial();
095
096    ////////////
097    // Length //
098    ////////////
099
100    /**
101     * A unit of length equal to <code>0.0254 m</code> (standard name
102     * <code>in</code>).
103     */
104    public static final Unit<Length> INCH = addUnit(USCustomary.INCH, "Inch", "in");
105
106    //////////
107    // Mass //
108    //////////
109
110    /**
111     * A unit of mass equal to <code>453.59237 grams</code> (avoirdupois pound,
112     * standard name <code>lb</code>).
113     */
114    static final Unit<Mass> POUND = addUnit(
115            KILOGRAM.multiply(AVOIRDUPOIS_POUND_DIVIDEND).divide(AVOIRDUPOIS_POUND_DIVISOR), "Pound", "lb", true);
116    /**
117     * An English and imperial unit of weight or mass now equal to 14
118     * avoirdupois pounds or 6.35029318 kg (<code>st</code>).
119     */
120    public static final Unit<Mass> STONE = addUnit(KILOGRAM.multiply(6.35029318), "st", true);
121
122    /**
123     * A unit of mass equal to <code>1 / 16 {@link #POUND}</code> (standard name
124     * <code>oz</code>).
125     */
126    public static final Unit<Mass> OUNCE = addUnit(POUND.divide(16), "oz");
127
128    /**
129     * A unit of mass equal to <code>2240 {@link #POUND}</code> (long ton,
130     * standard name <code>ton_uk</code>).
131     */
132    public static final Unit<Mass> TON_UK = addUnit(POUND.multiply(2240), "ton_uk");
133
134    /**
135     * A unit of mass equal to <code>1000 kg</code> (metric ton, standard name
136     * <code>t</code>).
137     */
138    public static final Unit<Mass> METRIC_TON = addUnit(KILOGRAM.multiply(1000), "t");
139
140    /////////////////
141    // Temperature //
142    /////////////////
143
144    /**
145     * A unit of temperature equal to <code>5/9 °K</code> (standard name
146     * <code>°R</code>).
147     */
148    static final Unit<Temperature> RANKINE = addUnit(KELVIN.multiply(5).divide(9), "°R", true);
149
150    /**
151     * A unit of temperature equal to degree Rankine minus
152     * <code>459.67 °R</code> (standard name <code>°F</code>).
153     * 
154     * @see #RANKINE
155     */
156    static final Unit<Temperature> FAHRENHEIT = addUnit(RANKINE.shift(459.67), "°F", true);
157
158    //////////////
159    // Time //
160    //////////////
161    /**
162     * A unit of time equal to <code>60 s</code> (standard name <code>min</code>
163     * ).
164     */
165    static final Unit<Time> MINUTE = addUnit(SECOND.multiply(60));
166
167    /**
168     * A unit of duration equal to <code>60 {@link #MINUTE}</code> (standard
169     * name <code>h</code>).
170     */
171    static final Unit<Time> HOUR = addUnit(MINUTE.multiply(60));
172    
173    // ////////////////
174    // Acceleration //
175    // ////////////////
176    /**
177     * A unit of acceleration equal to the gravity at the earth's surface
178     * (standard name <code>grav</code>).
179     */
180    static final Unit<Acceleration> G = addUnit(
181            METRE_PER_SQUARE_SECOND.multiply(STANDARD_GRAVITY_DIVIDEND).divide(STANDARD_GRAVITY_DIVISOR));
182
183    //////////
184    // Area //
185    //////////
186
187    /**
188     * A unit of area (standard name <code>sft</code> ).
189     */
190    public static final Unit<Area> SQUARE_FOOT = addUnit(USCustomary.SQUARE_FOOT, "sft", true);
191
192    /**
193     * One acre is 43,560 <code>square feet</code> (standard name <code>a</code>
194     * ).
195     */
196    public static final Unit<Area> ACRE = addUnit(USCustomary.SQUARE_FOOT.multiply(43560), "Acre", "ac", true);
197
198    ////////////
199    // Volume //
200    ////////////
201    /**
202     * A unit of volume equal to one cubic decimeter (default label
203     * <code>L</code>, also recognized <code>µL, mL, cL, dL</code>).
204     */
205    static final Unit<Volume> LITRE = addUnit(CUBIC_METRE.divide(1000), "L", true);
206
207    /**
208     * A unit of volume equal to one cubic inch (<code>in³</code>).
209     */
210    static final Unit<Volume> CUBIC_INCH = addUnit(new ProductUnit<Volume>(USCustomary.INCH.pow(3)), "Cubic Inch",
211            "in³");
212
213    /**
214     * A unit of volume equal to <code>4.546 09 {@link #LITRE}</code> (standard
215     * name <code>gal_uk</code>).
216     */
217    public static final Unit<Volume> GALLON_UK = addUnit(LITRE.multiply(454609).divide(100000), "gal_uk");
218
219    /**
220     * A unit of volume equal to one UK gallon, Liquid Unit.
221     */
222    // public static final Unit<Volume> GALLON_LIQUID =
223    // addUnit(CUBIC_INCH.multiply(277.42));
224
225    /**
226     * A unit of volume equal to <code>1 / 160 {@link #GALLON_UK}</code>
227     * (standard name <code>oz_fl_uk</code>).
228     */
229    static final Unit<Volume> OUNCE_LIQUID_UK = GALLON_UK.divide(160); // ,
230                                                                       // "oz_fl_uk",
231                                                                       // true);
232
233    /**
234     * A unit of volume equal to <code>1 / 160 {@link #GALLON_LIQUID}</code>
235     * (standard name <code>oz_fl</code>).
236     */
237    public static final Unit<Volume> OUNCE_LIQUID = addUnit(OUNCE_LIQUID_UK, "oz_fl", true);
238    // TODO possible ambiguity if US and Imperial
239    // are registered (try parse)
240
241    /**
242     * A unit of volume equal to <code>5 {@link #OUNCE_LIQUID}</code> (standard
243     * name <code>gi</code>).
244     */
245    public static final Unit<Volume> GILL = addUnit(OUNCE_LIQUID.multiply(5), "Gill", "gi");
246
247    /**
248     * A unit of volume equal to <code>20 {@link #OUNCE_LIQUID}</code> (standard
249     * name <code>pt</code>).
250     */
251    public static final Unit<Volume> PINT = addUnit(OUNCE_LIQUID.multiply(20), "Pint", "pt", true);
252
253    /**
254     * A unit of volume equal to <code>40 {@link #OUNCE_LIQUID}</code> (standard
255     * name <code>qt</code>).
256     */
257    public static final Unit<Volume> QUART = addUnit(OUNCE_LIQUID.multiply(40), "Quart", "qt");
258
259    /**
260     * A unit of volume <code>~ 1 drop or 0.95 grain of water </code> (standard
261     * name <code>min</code>).
262     */
263    public static final Unit<Volume> MINIM = addUnit(MICRO(LITRE).multiply(59.1938802d), "Minim", "min_br");
264
265    /**
266     * A unit of volume equal to <code>20 {@link #MINIM}</code> (standard name
267     * <code>fl scr</code>).
268     */
269    public static final Unit<Volume> FLUID_SCRUPLE = addUnit(MINIM.multiply(60), "fl scr", true);
270
271    /**
272     * A unit of volume equal to <code>3 {@link #FLUID_SCRUPLE}</code> (standard
273     * name <code>fl drc</code>).
274     */
275    public static final Unit<Volume> FLUID_DRACHM = addUnit(FLUID_SCRUPLE.multiply(3), "fl drc", true);
276    
277    /**
278     * A unit of force equal to <code>{@link #POUND}·{@link #G}</code>
279     * (standard name <code>lbf</code>).
280     */
281    static final Unit<Force> POUND_FORCE = addUnit(
282            NEWTON.multiply(1L * AVOIRDUPOIS_POUND_DIVIDEND * STANDARD_GRAVITY_DIVIDEND)
283                    .divide(1L * AVOIRDUPOIS_POUND_DIVISOR * STANDARD_GRAVITY_DIVISOR));
284    /**
285     * A unit of force equal to <code>9.80665 N</code> (standard name
286     * <code>kgf</code>).
287     */
288    static final Unit<Force> KILOGRAM_FORCE = addUnit(
289            NEWTON.multiply(STANDARD_GRAVITY_DIVIDEND).divide(STANDARD_GRAVITY_DIVISOR));
290
291
292    /**
293     * Adds a new unit not mapped to any specified quantity type.
294     *
295     * @param unit
296     *            the unit being added.
297     * @return <code>unit</code>.
298     */
299    private static <U extends Unit<?>> U addUnit(U unit) {
300        INSTANCE.units.add(unit);
301        return unit;
302    }
303
304    /**
305     * Adds a new unit not mapped to any specified quantity type and puts a text
306     * as symbol or label.
307     *
308     * @param unit
309     *            the unit being added.
310     * @param name
311     *            the string to use as name
312     * @param text
313     *            the string to use as label or symbol
314     * @param isLabel
315     *            if the string should be used as a label or not
316     * @return <code>unit</code>.
317     */
318    private static <U extends Unit<?>> U addUnit(U unit, String name, String text, boolean isLabel) {
319        if (isLabel) {
320            SimpleUnitFormat.getInstance().label(unit, text);
321        }
322        if (name != null && unit instanceof AbstractUnit) {
323            return Helper.addUnit(INSTANCE.units, unit, name);
324        } else {
325            INSTANCE.units.add(unit);
326        }
327        return unit;
328    }
329
330    /**
331     * Adds a new unit not mapped to any specified quantity type and puts a text
332     * as symbol or label.
333     *
334     * @param unit
335     *            the unit being added.
336     * @param name
337     *            the string to use as name
338     * @param label
339     *            the string to use as label
340     * @return <code>unit</code>.
341     */
342    private static <U extends Unit<?>> U addUnit(U unit, String name, String label) {
343        return addUnit(unit, name, label, true);
344    }
345
346    /**
347     * Adds a new unit not mapped to any specified quantity type and puts a text
348     * as symbol or label.
349     *
350     * @param unit
351     *            the unit being added.
352     * @param text
353     *            the string to use as label or symbol
354     * @param isLabel
355     *            if the string should be used as a label or not
356     * @return <code>unit</code>.
357     */
358    private static <U extends Unit<?>> U addUnit(U unit, String text, boolean isLabel) {
359        return addUnit(unit, null, text, isLabel);
360    }
361
362    /**
363     * Adds a new unit not mapped to any specified quantity type and puts a text
364     * as label.
365     *
366     * @param unit
367     *            the unit being added.
368     * @param text
369     *            the string to use as label or symbol
370     * @return <code>unit</code>.
371     */
372    private static <U extends Unit<?>> U addUnit(U unit, String text) {
373        return addUnit(unit, null, text, true);
374    }
375
376    // //////////////////////////////////////////////////////////////////////////
377    // Label adjustments for Imperial system
378    static {
379        SimpleUnitFormat.getInstance().label(FLUID_DRACHM, "fl drc");
380        SimpleUnitFormat.getInstance().label(FLUID_SCRUPLE, "fl scr");
381    }
382
383    // ///////////////////
384    // Collection View //
385    // ///////////////////
386
387    @Override
388    public String getName() {
389        return getClass().getSimpleName();
390    }
391}