Учитывая координаты широта / долгота, как мы можем узнать город / страну?
Например, если у нас есть этот набор координат
"latitude": 48.858844300000001,
"longitude": 2.2943506,
Как мы можем узнать город / страну?
16 ответов
Бесплатный API геокодирования Google предоставляет эту услугу через HTTP REST API. Обратите внимание, что API ограничен в использовании и скорости, но вы можете платить за неограниченный доступ.
Попробуйте эту ссылку, чтобы увидеть пример вывода (это в json, вывод также доступен в XML)
http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true
Другой вариант:
- Загрузите базу данных городов с http://download.geonames.org/export/dump/
- Добавьте каждый город в виде широты / долготы -> Отображение города в пространственный индекс, такой как R-Tree (некоторые БД также имеют функциональность)
- Используйте поиск ближайшего соседа, чтобы найти ближайший город для любой заданной точки
Преимущества:
- Не зависит от доступности внешнего сервера
- Очень быстро (легко делает тысячи поисков в секунду)
Недостатки:
- Не обновляется автоматически
- Требуется дополнительный код, если вы хотите различить случай, когда ближайший город находится в десятках миль
- Может дать странные результаты возле полюсов и международной линии дат (хотя в любом случае в этих местах нет городов)
Тебе нужно geopy
pip install geopy
а потом:
from geopy.geocoders import Nominatim
geolocator = Nominatim()
location = geolocator.reverse("48.8588443, 2.2943506")
print(location.address)
чтобы получить больше информации:
print (location.raw)
{'place_id': '24066644', 'osm_id': '2387784956', 'lat': '41.442115', 'lon': '-8.2939909', 'boundingbox': ['41.442015', '41.442215', '-8.2940909', '-8.2938909'], 'address': {'country': 'Portugal', 'suburb': 'Oliveira do Castelo', 'house_number': '99', 'city_district': 'Oliveira do Castelo', 'country_code': 'pt', 'city': 'Oliveira, São Paio e São Sebastião', 'state': 'Norte', 'state_district': 'Ave', 'pedestrian': 'Rua Doutor Avelino Germano', 'postcode': '4800-443', 'county': 'Guimarães'}, 'osm_type': 'node', 'display_name': '99, Rua Doutor Avelino Germano, Oliveira do Castelo, Oliveira, São Paio e São Sebastião, Guimarães, Braga, Ave, Norte, 4800-443, Portugal', 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'}
Альтернативой с открытым исходным кодом является Nominatim из Open Street Map. Все, что вам нужно сделать, это установить переменные в URL, и он возвращает город / страну этого местоположения. Пожалуйста, проверьте следующую ссылку для официальной документации: Nominatim
Я искал похожую функциональность и увидел, что данные " http://download.geonames.org/export/dump/" были предоставлены в предыдущем ответе (спасибо за обмен, это отличный источник), и реализовал сервис на основе на данных city1000.txt.
Вы можете увидеть это работает на http://scatter-otl.rhcloud.com/location?lat=36&long=-78.9 (неработающая ссылка) Просто измените широту и долготу для вашего местоположения.
Он развернут на OpenShift (платформа RedHat). Первый звонок после длительного простоя может занять некоторое время, но обычно производительность удовлетворительная. Не стесняйтесь использовать эту услугу, как вам нравится...
Также вы можете найти источник проекта по адресу https://github.com/turgos/Location.
Я использовал Geocoder, хорошую библиотеку Python, которая поддерживает несколько провайдеров, включая Google, Geonames и OpenStreetMaps, чтобы упомянуть лишь некоторые из них. Я пытался использовать библиотеку GeoPy, и она часто получает таймауты. Разработка собственного кода для GeoNames - не лучшее использование вашего времени, и вы можете получить нестабильный код. Geocoder очень прост в использовании и имеет достаточно хорошую документацию. Ниже приведен пример кода для поиска города по широте и долготе или поиска широты / долготы по названию города.
import geocoder
g = geocoder.osm([53.5343609, -113.5065084], method='reverse')
print g.json['city'] # Prints Edmonton
g = geocoder.osm('Edmonton, Canada')
print g.json['lat'], g.json['lng'] # Prints 53.5343609, -113.5065084
Я знаю, что этот вопрос действительно старый, но я работал над той же проблемой, и я нашел чрезвычайно эффективный и удобный пакет, reverse_geocoder
, построенный Ajay Thampi. Код доступен здесь. Он основан на параллельной реализации деревьев KD, которая чрезвычайно эффективна для большого количества баллов (мне потребовалось несколько секунд, чтобы получить 100000 баллов.
Он основан на этой базе данных, уже выделенной @turgos.
Если ваша задача - быстро найти страну и город из списка координат, это отличный инструмент.
Я потратил около 30 минут, пытаясь найти пример кода, как это сделать в Javascript. Я не смог найти быстрый четкий ответ на вопрос, который вы разместили. Итак... Я сделал свой собственный. Надеемся, что люди могут использовать это без необходимости копаться в API или смотреть на код, который они не знают, как читать. Ха, если ничего другого, я могу сослаться на этот пост для моего собственного материала.. Хороший вопрос и спасибо за форум обсуждения!
Это использует Google API.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=<YOURGOOGLEKEY>&sensor=false&v=3&libraries=geometry"></script>
,
//CHECK IF BROWSER HAS HTML5 GEO LOCATION
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
//GET USER CURRENT LOCATION
var locCurrent = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
//CHECK IF THE USERS GEOLOCATION IS IN AUSTRALIA
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'latLng': locCurrent }, function (results, status) {
var locItemCount = results.length;
var locCountryNameCount = locItemCount - 1;
var locCountryName = results[locCountryNameCount].formatted_address;
if (locCountryName == "Australia") {
//SET COOKIE FOR GIVING
jQuery.cookie('locCountry', locCountryName, { expires: 30, path: '/' });
}
});
}
}
Это действительно зависит от того, какие технологические ограничения у вас есть.
Одним из способов является создание пространственной базы данных с описанием стран и городов, которые вас интересуют. Под схемой я подразумеваю, что страны и города хранятся в виде полигона пространственного типа. Ваш набор координат может быть преобразован в точку пространственного типа и сопоставлен с полигонами, чтобы получить название страны / города, где расположена точка.
Вот некоторые базы данных, которые поддерживают пространственный тип: SQL Server 2008, MySQL, postGIS - расширение postgreSQL и Oracle.
Если вы хотите использовать сервис вместо собственной базы данных, вы можете использовать GeoPlanet от Yahoo. Для сервисного подхода вы можете захотеть проверить этот ответ на http://gis.stackexchange.com/, который охватывает доступность сервисов для решения вашей проблемы.
Loc2country - это инструмент на основе Golang, который возвращает код страны ISO альфа-3 для заданных координат местоположения (широта / долгота). Он отвечает в микросекундах. Он использует геохэш к карте страны.
Данные геохеша генерируются с помощью геораптора.
Мы используем геохэш на уровне 6 для этого инструмента, то есть ящики размером 1,2 км х 600 м.
Минимизируйте количество библиотек.
Получите ключ для использования API на своем веб-сайте и просто получите результат в http-запросе:
curl -i -H "ключ: ВАШ_КЛЮЧ" -X ПОЛУЧИТЬ https://api.latlong.dev/lookup?lat=38.7447913&long=-9.1625173
Вы можете использовать Google Geocoding API
Сильфон - это функция php, которая возвращает адрес, город, штат и страну
public function get_location($latitude='', $longitude='')
{
$geolocation = $latitude.','.$longitude;
$request = 'http://maps.googleapis.com/maps/api/geocode/json?latlng='.$geolocation.'&sensor=false';
$file_contents = file_get_contents($request);
$json_decode = json_decode($file_contents);
if(isset($json_decode->results[0])) {
$response = array();
foreach($json_decode->results[0]->address_components as $addressComponet) {
if(in_array('political', $addressComponet->types)) {
$response[] = $addressComponet->long_name;
}
}
if(isset($response[0])){ $first = $response[0]; } else { $first = 'null'; }
if(isset($response[1])){ $second = $response[1]; } else { $second = 'null'; }
if(isset($response[2])){ $third = $response[2]; } else { $third = 'null'; }
if(isset($response[3])){ $fourth = $response[3]; } else { $fourth = 'null'; }
if(isset($response[4])){ $fifth = $response[4]; } else { $fifth = 'null'; }
$loc['address']=''; $loc['city']=''; $loc['state']=''; $loc['country']='';
if( $first != 'null' && $second != 'null' && $third != 'null' && $fourth != 'null' && $fifth != 'null' ) {
$loc['address'] = $first;
$loc['city'] = $second;
$loc['state'] = $fourth;
$loc['country'] = $fifth;
}
else if ( $first != 'null' && $second != 'null' && $third != 'null' && $fourth != 'null' && $fifth == 'null' ) {
$loc['address'] = $first;
$loc['city'] = $second;
$loc['state'] = $third;
$loc['country'] = $fourth;
}
else if ( $first != 'null' && $second != 'null' && $third != 'null' && $fourth == 'null' && $fifth == 'null' ) {
$loc['city'] = $first;
$loc['state'] = $second;
$loc['country'] = $third;
}
else if ( $first != 'null' && $second != 'null' && $third == 'null' && $fourth == 'null' && $fifth == 'null' ) {
$loc['state'] = $first;
$loc['country'] = $second;
}
else if ( $first != 'null' && $second == 'null' && $third == 'null' && $fourth == 'null' && $fifth == 'null' ) {
$loc['country'] = $first;
}
}
return $loc;
}
Если вы используете API Google Адресов, вот как вы можете получить страну и город из объекта мест с помощью Javascript:
function getCityAndCountry(location) {
var components = {};
for(var i = 0; i < location.address_components.length; i++) {
components[location.address_components[i].types[0]] = location.address_components[i].long_name;
}
if(!components['country']) {
console.warn('Couldn\'t extract country');
return false;
}
if(components['locality']) {
return [components['locality'], components['country']];
} else if(components['administrative_area_level_1']) {
return [components['administrative_area_level_1'], components['country']];
} else {
console.warn('Couldn\'t extract city');
return false;
}
}
Вы можете сделать это с помощью: БЕСПЛАТНО.
Моя демонстрация в React и шаг за шагом, но вы можете сделать это любым способом, который вы хотите, ключом является этот Weather API, который принимает LON и LAT в виде строки для получения информации о городе и погоде -> https://api . Weatherapi.com/v1/forecast.json?key=ВАШ_КЛЮЧ&amp;q=ШИРОТА,ДОЛГОТА&amp;дни=1&amp;aqi=no&amp;alerts=n
Примечание: вы должны сгенерировать СВОЙ СОБСТВЕННЫЙ КЛЮЧ, зарегистрировавшись
Для этого вам понадобятся 3 состояния:
const [latitude, setLatitude] = useState("");
const [longitude, setLongitude] = useState("");
const [city, setCity] = useState("");
Во-первых: запросите доступ к «местоположению» у пользователя (у этого будет всплывающее окно), используя этот код, и установите для состояния широту и долготу.
useEffect(() => {
function getPosition() {
const successCallback = (position) => {
console.log(position);
setLatitude(position.coords.latitude);
setLongitude(position.coords.longitude);
};
const errorCallback = (error) => {
console.log(error);
};
navigator.geolocation.getCurrentPosition(successCallback, errorCallback);
}
getPosition();
}, []);
Во-вторых, используйте https://www.weatherapi.com/https://www.weatherapi.com/ API, чтобы получить город и другую информацию, основанную на широте и долготе.
API выглядит так: https://api.weatherapi.com/v1/forecast.json?key=3e5e13fac8354c818de152831211305&amp;q=53.3498053,-6.2603097&amp;days=1&amp;aqi=no&amp;alerts=n
API с объяснением: https://api.weatherapi.com/v1/forecast.json?key=3e5e13fac8354c818de152831211305&amp;q=ШИРОТА,ДОЛГОТА&amp;days=1&amp;aqi=no&amp;alerts=n
Теперь вызовите этот API с широтой и долготой, чтобы получить данные о местоположении, включая город. Я использую useEffect в качестве триггера, поэтому, как только я получаю информацию о Latitude, я вызываю API с помощью axios и устанавливаю состояние города на то, что когда-либо выходит из объекта API.
useEffect(() => {
async function getWeather() {
let res = await axios.get(
`https://api.weatherapi.com/v1/forecast.json?key=3e5e13fac8354c818de152831211305&q=${latitude},${longitude}&days=1&aqi=no&alerts=no`
);
console.log(res.data);
setCity(res.data.location.name);
}
getWeather();
}, [latitude, longitude]);
РЕЗУЛЬТАТ от API:
"location": {
"name": "Dublin",
"region": "Dublin",
"country": "Ireland",
"lat": 53.35,
"lon": -6.26,
"tz_id": "Europe/Dublin",
"localtime_epoch": 1673737376,
"localtime": "2023-01-14 23:02"
},
Вот видео на моем канале YouTube, где вы можете увидеть демонстрацию этого: https://youtu.be/gxcG8V3Fpbk
Пожалуйста, проверьте ответ ниже. Меня устраивает
if(navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position){
initialize(position.coords.latitude,position.coords.longitude);
});
}
function initialize(lat,lng) {
//directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
//directionsService = new google.maps.DirectionsService();
var latlng = new google.maps.LatLng(lat, lng);
//alert(latlng);
getLocation(latlng);
}
function getLocation(latlng){
var geocoder = new google.maps.Geocoder();
geocoder.geocode({'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0]) {
var loc = getCountry(results);
alert("location is::"+loc);
}
}
});
}
function getCountry(results)
{
for (var i = 0; i < results[0].address_components.length; i++)
{
var shortname = results[0].address_components[i].short_name;
var longname = results[0].address_components[i].long_name;
var type = results[0].address_components[i].types;
if (type.indexOf("country") != -1)
{
if (!isNullOrWhitespace(shortname))
{
return shortname;
}
else
{
return longname;
}
}
}
}
function isNullOrWhitespace(text) {
if (text == null) {
return true;
}
return text.replace(/\s/gi, '').length < 1;
}
Обновление: мое решение было недостаточно точным, иногда оно возвращало неправильную страну для координат рядом с границей или не возвращало страну, когда координаты были, например, на берегу моря. В конце концов я выбрал платный API обратного геокодирования MapBox. Запрос к URL
https://api.mapbox.com/geocoding/v5/mapbox.places/<longitude>,<latitude>.json?access_token=<access token>
возвращает geojson с данными о местоположении - название места, регион, страна.
Оригинальный ответ :
Загрузите страны с https://www.naturalearthdata.com/downloads/ (я рекомендую использовать 1:10 м для большей точности), сгенерируйте из него GeoJSON и используйте некоторый алгоритм, чтобы определить, находятся ли заданные координаты в пределах полигона (ов) страны.
Я использовал эти шаги для создания файла GeoJSON:
- Установите Анаконду: https://www.anaconda.com/products/distribution
- Установите гдал:
conda install -c conda-forge gdal
(используйте повышенные права администратора, больше информации на https://anaconda.org/conda-forge/gdal ) - Загрузите форму стран 1:10 млн https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/culture/ne_10m_admin_0_countries.zip , распакуйте ее.
- Установите переменную среды:
setx PROJ_LIB C:\ProgramData\Anaconda3\Library\share\proj\
- Команда Run
C:\ProgramData\Anaconda3\Library\bin\ogr2ogr.exe -f GeoJSON -t_srs crs:84 data.geo.json ne_10m_admin_0_countries.shp
Это создаст
data.geo.json
который имеет около 24 МБ. Вы также можете скачать его здесь .
С#:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace SmartGuide.Core.Services.CountryLocators
{
public static class CountryLocator
{
private static readonly Lazy<List<CountryPolygons>> _countryPolygonsByCountryName = new(() =>
{
var dataGeoJsonFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "data.geo.json");
var stream = new FileStream(dataGeoJsonFileName, FileMode.Open, FileAccess.Read);
var geoJson = _Deserialize<Root>(stream);
var countryPolygonsByCountryName = geoJson.Features.Select(
feature => new CountryPolygons
{
CountryName = feature.Properties.Name,
Polygons =
feature.Geometry.Type switch
{
"Polygon" => new List<List<GpsCoordinate>>(
new[]
{
feature.Geometry.Coordinates[0]
.Select(x => new GpsCoordinate(
Convert.ToDouble(x[1]),
Convert.ToDouble(x[0])
)
).ToList()
}
),
"MultiPolygon" => feature.Geometry.Coordinates.Select(
polygon => polygon[0].Select(x =>
new GpsCoordinate(
Convert.ToDouble(((JArray) x)[1]),
Convert.ToDouble(((JArray) x)[0])
)
).ToList()
)
.ToList(),
_ => throw new NotImplementedException($"Unknown geometry type {feature.Geometry.Type}")
}
}
).ToList();
return countryPolygonsByCountryName;
});
public static string GetCountryName(GpsCoordinate coordinate)
{
var country = _countryPolygonsByCountryName.Value.FirstOrDefault(country =>
country.Polygons.Any(polygon => _IsPointInPolygon(polygon, coordinate)));
return country?.CountryName;
}
// taken from https://stackoverflow.com/a/7739297/379279
private static bool _IsPointInPolygon(IReadOnlyList<GpsCoordinate> polygon, GpsCoordinate point)
{
int i, j;
bool c = false;
for (i = 0, j = polygon.Count - 1; i < polygon.Count; j = i++)
{
if ((((polygon[i].Latitude <= point.Latitude) && (point.Latitude < polygon[j].Latitude))
|| ((polygon[j].Latitude <= point.Latitude) && (point.Latitude < polygon[i].Latitude)))
&& (point.Longitude < (polygon[j].Longitude - polygon[i].Longitude) * (point.Latitude - polygon[i].Latitude)
/ (polygon[j].Latitude - polygon[i].Latitude) + polygon[i].Longitude))
{
c = !c;
}
}
return c;
}
private class CountryPolygons
{
public string CountryName { get; set; }
public List<List<GpsCoordinate>> Polygons { get; set; }
}
public static TResult _Deserialize<TResult>(Stream stream)
{
var serializer = new JsonSerializer();
using var sr = new StreamReader(stream);
using var jsonTextReader = new JsonTextReader(sr);
return serializer.Deserialize<TResult>(jsonTextReader);
}
public readonly struct GpsCoordinate
{
public GpsCoordinate(
double latitude,
double longitude
)
{
Latitude = latitude;
Longitude = longitude;
}
public double Latitude { get; }
public double Longitude { get; }
}
}
}
// Generated by https://json2csharp.com/ (with Use Pascal Case) from data.geo.json
public class Feature
{
public string Type { get; set; }
public string Id { get; set; }
public Properties Properties { get; set; }
public Geometry Geometry { get; set; }
}
public class Geometry
{
public string Type { get; set; }
public List<List<List<object>>> Coordinates { get; set; }
}
public class Properties
{
public string Name { get; set; }
}
public class Root
{
public string Type { get; set; }
public List<Feature> Features { get; set; }
}
Тесты:
[TestFixture]
public class when_locating_country
{
[TestCase(49.2231391, 17.8545076, "Czechia", TestName = "1 Vizovice, Czech Republic")]
[TestCase(2.9263126, -75.2891733, "Colombia", TestName = "2 Neiva, Colombia")]
[TestCase(12, -70, "Venezuela", TestName = "3 Paraguana, Venezuela")]
[TestCase(-5.0721976, 39.0993457, "Tanzania", TestName = "4 Tanga, Tanzania")]
[TestCase(42.9830241, 47.5048716, "Russia", TestName = "5 Makhachkala, Russia")]
public void country_is_located_correctly(double latitude, double longitude, string expectedCountryName)
{
var countryName = CountryLocator.GetCountryName(new CountryLocator.GpsCoordinate(latitude, longitude));
countryName.ShouldBe(expectedCountryName);
}
}
JS: вы можете использовать https://github.com/vkurchatkin/what-country и заменить не очень точный https://github.com/vkurchatkin/what-country/blob/master/lib/data.geo.json на сгенерированный. Хотя я не тестировал.