Best way to calculate distance between two Postcodes (UK)? - javascript

What method do you recommend I use to calculate the distance between two UK postcodes to decide whether it is in range or not?
I will not be displaying a map, simply showing a list of results of valid locations. e.g. Locations within 50 miles of BT53 6EX

This is just a suggestion, you don't really specify anything to answer you question in a satisfactory way.
Store latitude and longitude along postcodes and filter so that latitude AND longitude difference is within 50 miles:
SELECT * FROM postcodes WHERE ABS(latitude - #lat) < 50 AND ABS(longitude - #lng) < 50
Then filter the resulting set by computing the actual distance, because the query above would return all in a square 50 miles distance, not in a radial distance.

Related

ol3 - calculate real meters in epgs 3857

I use ol3 as a map service.
I have made a linestring with two points with coordinates : [[0,0],[0,1000]] and calculated the distance using the vincenty formula. This resulted in 1000 meter, what is accurate.
But when i made another linestring for example [[4052627,3971934],[4052627,3972934]] vincenty distance was around 850 meters.
I dont know what i forgot here. Any way to correct that? I want to calculate epgs:3857 meters (units) for a given real distance.
You can use ol.sphere.haversineDistance:
var c1 = [4052627, 3971934];
var c2 = [4052627,3972934];
var wgs84Sphere = new ol.Sphere(6378137);
var length = wgs84Sphere.haversineDistance(
ol.proj.transform(c1, 'EPSG:3857', 'EPSG:4326'),
ol.proj.transform(c2, 'EPSG:3857', 'EPSG:4326'));
// 833.12 m
Distances are tricky. The fact that the map units of a coordinate system are in meters (as epsg:3857) doesn't mean that you can measure distances in meters directly. See https://en.wikipedia.org/wiki/List_of_map_projections, and look how many of those have the "equidistant" property.
I suggest you use turf.js to calculate accurate geodetic distances: http://turfjs.org/static/docs/module-turf_distance.html
After alot of search I've found this PDF document:
Web Mercator:
Non-Conformal, Non-Mercator
There is something called Point Scale Factor - according to the way web Mercator is projected - which has tow values, not one like normal Mercator , North/South Scale Factor and East/West Scale Factor.
in my program I've ignored the East/West Scale Factors because it's to much small.
Once I've calculated the scale factor the real distance is almost equal to scale_factor * epgs_3857_distence

Query database values based on user's location

How can I perform a query on the database as per the user's location value? The application was developed with HTML5, CSS, Javascript, PHP has a database with columns as in the below table.
On the html webpage the users geo coordinates are collected and are to be compared with the values in the database to find the nearest place to the user with the places in the database.
Please let me know how to achieve this. Any examples / samples will be appreciated.
There is a question that compares the capabilities of various spatial databases, GIS: PostGIS/PostgreSQL vs. MySql vs. SQL Server?, where Postgis comes out a pretty clear winner over MySQL.
Whether you use MySQL or Postgis, you would be much better off, if you can, storing your latitude and longitude values as a geometry/geography (Point), as the functions that can be used to find things nearby, ST_Distance, ST_Distance_Sphere and the more obscure <-> operator, see Find n Nearest Neighbors for given Point using PostGIS? (for example usage) work directly on geometry/geography columns. Even more importantly, you can add a spatial index, which these functions need to work properly, which will outperform searches on separately indexed latitude and longitude columns by a large margin (this will depend on table size, but will grow as table size grows),
In Postgis, you can convert lat and lon to a geometry with:
alter table mytable add column geom (Geometry, 4326);
update mytable set geom = ST_SetSRID(ST_MakePoint(lon, lat), 4326)
create index ix_spatial_mytable_geom on mytable using gist(geom);
At this point, you will be able to very efficient queries to find points near other points, using any of the examples in the above links.
You can do similar things in MySQL, although, it does not support a spatial reference system, ie, the 4326 above, which means lat/lon, and it lacks a ST_MakePoint function, so you would need to use STGeomFromText and concatenate the lat/lon together to make a POINT. It also does everything in planar coordinates, as Claudio and others have stated, which is not an issue with Postgis.
I apologize for a long and somewhat tangential answer, but having done various migrations between databases on large amounts of data (MySQL, SQL Server and Postgres/GIS) and made lots of mistakes on the way, I hope I can set you off in the right direction (and add a bit of future proofing, if you want to start using some other spatial functionality, which Postigs has in spades).
For a rough measure I would try something like the following (only Euclidean geometry, it doesn't take into account the Earth curvature or problems like this).
First you could compute the difference between the user's coordinates and the coordinates of places in the database. Like this:
distLat = abs(userLat - placeLat)
distLong = abs(userLong - placeLong)
Then I would compute the distance between the two points using Pythagora's theorem. So:
distance = squareRoot(distLat * distLat + distLong * distLong)
You can compare the distances of all places in the database and take the minimum, which teoreticaly is the place nearest to the user's position.
If you use MySQL I think that a query like this should work:
SELECT * FROM places ORDER BY MIN(SQRT((p.latitude - userLatitude) * (p.latitude - userLatitude) + (p.longitude - userLongitude) * (p.longitude - userLongitude))) LIMIT 1
Beware that this query could be very slow depending on how many places you have, because it needs to read all the rows in the table and compute the distance for each one. Indexes have no effects.
Anyway, for this kind of problems you should better use GIS or databases with good geospatial extensions. MySQL geospatial extension is not very powerful, even in MySQL 5.6. It has a ST_DISTANCE function but still uses Euclidean geometry which is not very accurate for calculation on a spherical surface like the Earth. Anyway, if you use MySQL 5.6, I think that it should be better to use the ST_DISTANCE function, which is for sure much more optimized than doing calculations "manually" in the query.
See also this article for a deep explanation and more examples: http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc
EDIT
As requested by the OP, I add more details on how to deal with negative coordinates.
Negative coordinates are generally not a big issue. I will try to explain this with some examples.
Take for example the coordinates of the Brooklyn bridge: 40.704391, -73.994675.
With the above formula, the distance of the Brooklyn bridge from the Statue of Liberty is:
sqrt((40.704391 - 40.689167)^2 + (-73.994675 - -74.044444)^2) = 0.052045399
Now consider the distance between the Statue of Liberty and the Brooklyn Bowl (coordinates 40.7179666, -73.9670125), that is:
sqrt((40.7179666 - 40.689167)^2 + (-73.9670125 - -74.044444)^2) = 0.082613886
As you can see the distance of the Brooklyn Bowl from the Statue of Liberty is bigger than the distance of the Brooklyn Bridge. It is correct since the Brooklyn Bowl is 4 miles away from the Statue of Liberty, while the Brooklyn Bridge is only 1 mile away from it.
In this example both the two points has a negative longitude. But the formula works even if one of the two has positive coordinates. For example, the distance between the Statue of Liberty and the Tour Eiffel (Paris, coordinates 48.858360, 2.294460), is:
sqrt((48.858360 - 40.689167)^2 + (2.294460 - -74.044444)^2) = 76.77476134
Then calculate also the distance between the Statue of Liberty and the Colosseum (Rome, coordinates 41.890238, 12.492242):
sqrt((41.890238 - 40.689167)^2 + (12.492242 - -74.044444)^2) = 86.54502063
As you can see it works, the distance of the Colosseum is bigger since it is about 8000km away from the Statue of Liberty, while the Tour Eiffel is about 800 km closer.
The only issue I see is when you have to calculate the distance between two places that are in the far east and in the far west respectively. The above formula will give you a very high distance, but actually the they could be very close. Take for example Anchorage, a city in Alaska (coordinates 61.252240, -149.896769), and Beringovskij, a city in the very east of Russia (coordinates 63.049797, 179.310011). They have a distance of only about 1500 km but with the above formula you get:
sqrt((61.252240 - 63.049797)^2 + (-149.896769 - 179.310011)^2) = 329.2116875
Definitely a too high value for only 1500 km: I would expect something less than 50.
The problem is that the formula calculates the distance taking the central meridian as a reference point, that is the meridian with a 0 degrees latitude. This is good until the distance is "no more that half the Earth".
I think that a solution could be to calculate two distances.
The first with a reference point of 0 degrees: it is what the above formula does.
The second with a reference point of 180 degrees. It's like calculating the distance on a world map shifted by 180 degrees, like this: http://www.bouwman.com/world/Formilab-180.html.
And then take the minimum of these two distances.
Thus the formula becomes a little more complex:
distance = squareRoot(min((userLat - placeLat)^2, (userLat - placeLat - 360)^2) + (userLong - placeLong)^2)
Note that we subtract 360 because it is the distance between the degree -180 and the degree 180.
With this new formula we get correct results for places that are more then 180 degrees away from each other, and we get also the same result given by the previous formula when comparing places that are less then 180 degrees away from each other. The calculate distance Anchorage - Beringovskij is now: 30.84564166.
Of course, as I have already said, this is not an exact method for calculating distances. You can take a look at this article for more "scientific" techniques: https://en.wikipedia.org/wiki/Geographical_distance :D

Converting Southing/Easting GPS coordinates to Latitude/Longitude

I am developing a web application using JQuery Framework and am using Geolocation to determine the locations of our hardware stations to display on Google Maps.
In our database the locations of the sites are stored in Southing/Easting format.
I need a way to convert Southing/Easting coordinates to Latitude/Longitude that Google Maps can understand.
Can anyone please tell me the formula or the best way to approach this problem?
I have done searches on Southing/Easting however nothing came up, more like northing/westing etc and even then, not much info..
The programming part I don't really need much assistance just the actual concepts on how the conversion between these two formats can be performed.
Thanks!
There's not enough information in your question to answer it -- but you may be able to figure out the information on your own. Here's how I would go about it.
Southing and easting (and northing and westing) are simply measuring a distance from a certain "zero-point". It makes it much easier if you know what the zero-point is, and what the units are -- but it's not impossible to convert if you don't.
For example, the city of Atlanta was founded exactly 5 miles west of Decatur, Georgia (I'm assuming due west for this example, although it was actually 5 miles west-by-southwest). And Emory University is 1.5 miles north and 1.5 miles west of Decatur (this is an approximation, but for our purpose, let's assume it's exactly right).
Now let's assume a few things:
We have been told that Atlanta is north-0 and west-8800.
We have been told that Emory University is north-2640 and west-2640.
No one remembers that Decatur is the origin of the grid.
No one remembers what unit is represented by the distances (it's yards, by the way).
If we go to Google Maps and drop a latitude marker (may have to be enabled in Google Maps labs) on the zero-mile post in Atlanta, we find it is at 33.75116, -84.38740.
And if we do the same for Emory University, we find that it is at 33.7909, -84.3248.
Then we can do the following math to find the ratio of longitude to the unknown westing units:
abs( -84.38740 - -84.3248 ) = ( abs ( 8000 - 2640 ) ) * x
0.0626 = 5360 * x
x = 0.0626 / 5360
x = 0.000011679
And from there we can find the longitude of our theoretically-unknown zero-point by multiplying Atlanta's westing value by this factor and then adding it (because Atlanta is west of the prime meridian, and thus has negative longitude numbers) to Atlanta's known longitude:
zero-longitude = -84.38740 + ( 8000 * 0.000011679 )
zero-longitude = -84.293968
Applying the same logic to latitude, we could find a factor based on the unknown northing units:
abs( 33.75116 - 33.7909 ) = ( abs ( 2640 - 0 ) ) * y
0.03974 = 2640 * y
y = 0.03974 / 2640
y = 0.000015053
And we find the zero-latitude point the same way (which is obvious in this example because Atlanta was at north-0 -- but it's good to go through the motions anyway):
zero-latitude = 33.75116 + ( 0 * 0.000015053 )
zero-latitude = 33.75116
So our calculated zero-point is 33.75116, -84.293968. Google Maps confirms that this latitude falls where expected in relation to known points.
So then I could find any other of the northing and westing points by using this derived zero-point and the derived ratios. For example, if we were told something was north-3000 west-500, we'd get it's latitude and longitude as follows:
latitude = 33.75116 + ( 3000 * 0.000015053 )
(adding because we're moving north)
latitude = 33.796319
longitude = -84.293968 - ( 500 * 0.000011679 )
(subtracting because we're moving west)
longitude = -84.2998075
Thus, north-3000 west-500 = 33.796319, -84.2998075
If your zero-point and your units of measure haven't been lost to history, you've got a major head start. If they have, you can use this technique to deduce them -- but you may have to fine-tune it with multiple correlations until you have values that feel reliable.

Group array of lat/lng coordinates together on map

I'm trying to compare an array of lat/lng coordinates for a map to see if any "cluster" or group together. I want to remove the ones that are too close together so if there are 4-5 stacking on top of each other on a map, it wil only show 1 until you zoom in a bit more, and then it will recalculate all of them again.
I've tried comparing the array to itself, but it doesn't seem to give consistant results. Has anyone attempted something like this before?
JSON Example:
[
{
Latitude = "44.033843";
Longitude = "-79.48865499999999";
},
{
Latitude = "44.033843";
Longitude = "-79.48865499999999";
}]
Iterate the nodes and for a zoom level only display those that are beyond a set distance from each other. The haversine formula is simple enough to implement: example in JS here.
http://www.movable-type.co.uk/scripts/latlong.html
For the efficiency aspect, you probably don't want to calculate the entire list against the temporary list on every iteration so as a first level declutter a simple rounding works (every degree being ~60 miles from each other) ... start with rounding to the nearest 5 degrees, then 1, then 10ths, 100ths, etc as you zoom in. Ordering these lists and pulling unique array values first - then calculating distances from the resultant list.
There are certainly many other algorithms to do it - but at some point you have to calculate distances.
EDIT: this assumes you're happy to fudge things a little bit, and instead of worrying about the actual distance between points on the globe, you look at the "Manhattan" distance of their lat/long coordinates. It depends on how precise you need to be, and whether you have points near the Earth's poles. But for most practical purposes this assumption should be fine.
Suppose your desired precision is one decimal place. Then I would just iterate through the array, building up a has where the keys are the rounded coordinates and the values are arrays of lat/long pairs which round to the corresponding key.
hash = Hash.new
latLongArray.each { |point|
key = [point.lat.round(1), point.long.round(1)]
hash[key] = Array(hash[key]) + [point.lat, point.long]
}
This way you have them clustered, and you can in fact just put markers at the coordinates given by the keys themselves.

GPS coordinates: 1km square around a point

I was hoping someone out there could provide me with an equation to calculate a 1km square (X from a.aaa to b.bbb, Y from c.ccc to c.ccc) around a given point, say lat = 53.38292839 and lon = -6.1843984? I'll also need 2km, 5km and 10km squares around a point.
I've tried googling around to no avail... It's late at night and was hoping someone might have quick fix handy before I delve into the trigonometry...
I'll be running all this in Javascript, although any language is fine.
If the world were a perfect sphere, according to basic trigonometry...
Degrees of latitude have the same linear distance anywhere in the world, because all lines of latitude are the same size. So 1 degree of latitude is equal to 1/360th of the circumference of the Earth, which is 1/360th of 40,075 km.
The length of a lines of longitude depends on the latitude. The line of longitude at latitude l will be cos(l)*40,075 km. One degree of longitude will be 1/360th of that.
So you can work backwards from that. Assuming you want something very close to one square kilometre, you'll want 1 * (360/40075) = 0.008983 degrees of latitude.
At your example latitude of 53.38292839, the line of longitude will be cos(53.38292839)*40075 = [approx] 23903.297 km long. So 1 km is 1 * (360/23903.297) = 0.015060 degrees.
In reality the Earth isn't a perfect sphere, it's fatter at the equator. And the above gives a really good answer for most of the useful area of the world, but is prone to go a little odd near the poles (where rectangles in long/lat stop looking anything like rectangles on the globe). If you were on the equator, for example, the hypothetical line of longitude is 0 km long. So how you'd deal with a need to count degrees on that will depend on why you want the numbers.
Here is something from my notes to be used on Android with its decimal GPS.
Lat Long:
NY City 40N 47 73W 58 40.783333 73.966667
Wash DC 38N 53 77W 02 38.883333 77.033333
yields = 209 miles !! VERY CLOSE
Distance (miles) (x) = 69.1 (lat2-lat1)
Distance(miles) (y) = 53.0 (long2 - long1)
As crow flys sqrt (x2 + y2) ... duh!#
delta(LAT) / Mile = .014472
delta(LONG) / Mile = .018519
Using a box as approximation
To find someone within 100 miles (100 north / 100 south, 100 E / 100 W)
From 0,0
-14.472 / + 14.472 , -18.519 / 18.519
A simpler way of generating a gps square given the centre would be to use the indirect Vincenty algorithm.The Javascript code here shows how to do it http://www.movable-type.co.uk/scripts/latlong.html.
Creating a square using a circle isn't to hard. Squares are equal distance to each point. So given a centre point, distance from the centre, change the bearing from 0 or any number depending on rotation of the square and increment by 90 degrees or PI/2 radians. By incrementing by 90 degrees each time and you will up with a square in circular space.
I use this myself for generating GPS points around a centre point with a given distance
.---.
--/-
--0--
-/--
.---.
TL;DR
10 km = 0.08999 radius from a certain geopoint. This calculation is only based on latitude values and applies only to geopoints with WGS84 projection.
More details
If you want a more accurate answer you must have to calculate it by building a function of some sort. However it still don't guarantee because people even quarrel for the degrees of error. Taking altitude into account, mercator or not, etc.
Caution
The value above is just a rule of a thumb so don not use it for critical applications.
Reference
GIS StackExchange, How do I calculate the bounding box for given a distance and latitude/longitude, answer by David the Australian developer

Categories