How to move a marker 100 meters with coordinates - php

I have 2 coordinates. Coordinate 1 is a 'person'. Coordinate 2 is a destination.
How do I move coordinate 1 100 meters closer to coordinate 2?
This would be used in a cron job, so only php and mysql included.
For example:
Person is at: 51.26667, 3.45417
Destination is: 51.575001, 4.83889
How would i calculate the new coordinates for Person to be 100 meters closer?

Use Haversine to calculate the difference between the two points in metres; then adjust the value of the person coordinates proportionally.
$radius = 6378100; // radius of earth in meters
$latDist = $lat - $lat2;
$lngDist = $lng - $lng2;
$latDistRad = deg2rad($latDist);
$lngDistRad = deg2rad($lngDist);
$sinLatD = sin($latDistRad);
$sinLngD = sin($lngDistRad);
$cosLat1 = cos(deg2rad($lat));
$cosLat2 = cos(deg2rad($lat2));
$a = ($sinLatD/2)*($sinLatD/2) + $cosLat1*$cosLat2*($sinLngD/2)*($sinLngD/2);
if($a<0) $a = -1*$a;
$c = 2*atan2(sqrt($a), sqrt(1-$a));
$distance = $radius*$c;
Feeding your values of:
$lat = 51.26667; // Just South of Aardenburg in Belgium
$lng = 3.45417;
$lat2 = 51.575001; // To the East of Breda in Holland
$lng2 = 4.83889;
gives a result of 102059.82251083 metres, 102.06 kilometers
The ratio to adjust by is 100 / 102059.82251083 = 0.0009798174985988102859004569070625
$newLat = $lat + (($lat2 - $lat) * $ratio);
$newLng = $lng + (($lng2 - $lng) * $ratio);
Gives a new latitude of 51.266972108109 and longitude of 3.4555267728867

Find the angle theta between the x-axis and the vector from person to destination.
theta = Atan2(dest.y-person.y, dest.x-person.x).
Now use theta and the amount you want to advance the point to calculate the new point.
newPoint.x = advanceDistance * cos(theta) + person.x
newPoint.y = advanceDistance * sin(theta) + person.y

If you understand JavaScript, you may want to check out the moveTowards() method in the following Stack Overflow post:
How to add markers on Google Maps polylines based on distance along the line?
This method returns the destination point when given a start point, an end point, and the distance to travel along that line. You can use point 1 as the starting point, point 2 as the end point, and a distance of 100 meters. It's written in JavaScript, but I'm sure it can be easily ported to PHP or MySQL.
You may also want to check out this other Stack Overflow post which implements a part of the above JavaScript implementation, as a user defined function for SQL Server 2008, called func_MoveTowardsPoint:
Moving a Point along a Path in SQL Server 2008
The above uses SQL Server 2008's in-built geography data type. However you can easily use two decimal data types for latitude and longitude in place of the single geography data type.
Both the SQL Server and the JavaScript examples were based on implementations from Chris Veness's article Calculate distance, bearing and more between Latitude/Longitude points.

Related

How to fill any circle drawn on a map with smaller circles having variable radius?

To Do
Get sub areas of a bigger area in order to use it in subsequent calls to an API that provides data by location, but has Radius Limit.
Approach
Wrap the big area in a square
Use a method to get a new location given a main location, an angle and a distance
Calculate the first top-left sub-location position
Get the rest of sub-locations from top-left to bottom-right, except ones that get outside of main area too much
Issue
When the radius of the main area increases and approaches the poles, calculating a location based on another location, angle and distance, gets tricky. Please note how the top of the main area is not covered by sub areas.
And it gets to something like below when radius of main area increases dramatically.
Given the fact that my function that calculates location base on other location, angle and distance is the following (PHP). How can I improve it order to make it work regardless of what the bit area is?
function getLocation($lat, $lng, $dist, $brng)
{
$lat1 = degToRad($lat);
$lon1 = degToRad($lng);
$dist = $dist/AVG_ERAD; //Earth's radius in km
$brng = degToRad($brng);
$lat2 = asin(sin($lat1) * cos($dist) +
cos($lat1) * sin($dist) * cos($brng));
$lon2 = $lon1 + atan2(sin($brng) * sin($dist) * cos($lat1),
cos($dist) - sin($lat1) * sin($lat2));
$lon2 = fmod(($lon2 + 3 * pi()),(2 * pi())) - pi();
return array(
'lat' => radToDeg($lat2),
'lng' => radToDeg($lon2)
);
}
I'd suggest another order of small circle's filling:
Get the northest point of big circle (step R from center C to the
north), make it a center of the first small circle
Step about r*3/2 to the east and west until distance to C exceeds R+r to make the first row
Step central small circle about r*3/2 to the south. Repeat (2)
Repeat (3) until center small circle leaves big circle
Example of traversal order:
5 4 1 2 3
12 11 10 6 7 8 9
... 13...

