Get all locations within certain radius from SQLite Database in XCode - iphone

I have a SQLite Database which contains latitude and longitude of several locations.
I want to find the latitude and longitude of all locations which fall within 15km radius from my current location from my SQLite Database.
What will be my SQLite Query for this?

One degree difference of latitude is equal to 111 km distance, and One degree difference of longitude is equal to 94 km. So Now check for all the latitude which are at (+/-)(15/111) difference and longitudes which are (+/-)(15/94) difference from your current location.
Important link for reference.

For anyone still looking for an answer:
You can get nearby locations with this method adapted from #breceivemail's answer [JAVA]
Here is the translated version in Swift:
private func calculateDerivedPosition(point: CGPoint, range: Double, bearing: Double)-> CGPoint {
let EarthRadius: Double = 6371000
let latA = Double(point.x.degreesToRadians)
let lonA = Double(point.y.degreesToRadians)
let angularDistance = range / EarthRadius
let trueCourse = bearing.degreesToRadians
var lat = asin(sin(latA) * cos(angularDistance) +
cos(latA) * sin(angularDistance) *
cos(trueCourse))
let dlon = atan2(sin(trueCourse) * sin(angularDistance) * cos(latA),
cos(angularDistance) - sin(latA) * sin(lat))
var lon = ((lonA + dlon + Double.pi).truncatingRemainder(dividingBy: (Double.pi * 2))) - Double.pi
lat = lat.radiansToDegrees
lon = lon.radiansToDegrees
let newPoint = CGPoint(x: lat, y: lon)
return newPoint
}
radiansToDegree Extension
And You can use it like this with FMDB (or any Sqlite lib):
let center = CGPoint(x: currentLocation.latitude, y: currentLocation.longitude)
let mult: Double = 1 // mult = 1.1 is more reliable
let radius: Double = 5000 //in meters
let point1 = calculateDerivedPosition(point: center, range: radius * mult, bearing: 0)
let point2 = calculateDerivedPosition(point: center, range: radius * mult, bearing: 90)
let point3 = calculateDerivedPosition(point: center, range: radius * mult, bearing: 180)
let point4 = calculateDerivedPosition(point: center, range: radius * mult, bearing: 270)
let result = try!db.executeQuery("SELECT * FROM items WHERE lat > ? AND lat < ? AND lng < ? AND lng > ?" , values: [point3.x, point1.x, point2.y, point4.y])
Note: The results aren't sorted.

