brassiere
Version:
Compute bra measurements for various regional standards and length units
298 lines (266 loc) • 9.34 kB
JavaScript
(function() {
'use strict';
var Qty = require('js-quantities');
// Code lists
var itCupCodes = ['AA','A','B','C','D','E','F','FF','G','GG'];
var euCupCodes = ['AA','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R'];
var ukCupCodes = ['AA','A','B','C','D','DD','E','F','FF','G','GG','H','HH','J','JJ','K','KK','L','LL','M','MM','N'];
var usCupCodes = ['AA','A','B','C','D','DD','DDD','DDDD','H','I','J','K','L','M','N','O','P','Q','R','S','T','U'];
var itBandCodes = [0, 'I','II','III','IV','V','VI','VII','VIII','IX','X','XI','XII','XIII','XIIII'];
// Object returned by the getSize function
var BraSize = function(band, cup, unit) {
return {
band: band,
cup: cup,
unit: unit,
};
};
// Object used internally to represent a set of measures
var Measures = function(underbust, bust) {
// Parse a measurement value.
// Use metric system if no explicit unit is given
var normalize = function(value) {
if (typeof(value) === 'number') {
return new Qty(String(value) + ' cm');
} else if (typeof(value) === 'string') {
return new Qty(value);
}
};
return {
u: normalize(underbust),
b: normalize(bust),
};
};
// Convert measures to a specific length unit
// Example usage: convertMeasures(m, 'cm')
var convertMeasures = function(measures, unit) {
return {
u: measures.u.to(unit),
b: measures.b.to(unit),
};
};
// Compute bra size with the measures and functions given
var evaluateSize = function(measures, unit, computeBand, computeCup, options) {
options = options || {};
var m = convertMeasures(measures, unit);
var band = computeBand(m, options);
var cup = computeCup(m, band, options);
return new BraSize(band, cup, unit);
};
// Compute band length using a formula common to all standards
var evaluateBand = function(u, k, p, q) {
return k * Math.floor((u + p) / q);
};
// Look up cup name at index computed with given function
var evaluateCup = function(cups, getIndex) {
var cupIndex = Math.round(getIndex());
cupIndex = validateCupIndex(cupIndex, cups);
return cups[cupIndex];
};
// Check if index is in range of cup list given.
// Throw error otherwise
var validateCupIndex = function(cupIndex, cups) {
if (cupIndex < 0) {
throw new RangeError('Cup size too small');
} else if (cupIndex > cups.length - 1) {
throw new RangeError('Cup size too large');
}
return cupIndex;
};
// Compute overall bra size for European standard using the
// euBand and euCup methods
var euSize = function(measures) {
var unit = 'cm';
return evaluateSize(measures, unit, euBand, euCup);
};
// Compute band length for European standard
var euBand = function(m) {
return evaluateBand(m.u.scalar, 5, 5/2, 5);
};
// Compute cup size for European standard
var euCup = function(m) {
var getCupIndex = function() {
var b = m.b.scalar;
var u = m.u.scalar;
return Math.ceil((b - u - 11) / 2);
};
return evaluateCup(euCupCodes, getCupIndex);
};
// Compute overall bra size for French standard
var frSize = function(measures) {
var unit = 'cm';
return evaluateSize(measures, unit, frBand, euCup);
};
// Compute band length for French standard.
// Can be derived from European
var frBand = function(m) {
return euBand(m) + 15;
};
// Compute overall bra size for Italian standard
var itSize = function(measures) {
var unit = 'cm';
return evaluateSize(measures, unit, itBand, itCup);
};
// Compute band length for Italian standard
var itBand = function(m) {
var bandIndex = evaluateBand(m.u.scalar, 1, -57.5, 5);
if (bandIndex < 0) {
throw new RangeError('Underbust girth too small');
} else if (bandIndex > itBandCodes.length - 1) {
throw new RangeError('Underbust girth too large');
}
return itBandCodes[bandIndex];
};
// Compute cup size for Italian standard
var itCup = function(m) {
var getCupIndex = function() {
var b = m.b.scalar;
var u = m.u.scalar;
return Math.ceil((b - u - 12.5) / 2.5);
};
return evaluateCup(itCupCodes, getCupIndex);
};
// Compute band length for UK and US
var imperialBand = function(m) {
return evaluateBand(m.u.scalar, -2, 4, -2);
};
// Compute cup size for UK and US
var imperialCup = function(m, band, cups) {
var getCupIndex = function() {
var diff = m.b.scalar - band;
return diff + 1;
};
return evaluateCup(cups, getCupIndex);
};
// Compute overall bra size for UK standard
var ukSize = function(measures) {
var unit = 'in';
return evaluateSize(measures, unit, imperialBand, ukCup);
};
// Compute cup size for UK standard
var ukCup = function(m, band) {
return imperialCup(m, band, ukCupCodes);
};
// Compute overallbra size for US standard
var usSize = function(measures) {
var unit = 'in';
return evaluateSize(measures, unit, imperialBand, usCup);
};
// Compute cup size for US standard
var usCup = function(m, band) {
return imperialCup(m, band, usCupCodes);
};
// Compute bra size with algorithm used by bra calculator
// on sophisticatedpair.com ("sophisticated" standard)
var sophSize = function(measures, options) {
var preference = options.preference;
if (preference === undefined) {
throw new TypeError('Please include a preference ("tight", "moderate", or "loose") in the options');
}
var p = parseSophPreference(preference);
var unit = 'in';
return evaluateSize(measures, unit, sophBand, sophCup, {preference: p});
};
// Parse preference for "sophisticated" standard
var parseSophPreference = function(preference) {
if (preference === 'tight') {
return 1;
} else if (preference === 'moderate') {
return 2;
} else if (preference === 'loose') {
return 3;
} else {
throw new TypeError('Valid preferences are "tight", "moderate", and "loose".');
}
};
// Compute band length for "sophisticated" standard
var sophBand = function(m, options) {
var u = Math.round(m.u.scalar);
var uOdd = u % 2;
var d;
switch(options.preference) {
case 1:
if (uOdd) {
d = -1;
} else {
d = 0;
}
break;
case 2:
if (uOdd) {
d = 1;
} else {
d = 0;
}
break;
case 3:
if (uOdd) {
d = 3;
} else {
d = 2;
}
break;
default:
d = 0;
}
return u + d;
};
// Compute band length for "sophisticated" standard
var sophCup = function(m, band, options) {
var getIndex = function() {
var u = Math.round(m.u.scalar);
var b = Math.round(m.b.scalar);
var uOdd = u % 2;
var d;
switch(options.preference) {
case 1:
d = -band;
break;
case 2:
if (uOdd) {
d = -u;
} else {
d = -band;
}
break;
case 3:
if (uOdd) {
d = -band + 2;
} else {
d = -band + 1;
}
break;
default:
d = 0;
}
var index = b + d;
return index;
};
return evaluateCup(ukCupCodes, getIndex);
};
// Public method computing bra size for given standard
// and measurements
//
// Example usage:
// bra.getSize('eu', '70 cm', '85 cm');
// returns { band: 70, cup: 'B', unit: 'cm' }
var getSize = function(standard, underbust, bust, options) {
var standards = {
'eu': euSize,
'fr': frSize,
'it': itSize,
'uk': ukSize,
'us': usSize,
'sophisticated': sophSize,
};
if (standards[standard] === undefined) {
throw new TypeError('Standard "' + standard + '" is not defined');
}
var measures = new Measures(underbust, bust);
var size = standards[standard](measures, options);
return size;
};
module.exports = {
getSize: getSize,
};
})();