Find users within a given radius - mysqli

I have a mySQL table with user name, latitude and longitude of the user. I would like to get a list of user who are inside the circle of a given latitude and longitude with given distance. For example my input Lat= 78.3232 and Long = 65.3234 and distance = 5 km. I would like to get the list of users who are inside 5km distance from the point 78.3232 and 65.3234. Is it possible to solve this with single query? Or can you give me a hint start solving this query? I am new to the geo based information.

google gives me this :
http://www.movable-type.co.uk/scripts/latlong-db.html
it gives you a good idea to start your work.. based on the distance between points (your circle radius)
imo, you need to define all points (surface) that are into this "circle", and check if your users are into this surface... in fact, a good way to do this would be to define ranges... for example :
lat : 72, long between 65 & 67
lat : 73, long between 64 & 69
... ...
if you do it with your precision xx.yyyy that will increase consequently the possibilities... it's just a mathematical challenge... Good luck!

I think a good place to start is with the Pythagorean theorem a^2 + b^2 = c^2 where a would = the difference in lat from point to Origin and b would = the difference in long. and c would equal distance.
that solves the math point.
I would need some helping doing the conversion from distance in lat and distance in long.
is the going to be a local, state, or a world wide program? that will create changes as differences in longitude get small as you reach the poles and larger as your reach the equator.

Related

Using STDistance with Spatial index on SQL Server 2012 is slower then using COS, SIN & ACOS Calculations and gives oval shaped results

