彼此靠近的纬度、经度集群

Posted

技术标签:

【中文标题】彼此靠近的纬度、经度集群【英文标题】:Clusters of Lat, Long that are near to each other 【发布时间】:2018-04-16 07:59:31 【问题描述】:

我有一个场景,其中 N 个项目在 N 个位置(纬度、经度)交付。我想找到彼此靠近(100 米)交付的一组物品。比如说(Item1, Item9,...Item499)的交付使得它们之间的距离小于 100。 Item9 可以距离 Item499 超过 100 米,但如果它与组中的任何一个项目的距离小于 100 米,它将在该组中。

找到所有这样的组。 我希望有人指出正确的算法。然后我会努力的。首选语言是 C#

【问题讨论】:

【参考方案1】:

下面是我找到的解决这个问题的算法here

public class ClusterCreator

    public Dictionary<int, SimpleCluster> GetClusters(List<SimpleCluster> clusterList, int maxDistance)
    
        //LOAD DATA
        //var clusterList = new List<SimpleCluster>(); // LoadSimpleClusterList();
        //var latitudeSensitivity = 3;
        //var longitutdeSensitivity = 3;

        //CLUSTER THE DATA
        return ClusterTheData(clusterList, maxDistance);
    

    public Dictionary<int, SimpleCluster> ClusterTheData(List<SimpleCluster> clusterList, int maxDistance)
    
        //CLUSTER DICTIONARY
        var clusterDictionary = new Dictionary<int, SimpleCluster>();

        //Add the first node to the cluster list
        if (clusterList.Count > 0)
        
            clusterDictionary.Add(clusterList[0].ID, clusterList[0]);
        

        //ALGORITHM
        for (int i = 1; i < clusterList.Count; i++)
        
            SimpleCluster combinedCluster = null;
            SimpleCluster oldCluster = null;
            foreach (var clusterDict in clusterDictionary)
            
                //Check if the current item belongs to any of the existing clusters
                if (CheckIfInCluster(clusterDict.Value, clusterList[i], maxDistance))
                
                    //If it belongs to the cluster then combine them and copy the cluster to oldCluster variable;
                    combinedCluster = CombineClusters(clusterDict.Value, clusterList[i]);
                    oldCluster = new SimpleCluster(clusterDict.Value);
                
            

            //This check means that no suitable clusters were found to combine, so the current item in the list becomes a new cluster.
            if (combinedCluster == null)
            
                //Adding new cluster to the cluster dictionary 
                clusterDictionary.Add(clusterList[i].ID, clusterList[i]);
            
            else
            
                //We have created a combined cluster. Now it is time to remove the old cluster from the dictionary and instead of it add a new cluster.
                clusterDictionary.Remove(oldCluster.ID);
                clusterDictionary.Add(combinedCluster.ID, combinedCluster);
            
        
        return clusterDictionary;
    

    public static SimpleCluster CombineClusters(SimpleCluster home, SimpleCluster imposter)
    
        //Deep copy of the home object
        var combinedCluster = new SimpleCluster(home);
        combinedCluster.LAT_LON_LIST.AddRange(imposter.LAT_LON_LIST);
        combinedCluster.NAMES.AddRange(imposter.NAMES);

        //Combine the data of both clusters
        //combinedCluster.LAT_LON_LIST.AddRange(imposter.LAT_LON_LIST);
        //combinedCluster.NAMES.AddRange(imposter.NAMES);

        //Recalibrate the new center
        combinedCluster.LAT_LON_CENTER = new LAT_LONG
        
            LATITUDE = ((home.LAT_LON_CENTER.LATITUDE + imposter.LAT_LON_CENTER.LATITUDE) / 2.0),
            LONGITUDE = ((home.LAT_LON_CENTER.LONGITUDE + imposter.LAT_LON_CENTER.LONGITUDE) / 2.0)
        ;

        return combinedCluster;
    

    public bool CheckIfInCluster(SimpleCluster home, SimpleCluster imposter, int maxDistance)
    
        foreach (var item in home.LAT_LON_LIST)
        
            var sCoord = new GeoCoordinate(item.LATITUDE, item.LONGITUDE);
            var eCoord = new GeoCoordinate(imposter.LAT_LON_CENTER.LATITUDE, imposter.LAT_LON_CENTER.LONGITUDE);
            var distance = sCoord.GetDistanceTo(eCoord);
            if (distance <= maxDistance)
                return true;
        
        return false;


        //if ((home.LAT_LON_CENTER.LATITUDE + latitudeSensitivity) > imposter.LAT_LON_CENTER.LATITUDE
        //       && (home.LAT_LON_CENTER.LATITUDE - latitudeSensitivity) < imposter.LAT_LON_CENTER.LATITUDE
        //       && (home.LAT_LON_CENTER.LONGITUDE + longitutdeSensitivity) > imposter.LAT_LON_CENTER.LONGITUDE
        //       && (home.LAT_LON_CENTER.LONGITUDE - longitutdeSensitivity) < imposter.LAT_LON_CENTER.LONGITUDE
        //   )
        //
        //    return true;
        //
        //return false;
    


public class SimpleCluster

    #region Constructors
    public SimpleCluster(int id, string name, double latitude, double longitude)
    
        ID = id;
        LAT_LON_CENTER = new LAT_LONG
        
            LATITUDE = latitude,
            LONGITUDE = longitude
        ;
        NAMES = new List<string>();
        NAMES.Add(name);
        LAT_LON_LIST = new List<LAT_LONG>();
        LAT_LON_LIST.Add(LAT_LON_CENTER);
    

    public SimpleCluster(SimpleCluster old)
    
        ID = old.ID;
        LAT_LON_CENTER = new LAT_LONG
        
            LATITUDE = old.LAT_LON_CENTER.LATITUDE,
            LONGITUDE = old.LAT_LON_CENTER.LONGITUDE
        ;
        LAT_LON_LIST = new List<LAT_LONG>(old.LAT_LON_LIST);
        NAMES = new List<string>(old.NAMES);
    
    #endregion
    public int ID  get; set; 
    public List<string> NAMES  get; set; 
    public LAT_LONG LAT_LON_CENTER  get; set; 
    public List<LAT_LONG> LAT_LON_LIST  get; set; 


public class LAT_LONG

    public double LATITUDE  get; set; 
    public double LONGITUDE  get; set; 

【讨论】:

GeoCoordinate() 类在哪里? 没关系,我在System.Device.Location.GeoCoordinate 中找到了完整的.net,但是在.net Core 中有单独的包https://www.nuget.org/packages/GeoCoordinate/

以上是关于彼此靠近的纬度、经度集群的主要内容,如果未能解决你的问题,请参考以下文章

检查两条路线(以纬度和经度表示)是不是彼此相对

如果我正在做“靠近我”选项,我应该在数据库中存储经度/纬度吗?

来自给定纬度和经度 iphone 的短句

使用 MySQL SELECT AS 获取当前纬度/经度

功能缩放到集群关闭具有相同纬度/经度的多个标记的集群

使用纬度和经度iphone地图上两点之间的距离方程