/// <summary>
        /// clusters retrieved pins geographically 
        /// </summary>
        /// <param name="pins"></param>
        /// <param name="zoomLevel"></param>
        /// <param name="clusterWidth"></param>
        /// <param name="clusterHeight"></param>
        /// <returns></returns>
        public List<ClusteredPin> cluster(List<ClusteredPin> pins, int zoomLevel, int clusterWidth, int clusterHeight)
        {
            //sort pins - must be ordered correctly.
            PinXYComparer pinComparer = new PinXYComparer();
            pins.Sort(pinComparer);

            List<ClusteredPin> clusteredPins = new List<ClusteredPin>();

            for (int index = 0; index < pins.Count; index++)
            {

                    if ((!pins[index].IsClustered)) //skip already clusted pins
                    {
                        ClusteredPin currentClusterPin = new ClusteredPin();
                        //create our cluster object and add the first pin
                        currentClusterPin.AddPin(pins[index]);
                        pins[index].IsClustered = true;

                        //look backwards in the list for any points within the range that are not already grouped, as the points are in order we exit as soon as it exceeds the range.
                        addPinsWithinRange(pins, index, -1, currentClusterPin, zoomLevel, clusterWidth, clusterHeight);

                        //look forwards in the list for any points within the range, again we short out.
                        addPinsWithinRange(pins, index, 1, currentClusterPin, zoomLevel, clusterWidth, clusterHeight);

                        clusteredPins.Add(currentClusterPin);
                    }

            }
            return clusteredPins;
        }
        /// <summary>
        /// clusters retrieved pins geographically
        /// </summary>
        /// <param name="pins"></param>
        /// <param name="zoomLevel"></param>
        /// <param name="clusterWidth"></param>
        /// <param name="clusterHeight"></param>
        /// <returns></returns>
        public List <ClusteredPin> cluster(List <ClusteredPin> pins, int zoomLevel, int clusterWidth, int clusterHeight)
        {
            //sort pins - must be ordered correctly.
            PinXYComparer pinComparer = new PinXYComparer();

            pins.Sort(pinComparer);

            List <ClusteredPin> clusteredPins = new List <ClusteredPin>();

            for (int index = 0; index < pins.Count; index++)
            {
                if ((!pins[index].IsClustered))     //skip already clusted pins
                {
                    ClusteredPin currentClusterPin = new ClusteredPin();
                    //create our cluster object and add the first pin
                    currentClusterPin.AddPin(pins[index]);
                    pins[index].IsClustered = true;

                    //look backwards in the list for any points within the range that are not already grouped, as the points are in order we exit as soon as it exceeds the range.
                    addPinsWithinRange(pins, index, -1, currentClusterPin, zoomLevel, clusterWidth, clusterHeight);

                    //look forwards in the list for any points within the range, again we short out.
                    addPinsWithinRange(pins, index, 1, currentClusterPin, zoomLevel, clusterWidth, clusterHeight);

                    clusteredPins.Add(currentClusterPin);
                }
            }
            return(clusteredPins);
        }
        /// <summary>
        /// clusteres visually
        /// </summary>
        /// <param name="clusteredpins"></param>
        /// <param name="zoomLevel"></param>
        /// <param name="minClusterDistance"></param>
        /// <returns></returns>
        private List <ClusteredPin> reduceClusterDensity(List <ClusteredPin> clusteredpins, int zoomLevel, int minClusterDistance)
        {
            PinXYComparer pinComparer = new PinXYComparer();

            clusteredpins.Sort(pinComparer);
            List <ClusteredPin> pins = new List <ClusteredPin>();

            //reset flag
            //Only cluster already clusteredpoints and do not cluster Alerts
            for (int j = 0; j < clusteredpins.Count; j++)
            {
                if (clusteredpins[j].PinType == "clusterpoint")
                {
                    clusteredpins[j].IsClustered = false;
                }
                else
                {
                    clusteredpins[j].IsClustered = true;
                    pins.Add(clusteredpins[j]);
                }
            }
            for (int i = 0; i < clusteredpins.Count; i++)
            {
                if ((!clusteredpins[i].IsClustered)) //skip already clusted pins
                {
                    ClusteredPin currentClusterPin = new ClusteredPin();
                    //create our cluster object and add the first pin
                    currentClusterPin.AddPin(clusteredpins[i]);


                    //look backwards in the list for any points within the range that are not already grouped, as the points are in order we exit as soon as it exceeds the range.
                    addClusteredPinsWithinRange(clusteredpins, i, -1, clusteredpins[i], zoomLevel, minClusterDistance);

                    //look forwards in the list for any points within the range, again we short out.
                    addClusteredPinsWithinRange(clusteredpins, i, 1, clusteredpins[i], zoomLevel, minClusterDistance);

                    clusteredpins[i].IsClustered = true;

                    pins.Add(clusteredpins[i]);
                }
            }
            return(pins);
        }
        /// <summary>
        /// Adds pins to nearby cluster for theme
        /// </summary>
        /// <param name="pins"></param>
        /// <param name="index"></param>
        /// <param name="direction"></param>
        /// <param name="currentClusterPin"></param>
        /// <param name="zoomLevel"></param>
        /// <param name="themeParameter"></param>
        private void addPinsWithinRange(List <ClusteredPin> pins, int index, int direction, ClusteredPin currentClusterPin, int zoomLevel, string themeParameter)
        {
            bool finished = false;
            int  searchindex;

            searchindex = index + direction;
            while (!finished)
            {
                if (searchindex >= pins.Count || searchindex < 0)
                {
                    finished = true;
                }
                else
                {
                    if (!pins[searchindex].IsClustered)
                    {
                        // if (pins[searchindex].ThemeParameter == themeParameter)//only cluster if parameter are the same
                        //{
                        if (Math.Abs(pins[searchindex].GetPixelX(zoomLevel) - pins[index].GetPixelX(zoomLevel)) < CLUSTERWIDTH)      //within the same x range
                        {
                            if (Math.Abs(pins[searchindex].GetPixelY(zoomLevel) - pins[index].GetPixelY(zoomLevel)) < CLUSTERHEIGHT) //within the same y range = cluster needed
                            {
                                //add to cluster
                                currentClusterPin.AddPin(pins[searchindex]);

                                //stop any further clustering
                                pins[searchindex].IsClustered = true;
                            }
                        }
                        else
                        {
                            finished = true;
                        }
                        //}
                    }
                    ;
                    searchindex += direction;
                }
            }
        }
        /// <summary>
        /// Adds pins to nearby cluster
        /// </summary>
        /// <param name="pins"></param>
        /// <param name="index"></param>
        /// <param name="direction"></param>
        /// <param name="currentClusterPin"></param>
        /// <param name="zoomLevel"></param>
        /// <param name="clusterWidth"></param>
        /// <param name="clusterHeight"></param>
        private void addPinsWithinRange(List <ClusteredPin> pins, int index, int direction, ClusteredPin currentClusterPin, int zoomLevel, int clusterWidth, int clusterHeight)
        {
            bool finished = false;
            int  searchindex;

            searchindex = index + direction;
            while (!finished)
            {
                if (searchindex >= pins.Count || searchindex < 0)
                {
                    finished = true;
                }
                else
                {
                    if (!pins[searchindex].IsClustered)
                    {
                        if (Math.Abs(pins[searchindex].GetPixelX(zoomLevel) - pins[index].GetPixelX(zoomLevel)) < clusterWidth)      //within the same x range
                        {
                            if (Math.Abs(pins[searchindex].GetPixelY(zoomLevel) - pins[index].GetPixelY(zoomLevel)) < clusterHeight) //within the same y range = cluster needed
                            {
                                //add to cluster
                                currentClusterPin.AddPin(pins[searchindex]);

                                //stop any further clustering
                                pins[searchindex].IsClustered = true;
                            }
                        }
                        else
                        {
                            finished = true;
                        }
                    }
                    ;
                    searchindex += direction;
                }
            }
        }
        /// <summary>
        /// clusteres visually 
        /// </summary>
        /// <param name="clusteredpins"></param>
        /// <param name="zoomLevel"></param>
        /// <param name="minClusterDistance"></param>
        /// <returns></returns>
        private List<ClusteredPin> reduceClusterDensity(List<ClusteredPin> clusteredpins, int zoomLevel, int minClusterDistance)
        {
            PinXYComparer pinComparer = new PinXYComparer();
            clusteredpins.Sort(pinComparer);
            List<ClusteredPin> pins = new List<ClusteredPin>();
            //reset flag
            //Only cluster already clusteredpoints and do not cluster Alerts
            for (int j = 0; j < clusteredpins.Count; j++)
            {
                if (clusteredpins[j].PinType == "clusterpoint")
                {
                    clusteredpins[j].IsClustered = false;
                }
                else
                {
                    clusteredpins[j].IsClustered = true;
                    pins.Add(clusteredpins[j]);
                }
            }
            for (int i = 0; i < clusteredpins.Count; i++)
            {

                if ((!clusteredpins[i].IsClustered)) //skip already clusted pins
                {
                    ClusteredPin currentClusterPin = new ClusteredPin();
                    //create our cluster object and add the first pin
                    currentClusterPin.AddPin(clusteredpins[i]);

                    //look backwards in the list for any points within the range that are not already grouped, as the points are in order we exit as soon as it exceeds the range.
                    addClusteredPinsWithinRange(clusteredpins, i, -1, clusteredpins[i], zoomLevel, minClusterDistance);

                    //look forwards in the list for any points within the range, again we short out.
                    addClusteredPinsWithinRange(clusteredpins, i, 1, clusteredpins[i], zoomLevel, minClusterDistance);

                    clusteredpins[i].IsClustered = true;

                    pins.Add(clusteredpins[i]);
                }

            }
            return pins;
        }
        /// <summary>
        /// Adds pins to nearby cluster for theme
        /// </summary>
        /// <param name="pins"></param>
        /// <param name="index"></param>
        /// <param name="direction"></param>
        /// <param name="currentClusterPin"></param>
        /// <param name="zoomLevel"></param>
        /// <param name="themeParameter"></param>
        private void addPinsWithinRange(List<ClusteredPin> pins, int index, int direction, ClusteredPin currentClusterPin, int zoomLevel, string themeParameter)
        {
            bool finished = false;
            int searchindex;
            searchindex = index + direction;
            while (!finished)
            {
                if (searchindex >= pins.Count || searchindex < 0)
                {
                    finished = true;
                }
                else
                {
                    if (!pins[searchindex].IsClustered)
                    {
                       // if (pins[searchindex].ThemeParameter == themeParameter)//only cluster if parameter are the same
                        //{
                            if (Math.Abs(pins[searchindex].GetPixelX(zoomLevel) - pins[index].GetPixelX(zoomLevel)) < CLUSTERWIDTH) //within the same x range
                            {
                                if (Math.Abs(pins[searchindex].GetPixelY(zoomLevel) - pins[index].GetPixelY(zoomLevel)) < CLUSTERHEIGHT) //within the same y range = cluster needed
                                {
                                    //add to cluster
                                    currentClusterPin.AddPin(pins[searchindex]);

                                    //stop any further clustering
                                    pins[searchindex].IsClustered = true;
                                }
                            }
                            else
                            {
                                finished = true;
                            }
                        //}
                    };
                    searchindex += direction;
                }
            }
        }
        /// <summary>
        /// Adds pins to nearby cluster
        /// </summary>
        /// <param name="pins"></param>
        /// <param name="index"></param>
        /// <param name="direction"></param>
        /// <param name="currentClusterPin"></param>
        /// <param name="zoomLevel"></param>
        /// <param name="clusterWidth"></param>
        /// <param name="clusterHeight"></param>
        private void addPinsWithinRange(List<ClusteredPin> pins, int index, int direction, ClusteredPin currentClusterPin, int zoomLevel, int clusterWidth, int clusterHeight)
        {
            bool finished = false;
            int searchindex;
            searchindex = index + direction;
            while (!finished)
            {
                if (searchindex >= pins.Count || searchindex < 0)
                {
                    finished = true;
                }
                else
                {
                    if (!pins[searchindex].IsClustered)
                    {
                        if (Math.Abs(pins[searchindex].GetPixelX(zoomLevel) - pins[index].GetPixelX(zoomLevel)) < clusterWidth) //within the same x range
                        {
                            if (Math.Abs(pins[searchindex].GetPixelY(zoomLevel) - pins[index].GetPixelY(zoomLevel)) < clusterHeight) //within the same y range = cluster needed
                            {
                                //add to cluster
                                currentClusterPin.AddPin(pins[searchindex]);

                                //stop any further clustering
                                pins[searchindex].IsClustered = true;
                            }
                        }
                        else
                        {
                            finished = true;
                        }
                    };
                    searchindex += direction;
                }
            }
        }