Convert real distance to Google Map distance - google-maps

I have a marker on a Google Map (Android) and I want to move the marker to a new position given bearing and distance.
//lat, lng in degrees. Bearing in degrees. Distance in Km
private LatLng newPostion(Double lat,Double lng,Double bearing,Double distance) {
Double R = 6371; // Earth Radius in Km
Double lat2 = Math.asin(Math.sin(Math.PI / 180 * lat) * Math.cos(distance / R) + Math.cos(Math.PI / 180 * lat) * Math.sin(distance / R) * Math.cos(Math.PI / 180 * bearing));
Double lon2 = Math.PI / 180 * lng + Math.atan2(Math.sin( Math.PI / 180 * bearing) * Math.sin(distance / R) * Math.cos( Math.PI / 180 * lat ), Math.cos(distance / R) - Math.sin( Math.PI / 180 * lat) * Math.sin(lat2));
Double newLat = 180 / Math.PI * lat2;
Double newLng = 180 / Math.PI * lon2;
LatLng newLatLng = new LatLng(newLat, newLng);
return newLatLng;
}
LatLng newPos = newPostion(myMark.getPosition().latitude,myMark.getPosition().longitude, 90.0,3000.0);
Distance is calculated speed * time.
distance = speed * time
Let's say the marker represents a car and the car goes 100 km/h and I need to update the marker every 5 seconds.
distance = 100 * (5/60)
but the problem is showing distance on Google map because Google maps are scaled. Using distance calculated above to move the marker will move the marker much further.
Can anyone help me to convert real distance to Google map distance?

In your distance calculation, you're mixing seconds with minutes (5 seconds, 60 minutes). It should be:
distance = 100 km * (5 sec / 3600 sec)

Related

MySQL query to return closest place comparing to csv stored coordinates along with the distance in meters

I have these two tables:
Table locations
coords
28.08982880911016,-31.649963296195086
Table places
lat
lon
place
28.08982880911016
-31.649963296195086
Test
I want a MySQL (version 5.7.41 compatible) query which can return all records in table 1; however, I do not want to display the coords value as they stored; instead, I want to use ST_Distance_Sphere or Haversine formula to check each coords with the nearest place respecting these cases:
If the nearest value is less than 300 meter it returns that corresponding place value
If the nearest value is between 300 and 1500 meters it returns: "Near " + the value of the corresponding place + "~" + the nearest value in meters + "m"
If the nearest value is more than 1500 it returns "N/A" 3.
Please note that I have around a million records in the table locations, so I need the simplest query with minimal performance impact.
Thanks in advance.
Performing the distance calculation between all locations and all places would be very expensive so we will create a bounding box, which can use available indices to get a subset of places on which to perform the distance calculations.
We are building a bounding box slightly bigger than the 1500m radius we are interested in (to allow for inaccuracy):
dist in degrees latitude = (dist / rEarth) * (180 / pi)
dist in degrees longitude = (dist / rEarth) * (180 / pi) / cos(latitude * pi/180)
dist = 1.550 km
rEarth ≈ 6371 km
dist in degrees latitude = (dist / rEarth) * (180 / pi)
dist in degrees latitude = (1.55 / 6371) * (180 / pi)
dist in degrees latitude = DEGREES(1.55/6371)
dist in degrees latitude = 0.013939
dist in degrees longitude = (dist / rEarth) * (180 / pi) / cos(latitude * pi/180)
dist in degrees longitude = 0.013939 / COS(RADIANS(latitude))
Start the join with a 3.100 km x 3.100 km bounding box centered on the location.coords
Then do point to point distance calc for the entities found:
SELECT *,
/*
* We are pre-splitting the coords here so we don't have to do
* it repeatedly inside the correlated sub-query
*/
SUBSTRING_INDEX(l.coords, ',', 1) AS loc_lat,
SUBSTRING_INDEX(l.coords, ',', -1) AS loc_lon,
(
SELECT CONCAT(
ROUND(ST_Distance_Sphere(
ST_GeomFromText(CONCAT('POINT(', REPLACE(l.coords, ',', ' '),')')),
ST_GeomFromText(CONCAT('POINT(', lat, ' ', lon,')'))
), -1),
'::',
place
) dist
FROM places
WHERE lat BETWEEN loc_lat - 0.013939 AND loc_lat + 0.013939
AND lon BETWEEN loc_lon - (0.013939 / COS(RADIANS(loc_lat))) AND loc_lon + (0.013939 / COS(RADIANS(loc_lat)))
HAVING dist <= 1500
ORDER BY dist ASC
LIMIT 1
) AS place,
(
SELECT
CASE
WHEN SUBSTRING_INDEX(place, '::', 1) < 300 THEN SUBSTRING_INDEX(place, '::', -1)
WHEN SUBSTRING_INDEX(place, '::', 1) BETWEEN 300 AND 1500 THEN CONCAT('Near ', SUBSTRING_INDEX(place, '::', -1), '~', SUBSTRING_INDEX(place, '::', 1))
ELSE 'N/A'
END
) AS place_text
FROM locations l;
This query will work but how it will perform is another matter entirely. Ideally, you should have two composite indices on places: (lat, lon) and (lon, lat) but having at least one of these is critical, otherwise you will be constantly table scanning.

