private void ReduceResult(PublicTransportResult result, int count)
 {
     // find intersection bubbles
     for (int i = 0; i < Math.Min(count, result.Items.Count); i++)
     {
         var radiusKmBig = WalkingKmh * result.Items[i].TimeLeft / 60;
         for (int j = i + 1; j < result.Items.Count; j++)
         {
             var radiusKm = WalkingKmh * result.Items[j].TimeLeft / 60;
             if ((radiusKmBig - radiusKm) * (radiusKmBig - radiusKm) > result.Items[j].Center.DistanceInKmSquaredTo(result.Items[i].Center))
             {
                 result.Items.RemoveAt(j);
                 j--;
             }
         }
     }
 }
        private PublicTransportResult Calculate(LatLng startPosition, double maxTime, List <TravelTimeListPoint> points = null)
        {
            var stopQueue = new PriorityQueue <TravelTimeAlgorithmItem>();
            var stopList  = new Dictionary <int, TravelTimeAlgorithmItem>();


            // start search
            var startItem = new TravelTimeAlgorithmItem {
                Stop = new PublicTransportConnection()
                {
                    LatLng = startPosition, Cost = 0, ID = 0
                }, TotalCost = 0
            };

            stopQueue.Enqueue(startItem, 0);
            stopList[0] = startItem;

            while (stopQueue.Count > 0)
            {
                var stop = stopQueue.Dequeue();
                if (stop.TotalCost >= maxTime)
                {
                    break;
                }

                double timeLeft = maxTime - stop.TotalCost;

                List <PublicTransportConnection> reachableStops;
                if (stop.Stop.ID > 0)
                {
                    reachableStops = _dataProvider.GetReachableByTransport(stop.Stop.ID, timeLeft);
                }
                else
                {
                    // calculate approximate radius - its not exact as lat/lng circle cant be a perfect circle
                    double radius = LatLng.GetWalkingDistanceLatLng(startPosition.Lat, maxTime, WalkingKmh);
                    reachableStops = _dataProvider.GetInRange(startPosition, radius);
                }

                foreach (var reachableStop in reachableStops)
                {
                    double newTotalCost = stop.TotalCost + reachableStop.Cost;

                    TravelTimeAlgorithmItem existingStop;
                    if (stopList.TryGetValue(reachableStop.ID, out existingStop))
                    {
                        // update it - if cost smaller
                        if (newTotalCost < existingStop.TotalCost)
                        {
                            stopQueue.Remove(existingStop, existingStop.TotalCost);

                            existingStop.PreviousItem = stop;
                            existingStop.TotalCost    = newTotalCost;

                            stopQueue.Enqueue(existingStop, existingStop.TotalCost);
                        }
                    }
                    else
                    {
                        if (newTotalCost < maxTime)
                        {
                            // add it - its new
                            var newStop = new TravelTimeAlgorithmItem
                            {
                                PreviousItem = stop,
                                Stop         = reachableStop,
                                TotalCost    = newTotalCost
                            };

                            stopQueue.Enqueue(newStop, newStop.TotalCost);
                            stopList[reachableStop.ID] = newStop;
                        }
                    }
                }
            }

            PublicTransportResult result = new PublicTransportResult();

            foreach (var stop in stopList.Values.OrderBy(x => x.TotalCost))
            {
                result.Items.Add(new TravelTimeCircle {
                    Center = stop.Stop.LatLng, TimeLeft = maxTime - stop.TotalCost
                });

                // check if this point is closest to stop
                if (points != null)
                {
                    points.ForEach(p =>
                    {
                        var time = 60 * p.Coords.DistanceInKmTo(stop.Stop.LatLng) / WalkingKmh + stop.TotalCost;
                        if (p.Time > time)
                        {
                            p.Time = time;
                        }
                    });
                }
            }
            return(result);
        }