UNPKG

@geonet/geohash

Version:
197 lines (176 loc) 4.59 kB
/** **************************************************************************************************** * File: utils.js * Project: geohash * @author Nick Soggin <iSkore@users.noreply.github.com> on 19-Feb-2019 *******************************************************************************************************/ 'use strict'; const { ENCODE_AUTO, MIN_LNG, MIN_LAT, MAX_LNG, MAX_LAT } = require( './variables' ); /** * isNumber * @description * determine if value is a valid number * @param {number} n - value * @return {boolean} - true if value is a number */ function isNumber( n ) { return n === n && n === +n; } /** * clamp * @description * basic number clamp * @param {number} n - number to clamp * @param {number} min - minimum value * @param {number} max - maximum value * @return {number|*} - clamped value */ function clamp( n, min, max ) { return Math.min( Math.max( min, n ), max ); } /** * longitudeClamp * @description * Determines if longitude is in the realm of possibility * If it's not, clamp the longitude value to the MIN/MAX * @param {number} lng - longitude * @returns {number} - longitude */ function longitudeClamp( lng ) { if ( !isNumber( lng ) ) { throw new Error( 'number required for `lng`' ); } return clamp( lng, MIN_LNG, MAX_LNG ); } /** * latitudeClamp * @description * Determines if latitude is in the realm of possibility * If it's not, clamp the latitude value to the MIN/MAX * @param {number} lat - latitude * @returns {number} - latitude */ function latitudeClamp( lat ) { if ( !isNumber( lat ) ) { throw new Error( 'number required for `lat`' ); } return clamp( lat, MIN_LAT, MAX_LAT ); } /** * clampRelative * @description * basic relative value clamp * @param {number} n - number to clamp * @param {number} min - minimum value * @param {number} max - maximum value * @return {number|*} - clamped value or offset */ function clampRelative( n, min, max ) { return isNumber( n ) ? n > max ? min + n % max : n < min ? max + n % max : n : n; } /** * longitudeClampRelative * @description * Determines if longitude is in the realm of possibility * If it's not, return the longitude position relative to the amount offset * @param {number} lng - longitude * @returns {number} - longitude */ function longitudeClampRelative( lng ) { if ( !isNumber( lng ) ) { throw new Error( 'number required for `lng`' ); } return clampRelative( lng, MIN_LNG, MAX_LNG ); } /** * latitudeClampRelative * @description * Determines if latitude is in the realm of possibility * If it's not, return the latitude position relative to the amount offset * @param {number} lat - latitude * @returns {number} - latitude */ function latitudeClampRelative( lat ) { if ( !isNumber( lat ) ) { throw new Error( 'number required for `lat`' ); } return clampRelative( lat, MIN_LAT, MAX_LAT ); } /** * determinePrecision * @description * Estimate what precision to use based on the input longitude/latitude * * @param {number} lng - longitude * @param {number} lat - latitude * @param {number?} [precision=ENCODE_AUTO] - precision override * @returns {number} - precision estimate */ function determinePrecision( lng, lat, precision = ENCODE_AUTO ) { if ( !isNumber( precision ) ) { throw new Error( 'number required for `precision`' ); } if ( precision === ENCODE_AUTO ) { if ( !isNumber( lng ) ) { throw new Error( 'number required for `lng`' ); } else if ( !isNumber( lat ) ) { throw new Error( 'number required for `lat`' ); } lng = longitudeClampRelative( lng ); lat = latitudeClampRelative( lat ); if ( ~~lat === lat && ~~lng === lng ) { precision = 0; } else { const latLen = +( lat.toString( 10 ).length ), lngLen = +( lng.toString( 10 ).length ), average = ( latLen + lngLen ) / 2; precision = average >= 12 ? 12 : average; } } return ~~precision; } function determineDirection( [ x, y ] ) { if ( !isNumber( x ) ) { throw new Error( 'number required for `x`' ); } else if ( !isNumber( y ) ) { throw new Error( 'number required for `y`' ); } else if ( x === 0 && y === 0 ) { return 'c'; } else if ( !( x ^ y ) ) { return ( x & y ) === 1 ? 'ne' : 'sw'; } else if ( !!( x & y ) ) { return x === 1 ? 'se' : 'nw'; } else if ( ( x | y ) > 0 ) { return !!x ? 'e' : 'n'; } else { return !!x ? 'w' : 's'; } } module.exports = { isNumber, clampRelative, longitudeClamp, latitudeClamp, longitudeClampRelative, latitudeClampRelative, determinePrecision, determineDirection };