geolocation calculation: calculate points if they are within a radius - geolocation

ok here is the problem:
I want to show to my users the closest geopoints in his vicinity.
i have arround 55.000 fixed geopoints which could be shown. (I have for all of them long/lat)
dependent on the users location (long/lat) i want to show the closest 20 geopoints.
so of course i could just calculate all 55.000 geopoints and see if there are 20 within a certain radius of the users lang/lat and rank them afterwards but this would be somehow an overhead to calculate always 55tsd geopoints.
is there a posibility to "add" 5-miles/kilometers range to a users long and lat and calculate only the distance for those which are within this radius?
i hope you get what i mean. :)
Merci

If the calculation of distance between all points take too much time, you could narrow down the possible points just by simple difference between lat/lon (source_lat - target_lat) (source_lon - target_lon) and take only the closest point to final calculation of distance. You could use formula to calculate distance.
D = 60* 1.1515 * acos (sin(pi*y/180) * sin(pi*Y/180) +
cos(pi*y/180) * cos(pi*Y/180) * cos((z-Z) *pi / 180)
) * 180 / pi)
But the efficiency of calculation depends on used database technology as well.

Related

How to draw tiles on Map from Database?

I am developing a GIS based iOS application using Swift 3.0. I want to draw tiles on Map and tiles images are stored in SQLite Database.
My question is how can I retrieve tile image from database and draw thoses image on Map, as database contains columns zoom (values will be 12, 13, etc.), tile_row (values will be 4122, 3413, etc.), tile_column (values will be 4122, 3413, etc.) and data but I get zoom level value in thousands and I get latitude and longitude values in iOS app, so I need to convert these values to match values in database. I found a way to convert zoom level to 1 to 18 scale but I don't know can I match the tile_row and tile_column value using latitude and longitude.
Also please verify that my code which convert zoom level to 1 to 18 (similar to google map zoom level) is correct:
let zoomLevel = Int(log2(360 / MKCoordinateRegionForMapRect(mapRect).span.longitudeDelta))
Thanks.
In IOS (and most mapping systems) the tile images are stored in a directory structure where each zoom level is a parent directory named with the zoom-level number. Under that directory, there are one or more directories named with the longitudinal tile numbers of the tiles below - e.g., at zoom level 10 there are 1024 tiles across and your directories could be 750, 751, 752, and 753 if that's where their images fell relatively. Under each longitude (x-coordinate) directory are the images (256 X 256 pixels) for that y-coordinate, each named for the x tile coordinate, again out of 1024 at zoom level 10.
To find where you are in those ranges, use MKMapPointForCoordinate(CLLocationCoordinate2D), which will give you the lat (y) and lon (x) map points of a location when fully zoomed out. To get the longitude (y) tile number use:
Int((pow(2.0, Double(z)) as Double) * point.y / 268435456.0)
...where the big number is the total number of points on the x-axis at zoom level 0 (2^20 tiles * 256 pixels / tile). That way if point.x is 1/3 of the big number, the image is the tile 1/3 of the way through 1024, and the integer representing the 256-pixel interval (i.e., tile) that number falls into is the name of the directory.
The latitude (y) map point and tile number are calculated similarly, and that number is the name of the image file. So, at zoom level 10 the image for the tile 752 out of 1024 along the x-axis and 486 out of 1024 along the y-axis would be in the file:
...Documents/Maps/yourDirectory/10/752/486.png
...provided you name your overall map directory Maps and the specific directory for this set of tiles yourDirectory. When you use the overlay, you'd use this directory information along with the rest of the setup to instantiate an MKTileOverlay object. Note that the offsets are from the bottom left corner unless you specify that they're reversed since they're thinking x and y axes (remind you of using CoreGraphics for a UIImage?).
Finally, here's how I calculate the zoom level given two corner points of a region that I want to capture a snapshot for:
let position1 = MKMapPointForCoordinate(bottomRight)
let position2 = MKMapPointForCoordinate(topLeft)
let xPosition1 = position1.x / Setting.shared.mapScale
let xPosition2 = position2.x / Setting.shared.mapScale
let yPosition1 = position1.y / Setting.shared.mapScale
let yPosition2 = position2.y / Setting.shared.mapScale
let relativeSpanX = xPosition1 - xPosition2 // X distance between points relative to size of full map
let relativeSpanY = yPosition1 - yPosition2 // Y distance between points relative to size of full map
let spanForZoom = max(relativeSpanX, relativeSpanY)
startingZoom = max(10, Int(log2(1.0 / spanForZoom)) - 1)
That gets you the zoom level for a tile that fits the size of the area that includes both points, but note that no one standard tile of that size (or any size less than the full map) may include those two points depending on where they lie relative to the grid. For example if they span the prime meridian the first step to 4 tiles at zoom level 1 will separate them, so you may need 2 - 4 tiles of the starting zoom size to get both. Ideally, write a function that tells you the tile number (x and y) that includes a CLLocationCoordinate2D since that gets very handy as you pick, download, and collect your tiles.
While you can get away with a geometrical approach like you're showing to calculate longitudinal / y-axis values, MKMapPointForCoordinate() is indispensable for latitude / y-axis calculations since the mercator map is non-linear as you move north or south, and the function takes care of that for you.
That should get you started, but it's a picky process - one thing to focus on is the fact that the layout is always from the lower left; it's easy to get confused as you gather and label the tiles.
I use the following function to calculate the x and y coordinates for the tile that a point is in for a given zoom level:
func getTileCoordinates(location: CLLocationCoordinate2D, z: Int) -> (x: Int, y: Int)
{
let point = MKMapPointForCoordinate(location)
let locationX = Int((pow(2.0, Double(z)) as Double) * point.x / 268435456.0)
let locationY = Int((pow(2.0, Double(z)) as Double) * point.y / 268435456.0)
return (locationX, locationY)
}
...again, where 268435456.0 is the total number of pixels in the zoom level 20 map along the x or y axis. Note, all of this is for Apples MapKit maps and the functions to display them.

