给定纬度/经度坐标,我们如何找到城市/国家?

发布于 2024-11-10 04:57:26 字数 123 浏览 3 评论 0原文

例如,如果我们有这组坐标,

"latitude": 48.858844300000001,
"longitude": 2.2943506,

我们如何找到城市/国家?

For example if we have these set of coordinates

"latitude": 48.858844300000001,
"longitude": 2.2943506,

How can we find out the city/country?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

心病无药医 2024-11-17 04:57:26

另一种选择:

  • http://download.geonames.org/export/dump/
  • 将每个城市添加为纬度/经度 ->城市映射到空间索引,例如 R 树(某些数据库也具有该功能)
  • 使用最近邻搜索来查找任何给定点的最近城市

优点:

  • 不依赖于外部服务器可用
  • 非常快(轻松每秒进行数千次查找)

缺点:

  • 不能自动更新
  • 如果您想区分最近的城市在几十英里之外的情况,则需要额外的代码
  • 可能会在两极和国际日期变更线附近给出奇怪的结果(尽管有“无论如何,那些地方没有任何城市

Another option:

  • Download the cities database from http://download.geonames.org/export/dump/
  • Add each city as a lat/long -> City mapping to a spatial index such as an R-Tree (some DBs also have the functionality)
  • Use nearest-neighbour search to find the closest city for any given point

Advantages:

  • Does not depend on an external server to be available
  • Very fast (easily does thousands of lookups per second)

Disadvantages:

  • Not automatically up to date
  • Requires extra code if you want to distinguish the case where the nearest city is dozens of miles away
  • May give weird results near the poles and the international date line (though there aren't any cities in those places anyway
南七夏 2024-11-17 04:57:26

免费的 Google Geocoding API 通过 HTTP REST API 提供此服务。请注意,该 API 使用和费率受到限制,但您可以付费无限制访问。

尝试此链接查看输出示例(这是 json 格式,输出也可以是 XML 格式)

https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true

The free Google Geocoding API provides this service via a HTTP REST API. Note, the API is usage and rate limited, but you can pay for unlimited access.

Try this link to see an example of the output (this is in json, output is also available in XML)

https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true

去了角落 2024-11-17 04:57:26

您需要 geopy

pip install geopy

然后:

from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="my-app")
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'}

You need geopy

pip install geopy

and then:

from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="my-app")
location = geolocator.reverse("48.8588443, 2.2943506")

print(location.address)

to get more information:

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'}
小嗲 2024-11-17 04:57:26

Open Street Map 的 Nominatim 是一个开源替代方案。
您所要做的就是在 URL 中设置变量,它会返回该位置的城市/国家。请检查以下链接以获取官方文档:Nominatim

An Open Source alternative is Nominatim from Open Street Map.
All you have to do is set the variables in an URL and it returns the city/country of that location. Please check the following link for official documentation: Nominatim

窗影残 2024-11-17 04:57:26

我正在寻找类似的功能,并且看到了数据“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

I was searching for a similar functionality and I saw the data "http://download.geonames.org/export/dump/" shared on earlier reply (thank you for sharing, it is an excellent source), and implemented a service based on the cities1000.txt data.

You can see it running at
http://scatter-otl.rhcloud.com/location?lat=36&long=-78.9 (broken link)
Just change the latitude and longitude for your locations.

It is deployed on OpenShift (RedHat Platform). First call after a long idle period may take sometime, but usually performance is satisfactory.
Feel free to use this service as you like...

Also, you can find the project source at
https://github.com/turgos/Location.

落日海湾 2024-11-17 04:57:26

我使用过 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

I've used Geocoder, a good Python library that supports multiple providers, including Google, Geonames, and OpenStreetMaps, to mention just a few. I've tried using the GeoPy library, and it often gets timeouts. Developing your own code for GeoNames is not the best use of your time and you may end up getting unstable code. Geocoder is very simple to use in my experience, and has good enough documentation. Below is some sample code for looking up city by latitude and longitude, or finding latitude/longitude by city name.

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
情仇皆在手 2024-11-17 04:57:26

