| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="utf-8">
- <title>JSDoc: Source: geocoder.js</title>
- <script src="scripts/prettify/prettify.js"> </script>
- <script src="scripts/prettify/lang-css.js"> </script>
- <!--[if lt IE 9]>
- <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
- <![endif]-->
- <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
- <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
- </head>
- <body>
- <div id="main">
- <h1 class="page-title">Source: geocoder.js</h1>
-
-
- <section>
- <article>
- <pre class="prettyprint source linenums"><code>/**
- * @fileoverview Local reverse geocoder based on GeoNames data.
- * @author Thomas Steiner (tomac@google.com)
- * @license Apache 2.0
- *
- * @param {(object|object[])} points One single or an array of
- * latitude/longitude pairs
- * @param {integer} maxResults The maximum number of results to return
- * @callback callback The callback function with the results
- *
- * @returns {object[]} An array of GeoNames-based geocode results
- *
- * @example
- * // With just one point
- * var point = {latitude: 42.083333, longitude: 3.1};
- * geocoder.lookUp(point, 1, function(err, res) {
- * console.log(JSON.stringify(res, null, 2));
- * });
- *
- * // In batch mode with many points
- * var points = [
- * {latitude: 42.083333, longitude: 3.1},
- * {latitude: 48.466667, longitude: 9.133333}
- * ];
- * geocoder.lookUp(points, 1, function(err, res) {
- * console.log(JSON.stringify(res, null, 2));
- * });
- */
- 'use strict';
- var debug = require('debug')('local-reverse-geocoder');
- var fs = require('fs');
- var path = require('path');
- var parse = require('csv-parse');
- var kdTree = require('kdt');
- var request = require('request');
- var unzip = require('node-unzip-2');
- var async = require('async');
- var readline = require('readline');
- // All data from http://download.geonames.org/export/dump/
- var GEONAMES_URL = 'http://download.geonames.org/export/dump/';
- var CITIES_FILE = 'cities1000';
- var ADMIN_1_CODES_FILE = 'admin1CodesASCII';
- var ADMIN_2_CODES_FILE = 'admin2Codes';
- var ALL_COUNTRIES_FILE = 'allCountries';
- var ALTERNATE_NAMES_FILE = 'alternateNames';
- /* jshint maxlen: false */
- var GEONAMES_COLUMNS = [
- 'geoNameId', // integer id of record in geonames database
- 'name', // name of geographical point (utf8) varchar(200)
- 'asciiName', // name of geographical point in plain ascii characters, varchar(200)
- 'alternateNames', // alternatenames, comma separated, ascii names automatically transliterated, convenience attribute from alternatename table, varchar(10000)
- 'latitude', // latitude in decimal degrees (wgs84)
- 'longitude', // longitude in decimal degrees (wgs84)
- 'featureClass', // see http://www.geonames.org/export/codes.html, char(1)
- 'featureCode', // see http://www.geonames.org/export/codes.html, varchar(10)
- 'countryCode', // ISO-3166 2-letter country code, 2 characters
- 'cc2', // alternate country codes, comma separated, ISO-3166 2-letter country code, 60 characters
- 'admin1Code', // fipscode (subject to change to iso code), see exceptions below, see file admin1Codes.txt for display names of this code; varchar(20)
- 'admin2Code', // code for the second administrative division, a county in the US, see file admin2Codes.txt; varchar(80)
- 'admin3Code', // code for third level administrative division, varchar(20)
- 'admin4Code', // code for fourth level administrative division, varchar(20)
- 'population', // bigint (8 byte int)
- 'elevation', // in meters, integer
- 'dem', // digital elevation model, srtm3 or gtopo30, average elevation 3''x3'' (ca 90mx90m) or 30''x30'' (ca 900mx900m) area in meters, integer. srtm processed by cgiar/ciat.
- 'timezone', // the timezone id (see file timeZone.txt) varchar(40)
- 'modificationDate', // date of last modification in yyyy-MM-dd format
- ];
- /* jshint maxlen: 80 */
- var GEONAMES_ADMIN_CODES_COLUMNS = [
- 'concatenatedCodes',
- 'name',
- 'asciiName',
- 'geoNameId'
- ];
- /* jshint maxlen: false */
- var GEONAMES_ALTERNATE_NAMES_COLUMNS = [
- 'alternateNameId', // the id of this alternate name, int
- 'geoNameId', // geonameId referring to id in table 'geoname', int
- 'isoLanguage', // iso 639 language code 2- or 3-characters; 4-characters 'post' for postal codes and 'iata','icao' and faac for airport codes, fr_1793 for French Revolution name
- 'alternateNames', // alternate name or name variant, varchar(200)
- 'isPreferrredName', // '1', if this alternate name is an official/preferred name
- 'isShortName', // '1', if this is a short name like 'California' for 'State of California'
- 'isColloquial', // '1', if this alternate name is a colloquial or slang term
- 'isHistoric' // '1', if this alternate name is historic and was used in the past
- ];
- /* jshint maxlen: 80 */
- var GEONAMES_DUMP = __dirname + '/geonames_dump';
- var geocoder = {
- _kdTree: null,
- _admin1Codes: null,
- _admin2Codes: null,
- _admin3Codes: null,
- _admin4Codes: null,
- _alternateNames: null,
- // Distance function taken from
- // http://www.movable-type.co.uk/scripts/latlong.html
- _distanceFunc: function distance(x, y) {
- var toRadians = function(num) {
- return num * Math.PI / 180;
- };
- var lat1 = x.latitude;
- var lon1 = x.longitude;
- var lat2 = y.latitude;
- var lon2 = y.longitude;
- var R = 6371; // km
- var φ1 = toRadians(lat1);
- var φ2 = toRadians(lat2);
- var Δφ = toRadians(lat2 - lat1);
- var Δλ = toRadians(lon2 - lon1);
- var a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
- Math.cos(φ1) * Math.cos(φ2) *
- Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
- var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
- return R * c;
- },
- _getGeoNamesAlternateNamesData: function(callback) {
- var now = (new Date()).toISOString().substr(0, 10);
- // Use timestamped alternate names file OR bare alternate names file
- var timestampedFilename = GEONAMES_DUMP + '/alternate_names/' +
- ALTERNATE_NAMES_FILE + '_' + now + '.txt';
- if (fs.existsSync(timestampedFilename)) {
- debug('Using cached GeoNames alternate names data from ' +
- timestampedFilename);
- return callback(null, timestampedFilename);
- }
- var filename = GEONAMES_DUMP + '/alternate_names/' + ALTERNATE_NAMES_FILE +
- '.txt';
- if (fs.existsSync(filename)) {
- debug('Using cached GeoNames alternate names data from ' +
- filename);
- return callback(null, filename);
- }
- debug('Getting GeoNames alternate names data from ' +
- GEONAMES_URL + ALTERNATE_NAMES_FILE + '.zip (this may take a while)');
- var options = {
- url: GEONAMES_URL + ALTERNATE_NAMES_FILE + '.zip',
- encoding: null
- };
- request.get(options, function(err, response, body) {
- if (err || response.statusCode !== 200) {
- return callback('Error downloading GeoNames alternate names data' +
- (err ? ': ' + err : ''));
- }
- debug('Received zipped GeoNames alternate names data');
- // Store a dump locally
- if (!fs.existsSync(GEONAMES_DUMP + '/alternate_names')) {
- fs.mkdirSync(GEONAMES_DUMP + '/alternate_names');
- }
- var zipFilename = GEONAMES_DUMP + '/alternate_names/' +
- ALTERNATE_NAMES_FILE + '_' + now + '.zip';
- try {
- fs.writeFileSync(zipFilename, body);
- fs.createReadStream(zipFilename)
- .pipe(unzip.Extract({path: GEONAMES_DUMP + '/alternate_names'}))
- .on('error', function(e) {
- console.error(e);
- })
- .on('close', function() {
- fs.renameSync(filename, timestampedFilename);
- fs.unlinkSync(GEONAMES_DUMP + '/alternate_names/' +
- ALTERNATE_NAMES_FILE + '_' + now + '.zip');
- debug('Unzipped GeoNames alternate names data');
- // Housekeeping, remove old files
- var currentFileName = path.basename(timestampedFilename);
- fs.readdirSync(GEONAMES_DUMP + '/alternate_names').forEach(
- function(file) {
- if (file !== currentFileName) {
- fs.unlinkSync(GEONAMES_DUMP + '/alternate_names/' + file);
- }
- });
- return callback(null, timestampedFilename);
- });
- } catch (e) {
- debug('Warning: ' + e);
- return callback(null, timestampedFilename);
- }
- });
- },
- _parseGeoNamesAlternateNamesCsv: function(pathToCsv, callback) {
- var that = this;
- that._alternateNames = {};
- var lineReader = readline.createInterface({
- input: fs.createReadStream(pathToCsv)
- });
- lineReader.on('line', function(line) {
- line = line.split('\t');
- const [
- _,
- geoNameId,
- isoLanguage,
- altName,
- isPreferredName,
- isShortName,
- isColloquial,
- isHistoric
- ] = line;
- if (isoLanguage === '') {
- // consider data without country code as invalid
- return;
- }
- if (!that._alternateNames[geoNameId]) {
- that._alternateNames[geoNameId] = {};
- }
- that._alternateNames[geoNameId][isoLanguage] = {
- altName,
- isPreferredName: Boolean(isPreferredName),
- isShortName: Boolean(isShortName),
- isColloquial: Boolean(isColloquial),
- isHistoric: Boolean(isHistoric)
- };
- });
- lineReader.on('close', function() {
- return callback();
- });
- },
- _getGeoNamesAdmin1CodesData: function(callback) {
- var now = (new Date()).toISOString().substr(0, 10);
- var timestampedFilename = GEONAMES_DUMP + '/admin1_codes/' +
- ADMIN_1_CODES_FILE + '_' + now + '.txt';
- if (fs.existsSync(timestampedFilename)) {
- debug('Using cached GeoNames admin 1 codes data from ' +
- timestampedFilename);
- return callback(null, timestampedFilename);
- }
- var filename = GEONAMES_DUMP + '/admin1_codes/' + ADMIN_1_CODES_FILE +
- '.txt';
- if (fs.existsSync(filename)) {
- debug('Using cached GeoNames admin 1 codes data from ' +
- filename);
- return callback(null, filename);
- }
- debug('Getting GeoNames admin 1 codes data from ' +
- GEONAMES_URL + ADMIN_1_CODES_FILE + '.txt (this may take a while)');
- var url = GEONAMES_URL + ADMIN_1_CODES_FILE + '.txt';
- request.get(url, function(err, response, body) {
- if (err || response.statusCode !== 200) {
- return callback('Error downloading GeoNames admin 1 codes data' +
- (err ? ': ' + err : ''));
- }
- // Store a dump locally
- if (!fs.existsSync(GEONAMES_DUMP + '/admin1_codes')) {
- fs.mkdirSync(GEONAMES_DUMP + '/admin1_codes');
- }
- try {
- fs.writeFileSync(timestampedFilename, body);
- // Housekeeping, remove old files
- var currentFileName = path.basename(timestampedFilename);
- fs.readdirSync(GEONAMES_DUMP + '/admin1_codes').forEach(function(file) {
- if (file !== currentFileName) {
- fs.unlinkSync(GEONAMES_DUMP + '/admin1_codes/' + file);
- }
- });
- } catch (e) {
- throw(e);
- }
- return callback(null, timestampedFilename);
- });
- },
- _parseGeoNamesAdmin1CodesCsv: function(pathToCsv, callback) {
- var that = this;
- var lenI = GEONAMES_ADMIN_CODES_COLUMNS.length;
- that._admin1Codes = {};
- var lineReader = readline.createInterface({
- input: fs.createReadStream(pathToCsv)
- });
- lineReader.on('line', function(line) {
- line = line.split('\t');
- for (var i = 0; i < lenI; i++) {
- var value = line[i] || null;
- if (i === 0) {
- that._admin1Codes[value] = {};
- } else {
- that._admin1Codes[line[0]][GEONAMES_ADMIN_CODES_COLUMNS[i]] = value;
- }
- }
- });
- lineReader.on('close', function() {
- return callback();
- });
- },
- _getGeoNamesAdmin2CodesData: function(callback) {
- var now = (new Date()).toISOString().substr(0, 10);
- var timestampedFilename = GEONAMES_DUMP + '/admin2_codes/' +
- ADMIN_2_CODES_FILE + '_' + now + '.txt';
- if (fs.existsSync(timestampedFilename)) {
- debug('Using cached GeoNames admin 2 codes data from ' +
- timestampedFilename);
- return callback(null, timestampedFilename);
- }
- var filename = GEONAMES_DUMP + '/admin2_codes/' + ADMIN_2_CODES_FILE +
- '.txt';
- if (fs.existsSync(filename)) {
- debug('Using cached GeoNames admin 2 codes data from ' +
- filename);
- return callback(null, filename);
- }
- debug('Getting GeoNames admin 2 codes data from ' +
- GEONAMES_URL + ADMIN_2_CODES_FILE + '.txt (this may take a while)');
- var url = GEONAMES_URL + ADMIN_2_CODES_FILE + '.txt';
- request.get(url, function(err, response, body) {
- if (err || response.statusCode !== 200) {
- return callback('Error downloading GeoNames admin 2 codes data' +
- (err ? ': ' + err : ''));
- }
- // Store a dump locally
- if (!fs.existsSync(GEONAMES_DUMP + '/admin2_codes')) {
- fs.mkdirSync(GEONAMES_DUMP + '/admin2_codes');
- }
- try {
- fs.writeFileSync(timestampedFilename, body);
- // Housekeeping, remove old files
- var currentFileName = path.basename(timestampedFilename);
- fs.readdirSync(GEONAMES_DUMP + '/admin2_codes').forEach(function(file) {
- if (file !== currentFileName) {
- fs.unlinkSync(GEONAMES_DUMP + '/admin2_codes/' + file);
- }
- });
- } catch (e) {
- throw(e);
- }
- return callback(null, timestampedFilename);
- });
- },
- _parseGeoNamesAdmin2CodesCsv: function(pathToCsv, callback) {
- var that = this;
- var lenI = GEONAMES_ADMIN_CODES_COLUMNS.length;
- that._admin2Codes = {};
- var lineReader = readline.createInterface({
- input: fs.createReadStream(pathToCsv)
- });
- lineReader.on('line', function(line) {
- line = line.split('\t');
- for (var i = 0; i < lenI; i++) {
- var value = line[i] || null;
- if (i === 0) {
- that._admin2Codes[value] = {};
- } else {
- that._admin2Codes[line[0]][GEONAMES_ADMIN_CODES_COLUMNS[i]] = value;
- }
- }
- });
- lineReader.on('close', function() {
- return callback();
- });
- },
- _getGeoNamesCitiesData: function(callback) {
- var now = (new Date()).toISOString().substr(0, 10);
- // Use timestamped cities file OR bare cities file
- var timestampedFilename = GEONAMES_DUMP + '/cities/' + CITIES_FILE + '_' +
- now + '.txt';
- if (fs.existsSync(timestampedFilename)) {
- debug('Using cached GeoNames cities data from ' +
- timestampedFilename);
- return callback(null, timestampedFilename);
- }
- var filename = GEONAMES_DUMP + '/cities/' + CITIES_FILE + '.txt';
- if (fs.existsSync(filename)) {
- debug('Using cached GeoNames cities data from ' +
- filename);
- return callback(null, filename);
- }
- debug('Getting GeoNames cities data from ' + GEONAMES_URL +
- CITIES_FILE + '.zip (this may take a while)');
- var options = {
- url: GEONAMES_URL + CITIES_FILE + '.zip',
- encoding: null
- };
- request.get(options, function(err, response, body) {
- if (err || response.statusCode !== 200) {
- return callback('Error downloading GeoNames cities data' +
- (err ? ': ' + err : ''));
- }
- debug('Received zipped GeoNames cities data');
- // Store a dump locally
- if (!fs.existsSync(GEONAMES_DUMP + '/cities')) {
- fs.mkdirSync(GEONAMES_DUMP + '/cities');
- }
- var zipFilename = GEONAMES_DUMP + '/cities/' + CITIES_FILE + '_' + now +
- '.zip';
- try {
- fs.writeFileSync(zipFilename, body);
- fs.createReadStream(zipFilename)
- .pipe(unzip.Extract({path: GEONAMES_DUMP + '/cities'}))
- .on('close', function() {
- fs.renameSync(filename, timestampedFilename);
- fs.unlinkSync(GEONAMES_DUMP + '/cities/' + CITIES_FILE + '_' + now +
- '.zip');
- debug('Unzipped GeoNames cities data');
- // Housekeeping, remove old files
- var currentFileName = path.basename(timestampedFilename);
- fs.readdirSync(GEONAMES_DUMP + '/cities').forEach(function(file) {
- if (file !== currentFileName) {
- fs.unlinkSync(GEONAMES_DUMP + '/cities/' + file);
- }
- });
- return callback(null, timestampedFilename);
- });
- } catch (e) {
- debug('Warning: ' + e);
- return callback(null, timestampedFilename);
- }
- });
- },
- _parseGeoNamesCitiesCsv: function(pathToCsv, callback) {
- debug('Started parsing cities.txt (this may take a ' +
- 'while)');
- var data = [];
- var lenI = GEONAMES_COLUMNS.length;
- var that = this;
- var content = fs.readFileSync(pathToCsv);
- parse(content, {delimiter: '\t', quote: ''}, function(err, lines) {
- if (err) {
- return callback(err);
- }
- lines.forEach(function(line) {
- var lineObj = {};
- for (var i = 0; i < lenI; i++) {
- var column = line[i] || null;
- lineObj[GEONAMES_COLUMNS[i]] = column;
- }
- data.push(lineObj);
- });
- debug('Finished parsing cities.txt');
- debug('Started building cities k-d tree (this may take ' +
- 'a while)');
- var dimensions = [
- 'latitude',
- 'longitude'
- ];
- that._kdTree = kdTree.createKdTree(data, that._distanceFunc, dimensions);
- debug('Finished building cities k-d tree');
- return callback();
- });
- },
- _getGeoNamesAllCountriesData: function(callback) {
- var now = (new Date()).toISOString().substr(0, 10);
- var timestampedFilename = GEONAMES_DUMP + '/all_countries/' +
- ALL_COUNTRIES_FILE + '_' + now + '.txt';
- if (fs.existsSync(timestampedFilename)) {
- debug('Using cached GeoNames all countries data from ' +
- timestampedFilename);
- return callback(null, timestampedFilename);
- }
- var filename = GEONAMES_DUMP + '/all_countries/' + ALL_COUNTRIES_FILE +
- '.txt';
- if (fs.existsSync(filename)) {
- debug('Using cached GeoNames all countries data from ' +
- filename);
- return callback(null, filename);
- }
- debug('Getting GeoNames all countries data from ' +
- GEONAMES_URL + ALL_COUNTRIES_FILE + '.zip (this may take a while)');
- var options = {
- url: GEONAMES_URL + ALL_COUNTRIES_FILE + '.zip',
- encoding: null
- };
- request.get(options, function(err, response, body) {
- if (err || response.statusCode !== 200) {
- return callback('Error downloading GeoNames all countries data' +
- (err ? ': ' + err : ''));
- }
- debug('Received zipped GeoNames all countries data');
- // Store a dump locally
- if (!fs.existsSync(GEONAMES_DUMP + '/all_countries')) {
- fs.mkdirSync(GEONAMES_DUMP + '/all_countries');
- }
- var zipFilename = GEONAMES_DUMP + '/all_countries/' + ALL_COUNTRIES_FILE +
- '_' + now + '.zip';
- try {
- fs.writeFileSync(zipFilename, body);
- fs.createReadStream(zipFilename)
- .pipe(unzip.Extract({path: GEONAMES_DUMP + '/all_countries'}))
- .on('close', function() {
- fs.renameSync(filename, timestampedFilename);
- fs.unlinkSync(GEONAMES_DUMP + '/all_countries/' +
- ALL_COUNTRIES_FILE + '_' + now + '.zip');
- debug('Unzipped GeoNames all countries data');
- // Housekeeping, remove old files
- var currentFileName = path.basename(timestampedFilename);
- var directory = GEONAMES_DUMP + '/all_countries';
- fs.readdirSync(directory).forEach(function(file) {
- if (file !== currentFileName) {
- fs.unlinkSync(GEONAMES_DUMP + '/all_countries/' + file);
- }
- });
- return callback(null, timestampedFilename);
- });
- } catch (e) {
- debug('Warning: ' + e);
- return callback(null, timestampedFilename);
- }
- });
- },
- _parseGeoNamesAllCountriesCsv: function(pathToCsv, callback) {
- debug('Started parsing all countries.txt (this may take ' +
- 'a while)');
- var lenI = GEONAMES_COLUMNS.length;
- var that = this;
- // Indexes
- var featureCodeIndex = GEONAMES_COLUMNS.indexOf('featureCode');
- var countryCodeIndex = GEONAMES_COLUMNS.indexOf('countryCode');
- var admin1CodeIndex = GEONAMES_COLUMNS.indexOf('admin1Code');
- var admin2CodeIndex = GEONAMES_COLUMNS.indexOf('admin2Code');
- var admin3CodeIndex = GEONAMES_COLUMNS.indexOf('admin3Code');
- var admin4CodeIndex = GEONAMES_COLUMNS.indexOf('admin4Code');
- var nameIndex = GEONAMES_COLUMNS.indexOf('name');
- var asciiNameIndex = GEONAMES_COLUMNS.indexOf('asciiName');
- var geoNameIdIndex = GEONAMES_COLUMNS.indexOf('geoNameId');
- var counter = 0;
- that._admin3Codes = {};
- that._admin4Codes = {};
- var lineReader = readline.createInterface({
- input: fs.createReadStream(pathToCsv)
- });
- lineReader.on('line', function(line) {
- line = line.split('\t');
- var featureCode = line[featureCodeIndex];
- if ((featureCode === 'ADM3') || (featureCode === 'ADM4')) {
- var lineObj = {
- name: line[nameIndex],
- asciiName: line[asciiNameIndex],
- geoNameId: line[geoNameIdIndex]
- };
- var key = line[countryCodeIndex] + '.' + line[admin1CodeIndex] + '.' +
- line[admin2CodeIndex] + '.' + line[admin3CodeIndex];
- if (featureCode === 'ADM3') {
- that._admin3Codes[key] = lineObj;
- } else if (featureCode === 'ADM4') {
- that._admin4Codes[key + '.' + line[admin4CodeIndex]] = lineObj;
- }
- }
- if (counter % 100000 === 0) {
- debug('Parsing progress all countries ' + counter);
- }
- counter++;
- });
- lineReader.on('close', function() {
- debug('Finished parsing all countries.txt');
- return callback();
- });
- },
- init: function(options, callback) {
- options = options || {};
- if (options.dumpDirectory) {
- GEONAMES_DUMP = options.dumpDirectory;
- }
- options.load = options.load || {};
- if (options.load.admin1 === undefined) {
- options.load.admin1 = true;
- }
- if (options.load.admin2 === undefined) {
- options.load.admin2 = true;
- }
- if (options.load.admin3And4 === undefined) {
- options.load.admin3And4 = true;
- }
- if (options.load.alternateNames === undefined) {
- options.load.alternateNames = true;
- }
- debug('Initializing local reverse geocoder using dump ' +
- 'directory: ' + GEONAMES_DUMP);
- // Create local cache folder
- if (!fs.existsSync(GEONAMES_DUMP)) {
- fs.mkdirSync(GEONAMES_DUMP);
- }
- var that = this;
- async.parallel([
- // Get GeoNames cities
- function(waterfallCallback) {
- async.waterfall([
- that._getGeoNamesCitiesData.bind(that),
- that._parseGeoNamesCitiesCsv.bind(that)
- ], function() {
- return waterfallCallback();
- });
- },
- // Get GeoNames admin 1 codes
- function(waterfallCallback) {
- if (options.load.admin1) {
- async.waterfall([
- that._getGeoNamesAdmin1CodesData.bind(that),
- that._parseGeoNamesAdmin1CodesCsv.bind(that)
- ], function() {
- return waterfallCallback();
- });
- } else {
- return setImmediate(waterfallCallback);
- }
- },
- // Get GeoNames admin 2 codes
- function(waterfallCallback) {
- if (options.load.admin2) {
- async.waterfall([
- that._getGeoNamesAdmin2CodesData.bind(that),
- that._parseGeoNamesAdmin2CodesCsv.bind(that)
- ], function() {
- return waterfallCallback();
- });
- } else {
- return setImmediate(waterfallCallback);
- }
- },
- // Get GeoNames all countries
- function(waterfallCallback) {
- if (options.load.admin3And4) {
- async.waterfall([
- that._getGeoNamesAllCountriesData.bind(that),
- that._parseGeoNamesAllCountriesCsv.bind(that)
- ], function() {
- return waterfallCallback();
- });
- } else {
- return setImmediate(waterfallCallback);
- }
- },
- // Get GeoNames alternate names
- function(waterfallCallback) {
- if (options.load.alternateNames) {
- async.waterfall([
- that._getGeoNamesAlternateNamesData.bind(that),
- that._parseGeoNamesAlternateNamesCsv.bind(that)
- ], function() {
- return waterfallCallback();
- });
- } else {
- return setImmediate(waterfallCallback);
- }
- }
- ],
- // Main callback
- function(err) {
- if (err) {
- throw(err);
- }
- return callback();
- });
- },
- lookUp: function(points, arg2, arg3) {
- var callback;
- var maxResults;
- if (arguments.length === 2) {
- maxResults = 1;
- callback = arg2;
- } else {
- maxResults = arg2;
- callback = arg3;
- }
- this._lookUp(points, maxResults, function(err, results) {
- return callback(null, results);
- });
- },
- _lookUp: function(points, maxResults, callback) {
- var that = this;
- // If not yet initialied, then initialize
- if (!this._kdTree) {
- return this.init({}, function() {
- return that.lookUp(points, maxResults, callback);
- });
- }
- // Make sure we have an array of points
- if (!Array.isArray(points)) {
- points = [points];
- }
- var functions = [];
- points.forEach(function(point, i) {
- point = {
- latitude: parseFloat(point.latitude),
- longitude: parseFloat(point.longitude)
- };
- debug('Look-up request for point ' +
- JSON.stringify(point));
- functions[i] = function(innerCallback) {
- var result = that._kdTree.nearest(point, maxResults);
- result.reverse();
- for (var j = 0, lenJ = result.length; j < lenJ; j++) {
- if (result && result[j] && result[j][0]) {
- var countryCode = result[j][0].countryCode || '';
- var geoNameId = result[j][0].geoNameId || '';
- var admin1Code;
- var admin2Code;
- var admin3Code;
- var admin4Code;
- // Look-up of admin 1 code
- if (that._admin1Codes) {
- admin1Code = result[j][0].admin1Code || '';
- var admin1CodeKey = countryCode + '.' + admin1Code;
- result[j][0].admin1Code = that._admin1Codes[admin1CodeKey] ||
- result[j][0].admin1Code;
- }
- // Look-up of admin 2 code
- if (that._admin2Codes) {
- admin2Code = result[j][0].admin2Code || '';
- var admin2CodeKey = countryCode + '.' + admin1Code + '.' +
- admin2Code;
- result[j][0].admin2Code = that._admin2Codes[admin2CodeKey] ||
- result[j][0].admin2Code;
- }
- // Look-up of admin 3 code
- if (that._admin3Codes) {
- admin3Code = result[j][0].admin3Code || '';
- var admin3CodeKey = countryCode + '.' + admin1Code + '.' +
- admin2Code + '.' + admin3Code;
- result[j][0].admin3Code = that._admin3Codes[admin3CodeKey] ||
- result[j][0].admin3Code;
- }
- // Look-up of admin 4 code
- if (that._admin4Codes) {
- admin4Code = result[j][0].admin4Code || '';
- var admin4CodeKey = countryCode + '.' + admin1Code + '.' +
- admin2Code + '.' + admin3Code + '.' + admin4Code;
- result[j][0].admin4Code = that._admin4Codes[admin4CodeKey] ||
- result[j][0].admin4Code;
- }
- // Look-up of alternate name
- if (that._alternateNames) {
- result[j][0].alternateName = that._alternateNames[geoNameId] ||
- result[j][0].alternateName;
- }
- // Pull in the k-d tree distance in the main object
- result[j][0].distance = result[j][1];
- // Simplify the output by not returning an array
- result[j] = result[j][0];
- }
- }
- debug('Found result(s) for point ' +
- JSON.stringify(point) + result.map(function(subResult, i) {
- return '\n (' + (++i) + ') {"geoNameId":"' +
- subResult.geoNameId + '",' + '"name":"' + subResult.name +
- '"}';
- }));
- return innerCallback(null, result);
- };
- });
- async.series(
- functions,
- function(err, results) {
- debug('Delivering joint results');
- return callback(null, results);
- });
- }
- };
- module.exports = geocoder;
- </code></pre>
- </article>
- </section>
- </div>
- <nav>
- <h2><a href="index.html">Home</a></h2><h3><a href="global.html">Global</a></h3>
- </nav>
- <br class="clear">
- <footer>
- Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a> on Sat Sep 07 2019 23:12:47 GMT+0300 (Moscow Standard Time)
- </footer>
- <script> prettyPrint(); </script>
- <script src="scripts/linenumber.js"> </script>
- </body>
- </html>
|