Question

Cela peut être clair ou non, laissez-moi un commentaire si je suis en dehors de la base ou si vous avez besoin de plus d'informations. Peut-être existe-t-il déjà une solution pour ce que je veux en PHP.

Je recherche une fonction qui va ajouter ou soustraire une distance d’une valeur de longitude OU de latitude.

Raison: j'ai une base de données contenant toutes les latitudes et longitudes et je souhaite créer une requête pour extraire toutes les villes situées à moins de X kilomètres (ou miles). Ma requête ressemblerait à quelque chose comme ça ...

Select * From Cities Where (Longitude > X1 and Longitude < X2) And (Latitude > Y1 and Latitude < Y2)

 Where X1 = Longitude - (distance)
 Where X2 = Longitude + (distance)

 Where Y1 = Latitude - (distance)
 Where Y2 = Latitude + (distance)

Je travaille en PHP avec une base de données MySql.

Ouvert à toutes suggestions aussi! :)

Était-ce utile?

La solution

Ceci est une requête MySQL qui fera exactement ce que vous voulez. N'oubliez pas que ce genre de choses ne sont généralement que des approximations, car la terre n'est pas parfaitement sphérique et ne prend pas en compte les montagnes, les collines, les vallées, etc. Nous utilisons ce code sur AcademicHomes.com avec PHP et MySQL, il renvoie les enregistrements situés dans un rayon de $ kilomètres de rayon de $ latitude, $ longitude.

