1 /*
  2  * TemperatureUnit.js - Unit conversions for temperature measurements
  3  *
  4  * Copyright © 2014-2015, 2018 JEDLSoft
  5  *
  6  * Licensed under the Apache License, Version 2.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at
  9  *
 10  *     http://www.apache.org/licenses/LICENSE-2.0
 11  *
 12  * Unless required by applicable law or agreed to in writing, software
 13  * distributed under the License is distributed on an "AS IS" BASIS,
 14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  *
 16  * See the License for the specific language governing permissions and
 17  * limitations under the License.
 18  */
 19 
 20 /*
 21 !depends
 22 Measurement.js
 23 */
 24 
 25 var Measurement = require("./Measurement.js");
 26 
 27 /**
 28  * @class
 29  * Create a new Temperature measurement instance.
 30  *
 31  * @constructor
 32  * @extends Measurement
 33  * @param options {{unit:string,amount:number|string|undefined}} Options controlling
 34  * the construction of this instance
 35  */
 36 var TemperatureUnit = function (options) {
 37     this.unit = "celsius";
 38     this.amount = 0;
 39 
 40     this.ratios = TemperatureUnit.ratios;
 41     this.aliases = TemperatureUnit.aliases;
 42     this.aliasesLower = TemperatureUnit.aliasesLower;
 43     this.systems = TemperatureUnit.systems;
 44 
 45     this.parent.call(this, options);
 46 };
 47 
 48 TemperatureUnit.prototype = new Measurement();
 49 TemperatureUnit.prototype.parent = Measurement;
 50 TemperatureUnit.prototype.constructor = TemperatureUnit;
 51 
 52 TemperatureUnit.ratios = {
 53     /*            index, C            K            F   */
 54     "celsius":    [ 1,   1,           1,           9/5 ],
 55     "kelvin":     [ 2,   1,           1,           9/5 ],
 56     "fahrenheit": [ 3,   5/9,         5/9,         1   ]
 57 };
 58 
 59 /**
 60  * Return the type of this measurement. Examples are "mass",
 61  * "length", "speed", etc. Measurements can only be converted
 62  * to measurements of the same type.<p>
 63  *
 64  * The type of the units is determined automatically from the
 65  * units. For example, the unit "grams" is type "mass". Use the
 66  * static call {@link Measurement.getAvailableUnits}
 67  * to find out what units this version of ilib supports.
 68  *
 69  * @return {string} the name of the type of this measurement
 70  */
 71 TemperatureUnit.prototype.getMeasure = function() {
 72     return "temperature";
 73 };
 74 
 75 /**
 76  * Return a new instance of this type of measurement.
 77  *
 78  * @param {Object} params parameters to the constructor
 79  * @return {Measurement} a measurement subclass instance
 80  */
 81 TemperatureUnit.prototype.newUnit = function(params) {
 82     return new TemperatureUnit(params);
 83 };
 84 
 85 TemperatureUnit.systems = {
 86     "metric": [
 87         "celsius",
 88         "kelvin"
 89     ],
 90     "uscustomary": [
 91         "fahrenheit"
 92     ],
 93     "imperial": [
 94         "fahrenheit"
 95     ],
 96     "conversions": {
 97         "metric": {
 98             "uscustomary": {
 99                 "celsius": "fahrenheit",
100                 "kelvin": "fahrenheit"
101             },
102             "imperial": {
103                 "celsius": "fahrenheit",
104                 "kelvin": "fahrenheit"
105             }
106         },
107         "uscustomary": {
108             "metric": {
109                 "fahrenheit": "celsius"
110             }
111         },
112         "imperial": {
113             "metric": {
114                 "fahrenheit": "celsius"
115             }
116         }
117     }
118 };
119 
120 TemperatureUnit.aliases = {
121     "Celsius": "celsius",
122     "C": "celsius",
123     "Centegrade": "celsius",
124     "Centigrade": "celsius",
125     "Fahrenheit": "fahrenheit",
126     "F": "fahrenheit",
127     "K": "kelvin",
128     "Kelvin": "kelvin",
129     "°F": "fahrenheit",
130     "℉": "fahrenheit",
131     "℃": "celsius",
132     "°C": "celsius"
133 };
134 
135 (function() {
136     TemperatureUnit.aliasesLower = {};
137     for (var a in TemperatureUnit.aliases) {
138         TemperatureUnit.aliasesLower[a.toLowerCase()] = TemperatureUnit.aliases[a];
139     }
140 })();
141 
142 /**
143  * Return a new measurement instance that is converted to a new
144  * measurement unit. Measurements can only be converted
145  * to measurements of the same type.<p>
146  *
147  * @param {string} to The name of the units to convert to
148  * @return {number|undefined} the converted measurement
149  * or undefined if the requested units are for a different
150  * measurement type
151  */
152 TemperatureUnit.prototype.convert = function(to) {
153     if (!to || typeof(TemperatureUnit.ratios[this.normalizeUnits(to)]) === 'undefined') {
154         return undefined;
155     }
156     return TemperatureUnit.convert(to, this.unit, this.amount);
157 };
158 
159 /**
160  * Convert a temperature to another measure.
161  * @static
162  * @param to {string} unit to convert to
163  * @param from {string} unit to convert from
164  * @param temperature {number} amount to be convert
165  * @returns {number|undefined} the converted amount
166  */
167 TemperatureUnit.convert = function(to, from, temperature) {
168     var result = 0;
169     from = Measurement.getUnitIdCaseInsensitive(TemperatureUnit, from) || from;
170     to = Measurement.getUnitIdCaseInsensitive(TemperatureUnit, to) || to;
171     if (from === to) {
172         return temperature;
173     } else if (from === "celsius") {
174         if (to === "fahrenheit") {
175             result = ((temperature * 9 / 5) + 32);
176         } else if (to === "kelvin") {
177             result = (temperature + 273.15);
178         }
179     } else if (from === "fahrenheit") {
180         if (to === "celsius") {
181             result = ((5 / 9 * (temperature - 32)));
182         } else if (to === "kelvin") {
183             result = ((temperature + 459.67) * 5 / 9);
184         }
185     } else if (from === "kelvin") {
186         if (to === "celsius") {
187             result = (temperature - 273.15);
188         } else if (to === "fahrenheit") {
189             result = ((temperature * 9 / 5) - 459.67);
190         }
191     }
192 
193     return result;
194 };
195 
196 /**
197  * Scale the measurement unit to an acceptable level. The scaling
198  * happens so that the integer part of the amount is as small as
199  * possible without being below zero. This will result in the
200  * largest units that can represent this measurement without
201  * fractions. Measurements can only be scaled to other measurements
202  * of the same type.
203  *
204  * @param {string=} measurementsystem system to use (uscustomary|imperial|metric),
205  * or undefined if the system can be inferred from the current measure
206  * @return {Measurement} a new instance that is scaled to the
207  * right level
208  */
209 TemperatureUnit.prototype.scale = function(measurementsystem) {
210     // no scaling for temp units
211     return this;
212  };
213 
214 /**
215  * @private
216  * @static
217  */
218 TemperatureUnit.getMeasures = function () {
219     return ["celsius", "kelvin", "fahrenheit"];
220 };
221 
222 //register with the factory method
223 Measurement._constructors["temperature"] = TemperatureUnit;
224 
225 module.exports = TemperatureUnit;
226