Source: encode.js

  1. /** ****************************************************************************************************
  2. * File: encode.js
  3. * Project: geohash
  4. * @author Nick Soggin <iSkore@users.noreply.github.com> on 19-Feb-2019
  5. *******************************************************************************************************/
  6. 'use strict';
  7. const
  8. {
  9. BASE32,
  10. ENCODE_AUTO,
  11. MIN_LNG,
  12. MIN_LAT,
  13. MAX_LNG,
  14. MAX_LAT
  15. } = require( './variables' );
  16. const
  17. {
  18. determinePrecision,
  19. isNumber
  20. } = require( './utils' );
  21. /**
  22. * encode
  23. * Encodes latitude/longitude to geohash, either to specified precision or to automatically
  24. * evaluated precision.
  25. *
  26. * @param {number} lng - Longitude in degrees.
  27. * @param {number} lat - Latitude in degrees.
  28. * @param {number} [precision=ENCODE_AUTO] - Number of characters in resulting geohash.
  29. * @returns {string} Geohash of supplied latitude/longitude.
  30. * @throws Invalid geohash.
  31. *
  32. * @example
  33. * const geohash = Geohash.encode(52.205, 0.119, 7); // geohash: 'u120fxw'
  34. */
  35. function encode( lng, lat, precision = ENCODE_AUTO ) {
  36. lng = +lng;
  37. lat = +lat;
  38. precision = +precision;
  39. if ( !isNumber( lng ) ) {
  40. throw new Error( 'Invalid value for `lng`' );
  41. }
  42. else if ( !isNumber( lat ) ) {
  43. throw new Error( 'Invalid value for `lat`' );
  44. }
  45. else if ( !isNumber( precision ) ) {
  46. throw new Error( 'Invalid value for `precision`' );
  47. }
  48. precision = determinePrecision( lng, lat, precision );
  49. let
  50. geohash = '',
  51. hash = 0, // index into BASE32 map
  52. bit = 0, // each char holds 5 bits
  53. evenBit = true,
  54. lngMin = MIN_LNG,
  55. latMin = MIN_LAT,
  56. lngMax = MAX_LNG,
  57. latMax = MAX_LAT,
  58. mid = 0;
  59. while ( geohash.length < precision ) {
  60. if ( evenBit ) {
  61. // bisect E-W longitude
  62. mid = ( lngMin + lngMax ) / 2;
  63. if ( lng >= mid ) {
  64. hash = ( hash << 1 ) + 1;
  65. lngMin = mid;
  66. }
  67. else {
  68. hash = hash << 1;
  69. lngMax = mid;
  70. }
  71. }
  72. else {
  73. // bisect N-S latitude
  74. mid = ( latMin + latMax ) / 2;
  75. if ( lat >= mid ) {
  76. hash = ( hash << 1 ) + 1;
  77. latMin = mid;
  78. }
  79. else {
  80. hash = hash << 1;
  81. latMax = mid;
  82. }
  83. }
  84. evenBit = !evenBit;
  85. if ( ++bit === 5 ) {
  86. // 5 bits gives us a character: append it and start over
  87. geohash += BASE32[ hash ];
  88. bit = 0;
  89. hash = 0;
  90. }
  91. }
  92. return geohash;
  93. }
  94. module.exports = encode;