我知道这个问题确实很老了,但我一直在研究同样的问题,我发现了一个非常高效和方便的包,reverse_geocoder,由 Ajay Thampi 构建。
代码可在此处获取。它基于 KD 树的并行实现,对于大量点来说非常高效(我花了几秒钟才获得 100,000 个点。

它基于 数据库,已由 @turgos 突出显示。

如果您的任务是快速查找坐标列表中的国家/地区和城市,那么这是一个很棒的工具。

I know this question is really old, but I have been working on the same issue and I found an extremely efficient and convenient package, reverse_geocoder, built by Ajay Thampi.
The code is available here. It based on a parallelised implementation of K-D trees which is extremely efficient for large amounts of points (it took me few seconds to get 100,000 points.

It is based on this database, already highlighted by @turgos.

If your task is to quickly find the country and city of a list of coordinates, this is a great tool.

祁梦 2024-11-17 04:57:26

我花了大约 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: '/' }); 
                }
        });
    }
}

I spent about an 30min trying to find a code example of how to do this in Javascript. I couldn't find a quick clear answer to the question you posted. So... I made my own. Hopefully people can use this without having to go digging into the API or staring at code they have no idea how to read. Ha if nothing else I can reference this post for my own stuff.. Nice question and thanks for the forum of discussion!

This is utilizing the 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: '/' }); 
                }
        });
    }
}
初相遇 2024-11-17 04:57:26

这实际上取决于您有哪些技术限制。

一种方法是拥有一个空间数据库,其中包含您感兴趣的国家和城市的轮廓。我所说的轮廓是指国家和城市存储为空间类型多边形。您的坐标集可以转换为空间类型点,并针对多边形进行查询,以获取该点所在的国家/城市名称。

以下是一些支持空间类型的数据库: SQL Server 2008 MySQLpostGIS - postgreSQL 和 Oracle

如果您想使用服务而不是拥有自己的数据库,您可以使用雅虎的 GeoPlanet< /a>.对于服务方法,您可能需要查看答案gis.stackexchange.com,其中介绍了解决您问题的服务的可用性。

It really depends on what technology restrictions you have.

One way is to have a spatial database with the outline of the countries and cities you are interested in. By outline I mean that countries and cities are store as the spatial type polygon. Your set of coordinates can be converted to the spatial type point and queried against the polygons to get the country/city name where the point is located.

Here are some of the databases which support spatial type: SQL server 2008, MySQL, postGIS - an extension of postgreSQL and Oracle.

If you would like to use a service in stead of having your own database for this you can use Yahoo's GeoPlanet. For the service approach you might want to check out this answer on gis.stackexchange.com, which covers the availability of services for solving your problem.

别闹i 2024-11-17 04:57:26

Loc2country 是一个基于 Golang 的工具,它返回给定位置坐标 (lat/隆)。它以微秒级响应。它使用 geohash 来生成国家/地区地图。

geohash 数据是使用 georaptor 生成的。

我们在该工具中使用第 6 级的 geohash,即大小为 1.2km x 600m 的盒子。

Loc2country is a Golang based tool that returns the ISO alpha-3 country code for given location coordinates (lat/lon). It responds in microseconds. It uses a geohash to country map.

The geohash data is generated using georaptor.

We use geohash at level 6 for this tool, i.e., boxes of size 1.2km x 600m.

胡大本事 2024-11-17 04:57:26

您可以使用 Google Geocoding API

Bellow 是返回地址、城市、州和国家/地区的 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;
}

You can use Google Geocoding API

Bellow is php function that returns Adress, City, State and Country

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;
}
疯到世界奔溃 2024-11-17 04:57:26

如果您使用 Google 的 Places API,则可以通过以下方式使用 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;
  }
}

