문제

좌표 (LAT, Long)가 주어지면 좌표에서 멀리 떨어진 거리 (예 : 50km)의 정사각형 경계 상자를 계산하려고합니다. 따라서 입력으로서 나는 LAT, 길고 거리 및 출력으로 두 개의 좌표를 원합니다. 하나는 남서쪽 (왼쪽 하단) 코너이고 하나는 북동쪽 (오른쪽 상단) 코너입니다. 나는 여기에 Python 에서이 질문을 해결하려는 몇 가지 답을 보았지만 특히 Java 구현을 찾고 있습니다.

분명히 말하면, 나는 지구의 알고리즘을 사용하려고하므로 가변 반경을 수용 할 필요가 없습니다.

크게 정확할 필요는 없으며 (+/- 20%는 괜찮습니다) 작은 거리 (150km 이하)에서 경계 상자를 계산하는 데만 사용됩니다. 따라서 효율적인 알고리즘에 대한 정확성을 희생하게되어 기쁩니다. 모든 도움은 대단히 감사합니다.

편집 : 나는 더 명확 했어야했는데, 나는 정말로 원이 아닌 정사각형을 따른다. 나는 정사각형의 중심과 광장 주변을 따라 다양한 지점 사이의 거리는 원과 같은 일정한 값이 아니라는 것을 이해합니다. 나는 당신이 중앙에서 주변의 4 점 중 하나로 선을 그린다면 주변의 측면에 수직 인 선을 나타 내면 그 4 줄의 길이가 같은 정사각형이라고 생각합니다.

도움이 되었습니까?

해결책

경계 좌표 찾기에 관한 기사를 썼습니다.

http://janmatuschek.de/latitudelongitudeboundingcoordinates

이 기사는 공식을 설명하고 Java 구현도 제공합니다. (또한 Min/Max 경도에 대한 Ironman의 공식이 부정확 한 이유를 보여줍니다.)

다른 팁

double R = 6371;  // earth radius in km

double radius = 50; // km

double x1 = lon - Math.toDegrees(radius/R/Math.cos(Math.toRadians(lat)));

double x2 = lon + Math.toDegrees(radius/R/Math.cos(Math.toRadians(lat)));

double y1 = lat + Math.toDegrees(radius/R);

double y2 = lat - Math.toDegrees(radius/R);

나는 또한 JTS를 추천하지만.

import com.vividsolutions.jts.geom.Envelope;

...
Envelope env = new Envelope(centerPoint.getCoordinate());
env.expandBy(distance_in_degrees); 
...

이제 Env에는 봉투가 들어 있습니다. 실제로는 "정사각형"(구의 표면에서 의미가 무엇이든)은 아니지만해야합니다.

정도의 거리는 중심점의 위도에 따라 다릅니다. 적도에서는 위도 1도 약 111km이지만 뉴욕에서는 약 75km입니다.

정말 멋진 것은 모든 포인트를 com.vividsolutions.jts.index.strtree.STRtree 그런 다음 해당 봉투 내부의 점을 빠르게 계산하는 데 사용하십시오.

이전 답변은 모두 부분적으로 만 정확합니다. 특히 호주와 같은 지역에서는 항상 극을 포함하고 10km의 경우에도 매우 큰 사각형을 계산합니다.

특히 Jan Philip Matuschek의 알고리즘 http://janmatuschek.de/latitudelongitudeboundingcoordinates#usingindex 호주의 거의 모든 지점에 대해 (-37, -90, -180, 180)의 매우 큰 사각형이 포함되었습니다. 이로 인해 데이터베이스의 대규모 사용자가 발생하며 거의 절반의 모든 사용자에 대해 거리를 계산해야합니다.

나는 그것을 발견했다 Rochester Institute of Technology의 Drupal API Earth 알고리즘 폴과 다른 곳에서도 더 잘 작동하며 구현하기가 훨씬 쉽습니다.

https://www.rit.edu/drupal/api/drupal/sites%21all%21modules%21location%21earth.inc/7.54

사용 earth_latitude_range 그리고 earth_longitude_range 경계 사각형 계산을위한 위의 알고리즘에서

구현은 Java입니다

    /**
 * Get bouding rectangle using Drupal Earth Algorithm
 * @see https://www.rit.edu/drupal/api/drupal/sites%21all%21modules%21location%21earth.inc/7.54
 * @param lat
 * @param lng
 * @param distance
 * @return
 */
default BoundingRectangle getBoundingRectangleDrupalEarthAlgo(double lat, double lng, int distance) {
    lng = Math.toRadians(lng);
    lat = Math.toRadians(lat);
    double radius = earth_radius(lat);
    List<Double> retLats = earth_latitude_range(lat, radius, distance);
    List<Double> retLngs = earth_longitude_range(lat, lng, radius, distance);
    return new BoundingRectangle(retLats.get(0), retLats.get(1), retLngs.get(0), retLngs.get(1));
}


/**
 * Calculate latitude range based on earths radius at a given point
 * @param latitude
 * @param longitude
 * @param distance
 * @return
 */
default List<Double> earth_latitude_range(double lat, double radius, double distance) {
      // Estimate the min and max latitudes within distance of a given location.

      double angle = distance / radius;
      double minlat = lat - angle;
      double maxlat = lat + angle;
      double rightangle = Math.PI / 2;
      // Wrapped around the south pole.
      if (minlat < -rightangle) {
        double overshoot = -minlat - rightangle;
        minlat = -rightangle + overshoot;
        if (minlat > maxlat) {
          maxlat = minlat;
        }
        minlat = -rightangle;
      }
      // Wrapped around the north pole.
      if (maxlat > rightangle) {
        double overshoot = maxlat - rightangle;
        maxlat = rightangle - overshoot;
        if (maxlat < minlat) {
          minlat = maxlat;
        }
        maxlat = rightangle;
      }
      List<Double> ret = new ArrayList<>();
      ret.add((minlat));
      ret.add((maxlat));
      return ret;
    }

/**
 * Calculate longitude range based on earths radius at a given point
 * @param lat
 * @param lng
 * @param earth_radius
 * @param distance
 * @return
 */
default List<Double> earth_longitude_range(double lat, double lng, double earth_radius, int distance) {
      // Estimate the min and max longitudes within distance of a given location.
      double radius = earth_radius * Math.cos(lat);

      double angle;
      if (radius > 0) {
        angle = Math.abs(distance / radius);
        angle = Math.min(angle, Math.PI);
      }
      else {
        angle = Math.PI;
      }
      double minlong = lng - angle;
      double maxlong = lng + angle;
      if (minlong < -Math.PI) {
        minlong = minlong + Math.PI * 2;
      }
      if (maxlong > Math.PI) {
        maxlong = maxlong - Math.PI * 2;
      }

      List<Double> ret = new ArrayList<>();
      ret.add((minlong));
      ret.add((maxlong));
      return ret;
    }

/**
 * Calculate earth radius at given latitude
 * @param latitude
 * @return
 */
default Double earth_radius(double latitude) {
      // Estimate the Earth's radius at a given latitude.
      // Default to an approximate average radius for the United States.
      double lat = Math.toRadians(latitude);

      double x = Math.cos(lat) / 6378137.0;
      double y = Math.sin(lat) / (6378137.0 * (1 - (1 / 298.257223563)));

      //Make sure earth's radius is in km , not meters
      return (1 / (Math.sqrt(x * x + y * y)))/1000;
    }

그리고 사용하십시오 Google지도에서 문서화 한 거리 계산 공식 거리를 계산합니다

https://developers.google.com/maps/solutions/store-locator/clothing-store-locator#outputting-data-as-xml-using-php

마일 대신 킬로미터를 검색하려면 3959를 6371로 교체하십시오.for (lat, lng) = (37, -122) 및 열 LAT 및 LNG가있는 마커 테이블, 공식은 다음과 같습니다.

SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS distance FROM markers HAVING distance < 25 ORDER BY distance LIMIT 0 , 20;

다음은 내가 사용하는 경계 박스 좌표를 생성하는 데 사용한 간단한 솔루션입니다. Geonames Citiejson API GPS 소수점 좌표에서 근처의 대도시에 도착합니다.

이것은 내 Github 저장소의 Java 메소드입니다. FusiontableModifyjava

나는 소수점 GPS 위치를 가지고 있었고 그 위치에 가장 큰 도시/주를 "가까이"찾아야했습니다. Citiessson Geonames Webservice로 전달하기 위해 비교적 정확한 경계 상자가 필요했습니다. 나는 (KM)에 관심이있는 위치와 "반경"을 통과시키고 Citiessson으로 전달하는 데 필요한 북쪽, 남쪽, 동쪽, 서쪽 소수점 좌표를 돌려줍니다.

(이 자료가 내 연구에 유용한 것을 발견했습니다.

위도/경도 지점 사이에서 거리, 베어링 등을 계산합니다.

경도 -Wikipedia)

매우 정확하지는 않지만 사용하고 있던 것에 대해 충분히 정확합니다.

    // Compute bounding Box coordinates for use with Geonames API.
    class BoundingBox
    {
        public double north, south, east, west;
        public BoundingBox(String location, float km)
        {
             //System.out.println(location + " : "+ km);
            String[] parts = location.replaceAll("\\s","").split(","); //remove spaces and split on ,

            double lat = Double.parseDouble(parts[0]);
            double lng = Double.parseDouble(parts[1]);

            double adjust = .008983112; // 1km in degrees at equator.
            //adjust = 0.008983152770714983; // 1km in degrees at equator.

            //System.out.println("deg: "+(1.0/40075.017)*360.0);


            north = lat + ( km * adjust);
            south = lat - ( km * adjust);

            double lngRatio = 1/Math.cos(Math.toRadians(lat)); //ratio for lng size
            //System.out.println("lngRatio: "+lngRatio);

            east = lng + (km * adjust) * lngRatio;
            west = lng - (km * adjust) * lngRatio;
        }

    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top