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