Вычисление ограничивающей frameworks на некотором расстоянии от координаты lat / long в Java

Учитывая координату (lat, long), я пытаюсь вычислить квадратную ограничительную рамку, которая является заданным расстоянием (например, 50 км) от координаты. Так как вход у меня есть lat, long и distance, а в качестве вывода я бы хотел две координаты; один из которых – юго-западный (нижний левый) угол, а один – северо-восточный (верхний правый) угол. Я видел пару ответов здесь, которые пытаются решить этот вопрос в Python, но я ищу, в частности, реализацию Java.

Чтобы быть ясным, я намерен использовать только алгоритм на Земле, поэтому мне не нужно размещать переменный радиус.

Он не должен быть очень точным (+/- 20% в порядке), и он будет использоваться только для расчета ограничивающих коробок на небольших расстояниях (не более 150 км). Поэтому я рад пожертвовать некоторой точностью для эффективного алгоритма. Буду признателен за любую оказанную помощь.

Редактировать: я должен был быть более ясным, я действительно после квадрата, а не круга. Я понимаю, что расстояние между центром квадрата и различными точками по периметру квадрата не является постоянным значением, как с кругом. Я предполагаю, что я имею в виду квадрат, где, если вы нарисуете линию от центра до любой из четырех точек периметра, которая приводит к линии, перпендикулярной стороне периметра, то эти 4 линии имеют одинаковую длину.

    7 Solutions collect form web for “Вычисление ограничивающей frameworks на некотором расстоянии от координаты lat / long в Java”

    Я написал статью о поиске граничных координат:

    http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates

    Статья объясняет формулы, а также предоставляет реализацию Java. (Это также показывает, почему формула 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 содержит ваш конверт. На самом деле это не «квадрат» (что бы это ни значило на поверхности сферы), но он должен это делать.

    Следует отметить, что расстояние в gradleусах будет зависеть от широты центральной точки. На экваторе 1 gradleус широты около 111 км, но в Нью-Йорке это всего около 75 км.

    Действительно здорово, что вы можете подбросить все свои очки в com.vividsolutions.jts.index.strtree.STRtree а затем использовать его для быстрого вычисления точек внутри этого конверта.

    У меня есть PHP-скрипт и пример, который делает это. Учитывая начальную точку, он вычисляет углы прямоугольника вокруг него на определенном расстоянии. Он специально предназначен для Карт Google, но он может работать для чего угодно:

    http://www.richardpeacock.com/blog/2011/11/draw-box-around-coordinate-google-maps-based-miles-or-kilometers

     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.

    Это вычисляет, но Google Планета Земля не принимает и не отображает 3D-модель.

     /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package assetmap; public class Main { public double degrees; public double pi= 3.1416; public static double lon=80.304737; public static double lat=26.447521; public static double x1,x2,y1,y2; public static void main(String[] args) { double R = 6371; // earth radius in km 26.447521 double radius = 0.300; // km x1 = (lon - Math.toDegrees(radius / R / Math.cos(Math.toRadians(lat)))); x2 = (lon + Math.toDegrees(radius / R / Math.cos(Math.toRadians(lat)))); y1 = (lat + Math.toDegrees(radius / R)); y2 = (lat - Math.toDegrees(radius / R)); System.out.println(x1+"---|"+x2+"---|"+y1+"|---|"+y2); } } 

    Он печатает

     80.30172366789824---|80.30775033210176---|26.450218964817754|---|26.444823035182242 

    KML:

     < ?xml version="1.0" encoding="UTF-8"?>   United Nations Headquarters   26.447251203518224 26.447790796481772 80.30503833321018 80.30443566678983 0 30 absolute   128 -1 0 0    absolute  80.304737 26.447521 0.406173708576   0 0 0   10 10 10   un.dae    _01.jpg ../images/_01.jpg   _02.jpg ../images/_02.jpg   _04.jpg ../images/_04.jpg   _05.jpg ../images/_05.jpg   _06.jpg ../images/_06.jpg   _07.jpg ../images/_07.jpg   _08.jpg ../images/_08.jpg   _09.jpg ../images/_09.jpg      

    Все предыдущие ответы являются лишь частично правильными . Специально в регионе, таком как Австралия, они всегда include полюс и вычисляют очень большой прямоугольник даже для 10 км.

    Специально алгоритм Ян Филип Матучек по адресу http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#UsingIndex включал в себя очень большой прямоугольник из (-37, -90, -180, 180) почти для каждой точки Австралии. Это поражает крупных пользователей в базе данных, а расстояние должно быть рассчитано для всех пользователей почти в половине страны.

    Я обнаружил, что API-интерфейс Drupal API Earth от Rochester Institute of Technology работает лучше вокруг полюса, а также в другом месте и его намного проще реализовать.

    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 retLats = earth_latitude_range(lat, radius, distance); List 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 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 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 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 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. Для (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; 

    Вот простое решение, которое я использовал для создания координатных прямоугольных координат, которые я использую с API-интерфейсом GeoNames citieJSON, чтобы получить близлежащие большие города с десятичной координатой gps.

    Это метод Java из моего репозитория GitHub: FusionTableModifyJava

    У меня было десятичное местоположение GPS, и мне нужно было найти самый большой город / штат «рядом» с этим местоположением. Мне понадобилась относительно точная ограничивающая рамка, чтобы перейти в cityService.ru, чтобы вернуть самый большой город в этой ограничивающей коробке. Я передаю местоположение и «радиус», в которых меня интересует (в км), и он возвращает северные, южные, восточные, западные десятичные координаты, необходимые для перехода в города.

    (Я нашел эти ресурсы полезными при проведении моих исследований:

    Вычислите расстояние, опору и больше между точками широты / долготы.

    Долгота – Википедия )

    Это не слишком точно, но достаточно точно для того, что я использовал для:

      // 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; } } 
    Давайте будем гением компьютера.