Tri coordonnées gps

Fermé
nicdu40 Messages postés 25 Date d'inscription jeudi 18 novembre 2010 Statut Membre Dernière intervention 24 février 2020 - Modifié par nicdu40 le 2/10/2014 à 23:35
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 - 10 oct. 2014 à 11:13
Bonjour,

j'ai un tableau comme suit:

azert;brazil;-14.235004;-51.92528
azerty;bordeaux;44.837789;-0.57918
toto;liboune;44.912998;-0.243985
nom;paris;48.856614;2.3522219
tata;marseille;43.296482;5.36978
kiki;nice;43.7101728;7.2619532

j'ai donc le nom;adresse;latitude;longitude ,

j'arrive a trier sans problème individuellement, par contre comment m'y prendre pour pour faire un trie en fonction des distances entre chaque adresse?

je débute en perl , une piste serait la bien venue, Merci

A voir également:

5 réponses

Whismeril Messages postés 19029 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 26 avril 2024 931
2 oct. 2014 à 23:56
Bonsoir, à cette adresse une source récente pour le calcul de distance suivant la méthode sphérique.

https://codes-sources.commentcamarche.net/source/100762-classe-gps-calcul-distance

Cette méthode donne des résultats approximatifs.
Si tu veux plus précis recherche "loxodromie" sur les sites de l'IGN.


--
0
mpmp93 Messages postés 6652 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 septembre 2015 1 339
3 oct. 2014 à 00:17
Merci pour le "approximatif". Les distances sont précises à quelques mètres et sont valables pour l'altitude 0. Ce sont des distances à vol d'oiseau, c'est à dire en ligne droite.

A+
0
nicdu40 Messages postés 25 Date d'inscription jeudi 18 novembre 2010 Statut Membre Dernière intervention 24 février 2020 1
3 oct. 2014 à 00:23
oui merci pour les distances pas de soucis:

my $pi = 3.14159265358979;

sub deg_to_rad { ($_[0]/180) * $pi }
sub rad_to_deg { ($_[0]/$pi) * 180 }
sub asin { atan2($_[0], sqrt(1 - $_[0] * $_[0])) }
sub acos { atan2( sqrt(1 - $_[0] * $_[0]), $_[0] ) }
sub tan { sin($_[0]) / cos($_[0]) }
sub atan { atan2($_[0],1) };

my $lat_a = $lat;
my $lon_a = $lng;
my $aa = $pi / 180;
my $lat1 = $lat_a * $aa;
my $lat2 = $lat_b * $aa;
my $lon1 = $lon_a * $aa;
my $lon2 = $lon_b * $aa;

my $t1 = sin($lat1) * sin($lat2);
my $t2 = cos($lat1) * cos($lat2);
my $t3 = cos($lon1 - $lon2);
my $t4 = $t2 * $t3;
my $t5 = $t1 + $t4;
my $rad_dist = atan(-t5/sqrt(-$t5 * $t5 +1)) + 2 * atan(1);

my $dist = ($rad_dist * 3437.74677 * 1.1508) * 1.6093470878864446;



ce que je cherche c'est comment calculer la distance entre chaque ville pour me retrouver avec un tri a partir d'une ville de départ: exemple:
A la base j'ai:
azert;brazil;-14.235004;-51.92528
azerty;bordeaux;44.837789;-0.57918
toto;liboune;44.912998;-0.243985
nom;paris;48.856614;2.3522219
tata;marseille;43.296482;5.36978
kiki;nice;43.7101728;7.2619532

Si je part de nice,
ça me donnerait:
kiki;nice;43.7101728;7.2619532
tata;marseille;43.296482;5.36978
toto;liboune;44.912998;-0.243985
azerty;bordeaux;44.837789;-0.57918
nom;paris;48.856614;2.3522219
azert;brazil;-14.235004;-51.92528

en fait je pense qu'il faudrait calculer tous les km entre chaque ville a partir de nice, en calculant toutes les combinaisons, et en ne gardant que celle ou il y a le moins de distance.
0
Whismeril Messages postés 19029 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 26 avril 2024 931
3 oct. 2014 à 06:27
Je ne connais pas Perl, mais oui, si tu pars de Nice, tu calcules les distances vers tous les autres, tu stockes ça dans une collection (tableau, liste, etc..) et tu le trie.