How To Find Remaining Distance To Move UIView Between 2 Points

SCENARIO
I am working on an application that keeps track of blood glucose levels into a graph. On the graph there are "markings" (ex: -200mg) going in vertical order along the y axis on the right side of the screen and "hours" (ex: -12:00 PM) will be along the x axis on the bottom of the graph. I have to plot out little 'dots' to display what the blood glucose level was throughout the way.
ISSUE
I am trying to calculate how to position the 'dots' in the correct time and mg level and I'm having difficulty calculating the positions. I can access the "markings" and retrieve it's marking.center.x to indicate which 'Time Slot' (x axis) and the marking.center.y to indicate which 'MG Level' the 'dot' needs to go into. Problem is it isn't always exactly 12:00 PM or 200mg where it will need to be placed. In fact that would be very rare.
WHAT I NEED
Based on the following variables:
dot.mgLevel
The dot will already know where it needs to go based on the information retrieved from the medical device. It will know the time and mgLevel to assign itself.
marking.mgLevel
The markings will each have evenly distributed values that such as -100mg, -200mg, -300mg ect...
timemarking.timeslot
Each time marking on the bottom will each have evenly distributed times allocated every 30 min. Such as -12:00PM, -12:30PM, -1:00PM ect...
If the dot has a mg Level of 330mg and the closest marking on the mg Level is 300mg, then I need to be able to calculate how much further up the dot needs to move from 300 going towards the 400mg marker.
SO...
If the distance between the markings are 100pt and the dot's mgLevel is 330mg, then I know that I need to move the dot from the 300mg marking toward the 400mg marking by exactly 30pt. That's because it's simple math because the distance between the markings is 100. But in real life it isn't 100, so I need to be able to calculate this.
MY ULTIMATE QUESTION
Say distance between markings is 241 and each marking represents multiples of a hundred. Say my dot has a mgLevel of 412. How do I calculate how far I need to move the dot so that it will be in the correct place?
I THINK?
I think I need to make 241 equal 100%. But I need help.
Distance between markings is 241pt
Markings are multiples of 100mg
1mg will occupy 2.41pt. So 412mg will occupy (2.41 * 412) pt. To know how much to move for the next dot, take the difference in mg and multiply by 2.41.
In general, if distance between 2 markings in points is d, markings are multiples of m, and desired accuracy is k decimal places, 1mg will occupy g:
let divisor = pow(10.0, Double(k))
let g = round((d/m)*divisor) / divisor

iOS find the average speed in core location [duplicate]

