private void drawPlaces(Canvas canvas, double pixelsPerDegree, double offset) { try { if (OrientationManager.HasLocation && NearbyPlaces != null) { lock (NearbyPlaces) { var userLocation = OrientationManager.Location; var latitude1 = userLocation.Latitude; var longitude1 = userLocation.Longitude; _allBounds.Clear(); // Loop over the list of nearby places (those within 10 km of the user's current // location), and compute the relative bearing from the user's location to the // place's location. This determines the position on the compass view where the // pin will be drawn. foreach (var place in NearbyPlaces) { var latitude2 = place.Latitiude; var longitude2 = place.Longitude; var bearing = MathUtils.getBearing(latitude1, longitude1, latitude2, longitude2); var name = place.Name; var distanceKm = MathUtils.getDistance(latitude1, longitude1, latitude2, longitude2); var text = this.Context.Resources.GetString( Resource.String.place_text_format, name, _distanceFormat.Format(distanceKm)); // Measure the text and offset the text bounds to the location where the text // will finally be drawn. var textBounds = new Rect(); _placePaint.GetTextBounds(text, 0, text.Length, textBounds); textBounds.OffsetTo((int)(offset + bearing * pixelsPerDegree + PLACE_PIN_WIDTH / 2 + PLACE_TEXT_MARGIN), canvas.Height / 2 - (int)PLACE_TEXT_HEIGHT); // Extend the bounds rectangle to include the pin icon and a small margin // to the right of the text, for the overlap calculations below. textBounds.Left -= (int)(PLACE_PIN_WIDTH + PLACE_TEXT_MARGIN); textBounds.Right += (int)PLACE_TEXT_MARGIN; // This loop attempts to find the best vertical position for the string by // starting at the bottom of the display and checking to see if it overlaps // with any other labels that were already drawn. If there is an overlap, we // move up and check again, repeating this process until we find a vertical // position where there is no overlap, or when we reach the limit on // overlapping place names. bool intersects; var numberOfTries = 0; do { intersects = false; numberOfTries++; textBounds.Offset(0, (int)-(PLACE_TEXT_HEIGHT + PLACE_TEXT_LEADING)); foreach (var existing in _allBounds) { if (Rect.Intersects(existing, textBounds)) { intersects = true; break; } } } while (intersects && numberOfTries <= MAX_OVERLAPPING_PLACE_NAMES); // Only draw the string if it would not go high enough to overlap the compass // directions. This means some places may not be drawn, even if they're nearby. if (numberOfTries <= MAX_OVERLAPPING_PLACE_NAMES) { _allBounds.Add(textBounds); canvas.DrawBitmap(_placeBitmap, (float)(offset + bearing * pixelsPerDegree - PLACE_PIN_WIDTH / 2), textBounds.Top + 2, _paint); canvas.DrawText( text, (float)(offset + bearing * pixelsPerDegree + PLACE_PIN_WIDTH / 2 + PLACE_TEXT_MARGIN), (float)(textBounds.Top + PLACE_TEXT_HEIGHT), _placePaint); } } } } } catch (Exception e) { Log.Debug("Exception", e.Message); } }