How to create an MKCoordinate region similar to 50 miles radius in ios Swift? - swift

I'm trying to create a region similar to a circle radius using CLLocation. I understand radius logic and how its measured in meters, but not so clear on a MKCoordinate region and how long delta and lat delta translate to area. I would like to get a 75 mile region. Here is my code....
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
If you could please provide an explanation more than just a short answer it would be appreciated.

If you're trying to create an actual circular region:
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let radius: CLLocationDistance = 60350.4 // meters for 37.5 miles
let regionIdentifier = "CircularRegion" // any desired String
let circularRegion = CLCircularRegion(center: center, radius: radius, identifier: regionIdentifier)

You could use MKCoordinateRegionMakeWithDistance function:
Creates a new MKCoordinateRegion from the specified coordinate and
distance values.
func MKCoordinateRegionMakeWithDistance(
_ centerCoordinate: CLLocationCoordinate2D,
_ latitudinalMeters: CLLocationDistance,
_ longitudinalMeters: CLLocationDistance) -> MKCoordinateRegion
centerCoordinate - The center point of the new coordinate region.
latitudinalMeters - The amount of north-to-south distance (measured in meters) to use for the span.
longitudinalMeters - The amount of east-to-west distance (measured in meters) to use for the span.
So you will have something like:
let rect = MKCoordinateRegionMakeWithDistance(center, 50 * 1609.34, 50 * 1609.34)

Related

can I calculate accurate distance between two latitude and longitude inside a house within 5 meters? [duplicate]

This question already exists:
I want to build something like that if a user enters in a room he recieve a notification in swift ios is it possible?
Closed 3 months ago.
I want to calculate distance between two coordinates within 5 meters or even within one meters is it possible
I have tried haversine formula but not getting the desired result
func calculateDistanceWithHaversin(crrLat: Double, crrLong: Double, desLat: Double = 23.1780068, desLong: Double = 75.7865060, radius: Double = 6367444.7) -> Double {
print("CrrLat \(crrLat) = CrrLong = \(crrLong)")
let haversin = { (angle: Double) -> Double in
return (1 - cos(angle))/2
}
let ahaversin = { (angle: Double) -> Double in
return 2 * asin(sqrt(angle))
}
// degree to radian
let dToR = { (angle: Double) -> Double in
return (angle / 360) * 2 * .pi
}
let lat1 = dToR(crrLat)
let lon1 = dToR(crrLong)
let lat2 = dToR(desLat)
let lon2 = dToR(desLong)
return radius * ahaversin(haversin(lat2 - lat1) + cos(lat1) * cos(lat2) * haversin(lon2 - lon1))
}
i have tried this also
func calculateDistance(crrLat: Double, crrLong: Double) {
let destinationLocation = CLLocation(latitude: 23.1780068, longitude: 75.7865060)
let currentLocation = CLLocation(latitude: crrLat, longitude: crrLong)
distance = currentLocation.distance(from: destinationLocation)
print(String(format: "The distance to my buddy is %.02f m", distance))
}
You can calculate distance with this Builtin Function provided by CoreLocation . The provided distance will be in meters
import CoreLocation
let locationOne = CLLocation(latitude: 37.899, longitude: 74.8989)
let locationTwo = CLLocation(latitude: 38.0900, longitude: 78.98898)
let distance = locationOne.distance(from: locationTwo)

How to install custom annotation on the map depending on the zoom