--
0
mpmp93 Messages postés 6652 Date d'inscription mercredi 13 avril 2011 Statut Membre Dernière intervention 28 septembre 2015 1 339
3 oct. 2014 à 08:54
JE vous conseille de faire ce calcul dynamiquement, c'est à dire au moment où vous éditez une fiche ville, vous avez les distances vers toutes les autres villes.
0
nicdu40 Messages postés 25 Date d'inscription jeudi 18 novembre 2010 Statut Membre Dernière intervention 24 février 2020 1
Modifié par Whismeril le 4/10/2014 à 07:26
#!/usr/local/bin/perl                                                                                                                                                                          
                                                                                                                                                                                               
use POSIX qw(strftime);                                                                                                                                                                        
use Math::Complex;                                                                                                                                                                             
#use strict;                                                                                                                                                                                   
#use warnings;                                                                                                                                                                                                                                                                 
use DBI;                                                                                                                                                                                                                                                                       
use LWP::Simple; # from CPAN                                                                                                                                                                                                                                                   
use JSON qw( decode_json ); # from CPAN                                                                                                                                                                                                                                        
#récupère  l'entrée standard dans la variable $in                                                                                                                                                                                                                              
read(STDIN, $in, $ENV{CONTENT_LENGTH});                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                               
# la chaine $in est coupée suivant le caractère & et crée la liste @champs                                                                                                                                                                                                     
@champs = split(/&/,$in);                                                                                                                                                                                                                                                      
                                                                                                                                                                                                                                                                               
# traitement de chaque élément $e de la liste @champs                                                                                                                                                                                                                          
foreach $e (@champs) {                                                                                                                                                                                                                                                         
  # dissocie chaque élément, de la forme nom=valeur en une paire de variable (nom,valeur)                                                                                                                                                                                      
  ($nom, $valeur) = split(/=/,$e);                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                               
  # transforme tous les caractères saisis en minuscules                                                                                                                                                                                                                        
  $valeur =~  tr/A-Z/a-z/;                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                               
  # crée à partir du tableau @champs une liste associative %champs                                                                                                                                                                                                             
  $champs{$nom}=$valeur;
}

  my $format = "json"; #can also to 'xml'
  my $geocodeapi = "[https://maps.googleapis.com/maps/api/geocode/]";

# génére l'en-tête du document HTML renvoyé
print("Content-Type: text/html\n\n");
# puis le document HTML
print <<"SORTIE";
<HEAD><TITLE> Réponse </TITLE></HEAD>
<BODY>
<H2 ALIGN=CENTER>RESULTAT</H2>
<CENTER><TABLE BORDER><TR> <TH>Nom du champ <TH>Valeur</TR>
SORTIE

my $adresse;
my $NOM;
my $lat;
my $lng;

# le traitement est ici réduit à afficher les valeurs transmises
while (($nom, $valeur) = each(%champs)) {
        if  ($nom =~ /adresse/){
        $valeur =~ s/\%2c\+/-/g;
        $valeur =~ s/\+/\ /g;
        $adresse = $valeur;
        my $url = $geocodeapi . $format . "?address=" . $adresse . "&sensor=false" ;
        my $json = get($url);
        my $d_json = decode_json( $json );
        $lat = $d_json->{results}->[0]->{geometry}->{location}->{lat};
        $lng = $d_json->{results}->[0]->{geometry}->{location}->{lng};
        }
        if  ($nom =~ /nom/){
        $NOM = $valeur;
        }
print "<TR><Td>$nom = </td><Td>$valeur</td></TR>";
}

###############
open (FH, ">>test-perl");
print  FH "$NOM;$adresse;$lat;$lng\n";
close(FH);
##############
open(FH, "test-perl")  or die "!";
# Copie du contenu du fichier dans un tableau
my @table=<FH>;
# Afficher la taille du tableau
print scalar(@table)."\n";
print "<BR\>";
close(FH);

my $pi = 3.14159265358979;
sub atan { atan2($_[0],1) };
my $aa = $pi / 180;
my $local_lat = 43.637844;
my $local_long = -1.420939;
my $lat_a = $local_lat;
my $lon_a =  $local_long;
my $lat1 = $lat_a * $aa;
my $lon1 = $lon_a * $aa;