Getting radius in meters/km from latitudeDelta and longitudeDelta

I am requesting data from backend (laravel) based on a set distance between 2 points latitude and longitude eg. Lat= 78.3232 and Long = 65.3234 and distance = 30 miles/kilometers , get the rows within the 30 miles.
The problem I'm having is with distance.
I am using react-native-maps and the zoom in/out is based on the latitudeDelta and longitudeDelta and I don't know how to calculate the radius/distance of them when the user zooms in/out to be sent to the backend and get data based on the points and radius/distance
at the moment, I have this function on the client-side. to determine when to fetch new data when user changes the region. but it has a problem of hard-coded distance (5.0 KM)
const _onRegionChangeComplete = (onCompletedregion: Region) => {
if (initialRegion) {
const KMDistance = helper.distance(
initialRegion?.latitude,
initialRegion?.longitude,
onCompletedregion.latitude,
onCompletedregion.longitude,
"K"
);
if (KMDistance > 5.0) {
props.getNearByReports({ // request backend if distance difference more than 5 kilometers
latitude: onCompletedregion.latitude,
longitude: onCompletedregion.longitude
});
}
}
};
helper.distance // get the difference in distance between the initial points and after the user done changing the region
function distance(
lat1: number,
lon1: number,
lat2: number,
lon2: number,
unit: string
) {
var radlat1 = (Math.PI * lat1) / 180;
var radlat2 = (Math.PI * lat2) / 180;
var theta = lon1 - lon2;
var radtheta = (Math.PI * theta) / 180;
var dist =
Math.sin(radlat1) * Math.sin(radlat2) +
Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
dist = Math.acos(dist);
dist = (dist * 180) / Math.PI;
dist = dist * 60 * 1.1515;
if (unit == "K") {
dist = dist * 1.609344;
}
if (unit == "M") {
dist = dist * 0.8684;
}
return dist;
}
The distance value is hard coded in the backend and frontend (which shouldn't be) cuz when the user zooms in/out , the radius/distance should change too. I am unable to calculate the distance from latitudeDelta and longitudeDelta
// Backend query code (simplified)
SELECT
id, (
6371 * acos (
cos ( radians(78.3232) )
* cos( radians( lat ) )
* cos( radians( lng ) - radians(65.3234) )
+ sin ( radians(78.3232) )
* sin( radians( lat ) )
)
) AS distance
FROM markers
HAVING distance < 5 // hard-coded distance
ORDER BY distance
LIMIT 0 , 20;
latitudeDelta is the amount of degrees that are visible on the screen. 1 degree is always equal to approx. 69 miles, so you can calculate the diameter of the currently visible area in miles with this diameter = latitudeDelta * 69. This is assuming the screen is in portrait mode and, therefore, latitudeDelta is the larger value. If not, use longitudeDelta instead. I hope I understood your question correctly and this is helpful.

Find all nearest zip codes with lat and long from a particular latitude and longitude in sql query

I've a database table in which there are 4 columns.
1. id
2. person_name
3. country
4. zip_code
Now I want all the zip codes with their real latitude and longitude which come in a given radius of 10 mile from a given lat long.
suppose my latitude and longitudes are (19.24947300,72.85681400) and distance is 10 mile, then what SQL query should I make to return all nearest zip codes and their lat longs.
I only have the following query
SELECT ((ACOS(SIN($lat * PI() / 180) * SIN(lat * PI() / 180) + COS($lat * PI()
/ 180) * COS(lat * PI() / 180) * COS(($lon – lon) * PI() / 180)) * 180 / PI()) * 60 *
1.1515) AS `distance` FROM `members` HAVING `distance`<=’10’ ORDER BY `distance` ASC
But it requires the lat longs of all zip codes in the table but I want them in run time.
I'm not sure I understand what you mean by
But it requires the lat longs of all zip codes in the table but I want them in run time.
Since you want a SQL query, I assume that you have a table with every zip code's latitude and longitude.
You probably shouldn't do all that math in your SQL query. I would first pull every zip code that is in a 10 mile x 10 mile square centered in your queried position and then, if you really need just those that are positively in a 10 mile radius, check in your program (I assume you are using PHP, since you have variables starting with $).
SELECT zip, latitude, longitude FROM zip_positions
WHERE latitude > 19.24947300 - DISTANCE and latitude < 19.24947300 + DISTANCE
AND longitude > 72.85681400 - DISTANCE and longitude < 72.85681400 + DISTANCE
where DISTANCE is a rough equivalent to 10 miles in latitude/longitude that you would have to calculate.
Then you would, if you need it, check in PHP (or whatever language you're using) every result to see if it is indeed less than 10 miles from the point queried. I can't help you as to how to precisely convert latitude and longitude to distance in miles.
I assume this abandoned question was resolved, but let me share my opinions here in case someone else is wrestling with this one. I present 3 options for letting closet zip from DB using lat long as the lookup:
DB LOOKUP OPTION 1 (QUICK AND DIRTY):
SET #lat = 41.675868;
SET #long = -73.864484;
SET #tol = .05;
SELECT * FROM mytable.ZipCodes
WHERE latitude >= #lat AND latitude <= #lat + #tol
AND longitude >= #long AND longitude <= #long + #tol
ORDER BY (ABS(latitude-longitude) - ABS(#lat-#long)) ASC
LIMIT 1
OPTION #2 (VARIATION ON #1)
$qry = "SELECT zipcode,cityname,stateabbr FROM dealer-site.ZipCodes WHERE (latitude >= {$lat} AND latitude <= {$lat}+1) AND (ABS(longitude) >= ABS({$long}) AND ABS(longitude) < ABS({$long})+1) ORDER BY latitude ASC LIMIT 1”;
OPTION #3 BEST METHOD CALCULATE . I WOULD TRY TO USE THIS:
SET #latitude = 41.675868;
SET #longitude = -73.864484;
SELECT
*
FROM
(SELECT
*,
(((ACOS(SIN((#latitude * PI() / 180)) *
SIN((latitude * PI() / 180)) + COS((#latitude * PI() / 180)) * COS((latitude * PI() / 180)) * COS(((#longitude - longitude) * PI() / 180)))) * 180 / PI()) * 60 * 1.1515 * 1.609344) AS distance
FROM
mytable.ZipCodes) ZipCodes
WHERE
distance <= 5
LIMIT 10
PHP MYSQL (LEGACY CALL) :
$qry = "SELECT zipcode
FROM (SELECT *,
(((ACOS(SIN(({$lat} * PI() / 180)) *
SIN((`latitude` * PI() / 180)) + COS(({$lat} * PI() / 180)) * COS((`latitude` * PI() / 180)) *
COS((({$long} - `longitude`) * PI() / 180)))) * 180 / PI()) * 60 * 1.1515 * 1.609344)
AS distance
FROM
`MyDB`.ZipCodes) ZipCodes
WHERE distance <= 5
LIMIT 1
";

Draw polygon x meters around a point

How can I create a polygon(only a square in my case) around a given point(lat/lang) x meters around the given point. It's just a visual representation of a geofence but I dont need all the calculations whether a point is outside a geofence or not. I tried using the code below but its creating a rectangle instead of a square and I'm not even sure if the 1000 meter boudaries are being rendered correctly.
var map = new GMap2(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
map.addControl(new GSmallMapControl());
GEvent.addListener(map, 'click', function(overlay, latlng) {
var lat = latlng.lat();
var lng = latlng.lng();
var height = 1000; //meters
var width = 1000; //meters
var polygon = new GPolygon(
[
new GLatLng(lat + height / 2 * 90 / 10000000, lng + width / 2 * 90 / 10000000 / Math.cos(lat)),
new GLatLng(lat - height / 2 * 90 / 10000000, lng + width / 2 * 90 / 10000000 / Math.cos(lat)),
new GLatLng(lat - height / 2 * 90 / 10000000, lng - width / 2 * 90 / 10000000 / Math.cos(lat)),
new GLatLng(lat + height / 2 * 90 / 10000000, lng - width / 2 * 90 / 10000000 / Math.cos(lat)),
new GLatLng(lat + height / 2 * 90 / 10000000, lng + width / 2 * 90 / 10000000 / Math.cos(lat))
], "#f33f00", 2, 1, "#ff0000", 0.2);
map.addOverlay(polygon);
});
I ported this PHP function to calculate the location an arbitrary distance and bearing from a known location, to Javascript:
var EARTH_RADIUS_EQUATOR = 6378140.0;
var RADIAN = 180 / Math.PI;
function calcLatLong(longitude, lat, distance, bearing)
{
var b = bearing / RADIAN;
var lon = longitude / RADIAN;
var lat = lat / RADIAN;
var f = 1/298.257;
var e = 0.08181922;
var R = EARTH_RADIUS_EQUATOR * (1 - e * e) / Math.pow( (1 - e*e * Math.pow(Math.sin(lat),2)), 1.5);
var psi = distance/R;
var phi = Math.PI/2 - lat;
var arccos = Math.cos(psi) * Math.cos(phi) + Math.sin(psi) * Math.sin(phi) * Math.cos(b);
var latA = (Math.PI/2 - Math.acos(arccos)) * RADIAN;
var arcsin = Math.sin(b) * Math.sin(psi) / Math.sin(phi);
var longA = (lon - Math.asin(arcsin)) * RADIAN;
return new GLatLng (latA, longA);
}
I have written a working example of this function that you can check out (source).
I use the Pythagorean Theorem to translate from a width of a square to a radius, if you want to use a simple 1000 meter radius from the center you can do that instead:
// this
var radius = 1000;
// instead of this
var radius = (Math.sqrt (2 * (width * width))) / 2;

how to get accurate or (near accurate) distance between two places? Mysql/PHP

SELECT postcode, lat, lng,
truncate(
(degrees(acos
(sin(radians(lat))
*
sin( radians('.$latitude.'))
+
cos(radians(lat))
*
cos( radians('.$latitude.'))
*
cos( radians(lng - ('.$longitude.')))
)
)
* 69.172), 2)
as distance
FROM myData
This query calculates distance (in miles). But when I check distance for same lat and longitude at google maps my result doesnt match. If the distance is around 10 miles then my result is a bit accurate, but over that it gets wrong (for example, my result showed 13 miles and google showed 22 miles for same post code values)
I got this query from http://forums.mysql.com/read.php?23,3868,3868#msg-3868
How can I get it accurate. Any ideas?
Thanks for help.
UPDATE
I tried #Blixt code in PHP. Picked up 2 sample postcodes and their lats longs
//B28 9ET
$lat1 = 52.418819;
$long1 = -1.8481053;
//CV5 8BX
$lat2 = 52.4125573;
$long2 = -1.5407743;
$dtr = M_PI / 180;
$latA = $lat1 * $dtr;
$lonA = $long1 * $dtr;
$latB = $lat2 * $dtr;
$lonB = $long2 * $dtr;
$EarthRadius = 3958.76; //miles
echo $distance = $EarthRadius * acos(cos($latA) * cos($latB) * cos($lonB - $lonA) + sin($latA) * sin($latB));
Results:
My app - 12.95 miles
Google - 17.8 miles
Any ideas how to get it right?
Have a look at this source code. When I tested it against various other measurement services it seemed to get the same results. It's C# but the math should be easy enough to convert.
Here are the relevant pieces:
public const double EarthRadius = 6371.0072; // Kilometers
//public const double EarthRadius = 3958.76; // Miles
/* ... */
const double dtr = Math.PI / 180;
double latA = this.Latitude * dtr;
double lonA = this.Longitude * dtr;
double latB = other.Latitude * dtr;
double lonB = other.Longitude * dtr;
return GpsLocation.EarthRadius * Math.Acos(Math.Cos(latA) * Math.Cos(latB) * Math.Cos(lonB - lonA) + Math.Sin(latA) * Math.Sin(latB));
Note: The Earth is not perfectly spherical, so the constants used may differ. There is no easy way to make the measurements truly exact. See Wikipedia.