I have a table in a SQL Server 2012 database with 3.000.000 records. Those records represent a point on a map. Al those records have x, y coordinates and geography point as fields (x, y, geo).
I need to calculate all points within a distance of 10.000 meter from a certain point.
Query no. 1 I use :
DECLARE #point geography
DECLARE #rad float
SET #point = geography::STGeomFromText('POINT(51.2207099068778 4.39961050577564)', 4326);
SET #rad = 10000
SELECT count(1)
FROM t_mailbox WITH (INDEX(SIndx_t_mailbox_geo_MHHM_512))
WHERE
#point.STDistance(geo) <= #rad
Result : It takes 4 seconds to find 273.346 points. Drawing those points on a map results in an oval shape on the map.
For sure this is wrong because not all points are included in the result.
Query no. 2 I use :
declare #radius int = 10000
DECLARE #x float = 51.2207099068778
DECLARE #y float = 4.39961050577564
SELECT count(1)
FROM t_mailbox
WHERE
ACOS(COS(RADIANS(90-#x))*COS(RADIANS(90-x)) +SIN(RADIANS(90-#x)) *SIN(RADIANS(90-x))*COS(RADIANS(#y-y)))*6371000 <= #radius
Result : It takes 2 seconds to find 564.547 points. Drawing those points on a map results in a perfect shaped circle.
Questions :
Why is using SPATIAL INDEX and STDistance slower then the more complicated query with SIN, COS and ACOS?
Why is results in a wrong oval shaped set of points?
What am I doing wrong?
Geography data is drawn on the surface of a sphere. This means it looks different than geometry (flat) data.
Imagine taking a globe, and drawing a point on it. Then take a compass and draw a circle around that point. Now peel the skin off the globe. Notice it does not lie flat, to make it flat you have to stretch it. Now the way most people do that, is the stretch the top and bottom (north/south poles) and stretch it until it is the same length as the equator. This makes the circle you drew an oval which is bigger horizontally than vertically.
Now the formula you used is for points within a radius on flat plane. This means that you assume the distance between two lines of longitude is the same no matter what latitude you are (5 feet away from the north pole, the distance between 90 degrees and 91 degrees longitude is much smaller than at the equator).
On a mercator projection map, this formula will make a map that is a perfect circle, however on a globe, it is not. Hopefully this makes sense.
As for you speed issue: A: Apples to oranges, you are doing different calculations. and B: Without knowing how you have your index set up, it is very difficult to analyze, but geography indexing is pretty bad regardless, it works much better on very large geographies like countries.
Whilst hcaelxxam answers the "why" perfectly, you may find better performance by moving away from STDistance(). Whilst not always the case, I have generally found it better to use STIntersects() or STWithin() for distances - how you do this is pretty easy!
Try changing your query to the following. I'd be interested in the results:
DECLARE #point geography;
DECLARE #rad float = 10000;
SET #point = geography::STGeomFromText('POINT(51.2207099068778 4.39961050577564)', 4326).STBuffer(#rad); -- We're creating the "oval" here
SELECT count(1)
FROM t_mailbox WITH (INDEX(SIndx_t_mailbox_geo_MHHM_512))
WHERE
#point.STIntersects(geo) = 1
You may also like to try with and without the index hint. Sometimes, forcing it can generate an inefficient query plan.

Get metric distance between two points via a PostgreSQL/PostGIS request

I have a question about the use of postgreSQL/postGIS.
I would like to display markers on a map (stored in a database) which are some distance away from the user (coordinates given to the request).
The type of the field of the markers is POINT (I store lat/long).
The user position is detetermined by the Google Map API.
Here is the actual request :
SELECT * FROM geo_points WHERE ST_distance(ST_SetSRID(geo_points.coords::geometry,4326),ST_GeomFromEWKT('SRID=4326;POINT(45.0653944 4.859764599999996)')) > 65
I know (after some research on internet) that the function ST_distance gives me the distance in degree between markers and the user position and that I test the distance in km.
I think I have to use the function ST_tranform to transform the points in metric coordinates.
So my questions are :
- what is the SRID for France
- how can I make this dynamically for the entire world according to the user position ?
I also kow that the function ST_within exists and that could do this. But I anticipate the fact that later, I could need the distance.
Any help would be greatly appreciated
ps: there are maybe solutions in other post, but all the answers I have found during my researches were not really meeting my needs.
Firstly, pay attention to the axis order of coordinates used by PostGIS, it should be long/lat. Currently you are searching in Somalia. Swapping to the coordinates, you would be searching in France.
You can use a geodesic calculation with the geography type, or use geodesic functions like ST_Distance_Spheroid. With the geography type, you may want to use ST_DWithin for higher performance.
Here are geo_points 65 m away or less from the point of interest in France (not Somalia):
SELECT * FROM geo_points
WHERE ST_Distance_Spheroid(
ST_Transform(geo_points.coords::geometry, 4326),
ST_SetSRID(ST_MakePoint(4.859764599999996, 45.0653944), 4326),
'SPHEROID["WGS 84",6378137,298.257223563]') < 65.0;
However, it will be very slow, since it needs to find the distance to every geo_points, so only do this if you don't care about performance and have less than a few thousand points.
If you change and transform geo_points.coords to store lon/lat (WGS84) as a geography type:
SELECT * FROM geo_points
WHERE ST_DWithin(
geo_points::geography,
ST_SetSRID(ST_MakePoint(4.859764599999996, 45.0653944), 4326)::geography,
65.0);

Computing sub-solar point

I am just getting started with PyEphem. My immediate task is, given a date and time compute the sub-solar point on Earth with latitude-longitude values. I'll dig into PyEphem to work this out but if someone has already done this, I'd appreciate sample code.
I went looking for the same answer as the OP. Many posts "mention" how PyEphem is the way to go but without providing the actual example.
Here is my working example to calculate the subsolar point. Mapping everything to a longitude between -180 and + 180 degrees.
greenwich = ephem.Observer()
greenwich.lat = "0"
greenwich.lon = "0"
greenwich.date = datetime.utcnow()
sun = ephem.Sun(greenwich)
sun.compute(greenwich.date)
sun_lon = math.degrees(sun.ra - greenwich.sidereal_time() )
if sun_lon < -180.0 :
sun_lon = 360.0 + sun_lon
elif sun_lon > 180.0 :
sun_lon = sun_lon - 360.0
sun_lat = math.degrees(sun.dec)
print "Subsolar Point Sun Lon:",sun_lon, "Lat:",sun_lat
I am no expert in PyEphem and there may be a better approach - but my testing so far has this work for my purposes.
p.s. yes.. Greenwich above is not actually set to the actual lat/lon... it's really only the Longitude of 0.0 that's needed to get the appropriate Sidereal time we need.
I cannot test actual code from where I am this morning, but: an object at declination ϕ should always ride right above the series of locations on earth that have latitude ϕ, so the latitude number is given to you directly by a body's .dec attribute (or .a_dec or .g_dec depending on your application).
Now, what about longitude?
Imagine the situation, which I suppose must occur roughly once a day, when Greenwich at 0° longitude looks up and sees the line in the sky of 0° right ascension right overhead. At that moment, a body in the sky at right ascension θ would be looking down at longitude θ assuming that longitude is positive going east, as is the case with PyEphem.
Now, what if Greenwich is looking up at a non-zero line of right ascension instead? Then it seems to me that we just need to subtract that from a body's right ascension in order to make longitude, because as the day proceeds and the Earth turns and lines of right ascension pass over Greenwich with bigger and bigger right ascensions assigned to them, any given body is going to pass west across the Earth and its longitude will dwindle and then go negative as it passes over the Western Hemisphere.
The line of right ascension overhead at Greenwich at any given moment can be determined by creating an Observer at 0° longitude and asking for its .sidereal_time() if I recall the Quick Reference correctly. So I think that the longitude beneath of a body might be:
lon = body.ra - greenwich.sidereral_time()
I will do a quick test with this later on today to see if reasonable numbers come out.

Find coordinates nearest to my current GPS location

I have around 800 geo co-ordinates in my iPhone app as a flat file. I am searching for an effective way to find an algorithm which will take the current user location, loop through all these 800 coordinates and pull only the coordinates which are in 10 miles vicinity. How effectively this can be done? Also please share links which will get me the basic understanding on the maths behind this.
Here is a link for a question where the final code of OP may help you understand the how to create locations from coordinates and how to compute the distance between them.
Here is how to create a location:
CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
And here is how to find the distance between two locations:
CLLocationDistance distance = [locationA distanceFromLocation:locationB]; //CLLocationDistance is a double
However you don't have to sort the locations. Just loop through them and add the near locations to an array.
First, I think everyone agrees that to compute distance, you need to use the Haversine function.
Finding the closest point to a given point
If the search time is an issue (iterating over the 800 data points you mentioned) then how about a 2D hash? Simply load the dataset into buckets or regions based on lat/long - then, you won't have to search through the whole data set - only the possible buckets that may contain matches.
Good hash function for a 2d index

Need help with finding nearby location

I am working app which need to find nearby distributors of particular product. As of now I have current locations latitude and longitude. Besides that I also have list of all product distributors with their respective coordinates. I am running query which gives me nearest 10 locations but for that it goes thorough every record in DB calculate distance between current and that particular location. It takes way too much time. Is there any other alternative that can I take ?
Can you not first narrow down the data set by creating a max and min long and lat (say within 10 miles of the current location). You can then query the data set by lat > minLat and lat < maxLax, etc. You could then sort them as you are proposing by calculating the actual distances on the reduced subset if you need too.
To avoid calculating distance on every location you could create a lat long box (lets say for 10 miles) using the max top left lat long (10 miles up and 10 miles left) and the max bottom right lat long (10 miles down and 10 miles right). Then your query will find lat longs in that box using >= and <= and then calculate the distance for each of those to filter out the locations in the corners which exceed 10 miles.
Another other option is to look into spatial indexing for SQLite.
You can narrow down list of location by creating rectangular buffer around your location, to filter locations that are nearby.
SELECT * FROM table t
WHERE t.lat<(lat+buff) AND t.long<(long+buff) AND t.lat>(lat-buff) AND t.long>(long-buff)
lat, long - your location, buff - some value you can adjust to match your app need (e.g. 100
feet, 1 mile, etc)
Then you can ran your distance calculation on returned records.