foreach $line (@table) {
($nom, $adresse, $lat, $lng, $dist) = split(";", $line);
my $lat_b = $lat; 
my $lon_b =  $lng; 
my $lat2 = $lat_b * $aa;
my $lon2 = $lon_b * $aa;
my $t1 = sin($lat1) * sin($lat2);
my $t2 = cos($lat1) * cos($lat2);
my $t3 = cos($lon1 - $lon2);
my $t4 = $t2 * $t3;
my $t5 = $t1 + $t4;
my $rad_dist = atan(-$t5/sqrt(-$t5 * $t5 +1)) + 2 * atan(1);
my $dist = ($rad_dist * 3437.74677 * 1.1508) * 1.6093470878864446;
$line = $line . ";" . $dist;

}

  @out = sort {
       (split ';', $a )[4] <=> #cmp
     (split ';', $b )[4]
  } @table;
foreach $line (@out) {
($nom, $adresse, $lat, $lng, $dist) = split(";", $line);
print "<TR><Td>$nom</td><Td>$adresse</td><Td>$lat</td><Td>$lng</td><Td>$dist</td></TR>";
}


ce qui me donne:
nom ville lat long km
bobo orx 43.602883 -1.372563 5.49883038421565
nico seignosse 43.692694 -1.384908 6.74821123208138
rhune ascain 43.345172 -1.621327 36.3135240698413
bobo pau 43.2951 -0.370797 92.8625864850123
azert marseille 43.296482 5.36978 548.822503921505
bbb brazil -14.235004 -51.92528 8217.52868892235
nom mexico 23.634501 -102.552784 9051.01695660936
nom mexico 23.634501 -102.552784 9051.01695660936
nom mexico 23.634501 -102.552784 9051.01695660936
nom mexico 23.634501 -102.552784 9051.01695660936
bobo tokio 35.6894875 139.6917064 10350.9145027704

le départ se fait à partir d'une seulle ville : my $local_lat = 43.637844; my $local_long = -1.420939;

ça calcul les distances à partir de ce point, mais ce n'est pas ce que je voudrai
j'avance un peu , mais je n'est pas encore la bonne methode.....

EDIT: Ajout de la coloration syntaxique.
0
nicdu40 Messages postés 25 Date d'inscription jeudi 18 novembre 2010 Statut Membre Dernière intervention 24 février 2020 1
5 oct. 2014 à 16:04
bon voila , pour ceux qui sont intéressé: ça calcul la ville la plus proche du point de départ, puis ensuite depuis l'autre ville , ainsi de suite,
c'est pour optimiser les tournées de RDV , .... ,
Bon j'ai du faire des erreurs, je n'ai jamais suivi de cours , soyez indulgent ;-)


##############
#adresse de départ
my $local_lat = 43.637844;
my $local_long = -1.420939;

my $lat_a = $local_lat;
my $lon_a =  $local_long;

my $pi = 3.14159265358979;
sub atan { atan2($_[0],1) };
my $aa = $pi / 180;

open(FH, "test-perl")  or die "!";
# Copie du contenu du fichier dans un tableau
my @tabl=<FH>;
my $nb_lignes = scalar(@tabl);
# Afficher la taille du tableau
print "NB lignes = $nb_lignes \n";
#print "<BR\>";
close(FH);
#my $lat1 = $lat_a * $aa;
#my $lon1 = $lon_a * $aa;
my $line;

#boucle 
while ($nb_lignes > 0) {

foreach $line (@tabl) {
        my ($nom, $adresse, $lat, $lng) = split("\ ", $line);
        $line = join(' ',$nom,$adresse,$lat,$lng);
        my $lat_b = $lat; 
 my $lat1 = $lat_a * $aa;
my $lon1 = $lon_a * $aa;

        my $lon_b =  $lng; 
        my $lat2 = $lat_b * $aa;
        my $lon2 = $lon_b * $aa;
        my $t1 = sin($lat1) * sin($lat2);
        my $t2 = cos($lat1) * cos($lat2);
        my $t3 = cos($lon1 - $lon2);
        my $t4 = $t2 * $t3;
        my $t5 = $t1 + $t4;
my $dista;
                if (($lat_a == $lat_b)&&($lon_a == $lon_b)) {
                $dista = 0 ;
         
                }else{

                my $rad_dist = atan(-$t5/sqrt(-$t5 * $t5 +1)) + 2 * atan(1);
                $dista = ($rad_dist * 3437.74677 * 1.1508) * 1.6093470878864446;
                }
        $line =~ s/\n//g;
        $line = $line . " " . $dista ;
        }

        @out = sort {
        (split ' ' , $a )[4] <=> 
        (split ' ' , $b )[4]
        } @tabl;

my $proche = shift(@out);
#print "plus proche= $proche\n";
my @col = split( ' ' , $proche);
$lat_a = $col[2];
$lon_a = $col[3];
$nb_lignes -=1;
@tabl =  @out ; 

#print "\n";
my ($nom, $adresse, $lat, $lng, $dista) = split("\ ", $proche);
print "<TR><Td>$nom</td><Td>$adresse</td><Td>$lat</td><Td>$lng</td><Td>$dista</td></TR>";
}
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié par [Dal] le 9/10/2014 à 11:08
Salut nicdu40,

