001/*
002 *  SI Units
003 *  Copyright (c) 2005-2016, 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 nor the names of its 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 si.uom;
027
028import javax.measure.Quantity;
029import javax.measure.Unit;
030import javax.measure.quantity.Acceleration;
031import javax.measure.quantity.Angle;
032import javax.measure.quantity.Area;
033import javax.measure.quantity.Energy;
034import javax.measure.quantity.Length;
035import javax.measure.quantity.Mass;
036
037import si.uom.quantity.*;
038import tec.units.ri.AbstractSystemOfUnits;
039import tec.units.ri.AbstractUnit;
040import tec.units.ri.format.SimpleUnitFormat;
041import tec.units.ri.function.MultiplyConverter;
042import tec.units.ri.function.PiMultiplierConverter;
043import tec.units.ri.function.RationalConverter;
044import tec.units.ri.unit.AlternateUnit;
045import tec.units.ri.unit.ProductUnit;
046import tec.units.ri.unit.TransformedUnit;
047import tec.units.ri.unit.Units;
048
049/**
050 * <p>
051 * This class defines all SI (Système International d'Unités) base units and
052 * derived units as well as units that are accepted for use with the SI units.
053 * </p>
054 *
055 * @see <a href=
056 *      "http://en.wikipedia.org/wiki/International_System_of_Units">Wikipedia:
057 *      International System of Units</a>
058 * @see <a href="http://physics.nist.gov/cuu/Units/outside.html">Units outside
059 *      the SI that are accepted for use with the SI</a>
060 * @see <a href="http://www.bipm.org/utils/common/pdf/si_brochure_8.pdf">SI 2006
061 *      - Official Specification</a>
062 * @see MetricPrefix
063 * 
064 * @noextend This class is not intended to be extended by clients.
065 *
066 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
067 * @author <a href="mailto:werner@uom.si">Werner Keil</a>
068 * @version 1.0.1, October 23, 2016
069 */
070public final class SI extends Units {
071
072    /**
073     * The singleton instance.
074     */
075    private static final SI INSTANCE = new SI();
076
077    /**
078     * Default constructor (prevents this class from being instantiated).
079     */
080    private SI() {
081    }
082
083    /**
084     * Returns the singleton instance of this class.
085     *
086     * @return the metric system instance.
087     */
088    public static SI getInstance() {
089        return INSTANCE;
090    }
091
092    ////////////////////////////////
093    // SI DERIVED ALTERNATE UNITS //
094    ////////////////////////////////
095
096    /**
097     * The SI unit for magnetomotive force (standard name <code>At</code>).
098     */
099    public static final AlternateUnit<MagnetomotiveForce> AMPERE_TURN = addUnit(
100            new AlternateUnit<MagnetomotiveForce>(SI.AMPERE, "At"), MagnetomotiveForce.class);
101
102    //////////////////////////////
103    // SI DERIVED PRODUCT UNITS //
104    //////////////////////////////
105
106    /**
107     * The SI unit for acceleration quantities (standard name
108     * <code>m/s2</code>).
109     */
110    public static final Unit<Acceleration> METRE_PER_SQUARE_SECOND = addUnit(
111            new ProductUnit<Acceleration>(METRE_PER_SECOND.divide(SECOND)), Acceleration.class);
112    /**
113     * Alias for METRE_PER_SQUARE_SECOND.
114     * 
115     * @deprecated use METRE_PER_SQUARE_SECOND instead.
116     */
117    public static final Unit<Acceleration> METRES_PER_SQUARE_SECOND = METRE_PER_SQUARE_SECOND;
118
119    /**
120     * The SI unit for action quantities (standard name <code>j.s</code>).
121     */
122    public static final Unit<Action> JOULE_SECOND = addUnit(new ProductUnit<Action>(JOULE.multiply(SECOND)),
123            Action.class);
124
125    /**
126     * The SI unit for electric permittivity (standard name <code>ε</code>,
127     * <code>F/m </code> or <code>F·m−1</code>). In electromagnetism, absolute
128     * permittivity is the measure of resistance that is encountered when
129     * forming an electric field in a medium.
130     */
131    public static final Unit<ElectricPermittivity> FARAD_PER_METRE = addUnit(
132            new AlternateUnit<ElectricPermittivity>(FARAD.divide(METRE), "ε"), ElectricPermittivity.class);
133
134    /**
135     * The SI unit for magnetic permeability quantities (standard name
136     * <code>N/A2</code>).
137     */
138    public static final Unit<MagneticPermeability> NEWTON_PER_SQUARE_AMPERE = addUnit(
139            new ProductUnit<MagneticPermeability>(NEWTON.divide(AMPERE.pow(2))), MagneticPermeability.class);
140
141    /**
142     * Alias for NEWTON_PER_SQUARE_AMPERE.
143     * 
144     * @deprecated use NEWTON_PER_SQUARE_AMPERE.
145     */
146    public static final Unit<MagneticPermeability> NEWTONS_PER_SQUARE_AMPERE = NEWTON_PER_SQUARE_AMPERE;
147
148    /**
149     * The SI unit for wave number quantities (standard name <code>1/m</code>).
150     */
151    public static final Unit<WaveNumber> RECIPROCAL_METRE = addUnit(new ProductUnit<WaveNumber>(METRE.pow(-1)),
152            WaveNumber.class);
153
154    /**
155     * The SI unit for dynamic viscosity quantities (standard name
156     * <code>Pa.s</code>).
157     */
158    public static final Unit<DynamicViscosity> PASCAL_SECOND = addUnit(
159            new ProductUnit<DynamicViscosity>(PASCAL.multiply(SECOND)), DynamicViscosity.class);
160
161    /**
162     * Luminance is a photometric measure of the luminous intensity per unit
163     * area of light travelling in a given direction. It describes the amount of
164     * light that passes through, is emitted or reflected from a particular
165     * area, and falls within a given solid angle. The SI unit for luminance is
166     * candela per square metre (<code>cd/m2</code>).
167     * 
168     * @see <a href="https://en.wikipedia.org/wiki/Luminance"> Wikipedia:
169     *      Luminance</a>
170     */
171    public static final Unit<Luminance> CANDELA_PER_SQUARE_METRE = addUnit(
172            new ProductUnit<Luminance>(CANDELA.divide(SQUARE_METRE)), Luminance.class);
173
174    /**
175     * The SI unit for kinematic viscosity quantities (standard name
176     * <code>m2/s"</code>).
177     */
178    public static final Unit<KinematicViscosity> SQUARE_METRE_PER_SECOND = addUnit(
179            new ProductUnit<KinematicViscosity>(SQUARE_METRE.divide(SECOND)), KinematicViscosity.class);
180
181    /**
182     * Alias for SQUARE_METRE_PER_SECOND.
183     * 
184     * @deprecated use SQUARE_METRE_PER_SECOND.
185     */
186    public static final Unit<KinematicViscosity> SQUARE_METRES_PER_SECOND = SQUARE_METRE_PER_SECOND;
187
188    /**
189     * The SI unit for magnetic field strength quantities (standard name
190     * <code>A/m"</code>).
191     */
192    public static final Unit<MagneticFieldStrength> AMPERE_PER_METRE = addUnit(
193            new ProductUnit<MagneticFieldStrength>(AMPERE.divide(METRE)), MagneticFieldStrength.class);
194
195    /**
196     * Alias for AMPERE_PER_METRE.
197     * 
198     * @deprecated use AMPERE_PER_METRE.
199     */
200    public static final Unit<MagneticFieldStrength> AMPERES_PER_METRE = AMPERE_PER_METRE;
201
202    /**
203     * The SI unit for ionizing radiation quantities (standard name
204     * <code>C/kg"</code>).
205     */
206    public static final Unit<IonizingRadiation> COULOMB_PER_KILOGRAM = addUnit(
207            new ProductUnit<IonizingRadiation>(COULOMB.divide(KILOGRAM)), IonizingRadiation.class);
208    /**
209     * Alias for COULOMB_PER_KILOGRAM.
210     * 
211     * @deprecated use COULOMB_PER_KILOGRAM.
212     */
213    public static final Unit<IonizingRadiation> COULOMBS_PER_KILOGRAM = COULOMB_PER_KILOGRAM;
214
215    /**
216     * The SI unit for radiant intensity (standard name <code>W/sr</code>).
217     */
218    public static final Unit<RadiantIntensity> WATT_PER_STERADIAN = addUnit(
219            WATT.divide(STERADIAN).asType(RadiantIntensity.class));
220
221    /**
222     * The SI unit for radiance (standard name <code>W⋅sr−1⋅m−2</code>).
223     */
224    public static final Unit<Radiance> WATT_PER_STERADIAN_PER_SQUARE_METRE = addUnit(
225            WATT_PER_STERADIAN.divide(SQUARE_METRE).asType(Radiance.class));
226
227    /////////////////////////////////////////////////////////////////
228    // Units outside the SI that are accepted for use with the SI. //
229    /////////////////////////////////////////////////////////////////
230
231    /**
232     * An angle unit accepted for use with SI units (standard name
233     * <code>deg</code>).
234     * 
235     * @deprecated use NonSI
236     */
237    public static final Unit<Angle> DEGREE_ANGLE = addUnit(
238            new TransformedUnit<Angle>(RADIAN, new PiMultiplierConverter().concatenate(new RationalConverter(1, 180))));
239
240    /**
241     * An angle unit accepted for use with SI units (standard name
242     * <code>'</code>).
243     * 
244     * @deprecated use NonSI
245     */
246    public static final Unit<Angle> MINUTE_ANGLE = addUnit(new TransformedUnit<Angle>(RADIAN,
247            new PiMultiplierConverter().concatenate(new RationalConverter(1, 180 * 60))));
248
249    /**
250     * An angle unit accepted for use with SI units (standard name
251     * <code>''</code>).
252     * 
253     * @deprecated use NonSI
254     */
255    public static final Unit<Angle> SECOND_ANGLE = new TransformedUnit<Angle>(RADIAN,
256            new PiMultiplierConverter().concatenate(new RationalConverter(1, 180 * 60 * 60)));
257
258    /**
259     * A mass unit accepted for use with SI units (standard name
260     * <code>t</code>).
261     * 
262     * @deprecated use NonSI
263     */
264    public static final Unit<Mass> TONNE = AbstractSystemOfUnits.Helper.addUnit(INSTANCE.units,
265            new TransformedUnit<Mass>(KILOGRAM, new RationalConverter(1000, 1)), "Tonne", "t");
266
267    /**
268     * An energy unit accepted for use with SI units (standard name
269     * <code>eV</code>). The electronvolt is the kinetic energy acquired by an
270     * electron passing through a potential difference of 1 V in vacuum. The
271     * value must be obtained by experiment, and is therefore not known exactly.
272     */
273    public static final Unit<Energy> ELECTRON_VOLT = addUnit(
274            new TransformedUnit<Energy>(JOULE, new MultiplyConverter(1.602176487E-19)));
275    // CODATA 2006 - http://physics.nist.gov/cuu/Constants/codata.pdf
276
277    /**
278     * A mass unit accepted for use with SI units (standard name
279     * <code>u</code>). The unified atomic mass unit is equal to 1/12 of the
280     * mass of an unbound atom of the nuclide 12C, at rest and in its ground
281     * state. The value must be obtained by experiment, and is therefore not
282     * known exactly.
283     */
284    public static final Unit<Mass> UNIFIED_ATOMIC_MASS = addUnit(
285            new TransformedUnit<Mass>(KILOGRAM, new MultiplyConverter(1.660538782E-27)), "Unified atomic mass", "u",
286            true);
287    // CODATA 2006 - http://physics.nist.gov/cuu/Constants/codata.pdf
288
289    /**
290     * A length unit accepted for use with SI units (standard name
291     * <code>UA</code>). The astronomical unit is a unit of length. Its value is
292     * such that, when used to describe the motion of bodies in the solar
293     * system, the heliocentric gravitation constant is (0.017 202 098 95)2
294     * ua3·d-2. The value must be obtained by experiment, and is therefore not
295     * known exactly.
296     */
297    public static final Unit<Length> ASTRONOMICAL_UNIT = addUnit(
298            new TransformedUnit<Length>(METRE, new MultiplyConverter(149597871000.0)));
299    // Best estimate source: http://maia.usno.navy.mil/NSFA/CBE.html
300
301    /**
302     * An angle unit accepted for use with SI units (standard name
303     * <code>rev</code>).
304     */
305    public static final Unit<Angle> REVOLUTION = addUnit(
306            new TransformedUnit<Angle>(RADIAN, new PiMultiplierConverter().concatenate(new RationalConverter(2, 1))));
307
308    /**
309     * An angle unit accepted for use with SI units (standard name
310     * <code>ha</code>).
311     */
312    public static final Unit<Area> HECTARE = addUnit(
313            new TransformedUnit<Area>(SQUARE_METRE, new RationalConverter(10000, 1)));
314
315    /////////////////////
316    // Collection View //
317    /////////////////////
318
319    @Override
320    public String getName() {
321        return "SI";
322    }
323
324    /**
325     * Adds a new unit not mapped to any specified quantity type.
326     *
327     * @param unit
328     *            the unit being added.
329     * @return <code>unit</code>.
330     */
331    private static <U extends Unit<?>> U addUnit(U unit) {
332        INSTANCE.units.add(unit);
333        return unit;
334    }
335
336    /**
337     * Adds a new unit not mapped to any specified quantity type and puts a text
338     * as symbol or label.
339     *
340     * @param unit
341     *            the unit being added.
342     * @param name
343     *            the string to use as name
344     * @param text
345     *            the string to use as label or symbol
346     * @param isLabel
347     *            if the string should be used as a label or not
348     * @return <code>unit</code>.
349     */
350    private static <U extends Unit<?>> U addUnit(U unit, String name, String text, boolean isLabel) {
351        if (isLabel) {
352            SimpleUnitFormat.getInstance().label(unit, text);
353        }
354        if (name != null && unit instanceof AbstractUnit) {
355            return Helper.addUnit(INSTANCE.units, unit, name);
356        } else {
357            INSTANCE.units.add(unit);
358        }
359        return unit;
360    }
361
362    /**
363     * Adds a new unit not mapped to any specified quantity type and puts a text
364     * as symbol or label.
365     *
366     * @param unit
367     *            the unit being added.
368     * @param text
369     *            the string to use as label or symbol
370     * @param isLabel
371     *            if the string should be used as a label or not
372     * @return <code>unit</code>.
373     */
374    @SuppressWarnings("unused")
375    private static <U extends Unit<?>> U addUnit(U unit, String text, boolean isLabel) {
376        return addUnit(unit, null, text, isLabel);
377    }
378
379    /**
380     * Adds a new unit not mapped to any specified quantity type and puts a text
381     * as symbol or label.
382     *
383     * @param unit
384     *            the unit being added.
385     * @param name
386     *            the string to use as name
387     * @param label
388     *            the string to use as label
389     * @return <code>unit</code>.
390     */
391    private static <U extends Unit<?>> U addUnit(U unit, String name, String label) {
392        return addUnit(unit, name, label, true);
393    }
394
395    /**
396     * Adds a new unit and maps it to the specified quantity type.
397     *
398     * @param unit
399     *            the unit being added.
400     * @param type
401     *            the quantity type.
402     * @return <code>unit</code>.
403     */
404    private static <U extends AbstractUnit<?>> U addUnit(U unit, Class<? extends Quantity<?>> type) {
405        INSTANCE.units.add(unit);
406        INSTANCE.quantityToUnit.put(type, unit);
407        return unit;
408    }
409}