To arrange them in Ascending order, store all the distcnace in a dictionary with key. like,
distanceDic = [[NSMutableDictionary alloc]initWithObjectsAndKeys:[NSNumber numberWithFloat:distanceVal],#"distance",nil];
[distanceArray addObject:distanceDic];
Here, distanceDic is my Dictionary and distaceVal is string containing distance.
distanceArray is NSMutableArray Containing Distance.
Now Sort the distanceDic like,
NSArray *array = [NSArray arrayWithArray:[distanceArray mutableCopy]]; // Copying NSMutableArray to NSArray.
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"distance" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
array = [array sortedArrayUsingDescriptors:sortDescriptors];
NSLog(#"#The Final Distance Array After Sorting :%#",array);
This will give you resulting Distance Array sorted in Ascending order.

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)

Simplify this foreach loop (to find min/max in a nested array) in swift

I would love to get rid of the foreach loop. Currently I am doing a foreach loop to populate a temp variable to separate my array to get the min/max for each Lat/Lon.
eg: slopeLatLonArray = [ [111,111],[111.1,111.2] ]
func drawFullRouteOverlay() {
/// Reset Array to Nil
vLocations = []
/// populate vLocations as a CLLocation2D
for index in slopeLatLonArray.indices {
vLocations.append(CLLocationCoordinate2D(latitude: Double(slopeLatLonArray[index][0]), longitude: Double(slopeLatLonArray[index][1])))
}
/// Draw the resulting polyline
let polyline = MKPolyline(coordinates: vLocations, count: vLocations.count)
vcTrainMapView.addOverlay(polyline)
/// Bunch of stuffs to do to get the Max/Min of Lat/Lon
var tempLat: [Double] = []
var tempLon: [Double] = []
slopeLatLonArray.forEach {
tempLat.append($0[0])
tempLon.append($0[1])
}
/// Zoom to the entire route polyline
let center = CLLocationCoordinate2D(latitude : (tempLat.min()! + tempLat.max()!) / 2,
longitude: (tempLon.min()! + tempLon.max()!) / 2)
let span = MKCoordinateSpan(latitudeDelta : (tempLat.max()! - tempLat.min()!) * 1.3,
longitudeDelta: (tempLon.max()! - tempLon.min()!) * 1.3)
let region = MKCoordinateRegion(center: center, span: span)
vcTrainMapView.setRegion(region, animated: true)
}
You are unnecessarily iterating all your locations multiple times. First when populating vLocations. Second when populating slopeLatLonArray. Third, fourth, fifth and sixth when getting tempLat and tempLon minimum and maximum values. And another 4 times when getting them again for the span (this might be optimized by the compiler but I am not sure).
What I suggest is to get all those values during the first iteration when populating vLocations. This way you will iterate all locations only once:
func drawFullRouteOverlay() {
guard let first = slopeLatLonArray.first, first.count == 2 else { return }
var minLatitude = first[0]
var maxLatitude = first[0]
var minLongitude = first[1]
var maxLongitude = first[1]
vLocations = slopeLatLonArray.map {
let latitude = $0[0]
let longitude = $0[1]
minLatitude = min(minLatitude, latitude)
maxLatitude = max(maxLatitude, latitude)
minLongitude = min(minLongitude, longitude)
maxLongitude = max(maxLongitude, longitude)
return .init(latitude: latitude, longitude: longitude)
}
/// Draw the resulting polyline
let polyline = MKPolyline(coordinates: vLocations, count: vLocations.count)
vcTrainMapView.addOverlay(polyline)
/// Zoom to the entire route polyline
let center = CLLocationCoordinate2D(latitude: (minLatitude + maxLatitude) / 2, longitude: (minLongitude + maxLongitude) / 2)
let span = MKCoordinateSpan(latitudeDelta: (maxLatitude - minLatitude) * 1.3, longitudeDelta: (maxLongitude - minLongitude) * 1.3)
let region = MKCoordinateRegion(center: center, span: span)
vcTrainMapView.setRegion(region, animated: true)
}
How about either .map...
var tempLat = slopeLatLonArray.map { $0[0] }
var tempLon = slopeLatLonArray.map { $0[1] }
// Could also zip to vLocations for a 1 liner
var vLocations = zip(tempLat, tempLon).map(CLLocationCoordinate2D.init)
or setting in the initial for loop...
var tempLat: [Double] = []
var tempLon: [Double] = []
for index in slopeLatLonArray.indices {
tempLat[index] = Double(slopeLatLonArray[index][0])
tempLon[index] = Double(slopeLatLonArray[index][1])
vLocations.append(CLLocationCoordinate2D(latitude: tempLat[index], longitude: tempLon[index]))
}

How do I calculate the altitude needed to display the full MKCoordinateRegion in a MKMapView?

So I want to set a specific position with a specific region shown at a specific rotation.
I know there is a setRegion that calculates the altitude automatically, but it doesn't let you set a rotation. To set a rotation I need to use setRotation that takes a center, altitude and heading.
I have no idea how to calculate the altitude needed to file the full region on the screen, regardless of screen side.
I'm trying:
func updateUIView(_ view: ZooMap, context: Context) {
let coordinate = CLLocationCoordinate2D(
latitude: 21.270381425220606,
longitude: -157.81908260613335
)
let span = MKCoordinateSpan(latitudeDelta: 0.007075784913642025, longitudeDelta: 0.010196763428524491)
let region = MKCoordinateRegion(center: coordinate, span: span)
let camera = MKMapCamera()
camera.heading = 71
camera.centerCoordinate = coordinate;
camera.altitude = determineAltitudeForRegion(region: region, heading: camera.heading, viewport: UIScreen.main.bounds.size)
view.setCamera(camera, animated: false)
}
func determineAltitudeForRegion(region: MKCoordinateRegion, heading: Double, viewport: CGSize) -> Double {
// Calculate a new bounding rectangle that is corrected for the aspect ratio
// of the viewport/camera -- this will be needed to ensure the resulting
// altitude actually fits the polygon in view for the observer.
let upperLeftCoord = CLLocationCoordinate2DMake(region.center.latitude + region.span.latitudeDelta / 2, region.center.longitude - region.span.longitudeDelta / 2)
let upperRightCoord = CLLocationCoordinate2DMake(region.center.latitude + region.span.latitudeDelta / 2, region.center.longitude + region.span.longitudeDelta / 2)
let lowerLeftCoord = CLLocationCoordinate2DMake(region.center.latitude - region.span.latitudeDelta / 2, region.center.longitude - region.span.longitudeDelta / 2)
let hDist = MKMapPoint(upperLeftCoord).distance(to: MKMapPoint(upperRightCoord));
let vDist = MKMapPoint(upperLeftCoord).distance(to: MKMapPoint(lowerLeftCoord));
var adjacent: Double = 0;
var newHDist: Double = 0;
var newVDist: Double = 0;
let rect = RectForRegion(region: region)
if (rect.size.height > rect.size.width) {
newVDist = (Double(viewport.height) / Double(viewport.width)) * hDist;
adjacent = newVDist;
} else {
newHDist = (Double(viewport.width) / Double(viewport.height)) * vDist;
adjacent = newHDist;
}
return adjacent / tan(heading.degreesToRadians) / 2
}
func RectForRegion(region: MKCoordinateRegion) -> MKMapRect {
let a: MKMapPoint = MKMapPoint(CLLocationCoordinate2DMake(region.center.latitude + region.span.latitudeDelta / 2, region.center.longitude - region.span.longitudeDelta / 2))
let b: MKMapPoint = MKMapPoint(CLLocationCoordinate2DMake(region.center.latitude - region.span.latitudeDelta / 2, region.center.longitude + region.span.longitudeDelta / 2))
return MKMapRect(x: min(a.x, b.x), y: min(a.y, b.y), width: abs(a.x - b.x), height: abs(a.y - b.y))
}
but its not working properly. How do I do this??

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)