Plutôt que de calculer la distance à vol d'oiseau, tu pourrais utiliser une API pour calculer la distance par la route et le temps de trajet. Google a cela :

https://developers.google.com/maps/documentation/javascript/distancematrix
https://developers.google.com/maps/documentation/distance-matrix/start

qui te permet d'obtenir une matrice de distances et temps de parcours entre un ou plusieurs points de départ et un ou plusieurs points d'arrivée.

Par exemple :

#!/usr/bin/perl

use strict;
use warnings;

use LWP::Simple;
use JSON qw( decode_json );
use Data::Dumper;

my $origins         = "&origins=Paris+France|Bordeaux+France|Lyon+France|Marseille+France";
my $destinations    = "&destinations=Paris+France|Bordeaux+France|Lyon+France|Marseille+France";

my $content = get("https://maps.googleapis.com/maps/api/distancematrix/json?" . $origins . $destinations);
die "Couldn't get it!" unless defined $content;

my $data = decode_json($content);
my @rows = @{ $data->{'rows'} };

foreach my $r (@rows) {
    my @elements = @{ $r->{'elements'} };
    foreach my $d (@elements) {
        print $d->{'duration'}{'value'} . "\t\t";                                                                                                                                                                  
    }
    print "\n";
}


donne :

0		20925		15491		26226		
21151 0 18954 21478
15956 19102 0 11233
26751 21713 11269 0


Tu peux ensuite faire tes tris, en fonction de ta ville de départ.


Dal
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié par [Dal] le 10/10/2014 à 11:42
Quelques petits compléments d'information.

Le code que je propose ci-dessus utilisant l'API Google traite le résultat de la requête au format JSON, qui contient un tableau à deux dimensions des distances ou des durées de trajet par la route entre deux points.

En l'occurence, rows->elements->duration->value contient la durée en secondes du trajet entre deux points, qui est affichée par le script Perl.

Dans l'exemple que je donne avec mon code, comportant des villes d'origine et de destination identiques Paris, Bordeaux, Lyon, Marseille, les lignes (rows) correspondant aux points de départ, avec une légende, le tableau donne :


de	à Paris		à Bordeaux	à Lyon		à Marseille
Paris 0 20925 15491 26226
Bord. 21151 0 18954 21478
Lyon 15956 19102 0 11233
Mars. 26751 21713 11269 0


et tu vois qu'il est plus rapide d'environ 4 minutes d'aller de Paris à Bordeaux, que d'aller de Bordeaux à Paris, les routes et limitations de vitesse n'étant pas toujours les mêmes dans un sens et dans l'autre.

L'API est décrite dans les liens précédemment donnés. Elle est très riche (tu peux même indiquer que tu veux éviter les routes à péage).

Si tu en fais un usage intensif, tu devrais l'utiliser avec une clef d'API, pour augmenter les limites d'utilisation possibles.

Cependant, si les villes sont fixes, tu n'as qu'à récupérer l'information une fois (et la mettre à jour de temps en temps pour tenir compte des modifications du réseau routier).


Dal
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
nicdu40 Messages postés 25 Date d'inscription jeudi 18 novembre 2010 Statut Membre Dernière intervention 24 février 2020 1
9 oct. 2014 à 23:10
salut, merci Dal,
faut que j'aille voir ça.
merci à tous les autres dailleur .
de mon coté j'ai réussi a faire ce que je voulais au départ, mais c'est vrais que c'est a vol d'oiseau, c'est bon pour les avions quoi....

en fait j'ai fais tout grace a la permutation "Fischer-Krause ordered permutation generator"
ça m'a ouvert les yeux...
maintenant je vais faire la même avec les conseils de dal.
bon du coup voila, calcul du meilleur itinéraire pour les objets volants:

le fichier test-perl doit être écrit ainsi:
nico hossegor 43.6646192 -1.3976871
lolo orx 43.602883 -1.372563
pipo seignosse 43.69269 -1.384
coco tarnos 43.5408 -1.461038
gaga dax 43.708608 -1.051945



