From 879df94f4c4b2d532651bc9280ccd599acfc7eff Mon Sep 17 00:00:00 2001 From: Erik Golinelli Date: Mon, 13 May 2024 19:35:40 +0200 Subject: [PATCH] getByProximity return a list of countries within a specified proximity of the given country. --- src/getByProximity.ts | 100 +++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 40 deletions(-) diff --git a/src/getByProximity.ts b/src/getByProximity.ts index 1bf3757..ce8f92f 100644 --- a/src/getByProximity.ts +++ b/src/getByProximity.ts @@ -1,5 +1,5 @@ -import { getIso } from './getIso' -import { countriesExtra } from './data/countries-extra' +import { countriesExtra } from "./data/countries-extra"; +import { getIso } from "./getIso"; /** * Calculate the distance between two sets of coordinates using the Haversine formula. @@ -8,25 +8,28 @@ import { countriesExtra } from './data/countries-extra' * @param {Array} coordinates2 - The second set of coordinates [latitude, longitude] * @return {number} The distance between the two sets of coordinates in kilometers */ -function getDistance(coordinates: [number, number], coordinates2: [number, number]) { - const lat1 = coordinates[0] - const lon1 = coordinates[1] - const lat2 = coordinates2[0] - const lon2 = coordinates2[1] - // radius of the Earth in kilometers (6371 km) - const R = 6371 - const dLat = ((lat2 - lat1) * Math.PI) / 180 - const dLon = ((lon2 - lon1) * Math.PI) / 180 - // Haversine formula - const a = - Math.sin(dLat / 2) * Math.sin(dLat / 2) + - Math.cos((lat1 * Math.PI) / 180) * - Math.cos((lat2 * Math.PI) / 180) * - Math.sin(dLon / 2) * - Math.sin(dLon / 2) - const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) - const d = R * c - return d +function getDistance( + coordinates: [number, number], + coordinates2: [number, number], +) { + const lat1 = coordinates[0]; + const lon1 = coordinates[1]; + const lat2 = coordinates2[0]; + const lon2 = coordinates2[1]; + // radius of the Earth in kilometers (6371 km) + const R = 6371; + const dLat = ((lat2 - lat1) * Math.PI) / 180; + const dLon = ((lon2 - lon1) * Math.PI) / 180; + // Haversine formula + const a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos((lat1 * Math.PI) / 180) * + Math.cos((lat2 * Math.PI) / 180) * + Math.sin(dLon / 2) * + Math.sin(dLon / 2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + const d = R * c; + return d; } /** @@ -36,25 +39,42 @@ function getDistance(coordinates: [number, number], coordinates2: [number, numbe * @param {number} maxDistance - the maximum distance in kilometers * @return {Record | undefined} a record of countries within the specified proximity */ +export function getNearestCountries( + country: string, + maxDistance: number, +): { iso: string; coordinates: number[] | undefined; distance: number }[] { + const countryCoordinates = getIso(country, "country", "coordinates") as + | [number, number] + | null; + if (!countryCoordinates) { + throw new Error("Country not found"); + } + return getByProximity(countryCoordinates, maxDistance); +} + export function getByProximity( - country: string, - maxDistance: number + coordinates: [number, number], + maxDistance: number, ): { iso: string; coordinates: number[] | undefined; distance: number }[] { - const countryCoordinates = getIso(country, 'country', 'coordinates') as [number, number] | null - const countriesbyDistance: { - iso: string - coordinates: number[] | undefined - distance: number - }[] = [] - if (countryCoordinates !== null) { - Object.entries(countriesExtra).forEach(([iso, extras]) => { - const distance = getDistance(countryCoordinates, extras.coordinates as [number, number]) - if (distance <= maxDistance) { - countriesbyDistance.push({ iso, coordinates: extras.coordinates, distance }) - } - }) - // return the countries sorted by distance - countriesbyDistance.sort((a, b) => a.distance - b.distance) - } - return countriesbyDistance + const countriesbyDistance: { + iso: string; + coordinates: number[] | undefined; + distance: number; + }[] = []; + for (const [iso, extras] of Object.entries(countriesExtra)) { + const distance = getDistance( + coordinates, + extras.coordinates as [number, number], + ); + if (distance <= maxDistance) { + countriesbyDistance.push({ + iso, + coordinates: extras.coordinates, + distance, + }); + } + } + // return the countries sorted by distance + countriesbyDistance.sort((a, b) => a.distance - b.distance); + return countriesbyDistance; }