I have an array of users and their gps coordinates.
what formula can I use to get all the users that are within X KM range
from a user?
I need to avoid heavy calculations.
I was thinking about sorting the array, but I realized that it isn't a good idea, because I would have to set a sorted array for each user.
Use the Haversine formula to find the users that are within a specified distance from a specified point:
function getNearbyUsers(lat, lng, distanceInKm, users) {
var R = 6373;
var latRad = lat * Math.PI/180;
var lngRad = lng * Math.PI/180;
var returnUsers = [];
for (var i = 0; i < users.length; i++) {
var lat2Rad = users[i].lat * Math.PI/180;
var lng2Rad = users[i].lng * Math.PI/180;
var dlat = lat2Rad - latRad;
var dlng = lng2Rad - lngRad;
var a = Math.pow(Math.sin(dlat/2),2) + Math.cos(latRad) * Math.cos(lat2Rad) * Math.pow(Math.sin(dlng/2),2);
var c = 2 * Math.atan2(Math.sqrt(a),Math.sqrt(1-a)); // great circle distance in radians
var d = c * R; // Distance from user in km
if (d < distanceInKm) returnUsers.push(users[i]);
}
return returnUsers;
}
Related
I have an array with x elements given lat - lng value. My aim is to find the distance difference between the previous position and the next position in the loop as long as the number of elements (length) of the array with the haversine formula.
Example my array value;
var array = [
[51.06745252933975, -114.11267548799515],
[51.067506465746014, -114.09559518098831],
[51.0827140244322,-114.0949085354805],
[51.088267312195484,-114.10709649324417]];
I don't have a problem with math, my goal is to get the cursor in the loop as the previous element vs. the next actually pointer order.
Sketchy code recipe;
1st index of the loop; array[0] lat-lng and array[1] lat-lng calc distance
2nd index of the loop; array[1] lat-lng and array[2] lat-lng calc distance
I'm using Javascript and how do I do it most ideally?
Seems a bit easy, but I might be not understand the question at all, if the question is how to loop an array by comparing to the previous entry, there are several ways to do it, one way could be shown below
// https://stackoverflow.com/a/27943/28004
function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2-lat1); // deg2rad below
var dLon = deg2rad(lon2-lon1);
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)
;
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c; // Distance in km
return d;
}
function deg2rad(deg) {
return deg * (Math.PI/180)
}
// end of pasted code
// your entry
const points = [
[51.06745252933975, -114.11267548799515],
[51.067506465746014, -114.09559518098831],
[51.0827140244322,-114.0949085354805],
[51.088267312195484,-114.10709649324417]
]
// looping through all points starting from the second element
for (let i = 1; i < points.length; i += 1) {
const lastPosition = points[i-1];
const newPosition = points[i];
console.log(
`from position ${i-1} to ${i} it's %s Km`,
getDistanceFromLatLonInKm(lastPosition[0], lastPosition[1], newPosition[0], newPosition[1]))
}
Keep in mind that there's no validation (1 entry only will through an error) and that the Haversine formula only calculates a straight line between 2 points and does to take into account that the planet is not a sphere.
I'm trying to create a Javascript function that can find the closest coordinate match in an array of coordinates.
My coordinates: 33.9321, 18.8602
These coordinates will vary, but the 4 locations listed below will stay the same.
Location1: 33.9143, 18.5701
Location2: 26.2041, 28.0473
Location3: 25.7479, 28.2293
Location4: 29.8587, 31.0218
try to run my code to see if it helps you.
I have used var home as your stargint point if browser didn't work for you.
Also I have saved all locations in var points so you can change that if you need.
Then I just look over each point and it will output in the console what is the distance to ref point. In your case it's the first point
var home = [ '33.9321', '18.8602' ];
var points = [
[ '33.9143', '18.5701' ],
[ '26.2041', '28.0473' ],
[ '25.7479', '28.2293' ],
[ '29.8587', '31.0218' ]
];
// loop over each point and output distance!
for( var i = 0; i < points.length; i++){
var diff = twoPointsDiff(home[0],home[1],points[i][0],points[i][1]);
console.log( 'distance from point' + (i+1) + ': ' + diff );
}
// helper fn to calc distance
function twoPointsDiff(lat1,lon1,lat2,lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2-lat1); // deg2rad below
var dLon = deg2rad(lon2-lon1);
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)
;
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c; // Distance in km
return d;
}
// helper fn to convert deg to radians
function deg2rad(deg) {
return deg * (Math.PI/180)
}
I am creating a Tangram puzzle game using Javascript. And I need to detect when a user has drawn a circle (or circle like shape) with their finger. I have been able to gather hundreds (if not thousands) of x and y points with:
var touchX = event.targetTouches[0].pageX - canvas.offsetLeft;
var touchY = event.targetTouches[0].pageY - canvas.offsetTop;
I then push each x and y coordinate into an array:
touchMoveX.push(touchX);
touchMoveY.push(touchY);
I then loop through each array and create two points:
for(var i = 0; i < touchMoveX.length; i++)
{
for(var l=0; l < touchMoveY.length; l++)
{
var xPosition = touchMoveX[i];
var yPosition = touchMoveY[l];
var v1x = touchMoveX[i];
var v2x = touchMoveX[i + 1];
var v1y = touchMoveY[l];
var v2y = touchMoveY[l + 1];
Then using those two points, I use the following formula to figure out the angle between these two points in degrees:
var v1 = {x: v1x, y: v1y}, v2 = {x: v2x, y: v2y},
angleRad = Math.acos( (v1.x * v2.x + v1.y * v2.y) /
(Math.sqrt(v1.x*v1.x + v1.y*v1.y) * Math.sqrt(v2.x*v2.x + v2.y*v2.y) ) ),
angleDeg = angleRad * 180 / Math.PI;
I then sum up all of the angles and see if they are around 360 degrees.
But the above code I have described isn't working very well. Does someone out there have a better way to do this? Thank you very much.
yeah compute the average of all points (giving you a cheaply approximated center) then check if more than a certain percent of points are within a certain threshold. You can tune those values to adjust the precision until it feels right.
edit: Didn't consider that the circle could have multiple sizes, but you could just add another step computing the average of all distances. Adjusted the example for that.
var totalAmount = touchMoveX.length;
// sum up all coordinates and divide them by total length
// the average is a cheap approximation of the center.
var averageX = touchMoveX.reduce( function ( previous, current) {
return previous + current;
} ) / totalAmount ;
var averageY = touchMoveY.reduce( function ( previous, current) {
return previous + current;
} ) / totalAmount ;
// compute distance to approximated center from each point
var distances = touchMoveX.map ( function ( x, index ) {
var y = touchMoveY[index];
return Math.sqrt( Math.pow(x - averageX, 2) + Math.pow(y - averageY, 2) );
} );
// average of those distance is
var averageDistance = distances.reduce ( function ( previous, current ) {
return previous + current;
} ) / distances.length;
var min = averageDistance * 0.8;
var max = averageDistance * 1.2;
// filter out the ones not inside the min and max boundaries
var inRange = distances.filter ( function ( d ) {
return d > min && d < max;
} ).length;
var minPercentInRange = 80;
var percentInRange = inRange.length / totalAmount * 100;
// by the % of points within those boundaries we can guess if it's circle
if( percentInRange > minPercentInRange ) {
//it's probably a circle
}
So i want to calculate distance between my start point and multiple points, than display the shortest route to this point,but it show me always the last point. this is my distanceCal function it works fine :
function getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1); // deg2rad below
var dLon = deg2rad(lon2 - lon1);
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)
;
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c; // Distance in km
return d;
}
function deg2rad(deg) {
return deg * (Math.PI / 180)
}
and this is my points latt/long :
var dist = [
[35.733972, -5.881999],
[ 35.734077, -5.881033],
[ 35.736898, -5.877771],
[35.738396, -5.875154]
];
then my script to display directions :
function calcRoute() {
var start = new google.maps.LatLng(35.728329, -5.882750);
for (var i = 0; i < dist.length; i++)
{
var dis = dist[i];
//here i need something to choose the shortest route
var min = Math.min(getDistanceFromLatLonInKm(35.728329, -5.882750, dis[0], dis[1]));
var end = new google.maps.LatLng(dis[0], dis[1]);
}
var request = {
origin: start,
destination: end,
optimizeWaypoints: true,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
google.maps.event.addDomListener(window, 'load', getMap);
so please if someone have any idea or solution i will be very appreciate.
The following code uses Googles geometry library to calculate distances between points.The distances are stored in an array and then parsed to find minimum distance .
I have changed the array from dist[] to coords[] as we need an array to hold distances dist[].
<script type="text/javascript" src="//maps.googleapis.com/maps/api/js?libraries=geometry&sensor=false"></script>
<script type="text/javascript">
var coords = [
[35.733972, -5.881999],
[35.734077, -5.881033],
[35.736898, -5.877771],
[35.738396, -5.875154]
];
var dist = [];//Array to hold distances
function calcRoute() { {
var start = new google.maps.LatLng(35.728329, -5.882750);
for (var i = 0; i < coords.length; i++){
var point = new google.maps.LatLng(coords[i][0],coords[i][1]);
var distance = google.maps.geometry.spherical.computeDistanceBetween(start, point);
dist.push(distance);
}
var test = dist[0];
var index = 0;
for (var i = 1; i < dist.length; i++){
if(dist[i] < test){
test = dist[i];
index = i;
}
}
var end = new google.maps.LatLng(coords[index][0],coords[index][1]);
// Apply the rest of your code here
It sounds like you want to use optimizeWaypoints:true in your DirectionsServiceRequest:
optimizeWaypoints | boolean | If set to true, the DirectionService will attempt to re-order the supplied intermediate waypoints to minimize overall cost of the route. If waypoints are optimized, inspect DirectionsRoute.waypoint_order in the response to determine the new ordering.
The DirectionsResult
Each leg of each route returned includes distance and duration information.
Right now I have an array of locations and one of those locations will be a marker.
The second marker will be based on the location a user searches.
Right now the code is this:
function find_closest_marker( lat1, lon1 ) {
var pi = Math.PI;
var R = 6371; //equatorial radius
var distances = [];
var closest = -1;
var markers = allMyLocations;
for( i=0;i<markers.length; i++ ) {
var lat2 = markers[i][1];
var lon2 = markers[i][2];
var chLat = lat2-lat1;
var chLon = lon2-lon1;
var dLat = chLat*(pi/180);
var dLon = chLon*(pi/180);
var rLat1 = lat1*(pi/180);
var rLat2 = lat2*(pi/180);
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(rLat1) * Math.cos(rLat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
distances[i] = d;
if ( closest == -1 || d < distances[closest] ) {
closest = i;
}
var closestMarker = markers[closest];
var newLat = markers[closest][1]
var newLon = markers[closest][2]
var b = new google.maps.LatLng(newLat, newLon);
map.setCenter(b);
map.setZoom(10);
google.maps.event.addListenerOnce(map, 'tilesloaded', function(){
ShowHideMenu();
if($('#newPos').length==0){
$('div.gmnoprint').last().parent().wrap('<div id="newPos" />');
}
//showInfoWindow(map, closest);
});
}
}
Right now this code gets the closest location from where a user searches and centers that on the page. What I'm trying to do is make it zoom so that the the location searched is centered and the location in the array is within the area of the maps. The map isn't a normal size, it is 790px by 400px.
Can someone please help me with the logic of zoom and how I could make this possible?
Have you tried the LatLngBounds function This function will construct a viewable are based upon the soutwest and north east corners. As a result the pins will be centered in the map. You can use zoom if you want but you could omit it to see if it gives you the desired result.
A sample of the code would be:
make your declaration
var mybounds = new google.maps.LatLngBounds();
then within your event listener where you create the markers add
mybounds.extend(b);
then finally outside of the event listener
map.fitBounds(mybounds)