public IList<MapPoint> RunCluster()
        {
            // Skip points outside the grid, not visible to user then skip those
            //IList<MapPoint> filtered = ClusterInfo.DoFilterData(this._jsonReceive.Zoomlevel) // TODO: by kit
            //    ? FilterUtil.FilterDataByViewport(this.points, Grid)
            //    : this.points;

            IList<MapPoint> filtered = this.points;

            // Put points in buckets
            foreach (var p in filtered)
            {
                var idxy = GetPointMappedIds(p, Grid, DeltaX, DeltaY);
                var idx = idxy[0];
                var idy = idxy[1];

                // Bucket id
                var id = GetId(idx, idy);

                // Bucket exists, add point
                if (BucketsLookup.ContainsKey(id))
                {
                    BucketsLookup[id].Points.Add(p);
                }
                // New bucket, create and add point
                else
                {
                    var bucket = new Bucket(idx, idy, id);
                    bucket.Points.Add(p);
                    BucketsLookup.Add(id, bucket);
                }
            }

            // Calculate centroid for all buckets
            SetCentroidForAllBuckets(BucketsLookup.Values);

            // Merge if gridpoint is to close
            if (GmcSettings.Get.DoMergeGridIfCentroidsAreCloseToEachOther) MergeClustersGrid();

            if (GmcSettings.Get.DoUpdateAllCentroidsToNearestContainingPoint) UpdateAllCentroidsToNearestContainingPoint();

            // Check again
            // Merge if gridpoint is to close
            if (GmcSettings.Get.DoMergeGridIfCentroidsAreCloseToEachOther
                && GmcSettings.Get.DoUpdateAllCentroidsToNearestContainingPoint)
            {
                MergeClustersGrid();
                // And again set centroid to closest point in bucket 
                UpdateAllCentroidsToNearestContainingPoint();
            }

            return GetClusterResult(Grid);
        }
        // Update centroid location to nearest point, 
        // e.g. if you want to show cluster point on a real existing point area
        // O(n)
        public void UpdateCentroidToNearestContainingPoint(Bucket bucket)
        {
            if (bucket == null || bucket.Centroid == null ||
                bucket.Points == null || bucket.Points.Count == 0)
            {
                return;
            }

            var closest = GetClosestPoint(bucket.Centroid, bucket.Points);
            bucket.Centroid.X = closest.X; // no normalize, points are already normalized by default
            bucket.Centroid.Y = closest.Y;
        }