Tri coordonnées gps

nicdu40 Messages postés 27 Statut Membre -  
[Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   -
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

5 réponses

  1. Utilisateur anonyme
     
    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
    1. mpmp93 Messages postés 2931 Date d'inscription   Statut Membre Dernière intervention   1 343
       
      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
  2. nicdu40 Messages postés 27 Statut Membre 1
     
    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
    1. Utilisateur anonyme
       
      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
    2. mpmp93 Messages postés 2931 Date d'inscription   Statut Membre Dernière intervention   1 343
       
      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
  3. nicdu40 Messages postés 27 Statut Membre 1
     
    #!/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
    1. nicdu40 Messages postés 27 Statut Membre 1
       
      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
  4. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
     
    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
    1. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      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
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. nicdu40 Messages postés 27 Statut Membre 1
     
    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
    1. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      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