Question

Etant donné une coordonnée (lat, long), je suis en train de calculer un cadre de contour carré qui est une distance donnée (par exemple de 50 km) à l'écart de la coordonnée. Donc, comme je l'entrée de latitude, à long et à distance et en sortie, je voudrais deux coordonnées; étant le coin sud-ouest (en bas à gauche) et étant le coin nord-est (en haut à droite). Je l'ai vu quelques réponses ici qui tentent de répondre à cette question en Python, mais je suis à la recherche d'une implémentation Java en particulier.

Pour être clair, je compte sur l'utilisation de l'algorithme sur la Terre seulement et donc je ne pas besoin de recevoir un rayon variable.

Il ne doit pas être extrêmement précis (+/- 20% est très bien) et il sera seulement utilisé pour calculer boîtes englobantes sur de petites distances (plus de 150km). Je suis donc heureux de sacrifier une certaine précision pour un algorithme efficace. Toute aide est très appréciée.

Edit: Je suis plus claire, je suis vraiment après un carré, pas un cercle. Je comprends que la distance entre le centre d'un carré et des points différents le long du périmètre de la place n'est pas une valeur constante comme il est avec un cercle. Je suppose que ce que je veux dire est un carré où, si vous tracez une ligne du centre à l'une des quatre points sur le périmètre qui se traduit par une ligne perpendiculaire à un côté du périmètre, puis les 4 lignes ont la même longueur.

Était-ce utile?

La solution

J'ai écrit un article sur la recherche les coordonnées englobante:

http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates

L'article explique les formules et fournit également une implémentation Java. (Il montre aussi pourquoi la formule de IronMan pour la longitude min / max est inexacte.)

Autres conseils

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);

Bien que je recommande également JTS.

import com.vividsolutions.jts.geom.Envelope;

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

env contient votre enveloppe. Ce n'est pas en réalité un « carré » (quoi que cela signifie sur la surface d'une sphère), mais il doit le faire.

Vous devez noter que la distance en degrés dépendra de la latitude du point central. A l'équateur, 1 degré de latitude est d'environ 111 km, mais à New York, il est seulement à environ 75 km.

La chose vraiment cool est que vous pouvez lancer tous vos points dans un com.vividsolutions.jts.index.strtree.STRtree puis l'utiliser pour calculer rapidement des points à l'intérieur de cette enveloppe.

Toutes les réponses précédentes ne sont que partiellement correcte . Spécialement dans la région comme l'Australie, ils comprennent toujours poteau et calculer un rectangle très grand même pour 10kms.

l'algorithme spécialement par Jan Philip Matuschek http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#UsingIndex inclus un rectangle très large de (-37, -90, -180, 180) pour presque tous les points en Australie. Cette frappe une grande base de données utilisateurs et la distance doivent être calculées pour tous les utilisateurs dans près de la moitié du pays.

Je trouve que le Drupal API Google Earth algorithme par Rochester Institute of Technology fonctionne mieux autour du pôle ainsi qu'ailleurs et est beaucoup plus facile à mettre en œuvre.

https: // www .rit.edu / drupal / api /% / sites drupal 21Toute% 21modules% 21location% 21earth.inc / 7,54

Utilisation earth_latitude_range et earth_longitude_range de l'algorithme ci-dessus pour le calcul de rectangle de délimitation

Voici l'implémentation Java est

    /**
 * 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;
    }

Et utiliser le formule de calcul de la distance documentée par google maps pour calculer la distance

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

Pour effectuer une recherche par kilomètre au lieu de miles, remplacer 3959 par 6371. A (Lat, Lng) = (37, -122) et une table des marqueurs avec des colonnes lat et lng , la formule est la suivante:

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;

Voici une solution simple que j'utilisé pour générer les coordonnées de délimitation que la boîte que j'utilise avec API GeoNames citieJSON pour obtenir les grandes villes à proximité d'une décimale de coordonnées GPS.

Ceci est une méthode Java à partir de mon dépôt GitHub: FusionTableModifyJava

J'ai eu une position GPS décimal et je devais trouver la plus grande ville / état « près de » cet endroit. Je avais besoin d'un cadre de sélection relativement précise pour passer au citiesJSON GeoNames webservice pour récupérer la plus grande ville dans cette zone de délimitation. Je passe l'emplacement et le « rayon » Je suis intéressé (en km) et Redonne au nord, au sud, les coordonnées décimales, à l'est à l'ouest nécessaires pour passer à citiesJSON.

(j'ai trouvé ces ressources utiles pour faire mes recherches:

calculer la distance, portant en plus entre les points de latitude / longitude.

Longitude - Wikipédia )

Il est pas super assez précis mais précis pour ce que je l'ai utilisé pour:

    // 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;
        }

    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top