1) I need to set a custom annotation, depending on the zoom on the map, they will be placed throughout the track on the map. (Arrows showing the direction).
my code
class customPin: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
init(pinTitle:String, pinSubTitle:String, location:CLLocationCoordinate2D) {
self.title = pinTitle
self.subtitle = pinSubTitle
self.coordinate = location
}
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "customannotation")
annotationView.image = UIImage(named:"mov_on_2")
annotationView.canShowCallout = true
return annotationView
}
The best way I have found to do this is to determine the distance of screen width shown by the map. You can do that using the mapView's span like so in the maps regionDidChangeAnimated:
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
// Get the span and the center coordinate of the mapview
let span = mapView.region.span
let center = mapView.centerCoordinate
// Create two points on the left and right side of the region
let rightSide = CLLocationCoordinate2D(latitude: center.latitude + (span.latitudeDelta / 2), longitude: center.longitude)
let leftSide = CLLocationCoordinate2D(latitude: center.latitude - (span.latitudeDelta / 2), longitude: center.longitude)
// Calculate the distance between these two points (don't forget to convert to meters!)
let distance = calculateDistanceBetween(firstLoc: leftSide, secondGeoPoint: rightSide) * 1609.34
// Switch case the distance to handle zooming logic
switch distance {
case _ where distance < 1000:
// Handle logic for if the on screen width distance is < 1000 meters
case _ where distance < 5000:
// Handle logic for if the on screen width distance is < 5000 meters
default:
// Handle logic for if the on screen width distance is > 5000 meters
}
}
Where the distance between any two GPS coordinates can be found using:
// Calculates the distance between two locations, returned in miles
func calculateDistanceBetween(firstLoc: CLLocationCoordinate2D, secondLoc: CLLocationCoordinate2D) -> Double {
// Convert lat's and long's into radians
let firstLatR = firstLoc.latitude * Double.pi / 180
let firstLongR = firstLoc.longitude * Double.pi / 180
let secondLatR = secondLoc.latitude * Double.pi / 180
let secondLongR = secondLoc.longitude * Double.pi / 180
// Calculate and return the distance
return 2 * 3963.1 * asin((pow(sin((secondLatR - firstLatR) / 2), 2) + cos(firstLatR) * cos(secondLatR) * pow(sin((secondLongR - firstLongR) / 2), 2)).squareRoot())
}
It is worth noting that the above equation assumes the earth is a perfect sphere. This should be more than accurate enough for your application.
The problem with finding a true "zoom" level for the map is that the map distance of on screen width (Distance of a degree longitude) changes depending on your latitude.

Getting An Arbitrary Type From Reduce

I'm doing a very simple operation. I'm sorting through a bunch of locations in a map to create an enclosing circle, like so:
var maxLong: Double = -180
var maxLat: Double = -180
var minLong: Double = 180
var minLat: Double = 180
for coord in inCoordinates {
maxLong = max(coord.longitude, maxLong)
maxLat = max(coord.latitude, maxLat)
minLong = min(coord.longitude, minLong)
minLat = min(coord.latitude, minLat)
}
let nw: CLLocation = CLLocation(latitude: maxLat, longitude: minLong)
let se: CLLocation = CLLocation(latitude: minLat, longitude: maxLong)
let center = CLLocationCoordinate2D(latitude: (maxLat + minLat) / 2.0, longitude: (maxLong + minLong) / 2.0)
let radiusInMeters = abs(nw.distance(from: se)) / 2.0
return MKCircle(center: center, radius: radiusInMeters)
Pretty straightforward (Yeah, I know about the IDL issue, but I want to keep this simple).
What I'd like to know, is if there were some way I could boil the loop into a variant of reduce, where you would end up with something like this:
let enclosingRect: MKMapRect = inCoordinates.magikalReduce {
// Magic Happens Here -Queue Doug Henning GIF
}
So the returned rect contains the distilled points.
Yeah, I know that I can simply extend Array (with maybe a type qualifier) to do this with a calculated property, but that sort of defeats the purpose of this. The above is fairly efficient, and I'd rather not add overhead, just to be fancy (Which means, even if I could do it, it might be too inefficient to use).
This is more of a curiosity exploration than a technical need. The above code does fine for me, and is relatively zippy.
Do you mean
// calculate the enclosing rect with `reduce` and `union`, you have to create an `MKMapRect` from each coordinate
let enclosingRect = inCoordinates.reduce(MKMapRect.null) { $0.union(MKMapRect(origin: MKMapPoint($1), size: MKMapSize())) }
You can create a struct for holding the min/max longitude and latitude values, then use reduce, where you use the initial values for these for creating an initial result, then creating an updated version of the struct with the necessary min/max calculations.
struct MinMaxCoordinates {
let maxLong:Double
let maxLat:Double
let minLong:Double
let minLat:Double
}
let minMaxCoordinates = inCoordinates.reduce(MinMaxCoordinates(maxLong: -180, maxLat: -180, minLong: 180, minLat: 180), {minMax, coord in
return MinMaxCoordinates(maxLong: max(minMax.maxLong, coord.longitude), maxLat: max(minMax.maxLat, coord.latitude), minLong: min(minMax.minLong, coord.longitude), minLat: max(minMax.minLat, coord.latitude))
})
let nw: CLLocation = CLLocation(latitude: minMaxCoordinates.maxLat, longitude: minMaxCoordinates.minLong)
let se: CLLocation = CLLocation(latitude: minMaxCoordinates.minLat, longitude: minMaxCoordinates.maxLong)
let center = CLLocationCoordinate2D(latitude: (minMaxCoordinates.maxLat + minMaxCoordinates.minLat) / 2.0, longitude: (minMaxCoordinates.maxLong + minMaxCoordinates.minLong) / 2.0)
let radiusInMeters = abs(nw.distance(from: se)) / 2.0
return MKCircle(center: center, radius: radiusInMeters)

