Get a continent from longitude-latitude

For a project I’m working on I needed to know if a point (latitude,longitude) was in a continent, and if so, which one!

To do this, first I set up a Continent enum to work with, making it a String (to easily print) and CaseIterable (to iterate through the cases later):

enum Continent:String,CaseIterable {

    case australia
    case northAmerica
    case southAmerica
    case africa
    case europe
    case asia
    case antarctica
}

I found this stackoverflow post, which though it wasn’t written in Swift, gave some very general polygons that vaguely encompassed the seven continents, exactly what I needed:

m2fo5

I first set up a utility method to convert a latitude and longitude array into a GMSMutablePath. (I’m going to solve this using the Google Maps SDK)

I then used the polygons from the StackOverflow post and converted the Latitude and Longitude arrays into paths in static variables in the Continent enum:

Great! Now seeing if a point is inside a polygon is as simple as comparing a CLLocationCoordinate2D property with a GMSMutablePath property, and you can do that with the GMSGeometryContainsLocation function.

I set up a contains function in the enum that checks if a continent contains the point:

func contains(point:CLLocationCoordinate2D)->Bool {
    switch self {
    case .australia:
        return GMSGeometryContainsLocation(point, Continent.australiaPath, true)
    case .northAmerica:
        return GMSGeometryContainsLocation(point, Continent.northAmericaPath, true) ||
            GMSGeometryContainsLocation(point, Continent.northAmerica2Path, true)
    case .southAmerica:
        return GMSGeometryContainsLocation(point, Continent.southAmericaPath, true)
    case .africa:
        return GMSGeometryContainsLocation(point, Continent.africaPath, true)
    case .europe:
        return GMSGeometryContainsLocation(point, Continent.europePath, true)
    case .asia:
        return GMSGeometryContainsLocation(point, Continent.asiaPath, true) || GMSGeometryContainsLocation(point, Continent.asia2Path, true)
    case .antarctica:
        return GMSGeometryContainsLocation(point, Continent.antarcticaPath, true)
    }
}

North America and Asia both have two have polgyons that represent their areas.

So now, to determine which continent contains a point, all we have to do is iterate through the cases of the Continent enum, calling the contains method. I set up a getContinent method to do this:

static func getContinent(at point:CLLocationCoordinate2D)->Continent? {
    for continent in Continent.allCases {
        if continent.contains(point: point) {
            return continent
        }
    }
    return nil
}

To see how this could be used, imagine you’ve set up a map view in a view controller, let’s call it MapViewController, and we’ve set the view controller as the map view’s delegate. You could set up the mapView:didTapAt method to be called when the user taps on the map. We could use the coordinate property passed into the method to determine which continent the user has tapped, simply by passing the coordinate property into the Continent.getContinent method:

extension TestMapViewController:GMSMapViewDelegate {
    func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
        if let continent = Continent.getContinent(at: coordinate) {
            print(continent)
        }
}

iOS development with Swift - book: https://manning.com/books/ios-development-with-swift video course: https://www.manning.com/livevideo/ios-development-with-swift-lv

Tagged with: ,
Posted in Swift

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: