如何使用json数据中的纬度和经度找到最近的位置

问题描述 投票:0回答:4

我正在尝试创建一个网站,询问用户的位置,然后使用 GeoLocation 找到距用户位置最近的位置(100m 半径),并以 HTML 形式显示结果。

我尝试过的:

$.getJSON("places.json", function (data) {
        for (var i = 0; i < data.length; i++) {
            if ((data[i].lat - poslat) > 0.00200 || (data[i].lng - poslng) > 0.00200) {
            return data[i];
        }

        html += '<p>' + data[i].location + ' - ' + data[i].code + '</p>';
        $('#nearbystops').append(html);
    }
});

places.json

[
{
"code": "0001",
"lat": "1.28210155945393",
"lng": "103.81722480263163",
"location": "Stop 1"
},
{
"code": "0003",
"lat": "1.2777380589964",
"lng": "103.83749709165197",
"location": "Stop 2"
},
{
"code": "0002",
"lat": "1.27832046633393",
"lng": "103.83762574759974",
"location": "Stop 3"
}
]

提前谢谢您! :)

javascript html json geolocation
4个回答
29
投票

要计算两个坐标之间的距离,不能只将值相减。 这很好,但它为您提供了正方形内的坐标。 这可能是合适的,但大多数人确实倾向于按半径搜索位置。 这个函数可以做到这一点...

function distance(lat1, lon1, lat2, lon2, unit) {
    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);
    if (dist > 1) {
        dist = 1;
    }
    dist = Math.acos(dist)
    dist = dist * 180/Math.PI
    dist = dist * 60 * 1.1515
    if (unit=="K") { dist = dist * 1.609344 }
    if (unit=="N") { dist = dist * 0.8684 }
    return dist
}

这是我从这里复制的一段常见代码...

https://www.geodatasource.com/developers/javascript

这就是,在您的示例中使用的...

function distance(lat1, lon1, lat2, lon2, unit) {
  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);
  if (dist > 1) {
    dist = 1;
  }
  dist = Math.acos(dist)
  dist = dist * 180/Math.PI
  dist = dist * 60 * 1.1515
  if (unit=="K") { dist = dist * 1.609344 }
  if (unit=="N") { dist = dist * 0.8684 }
  return dist
}

var data = [{
    "code": "0001",
    "lat": "1.28210155945393",
    "lng": "103.81722480263163",
    "location": "Stop 1"
}, {
    "code": "0003",
    "lat": "1.2777380589964",
    "lng": "103.83749709165197",
    "location": "Stop 2"
}, {
    "code": "0002",
    "lat": "1.27832046633393",
    "lng": "103.83762574759974",
    "location": "Stop 3"
}];

var html = "";
var poslat = 1.28210155945393;
var poslng = 103.81722480263163;

for (var i = 0; i < data.length; i++) {
    // if this location is within 0.1KM of the user, add it to the list
    if (distance(poslat, poslng, data[i].lat, data[i].lng, "K") <= 0.1) {
        html += '<p>' + data[i].location + ' - ' + data[i].code + '</p>';
    }
}

$('#nearbystops').append(html);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="nearbystops"></div>


4
投票

使用 HTML5 地理定位获取当前用户的位置,并找到 100 米内最近的位置。

包含并使用下面的谷歌地图库

<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&libraries=geometry"> </script>


片段

//calculates distance between two points in km's
function calcDistance(p1, p2) {
  return (google.maps.geometry.spherical.computeDistanceBetween(p1, p2) / 1000).toFixed(2);
}

function getPosition(position) {
  var userPosition = {
    lat: position.coords.latitude,
    lng: position.coords.longitude
  };

  $.getJSON("places.json", function(data) {
    for (var i = 0; i < data.length; i++) {

      var p1 = new google.maps.LatLng(userPosition.lat, userPosition.lng);
      var p2 = new google.maps.LatLng(data[i].lat, data[i].lng);

      var distance = calcDistance(p1, p2) * 1000;

      if ((distance * 1000) <= 100) {
        html += '<p>' + data[i].location + ' - ' + data[i].code + '</p>';
        $('#nearbystops').append(html);
      }

    }

  })
}

// get user's current latitude & longitude
function getLocation() {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(getPosition);
  } else {
    alert("Geolocation is not supported by this browser.");
  }
}

getLocation();

3
投票

为了计算两点之间的距离(纬度,经度),在打字稿中实现了半正弦公式的函数。

//There are 6200 points in the JSON file
import data from './json/test.json';

let radians = function (degree: number) {

  // degrees to radians
  let rad: number = degree * Math.PI / 180;

  return rad;
}

const haversine = (lat1: number, lon1: number, lat2: number, lon2: number) => {

  let dlat, dlon, a, c, R: number;

  R = 6372.8; // km
  dlat = radians(lat2 - lat1);
  dlon = radians(lon2 - lon1);
  lat1 = radians(lat1);
  lat2 = radians(lat2);
  a = Math.sin(dlat / 2) * Math.sin(dlat / 2) + Math.sin(dlon / 2) * Math.sin(dlon / 2) * Math.cos(lat1) * Math.cos(lat2)
  c = 2 * Math.asin(Math.sqrt(a));
  return R * c;
}

let test = function () {
  const keys = Object.keys(data);

  let count: number = keys.length;
  for (var _i = 0; _i < count; _i++) {
    var _dummy: number = haversine(
      36.12, -86.67, data[_i].position.lat, data[_i].position.lng);
  }

}

0
投票

您可以使用一些算法:

半正矢公式维基百科

  • 计算球体上两点之间的大圆距离,适用于高精度不重要的小到中等距离。

文森蒂公式维基百科

  • 考虑地球椭球形状的迭代方法,与半正弦公式相比,可提供更高的长距离精度。

等距矩形近似的大圆距离维基百科

  • 一种更快但不太准确的方法,假设地球是平的,对于精度不那么重要的快速计算很有用。

测地线计算 维基百科

  • 使用 WGS84 等先进模型来计算高精度距离,非常适合需要精确测地测量的应用。

余弦球面定律 维基百科

  • 与半正矢公式类似,但结果可能略有不同;有利于球面距离计算。

运行下面的所有脚本,并注意它们如何相互比较,短距离(安娜湾到悉尼)和长距离(安娜湾到圣保罗 - 实际距离是 13,435 公里

半正矢算法:

interface City {
  city: string;
  lat: number;
  lng: number;
}

const cityCoordinates: City[] = [
  { city: 'Sydney', lat: -33.8688, lng: 151.2093 },
  { city: 'Melbourne', lat: -37.8136, lng: 144.9631 },
  { city: 'Wollongong', lat: -34.4278, lng: 150.8931 },
  { city: 'Canberra', lat: -35.2802, lng: 149.1310 },
  { city: 'Brisbane', lat: -27.4698, lng: 153.0251 },
  { city: 'Perth', lat: -31.9505, lng: 115.8605 },
  { city: 'Sao Paulo', lat: -23.5558, lng: 46.6396 }
];

const userLocation: { city: string; lat: number; lng: number } = {
  city: 'Anna Bay',
  lat: -32.7790,
  lng: 152.0858
};

// Function to calculate the distance between two coordinates using Haversine formula
const calculateDistance = (lat1: number, lng1: number, lat2: number, lng2: number): number => {
  const toRadians = (degree: number) => degree * (Math.PI / 180);
  const R = 6371; // Radius of the Earth in km

  const dLat = toRadians(lat2 - lat1);
  const dLng = toRadians(lng2 - lng1);
  const a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
    Math.sin(dLng / 2) * Math.sin(dLng / 2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  return R * c; // Distance in km
};

// Find the closest city to the user's location
const findClosestCity = (userLat: number, userLng: number, cities: City[]): City => {
  let closest: City & { distance: number } = { city: '', lat: 0, lng: 0, distance: Infinity };

  cities.forEach(city => {
    const distance = calculateDistance(userLat, userLng, city.lat, city.lng);
    console.log(`Distance from ${userLocation.city} to ${city.city}: ${distance.toFixed(2)} km`);
    if (distance < closest.distance) {
      closest = { ...city, distance };
    }
  });

  return closest;
};

const closestCity = findClosestCity(userLocation.lat, userLocation.lng, cityCoordinates);
console.log(closestCity)

等距矩形近似算法

// Equirectangular Approximation algorithm
interface City {
  city: string;
  lat: number;
  lng: number;
}

const cityCoordinates: City[] = [
  { city: 'Sydney', lat: -33.8688, lng: 151.2093 },
  { city: 'Melbourne', lat: -37.8136, lng: 144.9631 },
  { city: 'Wollongong', lat: -34.4278, lng: 150.8931 },
  { city: 'Canberra', lat: -35.2802, lng: 149.1310 },
  { city: 'Brisbane', lat: -27.4698, lng: 153.0251 },
  { city: 'Perth', lat: -31.9505, lng: 115.8605 },
  { city: 'Sao Paulo', lat: -23.5558, lng: 46.6396 }
];

const userLocation: { city: string; lat: number; lng: number } = {
  city: 'Anna Bay',
  lat: -32.7790,
  lng: 152.0858
};

// Equirectangular approximation for distance calculation
const equirectangularDistance = (lat1: number, lng1: number, lat2: number, lng2: number): number => {
  const R = 6371; // Radius of the Earth in km
  const dLat = (lat2 - lat1) * (Math.PI / 180);
  const dLng = (lng2 - lng1) * (Math.PI / 180);
  const a = Math.cos(lat1 * (Math.PI / 180)) * Math.sin(dLng);
  const b = Math.sin(dLat);
  return Math.sqrt(a * a + b * b) * R;
};

// Find the closest city to the user's location
const findClosestCity = (userLat: number, userLng: number, cities: City[]): City & { distance: number } => {
  let closest: City & { distance: number } = { city: '', lat: 0, lng: 0, distance: Infinity };

  cities.forEach(city => {
const distance = equirectangularDistance(userLat, userLng, city.lat, city.lng);
console.log(`Distance from ${userLocation.city} to ${city.city}: ${distance.toFixed(2)} km`);
if (distance < closest.distance) {
  closest = { ...city, distance };
}
  });

  return closest;
};

const closestCity = findClosestCity(userLocation.lat, userLocation.lng, cityCoordinates);

console.log('Closest City:', closestCity);

Vincenty 算法(这段代码是正确的,但在这里运行得不好,复制并粘贴到其他地方)

interface City {
  city: string;
  lat: number;
  lng: number;
}

const cityCoordinates: City[] = [
  { city: 'Sydney', lat: -33.8688, lng: 151.2093 },
  { city: 'Melbourne', lat: -37.8136, lng: 144.9631 },
  { city: 'Wollongong', lat: -34.4278, lng: 150.8931 },
  { city: 'Canberra', lat: -35.2802, lng: 149.1310 },
  { city: 'Brisbane', lat: -27.4698, lng: 153.0251 },
  { city: 'Perth', lat: -31.9505, lng: 115.8605 },
  { city: 'Sao Paulo', lat: -23.5558, lng: 46.6396 }
];

const userLocation: { city: string; lat: number; lng: number } = {
  city: 'Anna Bay',
  lat: -32.7790,
  lng: 152.0858
};

// Vincenty formula for distance calculation
const vincentyDistance = (lat1: number, lng1: number, lat2: number, lng2: number): number => {
  const a = 6378137; // Major radius (meters)
  const f = 1 / 298.257223563; // Flattening
  const b = (1 - f) * a; // Minor radius

  const toRadians = (degree: number) => degree * (Math.PI / 180);

  const phi1 = toRadians(lat1);
  const phi2 = toRadians(lat2);
  const L = toRadians(lng2 - lng1);

  const U1 = Math.atan((1 - f) * Math.tan(phi1));
  const U2 = Math.atan((1 - f) * Math.tan(phi2));
  const sinU1 = Math.sin(U1);
  const cosU1 = Math.cos(U1);
  const sinU2 = Math.sin(U2);
  const cosU2 = Math.cos(U2);

  let lambda = L;
  let lambdaPrev: number;
  let iterationLimit = 100;
  let sinSigma: number, cosSigma: number, sigma: number;
  let cos2SigmaM: number, sinAlpha: number, cosSqAlpha: number;
  
  do {
lambdaPrev = lambda;
const sinLambda = Math.sin(lambda);
const cosLambda = Math.cos(lambda);
sinSigma = Math.sqrt((cosU2 * sinLambda) ** 2 + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) ** 2);
cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
sigma = Math.atan2(sinSigma, cosSigma);
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
cosSqAlpha = 1 - sinAlpha ** 2;
cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
const C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
lambda = L + (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM ** 2)));
  } while (Math.abs(lambda - lambdaPrev) > 1e-12 && --iterationLimit > 0);

  const uSq = cosSqAlpha * (a ** 2 - b ** 2) / (b ** 2);
  const A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
  const B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));

  const deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM ** 2) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma ** 2) * (-3 + 4 * cos2SigmaM ** 2)));
  const s = b * A * (sigma - deltaSigma);

  return s / 1000; // Convert meters to kilometers
};

// Find the closest city to the user's location
const findClosestCity = (userLat: number, userLng: number, cities: City[]): City & { distance: number } => {
  let closest: City & { distance: number } = { city: '', lat: 0, lng: 0, distance: Infinity };

  cities.forEach(city => {
const distance = vincentyDistance(userLat, userLng, city.lat, city.lng);
console.log(`Distance from ${userLocation.city} to ${city.city}: ${distance.toFixed(2)} km`); 
if (distance < closest.distance) {
  closest = { ...city, distance };
}
  });

  return closest;
};

const closestCity = findClosestCity(userLocation.lat, userLocation.lng, cityCoordinates);

console.log('Closest City:', closestCity);

大地测量学

interface City {
  city: string;
  lat: number;
  lng: number;
}

const cityCoordinates: City[] = [
  { city: 'Sydney', lat: -33.8688, lng: 151.2093 },
  { city: 'Melbourne', lat: -37.8136, lng: 144.9631 },
  { city: 'Wollongong', lat: -34.4278, lng: 150.8931 },
  { city: 'Canberra', lat: -35.2802, lng: 149.1310 },
  { city: 'Brisbane', lat: -27.4698, lng: 153.0251 },
  { city: 'Perth', lat: -31.9505, lng: 115.8605 },
  {city: 'Sao Paulo', lat: -23.5558, lng: 46.6396}
];

const userLocation: { city: string; lat: number; lng: number } = {
  city: 'Anna Bay',
  lat: -32.7790,
  lng: 152.0858
};

// Function to calculate the geodesic distance using WGS84 ellipsoid
const geodesicDistance = (lat1: number, lng1: number, lat2: number, lng2: number): number => {
  const a = 6378137; // WGS84 major axis (meters)
  const f = 1 / 298.257223563; // Flattening
  const b = (1 - f) * a; // WGS84 minor axis

  const toRadians = (degree: number) => degree * (Math.PI / 180);

  const phi1 = toRadians(lat1);
  const phi2 = toRadians(lat2);
  const lambda1 = toRadians(lng1);
  const lambda2 = toRadians(lng2);

  const L = lambda2 - lambda1;

  const U1 = Math.atan((1 - f) * Math.tan(phi1));
  const U2 = Math.atan((1 - f) * Math.tan(phi2));

  let lambda = L;
  let lambdaPrev;
  let iterationLimit = 100;
  let sinSigma, cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM, C;

  do {
lambdaPrev = lambda;
const sinLambda = Math.sin(lambda);
const cosLambda = Math.cos(lambda);
sinSigma = Math.sqrt(
  (Math.cos(U2) * sinLambda) ** 2 +
  (Math.cos(U1) * Math.sin(U2) - Math.sin(U1) * Math.cos(U2) * cosLambda) ** 2
);
cosSigma = Math.sin(U1) * Math.sin(U2) + Math.cos(U1) * Math.cos(U2) * cosLambda;
sigma = Math.atan2(sinSigma, cosSigma);
sinAlpha = Math.cos(U1) * Math.cos(U2) * sinLambda / sinSigma;
cosSqAlpha = 1 - sinAlpha ** 2;
cos2SigmaM = cosSigma - 2 * Math.sin(U1) * Math.sin(U2) / cosSqAlpha;
C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
lambda = L + (1 - C) * f * sinAlpha * (
  sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM ** 2))
);
  } while (Math.abs(lambda - lambdaPrev) > 1e-12 && --iterationLimit > 0);

  const uSq = cosSqAlpha * (a ** 2 - b ** 2) / (b ** 2);
  const A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
  const B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));

  const deltaSigma = B * sinSigma * (
cos2SigmaM + B / 4 * (
  cosSigma * (-1 + 2 * cos2SigmaM ** 2) - 
  B / 6 * cos2SigmaM * (-3 + 4 * sinSigma ** 2) * (-3 + 4 * cos2SigmaM ** 2)
)
  );
  const s = b * A * (sigma - deltaSigma);

  return s / 1000; // Convert meters to kilometers
};

// Find the closest city to the user's location
const findClosestCity = (userLat: number, userLng: number, cities: City[]): City & { distance: number } => {
  let closest: City & { distance: number } = { city: '', lat: 0, lng: 0, distance: Infinity };

  cities.forEach(city => {
const distance = geodesicDistance(userLat, userLng, city.lat, city.lng);
console.log(`Distance from ${userLocation.city} to ${city.city}: ${distance.toFixed(2)} km\n`);
if (distance < closest.distance) {
  closest = { ...city, distance };
}
  });

  return closest;
};

const closestCity = findClosestCity(userLocation.lat, userLocation.lng, cityCoordinates);

console.log('Closest City:', closestCity);

余弦球面定律

interface City {
  city: string;
  lat: number;
  lng: number;
}

const cityCoordinates: City[] = [
  { city: 'Sydney', lat: -33.8688, lng: 151.2093 },
  { city: 'Melbourne', lat: -37.8136, lng: 144.9631 },
  { city: 'Wollongong', lat: -34.4278, lng: 150.8931 },
  { city: 'Canberra', lat: -35.2802, lng: 149.1310 },
  { city: 'Brisbane', lat: -27.4698, lng: 153.0251 },
  { city: 'Perth', lat: -31.9505, lng: 115.8605 },
  {city: 'Sao Paulo', lat: -23.5558, lng: 46.6396}
];

const userLocation: { city: string; lat: number; lng: number } = {
  city: 'Anna Bay',
  lat: -32.7790,
  lng: 152.0858
};

// Spherical Law of Cosines for distance calculation
const sphericalLawOfCosinesDistance = (lat1: number, lng1: number, lat2: number, lng2: number): number => {
  const toRadians = (degree: number) => degree * (Math.PI / 180);
  const R = 6371; // Radius of the Earth in km

  const lat1Rad = toRadians(lat1);
  const lat2Rad = toRadians(lat2);
  const dLngRad = toRadians(lng2 - lng1);

  const distance = Math.acos(
Math.sin(lat1Rad) * Math.sin(lat2Rad) +
Math.cos(lat1Rad) * Math.cos(lat2Rad) * Math.cos(dLngRad)
  ) * R;

  return distance;
};

// Find the closest city to the user's location
const findClosestCity = (userLat: number, userLng: number, cities: City[]): City & { distance: number } => {
  let closest: City & { distance: number } = { city: '', lat: 0, lng: 0, distance: Infinity };

  cities.forEach(city => {
const distance = sphericalLawOfCosinesDistance(userLat, userLng, city.lat, city.lng);
console.log(`Distance from ${userLocation.city} to ${city.city}: ${distance.toFixed(2)} km`);
if (distance < closest.distance) {
  closest = { ...city, distance };
}
  });

  return closest;
};

const closestCity = findClosestCity(userLocation.lat, userLocation.lng, cityCoordinates);

console.log('Closest City:', closestCity);

© www.soinside.com 2019 - 2024. All rights reserved.