Calculation that calculates the new latitude and longitude based on a starting point, bearing and distance?

Does anyone have a calculation that calculates the new
latitude and longitude based on a starting point, bearing and
distance?
I would greatly appreciate any help people might have.
I've used the code from Calculate new coordinate x meters and y degree away from one coordinate:
- (CLLocationCoordinate2D)coordinateFromCoord:(CLLocationCoordinate2D)fromCoord
atDistanceKm:(double)distanceKm
atBearingDegrees:(double)bearingDegrees
{
double distanceRadians = distanceKm / 6371.0;
//6,371 = Earth's radius in km
double bearingRadians = [self radiansFromDegrees:bearingDegrees];
double fromLatRadians = [self radiansFromDegrees:fromCoord.latitude];
double fromLonRadians = [self radiansFromDegrees:fromCoord.longitude];
double toLatRadians = asin(sin(fromLatRadians) * cos(distanceRadians)
+ cos(fromLatRadians) * sin(distanceRadians) * cos(bearingRadians) );
double toLonRadians = fromLonRadians + atan2(sin(bearingRadians)
* sin(distanceRadians) * cos(fromLatRadians), cos(distanceRadians)
- sin(fromLatRadians) * sin(toLatRadians));
// adjust toLonRadians to be in the range -180 to +180...
toLonRadians = fmod((toLonRadians + 3*M_PI), (2*M_PI)) - M_PI;
CLLocationCoordinate2D result;
result.latitude = [self degreesFromRadians:toLatRadians];
result.longitude = [self degreesFromRadians:toLonRadians];
return result;
}
- (double)radiansFromDegrees:(double)degrees
{
return degrees * (M_PI/180.0);
}
- (double)degreesFromRadians:(double)radians
{
return radians * (180.0/M_PI);
}
Or in Swift:
extension CLLocationCoordinate2D {
func adjusted(distance: Double, degrees: Double) -> CLLocationCoordinate2D {
let distanceRadians = distance / 6_371 // 6,371 == Earth's radius in km
let bearingRadians = degrees.radians
let fromLatRadians = latitude.radians
let fromLonRadians = longitude.radians
let toLatRadians = asin(sin(fromLatRadians) * cos(distanceRadians) + cos(fromLatRadians) * sin(distanceRadians) * cos(bearingRadians))
var toLonRadians = fromLonRadians + atan2(sin(bearingRadians)
* sin(distanceRadians) * cos(fromLatRadians), cos(distanceRadians)
- sin(fromLatRadians) * sin(toLatRadians))
// adjust toLonRadians to be in the range -180 to +180...
toLonRadians = fmod((toLonRadians + 3 * .pi), (2 * .pi)) - .pi
return CLLocationCoordinate2D(latitude: toLatRadians.degrees, longitude: toLonRadians.degrees)
}
}
extension CLLocationDegrees {
var radians: Double { self * .pi / 180 }
}
extension Double {
var degrees: CLLocationDegrees { self * 180 / .pi }
}
You will find all the calculations you could possibly want (including explanations etc) at http://www.movable-type.co.uk/scripts/latlong.html
The code you need is (in JavaScript) under the heading "Destination point given distance and bearing from start point". Excerpting:
var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) +
Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng) );
var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1),
Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));
Where R = radius of the earth, d = distance (in same units), and lat/long are in radians (since that's what the sin function expects). You go from degrees to radians with
radians = pi * degrees / 180;
You should be able to take it from here. Do look at the link I gave for more info.