i have array of lat long like :
var locationList = new Array( '23.2531803, 72.4774396', '22.808782, 70.823863', '24.3310019, 72.8516531', '22.3073095, 73.1810976', '22.3038945, 70.8021599', '23.850809, 72.114838' );
i want get nearest around 25 km 's lat long from first given array which is 23.2531803, 72.4774396
are there any calculation for nearest 25 km 's lat long from given array.
NOTE: for some reason i can not use sql query, because i get lat long from given address
Step 1: Calculate the distance between your start coordinate and every subcoordinate
Step 2: Pick the smallest distance
Step 3: Is it < 25 km? Success!
How to calculate distance between two coordinates:
function distance($lat1, $lon1, $lat2, $lon2) {
$D = 6371; // Earth Radius
$dLat = $lat2-$lat1;
$dLon = $lon2-$lon1;
$a = sin($dLat/2) * sin($dLat/2) +
sin($dLon/2) * sin($dLon/2) * cos($lat1) * cos($lat2);
$b = 2 * atan2(sqrt($a), sqrt(1-$a));
$c = 2 * atan2(sqrt($a), sqrt(1-$a));
return $D * $c;
}
This function thinks of the Earth as a perfect ball, which it is not - slight variations do apply, but are neglible at the 25km diameter you want.
First of all your data array is awfull. You need to make your data more computer readable. Then you can use Pythagorean theorem to calculate the distance from each location. You can save the first distance and index in an variable then replace it with new distance and index if it's shorter.
var closest = {id:0,dist:-1};
var myloc = [23.2531303, 72.4774398]
for(var i = 0; i < locationList.length; i++)
{
var long_lat = locationList[i].match(/([0-9.]+)+/)
long_lat[0] = parseFloat(long_lat[0]);
long_lat[1] = parseFloat(long_lat[1]);
var dist = Math.sqrt(Math.pow(long_lat[0] - myloc[0], 2)+Math.pow(long_lat[1] - myloc[1], 2)));
if((closest.dist == -1) || (closest.dist > dist))
{
closest.dist = dist;
closest.id = i;
}
}
When you like to calculate in JS you may use google.maps.geometry.spherical.computeDistanceBetween() to calculate the distance between the single points.
Store the results in an array, sort the array and when the smallest entry is <25km you got what you want.
Related
I have a map whose South-West and North-East bounds I take and use it to get places between them.
Because of the date-line sometimes the bounds doesn't come as they should as Explained here.
So I thought of working on:
Get which side the North-East lat lng is compared to the South-West,
if its on the right side its fine, but if it's on the left, I have to
do something.
So to know the side, I calculated the bearing(the angle between the line connecting these SW and NE points and a vertical line). So, if the bearing is between 0-90 its proper or else not.
But the problem is:
Here the top point qualifies for a North-East with both lat and lng
positive: 78.52379, 158.70952
and
The bottom point qualifies for a South-West with both lat and lng
negative: -32.1087, -150.3139
Still the map tries to connect the points in reverse direction(may be tries for least distance) and give the bearing as 342 which I will consider as a improper points and try to reverse 1 of them :(
Looks like this an expected way to calculate the bearing, if so is there a way to solve/achieve what I wanted?
EDIT:
function _getBearing($lat1, $lon1, $lat2, $lon2) {
//difference in longitudinal coordinates
$dLon = deg2rad($lon2) - deg2rad($lon1);
//difference in the phi of latitudinal coordinates
$dPhi = log(tan(deg2rad($lat2) / 2 + pi() / 4) / tan(deg2rad($lat1) / 2 + pi() / 4));
//we need to recalculate $dLon if it is greater than pi
if(abs($dLon) > pi()) {
if($dLon > 0) {
$dLon = (2 * pi() - $dLon) * -1;
}
else {
$dLon = 2 * pi() + $dLon;
}
}
//return the angle, normalized
return (rad2deg(atan2($dLon, $dPhi)) + 360) % 360;
}
How can I calculate every Lat/Long coordinates between two Lat/Long coordinates in PHP?
Lets say I have coordinates A:
(39.126331, -84.113288)
and coordinates B:
(39.526331, -84.213288)
How would I calculate every possible coordinates between those two Lat/Long coordinates (in a direct line) up to five decimal places (e.g. 39.12633, -84.11328) and get list of coordinates between the two?
In addition, I have another set of coordinates (Coordinates C) that are slightly off and not on the track of coordinates between A and B.
How could I calculate the distance between coordinates C and the closest coordinates between A and B?
You can compute a voronoi diagram from all the lat lon pairs and then look for adjacent cell. Also note that lat lon are angles and not world coordinate or cartesian coordinates. You can download my PHP class voronoi diagram # phpclasses.org.
Here is what solved this for me,
function point_to_line_segment_distance($startX,$startY, $endX,$endY, $pointX,$pointY)
{
$r_numerator = ($pointX - $startX) * ($endX - $startX) + ($pointY - $startY) * ($endY - $startY);
$r_denominator = ($endX - $startX) * ($endX - $startX) + ($endY - $startY) * ($endY - $startY);
$r = $r_numerator / $r_denominator;
$px = $startX + $r * ($endX - $startX);
$py = $startY + $r * ($endY - $startY);
$closest_point_on_segment_X = $px;
$closest_point_on_segment_Y = $py;
$distance = user_bomb_distance_calc($closest_point_on_segment_X, $closest_point_on_segment_Y, $pointX, $pointY);
return array($distance, $closest_point_on_segment_X, $closest_point_on_segment_Y);
}
function user_bomb_distance_calc($uLat , $uLong , $bLat , $bLong)
{
$earthRadius = 6371; #km
$dLat = deg2rad((double)$bLat - (double) $uLat);
$dlong = deg2rad((double)$bLong - (double) $uLong);
$a = sin($dLat / 2 ) * sin($dLat / 2 ) + cos(deg2rad((double)$uLat)) * cos(deg2rad((double)$bLat)) * sin($dlong / 2) * sin($dlong / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$distance = $earthRadius * $c;
$meter = 1000; //convert to meter 1KM = 1000M
return intval( $distance * $meter ) ;
}
i've to calculate the distance between
(40.851774999999996,14.268123999999998)
and each coordinates into results of an sql query:
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($results as $key => $value) {
echo "distance = ". calculateDistance("40.851774999999996","14.268123999999998",$value['lat'],$value['lng'])."<br>";
}
Where calculateDistance is
function calculateDistance($targetLat,$targetLng,$currentLat,$currentLng){
$r = 6371; // km
$dLat = $targetLat-$currentLat;
$dLng = $targetLng-$currentLng;
$a = sin($dLat/2)*sin($dLat/2) + sin($dLng/2)*sin($dLng/2);
$c = 2*atan2(sqrt($a), sqrt(1-$a));
return $r*$c;
}
it gives me strange result like:
distance = NAN //-> NAN???
distance = 3392.8405117312 // TOO MUCH!
distance = 3392.8405117312 // TOO MUCH!
...
Where is the problem? can someone help me to fix it? :)
According to this answer:
Calculate distance between two latitude-longitude points? (Haversine formula)
You don't convert from degrees to radians.
You formula is incorrect:
They say:
var a =
Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
Math.sin(dLon/2) * Math.sin(dLon/2);
You wrote:
$a = sin($dLat/2)*sin($dLat/2) + sin($dLng/2)*sin($dLng/2);
The cosine is missing in your code.
You need to convert degrees to radians before using it in sin function.
$radians = $degrees * (M_PI/180);
Look at this function, too. It looks a little bit different.
You are referring to the Haversine formula:
http://en.wikipedia.org/wiki/Haversine_formula
There are plenty of examples and code snippets in these pages:
http://rosettacode.org/wiki/Haversine_formula
http://www.codecodex.com/wiki/Calculate_distance_between_two_points_on_a_globe
I've used this snippet in my code, which works very well:
http://www.codecodex.com/wiki/Calculate_distance_between_two_points_on_a_globe#PHP
I have a mysql database table with a list points with their Co-ordinates (x,y)
I want to find the list of points which fall inside the rectangle. This would have been simple had any one side of the rectangle been aligned parallel or perpendicular to any axis. But is not. Which means the rectangle is rotated.
I also have to find the points inside a circle.
Known Data for Rectangle
-Coordinates for all the four points
Known Data for Circle
-Co-ordinates for the center and the radius.
How do I query the mysql table to find the points falling in the rectangle and the circle?
If it matters then the front end I am using is PHP.
A rectangle can be defined by two points representing the opposing corners, eg: A(x,y) and B(x,y). If you have a point C(x,y) that you want to test to see if it is inside the rectangle then:
IF( (Cx BETWEEN Ax AND Bx) AND (Cy BETWEEN Ay AND By) ) THEN
point C is in the rectangle defined by points A and B
ELSE
nope
ENDIF
A circle can be defined by a single point C(x,y) and a radius R. If the distance D between the center and the point P(x,y) is less than the radius R, then it is inside the circle:
And of course you remember the Pythagorean Theoreom, right?
C² = A² + B² SO C = SQRT(A² + B²)
So:
D = SQRT( ABS(Cx - Px)² + ABS(Cy - Py)²)
IF( D <= R ) THEN
point P is inside the circle with center C and radius R
ELSE
nope
ENDIF
edit:
The algorithm for checking if a point is within a polygon is a bit more complex than what I'd prefer to write in a SQL query or stored procedure, but it is entirely possible. It's worth noting that it runs in constant-time and is very lightweight. [requires roughly 6 arithmetic ops and maybe 2 or 3 logic ops for each point in the poly]
To pare down the number calculations required you can simply write your select to get points within a rough bounding box before procesing them further:
WHERE
x BETWEEN MIN(x1,x2,x3,x4) AND MAX(x1,x2,x3,x4)
AND
y BETWEEN MIN(y1,y2,y3,y4) AND MAX(y1,y2,y3,y4)
Assuming the columns containing the x and y values are indexed this might use a few less CPU cycles than simply doing the math, but it's debatable and I'm inclined to call it a wash.
As for the circle you can't possibly get more efficient than
WHERE
SQRT( POW(ABS($Cx - x),2) + POW(ABS($Cy - y),2) ) < $radius
You're far too concerned with the perceived cost of these calculations, just write the code and get it working. This is not the stage to be performing such niggling optimizations.
One thing to add to #Sammitch's answer is, calculating haversine distance in case you are looking at latitudes and longitudes on world map (distance calculation on a spherical surface, since Earth is a sphere ;) https://en.wikipedia.org/wiki/Haversine_formula)
Here's a vanilla Javascript example for calculating that:
function calculateHaversineDistance(lat1x, lon1, lat2x, lon2) {
var R = 6371; // km
var dLat = toRad(lat2x-lat1x);
var dLon = toRad(lon2-lon1);
var lat1 = toRad(lat1x);
var lat2 = toRad(lat2x);
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
}
function toRad(x) {
return x * Math.PI / 180;
}
EDIT->
Here's a php version I wrote:
function toRad($x) {
return $x * pi() / 180;
}
function calculateHaversineDistance($lat1, $lon1, $lat2, $lon2) {
$R = 6371; // km
$dLat = $this->toRad($lat2-$lat1);
$dLon = $this->toRad($lon2-$lon1);
$lat1 = $this->toRad($lat1);
$lat2 = $this->toRad($lat2);
$a = sin($dLat/2) * sin($dLat/2) +
sin($dLon/2) * sin($dLon/2) * cos($lat1) * cos($lat2);
$c = 2 * atan2(sqrt($a), sqrt(1-$a));
return $R * $c;
}
I have a from location (latitude, longitude) and to location (latitude, longitude). After calculating, it should show me what would be the nearest way to go from using a compass. The following is PHP code to do that, but its showing the wrong direction, I need little help on this.
function GreatCircleDirection ($OrigLat, $DestLat, $OrigLong, $DestLong, $Distance)
{
$Result = 0.0;
$L1 = deg2rad($OrigLat);
$L2 = deg2rad($DestLat);
$D = deg2rad($Distance / 60); # divide by 60 for nautical miles NM to degree
$I1 = deg2rad($OrigLong);
$I2 = deg2rad($DestLong);
$Dlong = $I1 - $I2;
$A = sin($L2) - cos($D + $L1 - pi() / 2);
$B = acos($A / (cos($L1) * sin($D)) + 1);
if ((abs($Dlong) < pi() and $Dlong < 0) or (abs($Dlong) > pi() and $Dlong > 0))
{
//$B = (2 * pi()) - $B;
}
$Result = $B;
return rad2deg($Result);
}
function GreatCircleDistance ($OrigLat , $DestLat, $OrigLong, $DestLong)
{
$L1 = deg2rad($OrigLat);
$L2 = deg2rad($DestLat);
$I1 = deg2rad($OrigLong);
$I2 = deg2rad($DestLong);
$D = acos(cos($L1 - $L2) - (1 - cos($I1 - $I2)) * cos($L1) * cos($L2));
# One degree of such an arc on the earth's surface is 60 international nautical miles NM
return rad2deg($D * 60);
}
Bug on if condition:
this is the values in the if condition of greatCircleDirection function, need to know what to change to fix it.
if (0.57700585070933 < 3.1415926535898 and 0.57700585070933 < 0) or (0.57700585070933 > 3.1415926535898 and 0.57700585070933 > 0)
example:
from lat: 33.71,
to lat: 21,
from long: 73.06,
to long: 40 ,
distance: 1908.842544944
direction 104.96527938779 (direction should be 255.87 or so)
Computing the distance is unnecessary; it simply adds more operations and can introduces more numerical errors. Using your style of coding, something like this should work:
function GreatCircleDirection($OrigLat, $OrigLong, $DestLat, $DestLong)
{
$L1 = deg2rad($OrigLat);
$I1 = deg2rad($OrigLong);
$L2 = deg2rad($DestLat);
$I2 = deg2rad($DestLong);
return rad2deg(atan2((sin($I2-$I1),cos($L1)*tan($L2)-sin($L1)*cos($I2-$I1)));
}
The atan2 function takes care of identifying the correct quadrant for the direction, and gives you the angle between -180 to 180 measured from true North, e.g., GreaterCircleDirection(39,-77,21,40) evaluates to 56.76 degrees. Sign convention used: latitudes are positive when north, negative when south; longitudes are positive when east, negative when west.
The calculation is discussed in, among other places, http://patriot.net/~abdali/ftp/qibla.pdf.
Well, your distance calculation checks out. But I see that the answer you get for the initial bearing is (0+105)mod360 rather than (0-105)mod360 (approximately) so I suspect a wrong sign somewhere in the if statement in your GreatCircleDirection function.
Perhaps the worked examples, under "Using the Sine Rule", at http://www.krysstal.com/sphertrig.html will help.