首页 > 解决方案 > 在地理坐标对列表中查找最近的城市

问题描述

假设有一个包含城市及其坐标的 JSON 文件。

  {
    "country": "AT",
    "name": "Fladnitz im Raabtal",
    "lat": "46.99167",
    "lng": "15.78528"
  }

我正在获取用户经度和纬度,例如纬度 46.98 和经度 15.77。现在我想在 JSON 中搜索城市和国家(在本例中为“名称”和“国家”)。但是值并不完全匹配。如何从 JSON 中获取最接近的纬度和经度值?

这是位置类

  public class Location
  {
    public string Country { get; set; }
    [JsonPropertyName("name")]
    public string City { get; set; }
    [JsonPropertyName("lat")]
    public double Latitude { get; set; }
    [JsonPropertyName("lng")]
    public double Longitude { get; set; }
  }

这是用于过滤的 LINQ,但我不知道如何执行“在此处获取最接近的数字操作”?

      City.Text = this.Locations.Where(w => w.Latitude == lat && w.Longitude == lng)
                                .Select(s => s.City)
                                .DefaultIfEmpty("Unknown")
                                .First()
                                .ToString();

标签: c#

解决方案


有两种方法可以通过不精确的坐标找到位置。第一个解决方案是使用坐标方差,第二个是使用距离。每个人都有自己的好处,所以要明智地选择。

解决方案 1: 由于坐标不完全匹配,我们必须提出允许的方差。对于这个例子,我将使用 0.001 方差来表示经纬度。

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
                    
public class Program {
    public class Location {
    public string Country { get; set; }
    public string City { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
    public Location(string Country_, string City_, double Latitude_, double Longitude_){
        this.Country = Country_;
        this.City = City_;
        this.Latitude = Latitude_;
        this.Longitude = Longitude_;
    }
  }
    
    public static void Main() {
        List<Location> locations = new List<Location>();
        locations.Add(new Location("USA", "Daytona Beach", 29.2108, 81.0228));
        locations.Add(new Location("USA", "Miami", 25.7617,80.1918));
        locations.Add(new Location("USA", "Jacksonville", 30.3322,81.6557));
        
        double variance = 0.001;
        
        double searchLat = 29.21; //unexact lat of daytona beach
        Console.WriteLine(
            locations.Where(w => w.Latitude >= searchLat - variance && w.Latitude <= searchLat + variance)
            .Select(s => s.City)
            .DefaultIfEmpty("Unknown")
            .First()
            .ToString()
        );
        
    }
}

解决方案 2:我真的不建议这样做,因为这可能会很繁重,但距离实际上很重要。您需要使用搜索坐标遍历每个位置坐标并选择最小距离。从这里翻录的坐标方法:计算两个纬度和经度地理坐标之间的距离

using System;
using System.Collections.Generic;
using System.Linq;
public class Program {
    public class Location {
        public string Country { get; set; }
        public string City { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
        public Location(string Country_, string City_, double Latitude_, double Longitude_) {
            this.Country = Country_;
            this.City = City_;
            this.Latitude = Latitude_;
            this.Longitude = Longitude_;
        }
    }

    static void Main(string[] args) {
        List<Location> locations = new List<Location>();
        locations.Add(new Location("USA", "Daytona Beach", 29.2108, 81.0228));
        locations.Add(new Location("USA", "Miami", 25.7617, 80.1918));
        locations.Add(new Location("USA", "Jacksonville", 30.3322, 81.6557));

        double searchLat = 30;
        double searchLong = 81;

        Dictionary<double, List<Location>> distances = new Dictionary<double, List<Location>>();

        locations.ForEach(location => {
            double distance = Program.GetDistance(location.Latitude, location.Longitude, searchLat, searchLong);
            if(distances.ContainsKey(distance)){
                distances[distance].Add(location);
            }else{
                distances.Add(distance, new List<Location>() { location });
            }
        });

        double closestDistanceFromSearch = distances.Keys.OrderBy(k => k).First();

        Console.WriteLine(
            distances[distances.Keys.OrderBy(k => k).First()].First().City
        );

    }
    public static double GetDistance(double latitude, double longitude, double otherLatitude, double otherLongitude) {
        var d1 = latitude * (Math.PI / 180.0);
        var num1 = longitude * (Math.PI / 180.0);
        var d2 = otherLatitude * (Math.PI / 180.0);
        var num2 = otherLongitude * (Math.PI / 180.0) - num1;
        var d3 = Math.Pow(Math.Sin((d2 - d1) / 2.0), 2.0) + Math.Cos(d1) * Math.Cos(d2) * Math.Pow(Math.Sin(num2 / 2.0), 2.0);

        return 6376500.0 * (2.0 * Math.Atan2(Math.Sqrt(d3), Math.Sqrt(1.0 - d3)));
    }
}

推荐阅读