I have just been developing a postcode distance calculator for my Dads company, where all our customers are kept on file and every time a new potential customer makes an enquiry the system will check against all other customers' postcodes. The problem is that it doesn't yet do the distance calculation. Typing in a DT1 postcode with the distance set to 5 miles says that DT1, 2 and 3 are close by. DT2 says DT1 and 2, DT3 says DT1, 3 and 4. This doesn't make any sense. Yet if I put in BH2 with a distance of 50 miles it will bring back Bournemouth, Dorchester, Portsmouth, Bath, Southampton and a couple of other towns. These are all correct - however I do not know what is going on with the DT postcodes. DT11 doesn't bring back any (under 5 miles), nor does DT10 (except for themselves).
I first of all used the root of (x * x + y * y) - I believe this is called Pythagoras' theorem.. not sure since it have been years since I used that term!!
I have also tried the following:
$sinstuff = sin(deg2rad($latitude))*sin(deg2rad($latitude2));
$cosstuff = cos(deg2rad($latitude))*cos(deg2rad($latitude2))*cos(deg2rad($longitude-$longitude2));
$sumstuff = $sinstuff + $cosstuff;
$acosstuff = rad2deg(acos($sumstuff));
$distance = $acosstuff*60*1.1515; //dunno what the 60 and 1.1515 is all about - I got this formula off a website.
This is the formula which seems to be bringing up the weird results. I also notice that the exact distance between DT11 and DT11 is something like +/- 0.00000989{and lots of other numbers}. This also seems a bit odd since, surely, the distance between DT11 and itself is 0...
Has anyone ever done anything like this successfully before?
I do have a massive batch of files - about 158MB in total - containing every UK postcode in full, with its corresponding latitude and longitude. My aim is, rather than comparing the specified full postcode to every other full postcode, to work out which area codes are less than a certain distance away then compare the specified postcode to all the full postcodes which are within these areas. Is this efficient? Is there a more efficient way?
Any help with this would be greatly appreciated.
Regards,
Richard
PS I know there are some sites out there which tell you how to work out distances but I dont seem to be able to get any of them working correctly (as you can tell from above).
PPS I know I can use the Google API for this - but this is not an option since this is going to be an offline application running on a local installation of wamp server. It is for use at trade shows where we cannot guarantee an internet connection.
You're use the haversine formula:
$l1 ==> latitude1
$o1 ==> longitude1
$l2 ==> latitude2
$o2 ==> longitude2
(taken from http://www.go4expert.com/forums/showthread.php?t=339)
function haversine ($l1, $o1, $l2, $o2)
{
$l1 = deg2rad ($l1);
$sinl1 = sin ($l1);
$l2 = deg2rad ($l2);
$o1 = deg2rad ($o1);
$o2 = deg2rad ($o2);
return (7926 - 26 * $sinl1) * asin (min (1, 0.707106781186548 * sqrt ((1 - (sin ($l2) * $sinl1) - cos ($l1) * cos ($l2) * cos ($o2 - $o1)))));
}
That should give you the distance between both points.
I think the Post Office maintains a Postcode-Address file which lists
every UK postcode and its associated address (not sure if it has
lattitude and longitude information). I've seen copies of this (maybe
not totally up to date) on cover discs on various PC magazines in the
past. I'm sure you have to pay for the latest version, but you might be
able to get a starting point by checking out the cover discs from back
issues.
Related
I am looking to get an approximation of the travel distance and time between several locations.
Ideally, I want to be able to send in the GPS coordinates of the locations, use the data of OpenStreetMap, and get as an output a distance matrix with the given locations, all of this would be done offline on my AWS server. (Using PHP or C++ would be good)
I am really new to using OpenStreetMap. I have just downloaded the ile-de-france.osm.pbf, which is the map for a region of France.
I have no clue where to start. I am not even sure if it is simple to do it.
Can anyone point me in the right direction? And If OpenStreetMap is not the best solution for getting a distance matrix offline, then what is?
For calculating traveling distances you have to install a router, too. Choose one of the available online routers (many of them can be installed locally and used offline, too) or offline routers. Good choices are OSRM, GraphHopper and gosmore.
OSRM has a distance matrix call, but it's currently limited to a certain quantity of locations.
I've built a script to make large distance matrices with a local OSRM server (it's really simple to compile on Ubuntu).
Here it is https://github.com/sabas/OSRMdistance
I've computed square matrices of more than 300 locations...
There are simple formula to calculate distance between 2 GPS coordinates. For example (you may need to pay attention to the units)
double t1 = sin(y1) * sin(y2);
double t2 = cos(y1) * cos(y2);
double t3 = cos(x1 - x2);
double t4 = t2 * t3;
double t5 = t1 + t4;
double rad_dist = atan(-t5/sqrt(-t5 * t5 +1)) + 2 * atan(1.0f);
double mile = rad_dist * 3437.74677 * 1.1508;
double meter = mile * 1609.3470878864446;
To find the walking/vehicle distance, you break the path into checkpoints by matching nearest "ways" in the database.
Background /
Currently right now we have a 100 or so Lat/Lng wich get mapped onto google maps. The aim is to show the hot spot location of these by selecting from the database La/Lo values that are within a few meters of each other.
The group values will then be used to find the central point and draw a circle on the map of the hot spot.
Current setup /
Currently the datase we are requesting from has just id(int),La(float),Lo(float)
Concept /
What i ''think'' is needed is this
Select * from table
Group by (
( La + 0.30 && La - 0.30) && ( Lo + 0.30 && Lo - 0.30)
)
First off, the earth is not a square so to get accurate distances you will need to use a haversine function (look it up), however, for distances of a few metres , maybe accuracy doesn't matter.
Second, the distance between degrees of lattitude varies between 110.574 and 111.694 km and for degrees of longitude between 111.32 and 0.0 km (yes 0.0km at the poles). In any case 0.3 is somewhere between 0 and 35,000 m - not exactly "a few" unless your hotspots are at the north and/or south poles.
Third, ignoring the bad geography, the SQL statement you are groping for will require a cross join and sorting on calculated distances and will be very slow even for a small data set - you need to look at using whatever support mysql has for native geography types. I know SQL Server has them and I suspect MySQL does too.
Edit
It does, see this question.
I'm working on a project that will track a vehicle as it drives around. The location of the vehicle is taken from the Geoloqi API and showed on a map that automatically is updated. The coordinates is passed to an AHAH function in Drupal that will load some more info about position via some other API:s. One of them is Geonames.org.
I do not want to load data from remote servers too often as this will increase load and use our credits too fast. However. I do want it to be as real time as possible as this is essential to the project. So I thought of doing it like this:
Geonames gives a string of GPS locations for the current street so that it can be drawn on a map. The "line" is given to the next intersection. We would eat our tickets too fast if we asked for current street name every time the location changed but how about at every intersection?
Would it be possible to, in PHP, check if a given gps coordinate is at the line between two other coordinates? It would also be good if this line could be extended a few meters in all directions in order to clear any offset.
Thank you so much for all suggestions.
Your original question comes down to a simple math problem: find an equation of a line given two points that it passes. This part is simple: say, you have two points with (lat1, lon1) and (lat2, lon2) coordinates, then the equation of the line will be
(lon2 - lon1) * X + (lat1 - lat2) * Y + (lat1 * lon2 + lat2 * lon1) = 0
Now, when you get any other point (lat, lon), just put those coordinates as (X, Y) respectively into the equation. If you get 0, then the point is on the line. Then check that your lat is between lat1 and lat2 and your lon is between lon1 and lon2. If yes, then the new point is on the line between the two existing points.
The more complicated part comes from two things:
GPS error. To account for that, you can do some approximation, for example, instead of comparing to 0, give it some leeway, e.g. compare from -err to +err where err is some value that you'd define.
The fact that most streets are not straight. The picture below shows the problem. If you look at the line between the two ends of the top street, the top of the vertical street will be on that line - but that's not what you want. .
Maybe a better approach would be to use a distance change. Do not re-query position if the GPS-reported distance changed by less than some predefined value.
i am designing a recruitment database, and i need it to perform several tasks that all involve integrating a way of calculating distance:
1) calculate the distance the candidate lives from the client?
2) calculate the clients within a radius of the candidates available for work on any given day?
3) calculating the number of candidates with the correct qualifications for the vacancy within a radius of the client.
as you can see i need to calculate the distance in 2 main ways 1) radius 2) as the crow flies, i would prefer exact distance but the first will do.
i know that i can integrate Google maps or some other web based mapping but i want the system to be stand alone so it can function without an internet connection.
the system will have a HTML5 front end and the Back end is in Mysql and PHP.
thank you biagio
The distance between 2 points could be calculated with the following formula :
6371*acos(cos(LatitudeA)*cos(LatitudeB)*cos(longitudeB-longitudeA)+sin(LatitudeA)*sin(latitudeB))
Of course it's a "crow flies" approximation in Km.
Wich can be translated to php by :
$longA = 2.3458*(M_PI/180); // M_PI is a php constant
$latA = 48.8608*(M_PI/180);
$longB = 5.0356*(M_PI/180);
$latB = 47.3225*(M_PI/180);
$subBA = bcsub ($longB, $longA, 20);
$cosLatA = cos($latA);
$cosLatB = cos($latB);
$sinLatA = sin($latA);
$sinLatB = sin($latB);
$distance = 6371*acos($cosLatA*$cosLatB*cos($subBA)+$sinLatA*$sinLatB);
echo $distance ;
With that you could compute the distance between two points (people) and of course determine if a point is in a radius of an other.
Just a thought: If your clients and candidates live in a very limited area, I would use a rectangular map and enter x and y values for all cities in that area in a database.
Due to the pythagorean theorem, you can say:
distance² = (x-value client - x-value candidate)² + (y-value client - y-value candidate)²
First, isn't the radius actually the 'as crow flies' distance from the client to the candidates? Anyway...you will need to figure out an algorithm for computing what you need based on the distance between the points.
If you want the system to be stand-alone you will need to have the values for the coordinates (latitude, longitude) of the points. For this, you will probably need and internet connection and the use of a service like google maps to find the coordinates based on the addresses of the points. But once you store then in your db, you will not need an internet connection.
There is a formula for computing the distance between two points based on the coordinates, you will easily find it :)
I am writing a tool for a game that involves calculating the distance between two coordinates on a toroidal plane 500 units across. That is, [0,0] through [499,499] are valid coordinates, and [0,0] and [499,499] are also right next to each other.
Currently, in my application, I am comparing the distance between a city with an [X,Y] location respective to the user's own [X,Y] location, which they have configured in advance.
To do this, I found this algorithm, which kind of works:
Math.sqrt ( dx * dx + dy * dy );
Because sorting a paged list by distance is a useful thing to be able to do, I implemented this algorithm in a MySQL query and have made it available to my application using the following part of my SELECT statement:
SQRT( POW( ( ".strval($sourceX)." - cityX ) , 2 ) + POW( ( ".strval($sourceY)." - cityY ) , 2 ) ) AS distance
This works fine for many calculations, but does not take into account the fact that [0,0] and [499,499] are kitty-corner to one another.
Is there any way I can tweak this algorithm to generate an accurate distance, given that 0 and 499 are adjacent?
I assume you mean wrapping coordinates and nothing spherical shaped. Like a flat piece of paper where the ends are magically connected to each other.
That means that for a map sized 500x500, the distance in the x (or y) direction is at most 250. (If it would be more than 250 steps, we could better walk 500-x steps backward.)
A simple way to fix this, would be
dx = Math.abs(dx);
dy = Math.abs(dy);
if (dx > 250)
dx = 500 - dx;
if (dy > 250)
dy = 500 - dy;
distance = Math.sqrt ( dx * dx + dy * dy );
Update (torus):
OK, from your own comments, it seems that you do mean the torus -- the surface of a donut -- and not the sphere. (This is a big difference, and you should edit your question: calling it a sphere is wrong.)
For this, the answer is fairly simple -- the cartesian formula you give is more or less correct. However, you need to wrap distances around so that anything greater than or equal to 250=500/2 gets translated down to between 0 and 250.
So the answer is something like (I don't know PHP at all, so this may need to be modified for syntax)
dx1 = min(dx, 500-dx)
dy1 = min(dy, 500-dy);
distance = Math.sqrt(dx1*dx1 + dy1*dy1);
(This assumes that you have defined dx and dy to be the absolute value of the differences.)
Just found this routine which implements the same calculation in a nicely-packaged function.
Original Answer (sphere):
You haven't explained how your (x,y) coordinates map to points on the sphere!
There are (literally) an infinite number of choices, each corresponding to a different map projection, and the formula is different for each of them. Note that no matter what choice you make, the meaning of the two coordinates is very different.
If your (x,y) are really longitude and latitude, for example, there are plenty of canned formulae (i.e., haversine) but you'll have to first translate 0->499 to 0->360 degrees for longitude and -90->90 degrees for latitude. (Note that lon and lat behave very differently on the sphere!)
But I emphasize that any choice you make will distort from the flat geometry that you get if you plot in (x,y) versus the way it really looks on the sphere.
(Finally, if you really mean that the top edge is the same as the bottom and the right the same as the left, then you probably have a torus and not a sphere!)
If you know latitude and longitude of two points - you could use haversine formula to compute distance between two points on sphere.
But as I understood you want formula which is accurate for nearly antipodal points. Haversine formula fails here. In such case you need Vincenty's formula which is accurate even in antipodal cases.
http://en.wikipedia.org/wiki/Great-circle_distance#Formulae
It sounds like you are simply using a special finite Cartesian space that is "tiled". In this case each object does not have a unique position. Instead of (x, y) it is (x + i*w, y + j*h) for all possible integer values i and j and where w and h are the widths and heights of your "window" respectively.
Obviously then the distance is not unique but the minimum distance is which is just min(d(p1,p2))) over all i, j.
If your coordinates are wrapped then you just need to compute it for i=-1,0,1 and j=-1,0,1 then take the smallest one.
That general algorithm is fine for rectangular coordinate systems or very sort distances in spherical coordinates, but it's not appropriate for a spherical coordinate system.
I think a better approach would be based on latitude and longitude, like this:
http://jan.ucc.nau.edu/~cvm/latlongdist.html
MySQL has geo-coding built into it. Why not use that?
http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
Although some of the answers here were very close, the problem was finally solved with this SELECT segment:
SQRT( POW( LEAST( ABS($sourceXstr-cityX), ( 500 +LEAST($sourceXstr,cityX)-GREATEST($sourceXstr,cityX))) , 2 ) + POW( LEAST( ABS($sourceYstr-cityY), ( 500 +LEAST($sourceYstr,cityY)-GREATEST($sourceYstr,cityY))) , 2 ) ) AS distance
I am writing answer if two coordinates are in 2 dimensional plane where ends are not meeting each other which OP has not asked. But it might help someone in future.
If your points are in a 2 dimensional plane, the distance between points (x1, y1) and (x2, y2) is given by the Pythagorean theorem:
d = squareroot( square(x2 - x1) + square(y2 - y1) )
In PHP,
$x1 = $y1 = 2;
$x2 = $y2 = 5;
$distance = sqrt( pow(($x2-$x1),2) + pow(($y2-$y1),2) );
echo $distance; // 4.2426406871193