$res = mysql_query("SELECT
    * 
FROM
    your_table
WHERE
    (
        (69.1 * (latitude - " . $latitude . ")) * 
        (69.1 * (latitude - " . $latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3))
    ) < " . pow($radius, 2) . " 
ORDER BY 
    (
        (69.1 * (latitude - " . $latitude . ")) * 
        (69.1 * (latitude - " . $latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $longitude . ") * COS(" . $latitude . " / 57.3))
    ) ASC");

Autres conseils

EDIT: Si vous avez, quelque part, une liste de toutes les villes du monde avec leur lat. et long. valeurs, vous pouvez faire une recherche. Dans ce cas, voir mon premier lien ci-dessous pour la formule permettant de calculer la largeur d'un degré longitudinal à la latitude alt text:

alt text

Honnêtement, les complications de ce problème sont telles que vous auriez intérêt à utiliser un service tel que Google Maps pour obtenir vos données. Plus précisément, la Terre n’est pas une sphère parfaite et la distance entre deux degrés varie à mesure que vous vous rapprochez / vous éloignez de l’équateur.

Voir http://en.wikipedia.org/wiki/Geographic_coordinate_system pour des exemples de ce que je veux dire et consultez l'API Google Maps .

En fonction du nombre de villes que vous incluez, vous pouvez précalculer la liste. Nous faisons cela ici pour une application interne où une imprécision de + 100m est trop importante pour notre configuration. Cela fonctionne en ayant une table à deux clés de location1, location2, distance. Nous pouvons alors retirer très rapidement les positions x la distance par rapport à la position1.

De plus, puisque les calculs peuvent être effectués hors ligne, cela n’a aucune incidence sur le fonctionnement du système. Les utilisateurs obtiennent également des résultats plus rapides.

J'ai essayé d'utiliser le code ci-dessus, et les réponses étaient décevantes lorsque la distance entre les points était comprise entre 20 et 30 milles, et je suis d'accord avec quelques milles d'erreur. J'ai discuté avec un copain de la cartographie et nous avons plutôt choisi celui-ci. Le code est en python, mais vous pouvez le traduire assez facilement. Afin d'éviter la conversion constante en radians, j'ai refait ma base de données en convertissant les points lat / lng de degrés en radians. La bonne chose à ce sujet est que la plus grande partie du calcul est principalement faite une fois.

ra = 3963.1906 # radius @ equator in miles, change to km  if you want distance in km
rb = 3949.90275  # radius @ poles in miles, change to km  if you want distance in km
ra2 = ra * ra
rb2 = rb * rb

phi = self.lat

big_ol_constant = (math.pow(ra2*math.cos(phi), 2) + pow(rb2*math.sin(phi), 2))/ (pow(ra*math.cos(phi), 2) + pow(rb*math.sin(phi), 2))

sqlWhere = "%(distance)g > sqrt((power(lat - %(lat)g,2) + power(lng-%(lng)g,2)) * %(big_ol_constant)g)" % {
    'big_ol_constant': big_ol_constant, 'lat': self.lat, 'lng': self.lng, 'distance': distance}

# This is the Django portion of it, where the ORM kicks in.  sqlWhere is what you would put after the WHERE part of your SQL Query.
qs = ZipData.objects.extra(where=[sqlWhere]);

semble être très précis lorsque la distance est petite, et dans un rayon de 10 miles ou plus lorsque la distance passe à 200 miles (bien sûr, à ce moment-là, vous avez des problèmes avec "à vol d'oiseau" ou "routes pavées"). ;).

Voici le modèle ZipData que j'ai mentionné ci-dessus.

class ZipData(models.Model):
    zipcode = ZipCodeField(null=False, blank=False, verbose_name="ZipCode", primary_key=True)
    city = models.CharField(max_length=32, null=False, blank=False)
    state = models.CharField(max_length=2)
    lat = models.FloatField(null=False, blank=False)
    lng = models.FloatField(null=False, blank=False)

Une remarque supplémentaire, c’est que vous pouvez obtenir BEAUCOUP de données géographiques liées aux codes postaux sur GeoNames. org et ils ont même des API de service Web que vous pouvez également utiliser.

Il y en a beaucoup (mauvaises options)

  • Calculez la distance en utilisant la formule mathématique (traiter X1-X2 et Y1-Y2) en tant que vecteurs.

  • Créez une table de recherche à l'avance avec toutes les combinaisons et conservez les distances.

  • Pensez à utiliser une extension MySQL spécifique au SIG. Voici un article que j'ai trouvé à ce sujet. .

lessthandot.com a en fait 3 manières différentes de le faire. vous devrez parcourir les blogs un peu, mais ils sont là. http://blogs.lessthandot.com/

La fonction ci-dessous provient du nerddinner (exemple d'application ASP.NET MVC disponible sur codeplex ) base de données (MSSQL).

ALTER FUNCTION [dbo].[DistanceBetween] (@Lat1 as real,
                @Long1 as real, @Lat2 as real, @Long2 as real)
RETURNS real
AS
BEGIN

DECLARE @dLat1InRad as float(53);
SET @dLat1InRad = @Lat1 * (PI()/180.0);
DECLARE @dLong1InRad as float(53);
SET @dLong1InRad = @Long1 * (PI()/180.0);
DECLARE @dLat2InRad as float(53);
SET @dLat2InRad = @Lat2 * (PI()/180.0);
DECLARE @dLong2InRad as float(53);
SET @dLong2InRad = @Long2 * (PI()/180.0);

DECLARE @dLongitude as float(53);
SET @dLongitude = @dLong2InRad - @dLong1InRad;
DECLARE @dLatitude as float(53);
SET @dLatitude = @dLat2InRad - @dLat1InRad;
/* Intermediate result a. */
DECLARE @a as float(53);
SET @a = SQUARE (SIN (@dLatitude / 2.0)) + COS (@dLat1InRad)
                 * COS (@dLat2InRad)
                 * SQUARE(SIN (@dLongitude / 2.0));
/* Intermediate result c (great circle distance in Radians). */
DECLARE @c as real;
SET @c = 2.0 * ATN2 (SQRT (@a), SQRT (1.0 - @a));
DECLARE @kEarthRadius as real;
/* SET kEarthRadius = 3956.0 miles */
SET @kEarthRadius = 6376.5;        /* kms */

DECLARE @dDistance as real;
SET @dDistance = @kEarthRadius * @c;
return (@dDistance);
END

Je suppose que cela pourrait être utile.

Vous pouvez utiliser le théorème de Pythagore pour calculer la proximité de deux paires de points lat / lon.

Si vous avez deux emplacements (Alpha et Beta), vous pouvez calculer leur distance séparément avec:

SQRT( POW(Alpha_lat - Beta_lat,2) + POW(Alpha_lon - Beta_lon,2) )

En utilisant la configuration de l'URL suivante, j'ai construit la requête ci-dessous. (Veuillez noter que j'utilise codeIgnitor pour interroger la base de données)

http: / /howto-use-mysql-spatial-ext.blogspot.com/2007/11/using-circular-area-selection.html

function getRadius($point="POINT(-29.8368 30.9096)", $radius=2)
{
    $km = 0.009;
    $center = "GeomFromText('$point')";
    $radius = $radius*$km;
    $bbox = "CONCAT('POLYGON((',
        X($center) - $radius, ' ', Y($center) - $radius, ',',
        X($center) + $radius, ' ', Y($center) - $radius, ',',
        X($center) + $radius, ' ', Y($center) + $radius, ',',
        X($center) - $radius, ' ', Y($center) + $radius, ',',
        X($center) - $radius, ' ', Y($center) - $radius, '
    ))')";

    $query = $this->db->query("
    SELECT id, AsText(latLng) AS latLng, (SQRT(POW( ABS( X(latLng) - X({$center})), 2) + POW( ABS(Y(latLng) - Y({$center})), 2 )))/0.009 AS distance
    FROM crime_listing
    WHERE Intersects( latLng, GeomFromText($bbox) )
    AND SQRT(POW( ABS( X(latLng) - X({$center})), 2) + POW( ABS(Y(latLng) - Y({$center})), 2 )) < $radius
    ORDER BY distance
        ");

    if($query->num_rows()>0){
        return($query->result());
    }else{
        return false;
    }
}

Ne réinventez pas la roue. Ceci est une requête spatiale. Utilisez MySQL extensions spatiales intégrées pour stocker les données de coordonnées latitude-longitude dans type de colonne de géométrie MySQL natif . Ensuite, utilisez la Distance pour rechercher des points situés à une distance spécifiée les uns des autres.

Avertissement: ceci est basé sur la lecture de la documentation, je ne l'ai pas essayé moi-même.

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