Finding Points in a Rectangle or Circle with mysql

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;
}

LinearRing with direction KML

I have a database with points (coordinates) and headings (direction/azimuths). I would like to create pie shaped sectors(LinearRing) pointing in the headings direction in kml. Anyone has any suggestions on how to build this using php?
Ok, php is not my strength. Here is pseudo-code, which might help you (*).
"On a sphere of radius r, compute points on a great circle at specified azimuths and ranges. PHI, LAMBDA, PHI0, LAMBDA0, and AZ are angles in radians, and RNG is a distance having the same units as R."
INPUT: phi0, lambda0, az, rng, r
OUTPUT: phi,lambda
rng = rng / r; // Convert the range to an angle on the sphere (in radians).
epsilon = 1.7453e-07; // Set tolerance
if(phi0 >= pi / 2 - epsilon) // starting at north pole
az = pi;
if(phi0 <= epsilon - pi / 2) // starting at south pole
az = 0;
// Calculate coordinates of great circle end point using spherical trig.
phi = asin( sin(phi0) * cos(rng) + cos(phi0) * sin(rng) * cos(az) );
lambda = lambda0 + atan2( sin(rng) * sin(az) , cos(phi0) * cos(rng) - sin(phi0) * sin(rng) * cos(az) );
phi0 and lambda0 are your initial coordinates and az your heading. Vary az +/- a certain range in order to obtain points, which form the circle segment of the pie. The rest should be straight-forward.
(*) Source: http://mind.cog.jhu.edu/courses/680/octave/Installers/Octave/Octave.OSX10.6/Applications/MATLAB_R2009b.app/toolbox/map/map/private/greatcirclefwd.m

latitude / longitude formula in php solution for determining a NSWE corners from a central point

lat/long outward distance approx 800ft on each side from center.
I have a central point of:
Latitude:38.6806353
Longitude:-96.5001029
I am trying to resolve a formula with php how to get the latitude / longitude to the NWSE corners approx 800ft outward from a center point.
So I would end up with a result similar to (but not correct):
Central:
38.6806353 -96.5001029
N: 38.6806353 -96.5001029
W: 38.6806353 -96.5001029
S: 38.6806353 -96.5001029
E: 38.6806353 -96.5001029
I've been trying to reverse engineer a few Javascripts that I found, but having absolutly no luck.
Is there a php Class available that does this math or similar that would require minor revisions? I can't find one thus far...
I found this function and I've been toying with it. I can get a nice array output like:
Array ( [0] => -112.35301079549 [1] => 36.105603064867 [2] => -112.25722008867 [3] => 36.105603064867 )
But I can't get a N W S E coordinates set to generate? Anyone know what I am doing wrong with this? I need 4 sets of values instead of two like:
N: 38.6806353 -96.5001029
W: 38.6806353 -96.5001029
S: 38.6806353 -96.5001029
E: 38.6806353 -96.5001029
<?php function getBoundingBox($lon_degrees,$lat_degrees,$distance_in_miles) {
$radius = 3963.1; // of earth in miles
// bearings
$due_north = 0;
$due_south = 180;
$due_east = 90;
$due_west = 270;
// convert latitude and longitude into radians
$lat_r = deg2rad($lat_degrees);
$lon_r = deg2rad($lon_degrees);
// find the northmost, southmost, eastmost and westmost corners $distance_in_miles away
// original formula from
// http://www.movable-type.co.uk/scripts/latlong.html
$northmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_north));
$southmost = asin(sin($lat_r) * cos($distance_in_miles/$radius) + cos($lat_r) * sin ($distance_in_miles/$radius) * cos($due_south));
$eastmost = $lon_r + atan2(sin($due_east)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)-sin($lat_r)*sin($lat_r));
$westmost = $lon_r + atan2(sin($due_west)*sin($distance_in_miles/$radius)*cos($lat_r),cos($distance_in_miles/$radius)-sin($lat_r)*sin($lat_r));
$northmost = rad2deg($northmost);
$southmost = rad2deg($southmost);
$eastmost = rad2deg($eastmost);
$westmost = rad2deg($westmost);
// sort the lat and long so that we can use them for a between query
if ($northmost > $southmost) {
$lat1 = $southmost;
$lat2 = $northmost;
} else {
$lat1 = $northmost;
$lat2 = $southmost;
}
if ($eastmost > $westmost) {
$lon1 = $westmost;
$lon2 = $eastmost;
} else {
$lon1 = $eastmost;
$lon2 = $westmost;
}
return array($lon1,$lat1,$lon2,$lat1);
}
?>
I noticed that $due_north, $due_south, etc are in degrees but you have sin($due_east) without a conversion of $due_east to radians.
For 90 deg bearing (east), θ= pi/2 (90 deg), d/R will be 800ft / 5280 ft/mi / 3959 miles (radius of earth in miles), lat1/lon1 are your center point lat/lon in radians.
east_lat = asin(sin(lat1)*cos(d/R) + cos(lat1)*sin(d/R)*cos(θ))
east_lon = lon1 + atan2(sin(θ)*sin(d/R)*cos(lat1), cos(d/R)−sin(lat1)*sin(lat2))
Convert back to degrees then repeat for the other 3 corners.
The comment in your code references the website:
http://www.movable-type.co.uk/scripts/latlong.html
Go to the section Destination point given distance and bearing from start point. You can check your calculations with the calculator on the web page.
The bounding box must satisfy some conditions you didn't mentioned. For example Google Maps uses a z curve and 21 zoom level to subdivide the map into smaller tiles. I don't know how big is a single tile in distance but I use the script from John Brafford to convert from geo coordinate to WGS84 Datum. There is also a method to return the bounding box of a tile. You can find the script here: http://bafford.com/software/aggregate-map-tools/GlobalMapTiles.php.txt.