Get altitude from a specific given point - mapkit

I am trying to find out altitude from a given point, but I am not getting that with my iPad.
I have defined my altitude var like this:
var altitude: CLLocationDistance = 0.0
I have made this func:
func getAltitude(latitude: CLLocationDistance, longitude: CLLocationDistance) -> CLLocationDistance {
//Get altitude of touched point
locationManager.requestWhenInUseAuthorization()
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyBest
let touchPointLocation = CLLocation(latitude: latitude, longitude: longitude)
let altitude = touchPointLocation.altitude
return altitude
}
For example when I touch the map I tried to get altitude like this, inside the longpress:
let touchPoint = gestureRecognizer.location(in: self.map)
let coord = map.convert(touchPoint, toCoordinateFrom: self.map) //now this coord is working ok. Its touched point coordinates
let altitude = getAltitude(latitude: coord.latitude, longitude: coord.longitude)
print(altitude) //I get 0.0 here :(
Why is this wrong? How can I do this?

Get viewport coordinates from mapView? regionDidChanged swift

The following function is called when the user moved the map.
It is possible to get the viewport? Viewport is latitude and longitude of north/east and the lat. and lon. of south/west.
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool){
print("The \(mapView.centerCoordinate)")
print("the maprect \(mapView.visibleMapRect.origin)")
print("the maprect \(mapView.visibleMapRect.size)")
//I find just this attributes for mapView
}
I don't know how get the viewports out of my data. I can't find anything in the www.
The destination is that I log the coordinates with google analytics and another tool evaluate the datas.
Has somebody an idea? Thanks a lot
MapKit
let northEast = mapView.convertPoint(CGPoint(x: mapView.bounds.width, y: 0), toCoordinateFromView: mapView)
let southWest = mapView.convertPoint(CGPoint(x: 0, y: mapView.bounds.height), toCoordinateFromView: mapView)
googleMaps
mapView has a property "projection" where you can use "coordinateForPoint" to convert a point from the mapView to a coordinate. so the following could work:
swift 3 for google maps
let northEast = mapView.projection.coordinate(for: CGPoint(x: mapView.layer.frame.width, y: 0))
let southWest = mapView.projection.coordinate(for: CGPoint(x: 0, y: mapView.layer.frame.height))
swift 2
let northEast = mapView.projection.coordinateForPoint(CGPoint(x: mapWidth, y: 0 ))
let southWest = mapView.projection.coordinateForPoint(CGPoint(x: 0, y: mapHeight))
you just need to enter your mapView width and height
Based on fel1xw answer
Swift 3 MapKit
let northEast = mapView.convert(CGPoint(x: mapView.bounds.width, y: 0), toCoordinateFrom: mapView)
let southWest = mapView.convert(CGPoint(x: 0, y: mapView.bounds.height), toCoordinateFrom: mapView)