This question already has answers here:
iOS find average speed
(2 answers)
Closed 8 years ago.
I want to be able to calculate the average speed with core location. I already have the current speed:
- (void)locationUpdate:(CLLocation *)location {
speedLabel.text = [NSString stringWithFormat:#"%.2f", [location speed]*2.236936284];
And also I want to be able to show it in a label and reset it with a button.
I want it to start averaging when a button is pressed and update the average about every 5 seconds and then stop averaging after another button is pressed.
Thank you!
As defined: Average refers to the sum of numbers divided by n. That is, when dealing with an average, you usually have at least 2 or more observations from which you wish to calculate an average. The average of your current speed is just, well, your current speed divided by one. I'm sure that's not what you are looking for.
You will need to ask yourself for how long time you wish to average. Five seconds? 10 seconds? The shorter the interval (fewer observations), the more sensitive to significant changes your average will be.
Basically what you would do is to store your observations in a mutable collection, eg NSMutableArray, and then just sum them up and divide the sum by the array's count property, corresponding to the number of observations. Or, as NSHipster has a great article on, you could take advantage of valueForKeyPath:
NSMutableArray *speedObservations = [[NSMutableArray alloc] initWithCapacity:n];
...
CGFloat average = [speedObservations valueForKeyPath:#"#avg.floatValue"];
Hmm. I would do this differently.
Average speed is distance traveled from a start time to an end time. I would record the user's location when they start asking for average speed, along with the current date. Then I would periodically get a new location reading and calculate distance traveled from the old location to the new location divided by the elapsed time between the current location reading and the first location reading.

Find closest point on path forwards

Given a path say 1000 meters long from start to goal consisting of a finite number of CLLocation points (guesstimate around 100). Assuming the user is somewhere on the path and a CLLocation coming from iOS location services, what would be the best way to calculate the nearest point forwards along the route?
Finding the nearest point is easy enough using -[CLLocation distanceFromLocation:], but as the user passes a point and moves towards the next, the previous point will still be the nearest until he passes the midway between the previous and next point.
You could keep a array consisting of the sorted (start to the end of the path) CLLocation points (hypothetical 100) and evaluate only those poins to find the nearest one that will be visited. To find a visited point you keep the starting position and mesure the distance from the start to the current location of the user(d1). If d1 > distance from start to the next point in the sorted array and the current location is nearby (10 - 100 m) the next point in sorted array then remove the point else user did not visit / passed by that location so you keep it in the sorted array.

How to create Random Geo-Points within a distance d from another Geo-point?

How to get Random Geo-points[ lat/long in decimal], placed anywhere inside a 100 meter radius circle? The center of the circle is another reference GeoPoint.
Is there any Function/Formulae that implements this?
Basically I am reading the GPS input of my android device and need to generate random Geo-Points around the device [In a circle of radius 100 meters centered at my device].
Please note : There are no Geo-Points pre-stored in Database. I need to create all the Geo-points on the fly as mentioned above.
I just wrote a a Ruby method which extends Random to provide this.
Caveat: The points all lay within a box, not a circle.
class Random
def location(lat, lng, max_dist_meters)
This is called with Random.new.location(mid_lat, mid_lng, dist). It will return a point which is probably within max_dist_meters of a the mid point.
max_radius = Math.sqrt((max_dist_meters ** 2) / 2.0)
Without adjusting to max_radius we'd get points inside a square outside the circle (i.e. in the corners), where the distance would be greater than max_dist_meters. This constrains us to a square inside the circle which is probably more what you want.
lat_offset = rand(10 ** (Math.log10(max_radius / 1.11)-5))
lng_offset = rand(10 ** (Math.log10(max_radius / 1.11)-5))
The 1.11 and 5 come from here.
lat += [1,-1].sample * lat_offset
lng += [1,-1].sample * lng_offset
lat = [[-90, lat].max, 90].min
lng = [[-180, lng].max, 180].min
We should probably wrap around here instead of just clamping the value, fixes welcome.
[lat, lng]
end
end
Comments / clean up welcome!
Sample output here which you can see nicely if you paste the lat/lngs here.
Pick random points on a square (i.e. pairs of uniform random numbers), then discard any that don't lie within a circle inscribed in that square. Given (x,y) pairs, a point is within your circle if:
(x - c_x)^2 + (y - c_y)^2 < r,
where (c_x, c_y) is the centre of your circle and r is its radius.
Start here: Generate a random point within a circle (uniformly). Then figure out how to center that circle at the reference lat/long. Then figure out how to map the randomly generated points to lat/long values. Hint: you want to add the individual components (say, x and y on your circle) to the circle's center.

Resources