Displaying maps on iOS often is not enough. We would like to show some kind of tips, identifiers or other objects.

If u deal with not only displayable information but also provides functionality for rich editing or creating/managing something - drawing different shapes can be an essential part of this process.

Previously, I already cover few subjects related to the map, and in this article, I would like to show how we can draw a circle on the map using polyline only.

Previous posts related to tasks with map:

The problem

In the current project, we are using maps extensively, but the SDK that we use has some limited out-of-the-box functionality, and drawing the circle is not one of them. What can be done - is just drawing a filled circle, line or polygon. :[

The purpose of such function can be simple hightlight of some circular zone (for example selected spot):

design



Left side: unselected blue circle and selected white and on right - blue circle selected, white unselected

The solution

The solution to the problem can be a circle drawn with some kind of simplicity.

The good question here - is “how the circle can be drawn on the screen, in the simplest way possible?”. The answer is in the next picture.

how the circle can be drawn on the screen, in the simplest way?



This image is from the page Simple Circle Algorithms

Also, the equation of the circle can helps us a lot:

equation of the circle



Unfortunately, I’m not a math guy… so I just looked for some existing algorithms for drawing circles and found a few already well-explained.

All I need to do - is just use them in the code - generate the points and draw a polyline using a set of these points.

The possible solution could be next:

public static func circlePolylinePointsWithCenterAt(
    point: CLLocationCoordinate2D,
    radiusInMeters: Double,
    pointsCount: Int = 72
  ) -> [CLLocationCoordinate2D] {
    let earthsRadius = point.earthRadius()
    let radiusLatitude = (radiusInMeters / earthsRadius).radiansToDegrees
    let radiusLongitude = radiusLatitude / cos(point.latitude.degreesToRadians)
    
    var circlePoints: [CLLocationCoordinate2D] = []
    for i in 0... pointsCount {
      let theta = Double.pi * (Double(i) / Double(pointsCount/2))
      let longitudePoint = point.longitude + (radiusLongitude * cos(theta))
      let latitudePoint = point.latitude + (radiusLatitude * sin(theta))
      circlePoints.append(.init(latitude: latitudePoint, longitude: longitudePoint))
    }
    
    return circle points
}

where the Earch radius (as described in prev post):

extension CLLocationCoordinate2D {
  
  public func earthRadius() -> CLLocationDistance {
    let earthRadiusInMetersAtSeaLevel = 6378137.0
    let earthRadiusInMetersAtPole = 6356752.314
    
    let r1 = earthRadiusInMetersAtSeaLevel
    let r2 = earthRadiusInMetersAtPole
    let beta = latitude.degreesToRadians
    
    let earthRadiuseAtGivenLatitude = (
      ( pow(pow(r1, 2) * cos(beta), 2) + pow(pow(r2, 2) * sin(beta), 2) ) /
        ( pow(r1 * cos(beta), 2) + pow(r2 * sin(beta), 2) )
    )
    .squareRoot()
    
    return earthRadiuseAtGivenLatitude
  }
}

Then, we can just draw a polyline using the array of the CLLocationCoordinate2D.

The result:

the result



changing the pointsCount can leads to the change of the quality and performance, so try it out and select the trade-off most suitable for u.

Resources