rhumb line calculation - javascript to php

This example and java script code is from link text
Look at the section on rhumb lines.
Given a start point and a distance d along constant bearing θ, this will calculate the destination point. If you maintain a constant bearing along a rhumb line, you will gradually spiral in towards one of the poles.
Formula:
α = d/R (angular distance)
lat2 = lat1 + α.cos(θ)
Δφ = ln(tan(lat2/2+π/4)/tan(lat1/2+π/4)) [= the ‘stretched’ latitude difference]
if E:W line q = cos(lat1)
otherwise q = Δlat/Δφ
Δlon = α.sin(θ)/q
lon2 = (lon1+Δlon+π) % 2.π − π
where ln is natural log and % is modulo, Δlon is taking shortest route (<180°), and R is the earth’s radius
JavaScript:
lat2 = lat1 + d*Math.cos(brng);
var dPhi = Math.log(Math.tan(lat2/2+Math.PI/4)/Math.tan(lat1/2+Math.PI/4));
var q = (!isNaN(dLat/dPhi)) ? dLat/dPhi : Math.cos(lat1); // E-W line gives dPhi=0
var dLon = d*Math.sin(brng)/q;
// check for some daft bugger going past the pole, normalise latitude if so
if (Math.abs(lat2) > Math.PI/2) lat2 = lat2>0 ? Math.PI-lat2 : -(Math.PI-lat2);
lon2 = (lon1+dLon+Math.PI)%(2*Math.PI) - Math.PI;
I am trying to convert it into php syntax but I am not getting the desired result. I have the latitude part working fine. I also included my test data.
MY PHP CODE
// test data
$R = 6371;
$tlatitude = 50.7;
$tlongitude = -105.214;
$theading = 124;
$d = 50;
$projlat = $tlatitude + rad2deg(($d/$R)*COS(deg2rad($theading)));
//Δφ = ln(tan(lat2/2+π/4)/tan(lat1/2+π/4))
$delta_phi = log(tan(deg2rad($projlat/2) + pi()/4)/(tan(deg2rad($tlatitude/2) + pi()/4)));
//q = Δlat/Δφ
$delta_lat = deg2rad($projlat - $tlatitude);
$q = $delta_lat/$delta_phi;
//Δlon = α.sin(θ)/q
$delta_long = rad2deg($d/$R*sin(deg2rad($theading))/$q);
$projlong = $tlongitude + $delta_long;
I get $projlong = -104.84
according to the referenced page the answer should be -104.63.
Now I am trying to get this to work disregarding the east-west and over the pole possibilities.
I had some problems when making distance calculations where my errors would grow quite a bit after a while. I discovered that if I made a cast to (double) in my code the precision increased. I have not looked in to the C-code in PHP to see what caused this though. I could after this scrap my BC-version of the code.
If you need additional precision please check out the BC-functions in PHP.
http://php.net/manual/en/book.bc.php
Also, please remember that the order that you make calculations in a computer will affect your precision. That is, the calculation bellow
$d/$R*sin(deg2rad($theading))/$q
will not render the same result as
$d*sin(deg2rad($theading))/$q/$R
and this can also give a third result
$d*sin(deg2rad($theading))/($q*$R)
This has to do with the limited precision for numbers close to zero (0) in computers.
javascript has more precision than php
look at this joke http://ru2.php.net/manual/en/function.doubleval.php
I once needed to check some IBAN with the Luhn's algorithm.
My javascript code worked nicely.
But my php failed, so after some research, i found the joke and had to recode basic operations (add, sub, compute, divide, modulo) based on string and not number.
Maybe should you recode it too, to get your expected precision.
We should not use php for high precision calculations.

Categories