If you are using Google's Places API, this is how you can get country and city from the place object using 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;
  }
}
星光不落少年眉 2024-11-17 04:57:26

您可以通过以下方式实现:https://www.weatherapi.com/ 免费。

我的演示是在 React 中一步步进行的,但是你可以用任何你想要的方式来完成,关键是这个 Weather API,它接受 LON 和 LAT 作为字符串来生成城市和天气信息 -> https://api.weatherapi.com/v1/forecast.json?key=YOUR_KEY&q=LATITUDE,LONGITUDE&days=1&aqi=no&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/ API 获取城市和其他信息(基于 Lat) Lon

API 如下所示: https://api.weatherapi.com/v1/forecast.json?key=3e5e13fac8354c818de152831211305&q=53.3498053,-6.2603097&days=1&aqi=no&alerts=n

API 及说明: https://api.weatherapi.com/v1/forecast.json?key=3e5e13fac8354c818de152831211305&q=LATITUDE,LONGITUDE&days=1&aqi=no&alerts=n

现在调用这个具有纬度和经度的 API,用于获取位置数据,包括城市。我使用 useEffect 作为触发器,因此一旦获得有关 Latitude 的信息,我就会使用 axios 调用 api,并将 City state 设置为来自 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

You can do it with: https://www.weatherapi.com/ its FREE.

My demo is in React and step by step, but you can do it in any way you want, the key is this Weather API, that accepts LON and LAT as a string to produce city and weather info -> https://api.weatherapi.com/v1/forecast.json?key=YOUR_KEY&q=LATITUDE,LONGITUDE&days=1&aqi=no&alerts=n

Note: you will to generate YOUR OWN KEY, by signing up

You will need 3 states for this:

const [latitude, setLatitude] = useState("");
const [longitude, setLongitude] = useState("");
const [city, setCity] = useState("");

First: Request access to 'location' from user (this will have a POP-UP), by using this code and set state to Latitude and Longitude.

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();
}, []);

Second use https://www.weatherapi.com/ API to get City and other intel, based on Lat and Lon

API looks like this: https://api.weatherapi.com/v1/forecast.json?key=3e5e13fac8354c818de152831211305&q=53.3498053,-6.2603097&days=1&aqi=no&alerts=n

API with explanation: https://api.weatherapi.com/v1/forecast.json?key=3e5e13fac8354c818de152831211305&q=LATITUDE,LONGITUDE&days=1&aqi=no&alerts=n

Now call this API with latitude and longitude to get location data, including city. I am using useEffect as a trigger, so as soon as I get info on Latitude I call the api using axios and set City state to what ever comes out of the api object.

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]);

RESULT from 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"
},

Here is video to my youtube channel, where you can see a demo of this: https://youtu.be/gxcG8V3Fpbk

贪恋 2024-11-17 04:57:26

请检查以下答案。这对我有用

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;
}

Please check the below answer. It works for me

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;
}
秋叶绚丽 2024-11-17 04:57:26

尽量减少库的数量。

获取在其网站上使用 api 的密钥,然后在 http 请求中获取结果:

curl -i -H "key: YOUR_KEY" -X GET https://api.latlong.dev/lookup?lat=38.7447913&long=-9.1625173

Minimize the amount of libraries.

Get a key to use the api at their website and just get the result in a http request:

curl -i -H "key: YOUR_KEY" -X GET https://api.latlong.dev/lookup?lat=38.7447913&long=-9.1625173
牛↙奶布丁 2024-11-17 04:57:26

更新:我的解决方案不够准确,有时它会返回边界旁边的不正确的国家/地区坐标,或者当坐标位于海边时,它不会返回任何国家/地区。最后我选择了付费的 MapBox 反向地理编码 API。对 URL https://api.mapbox.com/geocoding/v5/mapbox.places/,.json?access_token= 的请求返回 geojson包含位置数据 - 地名、地区、国家。


原始答案

