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