private static void UpdateCurrentLocation(DependencyObject d, DependencyPropertyChangedEventArgs e) { var map = d as Map; var currentGeoCoordinate = e.NewValue as GeoCoordinate; if (currentGeoCoordinate != null && map != null) { DataTemplate currentLocationPushpinTemplate = GetCurrentLocationPushpinTemplate(d); map.Dispatcher.BeginInvoke( () => { // Remove layer which hosts pushpins var removeLayer = map.Layers.FirstOrDefault(x => x.All(y => y.Content is UserLocationMarker)); map.Layers.Remove(removeLayer); // Create new layer with current location pin var layer = new MapLayer { new MapOverlay { GeoCoordinate = currentGeoCoordinate, Content = new UserLocationMarker(currentGeoCoordinate), ContentTemplate = currentLocationPushpinTemplate, PositionOrigin = new System.Windows.Point(0.5, 0.5) } }; if (layer.Any()) { map.Layers.Insert(CurrentLocationLayerIndex, layer); } }); } }
private static void UpdateItemsSource(DependencyObject d, DependencyPropertyChangedEventArgs e) { var map = d as Map; var newPushPinCollection = e.NewValue as IEnumerable <IClusteredGeoObject>; if (newPushPinCollection != null && newPushPinCollection.Any() && map != null) { // Read dependency properties var pushpinTemplate = GetPushpinTemplate(d); var clusterPushpinTemplate = GetClusterTemplate(d); ////var clusteringDistance = GetClusteringDistance(d); // Perform clustering var visibleAreaTopLeft = map.ConvertViewportPointToGeoCoordinate(new Point(0, 0)); var visibleAreaBottomRight = map.ConvertViewportPointToGeoCoordinate(new Point(map.ActualWidth, map.ActualHeight)); var boundingRectangle = LocationRect.CreateLocationRect(visibleAreaTopLeft.ToPosition(), visibleAreaBottomRight.ToPosition()); //var clusterer = new SectorClusterer<IClusteredGeoObject>(); var clusterer = new RectangularClusterer <IClusteredGeoObject>(); //var stopwatch = new Stopwatch(); //stopwatch.Start(); IEnumerable <IClusteredLocation <IClusteredGeoObject> > clusteredLocations = clusterer.Cluster(newPushPinCollection, boundingRectangle, map.ZoomLevel); if (map.ZoomLevel >= 18) { clusteredLocations = clusteredLocations.SelectMany(x => x.ClusteredItems).Select( clusteredGeoObject => { var rect = new ClusteredLocationRect <IClusteredGeoObject>(boundingRectangle); rect.Add(clusteredGeoObject); return(rect); }).ToList(); } //stopwatch.Stop(); //Console.WriteLine("UPDATED CLUSTER IN {0}ms", stopwatch.ElapsedMilliseconds); // Update map on UI map.Dispatcher.BeginInvoke( () => { // Remove layer which hosts pushpins var clusteredPushpinLayer = map.Layers.FirstOrDefault(x => x.All(y => y.Content is IClusteredLocation <IClusteredGeoObject>)); map.Layers.Remove(clusteredPushpinLayer); // Create new layer var layer = new MapLayer(); // The descending-by-latitude ordering makes sure the pins are not overlapping eachother Position lastGeoCoordinate = Position.Unknown; foreach (var pushPinModel in clusteredLocations.OrderByDescending(p => p.Location.Latitude)) { var mapOverlay = new MapOverlay { GeoCoordinate = new GeoCoordinate(pushPinModel.Location.Latitude, pushPinModel.Location.Longitude), Content = pushPinModel }; if (pushPinModel.IsClustered) { mapOverlay.ContentTemplate = clusterPushpinTemplate; mapOverlay.PositionOrigin = new System.Windows.Point(0.5, 0.5); } else { mapOverlay.ContentTemplate = pushpinTemplate; // In case two/more pins have the same GPS position, we add a random offset to longitude/latitude. if (Math.Abs(pushPinModel.Location.Latitude - lastGeoCoordinate.Latitude) < 0.00005 && Math.Abs(pushPinModel.Location.Longitude - lastGeoCoordinate.Longitude) < 0.00005) { mapOverlay.GeoCoordinate = lastGeoCoordinate.WithRandomOffset().ToGeoCoordinate(); } lastGeoCoordinate = pushPinModel.Location; } layer.Add(mapOverlay); } // Finally, add all items (pushpins, clusters and current location) to the map. if (layer.Any()) { map.Layers.Insert(ItemsSourceLayerIndex, layer); } }); } }