https://www.naturalearthdata.com/downloads/ 下载国​​家/地区 (我建议使用 1:10m 以获得更好的精度),从中生成 GeoJSON,并使用某种算法来检测给定坐标是否在国家/地区多边形内。

我使用以下步骤生成 GeoJSON 文件:

  1. 安装 Anaconda: https://www.anaconda.com/products/发行版
  2. 安装 gdal:conda install -c conda-forge gdal(使用提升的管理员权限,更多信息请参阅https://anaconda.org/conda-forge/gdal)
  3. 下载 1:10m 个国家/地区表格 https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/culture/ne_10m_admin_0_countries.zip,解压。
  4. 设置环境变量:setx PROJ_LIB C:\ProgramData\Anaconda3\Library\share\proj\
  5. 运行命令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 大约有 24MB。您也可以在此处下载。

C#:

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/which-country 并替换不太准确的 https://github.com/vkurchatkin/which-country/blob/master/lib/data.geo.json 由生成的。不过我没有测试过。

Update: My solution was not accurate enough, sometimes it returned incorrect country for coordinates right next to a border, or it would not return any country when the coordinates were at a seashore for example. At the end I went for paid MapBox reverse geocoding API. A request to URL https://api.mapbox.com/geocoding/v5/mapbox.places/<longitude>,<latitude>.json?access_token=<access token> returns geojson with location data - place name, region, country.


Original answer:

Download countries from https://www.naturalearthdata.com/downloads/ (I recommend using 1:10m for better accuracy), generate GeoJSON from it, and use some algorithm to detect if given coordinates are within a country polygon(s).

I used these steps to generate GeoJSON file:

  1. Install Anaconda: https://www.anaconda.com/products/distribution
  2. Install gdal: conda install -c conda-forge gdal (use elevated admin rights, more info on https://anaconda.org/conda-forge/gdal)
  3. Download 1:10m countries form https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_0_countries.zip, extract it.
  4. Set environment variable: setx PROJ_LIB C:\ProgramData\Anaconda3\Library\share\proj\
  5. Run command C:\ProgramData\Anaconda3\Library\bin\ogr2ogr.exe -f GeoJSON -t_srs crs:84 data.geo.json ne_10m_admin_0_countries.shp

This will generate data.geo.json which has around 24MB. You can alternatively download it here.

C#:

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(
quot;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; }
    }

Tests:

    [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: you can use https://github.com/vkurchatkin/which-country and replace the not so accurate https://github.com/vkurchatkin/which-country/blob/master/lib/data.geo.json by the generated one. I didn't test it though.

染火枫林 2024-11-17 04:57:26

根据之前的答案,我采用了使用 GeoNames 的想法。我需要一种方法来根据汽车仪表板的坐标获取近似城市,这需要大量请求(至少每秒 1 个),并且不应依赖于可靠的互联网连接。因为数据库可以离线使用,所以这对我来说是最好的解决方案。

在实现方面,我选择了 redis 作为后端数据库,并选择 GEO* 命令来进行查找。

基本上,您下载一个国家/地区信息文件(例如: http://download.geonames.org /export/dump/BE.zip),这是一个文本文件,其中的字段由制表符分隔。架构可在 http://download.geonames.org/export/dump 自述文件中找到。

对于每一行,您添加地理空间条目:

GEOADD geonames.main [lon] [lat] [name]

然后使用简单的 GEORADIUS 您可以根据您的位置获取最近的条目。这并不完全准确,只能给出近似值,但对于离线免费服务来说,这已经相当不错了。显然,一切都取决于您的需求。

我编写了一个脚本,下载整个欧洲并将其添加到 redis 中,并添加一些示例代码来查询数据库,全部用 python 编写,您可以在这里找到代码: https://github.com/maxux/magibux-dashboard/blob/master/backend/tools/geonames.py

对于整个欧洲(不包括俄罗斯,它不是我的需要,而且相当大),内存数据库约为 30 MB。

Based on previous answers, I took the idea using GeoNames. I needed a way to get approximation city based from a coordinate for Car Dashboard, this require lot of requests (at least 1 per second) and should not rely on a reliable internet connection. Because database is available offline, that was the best solution for me.

Implementation wise, I selected redis for the backend database and GEO* commands to do lookup.

Basically, you download a country info file (eg: http://download.geonames.org/export/dump/BE.zip) which is a text file with fields separated by tabs. Schema is available on http://download.geonames.org/export/dump readme.

For each line, you add the geospatial entry:

GEOADD geonames.main [lon] [lat] [name]

Then using a simple GEORADIUS you can get the nearest entry based on your location. This is not fully accurate and this only give an approximation but for an offline free service, this is pretty good. All depend of your needs obviously.

I wrote a script which download whole Europe and add it into redis and add some sample code to query database, all in python, you can found code here: https://github.com/maxux/magibux-dashboard/blob/master/backend/tools/geonames.py

For whole Europe (excluding Russia which was not needed for my needs and is quite large), in memory database is ~30 MB.

落花浅忆 2024-11-17 04:57:26

下载 https://download.geonames.org/export/dump/cities15000.zip< /a> 文件,并尝试类似这样的操作(避免 Web 服务并具有合理的性能):

def distance(x1,y1,x2,y2):
    import geopy.distance
    return geopy.distance.geodesic((x1, y1), (x2, y2)).mi

def loadCities():
    import csv
    idx = {}
    with open('cities15000.txt', newline = '') as cities:
        city_reader = csv.reader(cities, delimiter='\t')
        for city in city_reader:
            city_name = city[1]
            city_x = float(city[4])
            city_y = float(city[5])

            rec = {"name":city_name, "x":city_x, "y":city_y}
            x_i = int(city_x)
            if not x_i in idx:
                idx[x_i] = []
            idx[x_i].append(rec)
    return idx

def findCity(idx, loc_x, loc_y):
    arr = []
    x_i = int(loc_x)
    for city in idx[x_i] + idx[x_i-1] +  idx[x_i+1]:
        miles = distance(city["x"], city["y"], loc_x, loc_y)
        arr.append((miles, city["name"]))
    arr.sort()
    print(arr[0])

idx = loadCities()

findCity(idx, 37.38605, -122.08385) # Mountain View
findCity(idx, 35.7186,  139.7959)   # Asakusa

此逻辑使用非常简单的空间索引来避免对城市进行完整扫描。但这意味着垂直距离超过 70 英里的城市可能会从最近的城市搜索中跳过。

Download the https://download.geonames.org/export/dump/cities15000.zip file, and try something like this (avoids webservices and has reasonable performance):

def distance(x1,y1,x2,y2):
    import geopy.distance
    return geopy.distance.geodesic((x1, y1), (x2, y2)).mi

def loadCities():
    import csv
    idx = {}
    with open('cities15000.txt', newline = '') as cities:
        city_reader = csv.reader(cities, delimiter='\t')
        for city in city_reader:
            city_name = city[1]
            city_x = float(city[4])
            city_y = float(city[5])

            rec = {"name":city_name, "x":city_x, "y":city_y}
            x_i = int(city_x)
            if not x_i in idx:
                idx[x_i] = []
            idx[x_i].append(rec)
    return idx

def findCity(idx, loc_x, loc_y):
    arr = []
    x_i = int(loc_x)
    for city in idx[x_i] + idx[x_i-1] +  idx[x_i+1]:
        miles = distance(city["x"], city["y"], loc_x, loc_y)
        arr.append((miles, city["name"]))
    arr.sort()
    print(arr[0])

idx = loadCities()

findCity(idx, 37.38605, -122.08385) # Mountain View
findCity(idx, 35.7186,  139.7959)   # Asakusa

This logic uses a very simple spatial index to avoid a complete scan of the cities. But it means that cities more than 70 miles vertically might be skipped from the nearest city search.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文