Distance using Latitude and Longitude = NaN (in some cases) - javascript

For two points:
{ lat: -6.346640110015869, lng: -39.293800354003906 }
{ lat: 66.450861, lng: 143.261551 }
Using popular method:
getDistanceBetweenPoints(location1: ILocation, location2: ILocation): number {
const lat1: number = location1.lat,
lng1: number = location1.lng,
lat2: number = location2.lat,
lng2: number = location2.lng,
R = 6378137,
dLat: number = this.toRadians(lat2 - lat1),
dLong: number = this.toRadians(lng2 - lng1),
const a: number =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(this.toRadians(lat1)) *
Math.cos(this.toRadians(lat1)) *
Math.sin(dLong / 2) *
Math.sin(dLong / 2);
// temp helpers
const xx = Math.sqrt(1 - a); ----> a = 1.339 => sqrt(-number) = NaN
const yy = Math.sqrt(a);
const zz = Math.atan2(xx, yy);
const c: number = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance: number = (R * c) / 1000;
I found problem in debug mode:
a > 1
Math.sqrt(1 - a) -> sqrt(<0) = NaN
It means, that a cannot be > 1.
But how to fix that?
map screen

I hope this will work (based on the Wikipedia article):
const RADIUS_OF_EARTH = 6378137;
const from = { lat: -6.346640110015869, lng: -39.293800354003906 };
const to = { lat: 66.450861, lng: 143.261551 };
const distance = (from, to) => {
const latF = from.lat / 180 * Math.PI;
const lngF = from.lng / 180 * Math.PI;
const latT = to.lat / 180 * Math.PI;
const lngT = to.lng / 180 * Math.PI;
const latD = Math.abs(latF - latT);
const lngD = Math.abs(lngF - lngT);
const latH = Math.pow(Math.sin(latD / 2), 2);
const lngH = Math.pow(Math.sin(lngD / 2), 2);
const delta = 2 * Math.asin(Math.sqrt(latH + Math.cos(latF) * Math.cos(latT) * lngH));
return RADIUS_OF_EARTH * delta;
};
console.log(distance(from, to));

Related

How to implement inverse cosine in react js without using math library?

How can I use inverse cosine here?
const volumeCalculator = () => {
const dens = tank.density;
const lHeight = pressure / (dens * 9.81);
// const resHeight = tank.height - lHeight;
const len = tank.length;
const rad = tank.radius;
const circum = 3.1416 * (rad ** 2);
if (tank.vertical === 'Vertical') {
const volume = circum * lHeight;
return volume;
}
const volume = [Math.acos((rad - lHeight) / rad)(rad * 2) - (rad - lHeight) * Math.sqrt(2 * rad * lHeight - (lHeight * 2))] * len;
return volume;
};
I am expecting inverse cosine result on a number.

Recursive golden triangle, which point does the triangles approach?

I am trying to make a rotating zooming recursive golden triangle. It draws a golden triangle, then it draws another one inside it and so on. This was easy, but the challenge is making it zoom in and rotate around the point that the triangles are approaching.
To make it zoom in on that point infinitely I need to come up with the formula to calculate which point the triangles are approaching.
Running demo at this point: https://waltari10.github.io/recursive-golden-triangle/index.html
Repository: https://github.com/Waltari10/recursive-golden-triangle
/**
*
* #param {float[]} pivot
* #param {float} angle
* #param {float[]} point
* #returns {float[]} point
*/
function rotatePoint(pivot, angle, point)
{
const s = Math.sin(angle);
const c = Math.cos(angle);
const pointOriginX = point[0] - pivot[0];
const pointOriginY = point[1] - pivot[1];
// rotate point
const xNew = (pointOriginX * c) - (pointOriginY * s);
const yNew = (pointOriginX * s) + (pointOriginY * c);
const newPoint = [
pivot[0] + xNew,
pivot[1] + yNew,
]
return newPoint;
}
// https://www.onlinemath4all.com/90-degree-clockwise-rotation.html
// https://stackoverflow.com/questions/2259476/rotating-a-point-about-another-point-2d
// Position is half way between points B and C 72 and 72, because AB/BC is golden ratio
function drawGoldenTriangle(pos, height, rotation, color = [0,255,0,255], pivot) {
// golden triangle degrees 72, 72, 36
// golden gnomon 36, 36, 108
// AB/BC is the golden ratio number
// https://www.mathsisfun.com/algebra/sohcahtoa.html
const baseLength = (Math.tan(degToRad(18)) * height) * 2;
const pointA = rotatePoint(pos, rotation, [pos[0], pos[1] - height]); // sharpest angle
const pointB = rotatePoint(pos, rotation, [pos[0] - (baseLength / 2), pos[1]]);
const pointC = rotatePoint(pos, rotation, [pos[0] + (baseLength / 2), pos[1]]);
drawTriangle(pointA, pointB, pointC, [0,255,0,255]);
}
let i = 0;
function drawRecursiveGoldenTriangle(pos, height, rotation, pivot) {
drawGoldenTriangle(pos, height, rotation, [0,255,0,255], pivot);
i++;
if (i > 10) {
return;
}
const hypotenuseLength = height / Math.cos(degToRad(18));
const baseLength = (Math.tan(degToRad(18)) * height) * 2;
const goldenRatio = hypotenuseLength / baseLength;
const newHeight = height / goldenRatio;
const newRotation = rotation - 108 * Math.PI/180
const newPointC = rotatePoint(pos, rotation, [pos[0] + (baseLength / 2), pos[1]]);
// Go half baselength up CA direction from pointC to get new position
const newHypotenuseLength = baseLength;
const newBaseLength = newHypotenuseLength / goldenRatio;
let newPosXRelative = Math.cos(newRotation) * (newBaseLength / 2)
let newPosYRelative = Math.sin(newRotation) * (newBaseLength / 2)
const newPos = [newPointC[0] + newPosXRelative, newPointC[1] + newPosYRelative];
drawRecursiveGoldenTriangle(newPos, newHeight, newRotation, [0,255,0,255], pivot);
}
let triangleHeight = height - 50;
let pivotPoint = [(width/2),(height/2) -50];
let triangleLocation = [width/2, height/2 + 300];
let triangleRotation = 0;
function loop() {
i = 0;
const startTime = Date.now()
wipeCanvasData();
// triangleHeight++;
// triangleRotation = triangleRotation + 0.005;
// drawX(pivotPoint)
// drawX(triangleLocation)
// Pivot point determines the point which the recursive golden
// triangle rotates around. Should be the point that triangles
// approach.
drawRecursiveGoldenTriangle(triangleLocation, triangleHeight, triangleRotation, pivotPoint);
updateCanvas()
const renderTime = Date.now() - startTime
timeDelta = renderTime < targetFrameDuration ? targetFrameDuration : renderTime
this.setTimeout(() => {
loop()
}, targetFrameDuration - renderTime)
}
loop()
What would be the formula to calculate the point that recursive golden triangle is approaching? Or is there some clever hack I could do in this situation?
The starting point of the logarithmic spiral is calculated by startingPoint(a,b,c) where a,b,c are the points of your triangle:
The triangle in the snippet is not a proper 'golden triangle' but the calculations should be correct...
const distance = (p1, p2) => Math.hypot(p2.x - p1.x, p2.y - p1.y);
const intersection = (p1, p2, p3, p4) => {
const l1A = (p2.y - p1.y) / (p2.x - p1.x);
const l1B = p1.y - l1A * p1.x;
const l2A = (p4.y - p3.y) / (p4.x - p3.x);
const l2B = p3.y - l2A * p3.x;
const x = (l2B - l1B) / (l1A - l2A);
const y = x * l1A + l1B;
return {x, y};
}
const startingPoint = (a, b, c) => {
const ac = distance(a, c);
const ab = distance(a, b);
const bc = distance(b, c);
// Law of cosines
const alpha = Math.acos((ab * ab + ac * ac - bc * bc) / (2 * ab * ac));
const gamma = Math.acos((ac * ac + bc * bc - ab * ab) / (2 * ac * bc));
const delta = Math.PI - alpha / 2 - gamma;
// Law of sines
const cd = ac * Math.sin(alpha / 2) / Math.sin(delta);
const d = {
x: cd * (b.x - c.x) / bc + c.x,
y: cd * (b.y - c.y) / bc + c.y
};
const e = {
x: (a.x + c.x) / 2,
y: (a.y + c.y) / 2
};
const f = {
x: (a.x + b.x) / 2,
y: (a.y + b.y) / 2,
};
return intersection(c, f, d, e);
};
d3.select('svg').append('path')
.attr('d', 'M 100,50 L150,200 H 50 Z')
.style('fill', 'none')
.style('stroke', 'blue')
const point = startingPoint({x: 50, y: 200},{x: 100, y: 50},{x: 150, y: 200});
console.log(point);
d3.select('svg').append('circle')
.attr('cx', point.x)
.attr('cy', point.y)
.attr('r', 5)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="200" height="400"></svg>

Inverse of local coordinate system to latitude and longitude

I have a function to convert latitude and longitude to localCordinateSystem
const EARTH_RADIUS_KM = 6371.0;
const distanceInMeters = (lat1, lon1, lat2, lon2) => {
const lonDiff = toRadians(lon2 - lon1);
const latDiff = toRadians(lat2 - lat1);
const a = Math.pow(Math.sin(latDiff / 2), 2) + Math.cos(toRadians(lat1)) *
Math.cos(toRadians(lat2)) * Math.pow(Math.sin(lonDiff / 2), 2);
const angle = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return angle * EARTH_RADIUS_KM * 1000.0;
};
const localCoordinateSystem = (lat, lon, originLat, originLon, radius) => {
let latDist = distanceInMeters(originLat, originLon, lat, originLon);
let lonDist = distanceInMeters(originLat, originLon, originLat, lon);
if (lat < originLat) latDist *= -1;
if (lon < originLon) lonDist *= -1;
return {
x: parseFloat(latDist) + parseFloat(radius),
y: parseFloat(lonDist) + parseFloat(radius),
};
};
If you see the function localCoordinateSystem takes lat, lon, originLat, originLon and radius and returns x and y.
But now I want a function that takes x, y, originLat, originLon and radius and returns lat and lon.

I am trying to get markers near user location by calculating distance using haversine formula

Hey guys can anybody help me why i am getting an error in this code
Here is the code.
getWithinDistance: function(){
var selectedMarker = [];
var lat1 = this.state.region.latitude;
var lon1 = this.state.region.longitude;
for(var i = 0 ; i <= 3 ; i++)
{
var lat2 = this.state.a[i].latitude;
var lon2 = this.state.a[i].longitude;
var R = 6371;
var dLat = (lat2-lat1) * (Math.PI/180);
var dLon = (lon2-lon1) * (Math.PI/180);
var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos((lat1) * (Math.PI/180)) * Math.cos((lat2) * (Math.PI/180)) * Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
if(d <= 2.00){
var latlng = {
latitude: lat2,
longitude: lon2
}
selectedMarker.push(latlng);
}
}
console.log(selectedMarker);
var at = selectedMarker.map(marker => {
return(
<MapView.Marker coordinate={marker.latlng} />
);
})
},
I am getting Warning: Failed prop type: Required prop coordinate was not specified. but when i log it i can see two markers in the array selectedMarker[]
here is the snap of log which i get
Thanks in advance.
You have placed the return statement inside your for loop. So the the loop will exit after the first iteration.
Take these lines out of the for loop.
return (
<MapView.Marker coordinate={this.state.a[i]} />
);
Edit your for loop to store all the markers that are within the required distance in an array and then after the for loop return that array
You can use Array.prototype.map() to iterate and get the values.
Like this:
(ES6 Style)
getWithinDistance: function(){
const lat1 = this.state.region.latitude;
const lon1 = this.state.region.longitude;
const R = 6371
this.state.a.map(coordinate => {
const dLat = (coordinate.latitude - lat1) * (Math.PI/180)
const dLon = (coordinate.longitude - lon1) * (Math.PI/180)
const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos((lat1) * (Math.PI/180)) * Math.cos((lat2) * (Math.PI/180)) * Math.sin(dLon/2) * Math.sin(dLon/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
const d = R * c
console.log(coordinate, d)
}
}
This will show the coordinates with their distance to your location.
The return statement has to be outside the map() function. And return whatever you want to achieve.

Using the Haversine Formula in Javascript

I'm trying to use the Haversine Distance Formula (as found here: http://www.movable-type.co.uk/scripts/latlong.html) but I can't get it to work, please see the following code
function test() {
var lat2 = 42.741;
var lon2 = -71.3161;
var lat1 = 42.806911;
var lon1 = -71.290611;
var R = 6371; // km
//has a problem with the .toRad() method below.
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
alert(d);
}
And the error is:
Uncaught TypeError: Object -0.06591099999999983 has no method 'toRad'
Which I understand to be because it needs to do the following:
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
But when I put this below the function, it still comes back with the same error message. How do I make it use the helper method? Or is there an alternative way to code this to get it to work? Thanks!
This code is working:
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
var lat2 = 42.741;
var lon2 = -71.3161;
var lat1 = 42.806911;
var lon1 = -71.290611;
var R = 6371; // km
//has a problem with the .toRad() method below.
var x1 = lat2-lat1;
var dLat = x1.toRad();
var x2 = lon2-lon1;
var dLon = x2.toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
alert(d);
Notice how I defined x1 and x2.
Play with it at: https://tinker.io/3f794
Here's a refactored function based on 3 of the other answers!
Please note that the coords arguments are [longitude, latitude].
function haversineDistance(coords1, coords2, isMiles) {
function toRad(x) {
return x * Math.PI / 180;
}
var lon1 = coords1[0];
var lat1 = coords1[1];
var lon2 = coords2[0];
var lat2 = coords2[1];
var R = 6371; // km
var x1 = lat2 - lat1;
var dLat = toRad(x1);
var x2 = lon2 - lon1;
var dLon = toRad(x2)
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRad(lat1)) * Math.cos(toRad(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;
if(isMiles) d /= 1.60934;
return d;
}
ES6 JavaScript/NodeJS refactored version:
/**
* Calculates the haversine distance between point A, and B.
* #param {number[]} latlngA [lat, lng] point A
* #param {number[]} latlngB [lat, lng] point B
* #param {boolean} isMiles If we are using miles, else km.
*/
const haversineDistance = ([lat1, lon1], [lat2, lon2], isMiles = false) => {
const toRadian = angle => (Math.PI / 180) * angle;
const distance = (a, b) => (Math.PI / 180) * (a - b);
const RADIUS_OF_EARTH_IN_KM = 6371;
const dLat = distance(lat2, lat1);
const dLon = distance(lon2, lon1);
lat1 = toRadian(lat1);
lat2 = toRadian(lat2);
// Haversine Formula
const a =
Math.pow(Math.sin(dLat / 2), 2) +
Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2);
const c = 2 * Math.asin(Math.sqrt(a));
let finalDistance = RADIUS_OF_EARTH_IN_KM * c;
if (isMiles) {
finalDistance /= 1.60934;
}
return finalDistance;
};
See codepen for tests against accepted answer: https://codepen.io/harrymt/pen/dyYvLpJ?editors=1011
Why not try the straight forward solution? Instead of extending Number prototype, just define toRad as a regular function:
function toRad(x) {
return x * Math.PI / 180;
}
and then call toRad everywhere:
var dLat = toRad(lat2-lat1);
Extending the Number prototype does not always work as expected. For example calling 123.toRad() does not work. I think that if you do var x1 = lat2 - lat1; x1.toRad(); works better than doing (lat2-lat1).toRad()
when I put this below the function
You only need to put it above the point where you call test(). Where the test function itself is declared does not matter.
You need to extend the Number prototype, before calling those extensions in a function.
So just ensure
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
is called before your function is called.
Another variant to reduce redundancy and also compatible with Google LatLng objects:
function haversine_distance(coords1, coords2) {
function toRad(x) {
return x * Math.PI / 180;
}
var dLat = toRad(coords2.latitude - coords1.latitude);
var dLon = toRad(coords2.longitude - coords1.longitude)
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRad(coords1.latitude)) *
Math.cos(toRad(coords2.latitude)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
return 12742 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
Here's another refactored answer in JavaScript:
getHaversineDistance = (firstLocation, secondLocation) => {
const earthRadius = 6371; // km
const diffLat = (secondLocation.lat-firstLocation.lat) * Math.PI / 180;
const diffLng = (secondLocation.lng-firstLocation.lng) * Math.PI / 180;
const arc = Math.cos(
firstLocation.lat * Math.PI / 180) * Math.cos(secondLocation.lat * Math.PI / 180)
* Math.sin(diffLng/2) * Math.sin(diffLng/2)
+ Math.sin(diffLat/2) * Math.sin(diffLat/2);
const line = 2 * Math.atan2(Math.sqrt(arc), Math.sqrt(1-arc));
const distance = earthRadius * line;
return distance;
}
const philly = { lat: 39.9526, lng: -75.1652 }
const nyc = { lat: 40.7128, lng: -74.0060 }
const losAngeles = { lat: 34.0522, lng: -118.2437 }
console.log(getHaversineDistance(philly, nyc)) //129.61277152662188
console.log(getHaversineDistance(philly, losAngeles)) //3843.4534005980404
This is a java implemetation of talkol's solution above. His or her solution worked very well for us. I'm not trying to answer the question, since the original question was for javascript. I'm just sharing our java implementation of the given javascript solution in case others find it of use.
// this was a pojo class we used internally...
public class GisPostalCode {
private String country;
private String postalCode;
private double latitude;
private double longitude;
// getters/setters, etc.
}
public static double distanceBetweenCoordinatesInMiles2(GisPostalCode c1, GisPostalCode c2) {
double lat2 = c2.getLatitude();
double lon2 = c2.getLongitude();
double lat1 = c1.getLatitude();
double lon1 = c1.getLongitude();
double R = 6371; // km
double x1 = lat2 - lat1;
double dLat = x1 * Math.PI / 180;
double x2 = lon2 - lon1;
double dLon = x2 * Math.PI / 180;
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1*Math.PI/180) * Math.cos(lat2*Math.PI/180) *
Math.sin(dLon/2) * Math.sin(dLon/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double d = R * c;
// convert to miles
return d / 1.60934;
}

Categories

Resources