##############
#adresse de départ
my $local_lat = 43.6305177;
my $local_long = -1.3927591;
my $addr = "magazin";
my $lat_a = $local_lat;
my $lon_a =  $local_long;

my $total = 0;
my $pi = 3.14159265358979;
my $pii = $pi / 180;

open(FH, "test-perl")  or die "!";
# Copie du contenu du fichier dans un tableau
my @tabl=<FH>;
my $nb_lignes = scalar(@tabl);
# Afficher la taille du tableau
print "NB lignes = $nb_lignes \n";
#print "<BR\>";
close(FH);

#calcul des distances
sub distanceA_B {
 my ($lat_A,$lat_B,$lon_A,$lon_B) = @_;
	my $lat_a = $lat_A;
	my $lat_b = $lat_B;
	my $lon_a =  $lon_A;
	my $lon_b =  $lon_B;
	my $lat1 = $lat_a * $pii;
	my $lon1 = $lon_a * $pii;  
        my $lat2 = $lat_b * $pii;
        my $lon2 = $lon_b * $pii;
        my $t1 = sin($lat1) * sin($lat2);
        my $t2 = cos($lat1) * cos($lat2);
        my $t3 = cos($lon1 - $lon2);
        my $t4 = $t2 * $t3;
        my $t5 = $t1 + $t4; 
	my $dista;
                if (($lat_a == $lat_b)&&($lon_a == $lon_b)) {
                $dista = 0 ;
                }else{
                my $rad_dist = atan(-$t5/sqrt(-$t5 * $t5 +1)) + 2 * atan(1);
                $dista = ($rad_dist * 3437.74677 * 1.1508) * 1.6093470878864446;
                }
return ($dista);
                
}
######################################################################################################"
foreach my $ligne (@tabl) {
  my ($nom, $adresse, $lat, $lng) = split("\ ", $ligne);
  $ligne = join('_',$nom,$adresse,$lat,$lng);
 }

###permutation :-) 
sub permute (&@) {
  my $code = shift;
  my @idx = 0..$#_;
  while ( $code->(@_[@idx]) ) {
    my $p = $#idx;
    --$p while $idx[$p-1] > $idx[$p];
    my $q = $p or return;
    push @idx, reverse splice @idx, $p;
    ++$q while $idx[$p-1] > $idx[$q];
    @idx[$p-1,$q]=@idx[$q,$p-1];
  }
}
my @a;
permute { push @a, "@_" } @tabl;


foreach my $aa (@a) {
### on remet les coordonnées de départ avant chaque tour de @a
  $lat_a = $local_lat;
  $lon_a =  $local_long;
  my @array = split(' ',$aa);
  
  foreach my $array (@array) {
    $array =~ s/\n//g;
    my ($nom, $adresse, $lat, $lng) = split("_", $array);
    if ($addr eq $adresse) {
      $dista = 0;
    }	else{
	($dista) = distanceA_B ($lat_a,$lat,$lon_a,$lng);  
	}
 #  $array = $array . " " . $dista ;
 #print $array . "\n";

 $total += $dista  ;
### a chaque tour de @array le point gps precedant devient le départ.
  $lat_a = $lat;
  $lon_a = $lng;  
   }
#print   "total distance= $total \n";
$aa = $aa . " " . $total ;
#print $aa . "\n";
  $total=0;
}

###numero de colone oû se trouve le total de chaque possibilité = nb de villes a calculer (+1)
my $col_tot = $nb_lignes ;

###calcul du meilleur total
  @out = sort {
        (split ' ' , $a )[$col_tot] <=> 
        (split ' ' , $b )[$col_tot]
        } @a;

#recupere la 1er ligne
my $proche = shift(@out);
print $proche . "\n";


@tableau_web = split(' ',$proche);

#recupere le nombre de km:
my $total_dist = pop(@tableau_web);

##inscription dans un tableau le meilleur parcour !
foreach my $ligne_web (@tableau_web) {
	my ($nom, $adresse, $lat, $lng) = split("_", $ligne_web);
	print "<TR><Td>$nom</td><Td>$adresse</td><Td>$lat</td><Td>$lng</td></TR>";
print "\n";
}
print "<TR><Td>distance-totale=</td><Td>$total_dist</td></TR>";
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié par [Dal] le 10/10/2014 à 11:44
de rien, si cela peut t'aider j'en suis ravi.

Je n'ai pas étudié dans le détail ton code, merci de le contribuer au forum :-)

J'ai complété ma réponse précédente, en ajoutant un commentaire avec un complément d'information.


Dal
0