/**
* The steradian module can itself be used as a default instance of the [Steradian]{@link Steradian} type,
* or as a constructor of new instances of Steradian objects.
*
* Use the module as default instance if you want a single, global instance of Steradian that comes
* pre-loaded with the Units from the SI and Imperial Systems.
*
* Use the module as a constructor if you want one or more Steradian instances that do not come
* preloaded with any Units.
*
* @module steradian
* @see Steradian
*/
define(
[
'Guard', 'Test',
'Quantity','UnitRegistry',
'model/systems/StandardSystems',
'Convert'
],
function(
Guard, Test,
Quantity,UnitRegistry,
StandardSystems,
Convert) {
/**
* Creates an empty instance of Steradian.
*
* Use an instance of Steradian to construct new [Quantities]{@link Quantity}, [Units]{@link Unit},
* and [Systems]{@link System}, and perform conversions between them.
* @class
* @alias Steradian
* @example
* // this instance comes pre-loaded with SI and Imperial.
* const Sr = require('steradian');
* @example
* // the main module is also a function.
* const Steradian = require('steradian');
* // constructed instances are empty and fully customizable.
* const Sr = Steradian();
*/
function Steradian() {
var registry = new UnitRegistry();
/**
* A definition of a BaseUnit.
* @typedef {Object} BaseUnitDefinition
* @property {string} name - Full name of the Unit you are creating. This is the name that will be used to retrieve the Unit.
* @property {string} type - String corresponding to the type of unit being created. Valid names can be found in the UnitType enumeration.
* @property {string} symbol - The symbol that will be used for the Unit in string representations of Quantities and UnitExpressions.
* @property {number} scale - The "scale" of the Unit, which represents its size relative to a default Unit of the same type, which should have the scale of 1.0.
* The correct question to ask when picking a scale is "how many of these units fit *inside* the default unit?"
* Example: 'meter' is the default unit of measure. How many feet fit inside a meter? About 3.28084.
* So the scale of 'foot' should be 3.28084.
* Larger-than-default units will have scales less than 1.0.
* Example: 'second' is the default unit of time. How many minutes fit inside a second? 1/60th of one minute.
* So the scale of 'minute' should be 1/60, or 0.01666.
*/
/**
* A definition of a DerivedUnit.
* @typedef {Object} DerivedUnitDefinition
* @property {string} name - Full name of the Unit you are creating. This is the name that will be used to retrieve the Unit.
* @property {array} units - units
* @property {string} symbol - The symbol that will be used for the Unit in string representations of Quantities and UnitExpressions.
* @property {number} scale - The "scale" of the Unit, which represents its size relative to a default Unit of the same type, which should have the scale of 1.0.
* The correct question to ask when picking a scale is "how many of these units fit *inside* the default unit?"
* Example: 'meter' is the default unit of measure. How many feet fit inside a meter? About 3.28084.
* So the scale of 'foot' should be 3.28084.
* Larger-than-default units will have scales less than 1.0.
* Example: 'second' is the default unit of time. How many minutes fit inside a second? 1/60th of one minute.
* So the scale of 'minute' should be 1/60, or 0.01666.
*/
/**
* A definition of a System
* @typedef {Object} SystemDefinition
* @property {string} name - name of the System.
* @property {Object} base - an object containing all "standard" BaseUnits in the System.
* @property {Object} derived - an object containing all "standard" DerivedUnits of in the System.
* @property {array} other - an array containing all other (non-standard) units in the System.
*/
var SrInstance =
/** @lends Steradian# */
{
/**
* Gets a [Unit]{@link Unit} (either [BaseUnit]{@link BaseUnit} or [DerivedUnit]{@link DerivedUnit}) by the specified name, or creates a new BaseUnit
* according to the given [BaseUnitDefinition]{@link BaseUnitDefinition}.
* @param {string|BaseUnitDefinition} idOrDef - String representing the id of the Unit to retrieve, or Object containing definition of a new Unit.
* @method
* @type {Unit}
*/
unit: function(idOrDef) {
// getter
if (Test.isString(idOrDef)) {
var id = idOrDef;
return registry.get(id);
}
// setter
else {
return registry.register(idOrDef);
}
},
/**
* Gets a [System]{@link System} by the specified name, or creates a new [System]{@link System}
* according to the given [SystemDefinition]{@link SystemDefinition}.
* @method
* @param {string|SystemDefinition|System} idOrDefOrSystem
* @type {System}
*/
system: function(idOrDefOrSystem) {
// getter
if (Test.isString(idOrDefOrSystem)) {
var id = idOrDefOrSystem;
return registry.getSystem(id);
}
// setter
else {
var defOrSystem = idOrDefOrSystem;
return registry.registerSystem(defOrSystem);
}
},
/**
* Creates a new [DerivedUnit]{@link DerivedUnit} from the given [DerivedUnitDefinition]{@link DerivedUnitDefinition}.
* @method
* @param {DerivedUnitDefinition} def
* @type {DerivedUnit}
*/
derivedUnit: function (def) {
return registry.register(def);
},
/**
* Constructs a [Quantity]{@link Quantity} from the given unitExpression and value.
* @method
* @param {string|Unit|UnitExpression} unitExpression - A Unit name, [Unit]{@link Unit} instance or [UnitExpression]{@link UnitExpression} from which to construct a [Quantity]{@link Quantity}.
* @param {number} value - the numeric value associated with the Quantity.
* @type {Quantity}
*/
quantity: function (unitExpression, value) {
unitExpression = Convert.toUnitExpression(unitExpression, registry);
if (!SrInstance) {
throw new Error("SrInstance was not an object");
}
var q = new Quantity(unitExpression, value, SrInstance);
return q;
},
/**
* Converts the given quantity to the target [Units]{@link Unit} or [System]{@link System}.
* If targetUnitsOrSystem is a string, then it must correspond to
* a defined [Unit]{@link Unit} or [System]{@link System}.
* @method
* @param {Quantity} quantity
* @param {string|Unit|UnitExpression|System} targetUnitsOrSystem
* @type {Quantity}
*/
convert: function(q, targetUnitsOrSystem) {
var protoQuantity = Convert.quantity(q, targetUnitsOrSystem, registry);
return SrInstance.quantity(protoQuantity.units, protoQuantity.value);
}
};
return SrInstance;
}
function copyProperties(src, dest) {
for(var key in src) {
if (src.hasOwnProperty(key)) {
dest[key] = src[key];
}
}
}
// Decorate the Steradian function (the result of this module def)
// with the members of a Steradian object. This gives
// the Steradian module the nice property of being both a
// Steradian function (so you CAN manufacture your own Steradian object)
// and a Steradian object (so you don't HAVE to manufacture your own
// Steradian object).
var Sr = Steradian();
copyProperties(Sr, Steradian);
StandardSystems.systems().forEach(function(system) {
Sr.system(system);
});
return Steradian;
}
);