コード例 #1
0
ファイル: SimpleCluster.cs プロジェクト: michaeloed/mgmgeo
 /// <summary>
 /// Constructor
 /// I would like to refer to the second constructor as the "copy" constructor.
 /// While iterating through the list I came up to a problem of interfering with object data using the new keyword for an copy of the instance and
 /// I needed a quick solution for a deep copy of an object.
 /// This maybe a bit lazyish to someone, but feel free to implement this any way you want.
 /// </summary>
 /// <param name="old">Cluster to copy</param>
 public SimpleCluster(SimpleCluster old)
 {
     ID             = old.ID;
     LAT_LON_CENTER = new PointDouble(old.LAT_LON_CENTER.X, old.LAT_LON_CENTER.Y);
     LAT_LON_LIST   = new List <PointDouble>(old.LAT_LON_LIST);
     NAMES          = new List <string>(old.NAMES);
 }
コード例 #2
0
ファイル: SimpleCluster.cs プロジェクト: michaeloed/mgmgeo
 /// <summary>
 /// This is the check I have used for testing if an item belongs to a cluster.
 /// In its essence, from the center point of the current cluster in the cluster dictionary list,
 /// create an rectangle area using the latitude and longitude sensitivities.
 /// The sensitivity is added left and right from the longitude, and up and down to the latitude.
 /// A fact that is worth mentioning is that this technique is used quite often in 2D games programming.
 /// </summary>
 /// <param name="home">cluster to check if imposter is include in</param>
 /// <param name="imposter">cluster to check if included in home</param>
 /// <param name="latitudeSensitivity">latitude outer bounds of the cluster square area</param>
 /// <param name="longitutdeSensitivity">longitude outer bounds of the cluster square area</param>
 /// <returns>true if item belongs to a cluster</returns>
 static public bool CheckIfInCluster(SimpleCluster home, SimpleCluster imposter, double latitudeSensitivity, double longitutdeSensitivity)
 {
     if ((home.LAT_LON_CENTER.X + latitudeSensitivity) > imposter.LAT_LON_CENTER.X &&
         (home.LAT_LON_CENTER.X - latitudeSensitivity) < imposter.LAT_LON_CENTER.X &&
         (home.LAT_LON_CENTER.Y + longitutdeSensitivity) > imposter.LAT_LON_CENTER.Y &&
         (home.LAT_LON_CENTER.Y - longitutdeSensitivity) < imposter.LAT_LON_CENTER.Y
         )
     {
         return(true);
     }
     return(false);
 }
コード例 #3
0
ファイル: SimpleCluster.cs プロジェクト: michaeloed/mgmgeo
        /// <summary>
        /// This small piece of code represents the generalized algorithm.
        /// The clusterList is loaded from some source, and we have the settings for the latitude and logitude sensitivity.
        /// This is the data that is needed to be passed to the ClusterTheData method which will, like the name says, cluster the data.
        /// As mentioned, you can surround that method with some kind of a loop if you need multiple clusterizations of the data.
        /// Technically we are going through two loops.
        /// One is going through the list of items that we received as a list of data objects and the second one is looping through the temporary dictionary list of clusters.
        /// Through each iteration of the first loop we alter the dictionary in some way.
        /// In its base, if the current item belongs to a cluster, join the data from the currently inspected item to the cluster,
        /// remove the old reference in the dictionary and add the combined object as the new cluster.
        /// In case there aren't any cluster that the current item belongs to, create a new item in the dictionary list.
        /// Every time a new cluster is created or the current one is altered, recalculate the current latitude and longitude center
        /// point of the cluster and set it as the new position in the coordinate system.
        ///
        /// I am assuming that you will need new unique IDs when dealing with the resulting list.
        /// The only important thing here is for the ID to be unique so the clustering would work.
        /// For the unique ID you could implement a function that gives the combined cluster a new ID based on your business logic.
        /// Another approach maybe assigning the IDs when looping through the resulting list after the clustering was done.
        /// In the end, you may have noticed that you can reiterate through the entire algorithm again with the resulting dictionary cluster list.
        /// Of course, that would mean that you are combining those clusters in a bigger cluster, so in accordance to that,
        /// you would have to change the sensitivity of the clusters, because with the fixed latitude and longitude sensitivities
        /// you would receive a result that is pretty much the same as previous one.
        /// The end result of the algorithm gives you a list of items which you can store and edit for later or immediate use.
        ///
        /// Complexity
        /// The time complexity shouldn't be too bad for this algorithm.
        /// You are passing through the entire list once and through each iteration you pass through the list of cluster.
        /// In worst case scenario it would be something around n*k! where the n is the number of items in the list and k is the number of clusters.
        /// In worst case scenario it would be n*n which doesn't make much sense because it would mean that data wasn't clustered at all and we don't want that now, do we?.
        /// </summary>
        /// <param name="clusterList">initial source, each element is a cluster</param>
        /// <param name="radius">radius for outer bounds of the cluster circle area (in degrees)</param>
        /// <returns>final list of clusters</returns>
        static public Dictionary <int, SimpleCluster> ClusterTheData(List <SimpleCluster> clusterList, double radius)
        {
            //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], radius))
                    {
                        //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);
                }
            }

            // Remove duplicates (filtering)
            foreach (KeyValuePair <int, SimpleCluster> pair in clusterDictionary)
            {
                pair.Value.RemoveDuplicates();
            }
            return(clusterDictionary);
        }
コード例 #4
0
ファイル: SimpleCluster.cs プロジェクト: michaeloed/mgmgeo
        /// <summary>
        /// As the method name suggests this is the place where combining of the clusters occurs.
        /// This idea is simple. Assign the home cluster as a combined cluster, add the data from the imposter cluster to the combined cluster.
        /// Probably some filtering of the data is required, and I am leaving that to the reader to figure that out and design it to his/hers needs.
        /// The important part is the re-calibration of the center point of the cluster.
        /// You have added new points to the cluster and because of that you have to recalculate the center point.
        /// For example, points might be on the one of the edges, and you are just making sure that the cluster is respecting that dynamically, by following the group.
        /// Also notice that the combined cluster receives the home cluster ID.
        /// This ID (even if not unique compared to the original list) is enough for the algorithm to function, and I didn't have the need of special IDs.
        /// </summary>
        /// <param name="home">cluster that will be combined with imposter</param>
        /// <param name="imposter">cluster that will be combined into home</param>
        /// <returns>compined cluster</returns>
        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 PointDouble(
                ((home.LAT_LON_CENTER.X + imposter.LAT_LON_CENTER.X) / 2.0),
                ((home.LAT_LON_CENTER.Y + imposter.LAT_LON_CENTER.Y) / 2.0));

            return(combinedCluster);
        }
コード例 #5
0
ファイル: SimpleCluster.cs プロジェクト: michaeloed/mgmgeo
 /// <summary>
 /// This is the check I have used for testing if an item belongs to a cluster.
 /// In its essence, from the center point of the current cluster in the cluster dictionary list,
 /// create an circle area using the radius.
 /// </summary>
 /// <param name="home">cluster to check if imposter is include in</param>
 /// <param name="imposter">cluster to check if included in home</param>
 /// <param name="radius">radius of the cluster circle</param>
 /// <returns>true if item belongs to a cluster</returns>
 static public bool CheckIfInCluster(SimpleCluster home, SimpleCluster imposter, double radius)
 {
     return(MyTools.PointInCircle(home.LAT_LON_CENTER.X, home.LAT_LON_CENTER.Y, radius, imposter.LAT_LON_CENTER.X, imposter.LAT_LON_CENTER.Y));
 }