Décodage de la latitude et de la longitude

Comme on l'a vu la latitude et la longitude sont codées par des chaines
ddmm.mmmm pour la latitude et dddmm.mmmm pour la longitude.
Dans ce codage les 'dd' (resp 'ddd') codent des degrés et les mm.mmmm
codent des minutes exprimées en base 10. Le point sépare la partie entière
de la partie fractionnaire des minutes.

Cependant les codages les plus couramment utilisés , notamment par les cartes IGN
où Google-Map sont exprimés soit en degrés décimaux, soit en degrés minutes et
secondes . Exemple :


    ddmm.mmmm        interpretation      degrés décimaux      degrés,min, sec
    4921.4466        49°21.4466'         49.3574°             49°21'26"

Expression en degrés décimaux

Principe

Si l'on pose d = valeur numérique codée par les minutes mm.mmmm alors d < 60 .
Comme 1 degré vaut 60 minutes il s'en suit que la valeur de la partie fractionnaire
des degrés est d/60 < 1.
Exemple 4921.4466 donnent 49 degrés et d = 21.4466 .
d/60 vaut 0.3574 ce qui fait que la valeur finale en degrés décimaux est de 49.3574 .

Mise en oeuvre pratique

Dans ce qui suit D1 désignent un entiers de type unsigned long .
La division utilisée / est donc la division entière.
Notons D = valeur numérique exprimée par la chaine mm.mmmm .
On a vu que (D/60) constitue la partie décimale des degrés.
Si on pose D1 = 10000 * D alors D1 est exprimé par la chaine mmmmmm .
La routine ascToLong() permet d'exprimer D1 à partir de la chaine mmmmmm.
Par exemple si D = 21.4466 alors D1 vaut 214466 .
On calcule D1/60 (3574) qui est la valeur décimale cherchée .
La routine de conversion longToAsc() en fournit une représentation sous forme de chaine
de caractères.


void decodeDegre10(int type, char *nmeall, char *latlong){
  
  //  type = 0 latitude ; type = 1 longitude
  //  nmeall :  chaine brute latitude (resp longitude)  extraite de la trame nmea
  //  latlong : chaine exprimant la latitude (resp longitude) en degre decimal
  
  char decim1[7]              ;
  char decim2[5]              ;
  unsigned  point,i ,j, pdec  ;
  unsigned long decimal       ;

  //  determination de l'offset du point décimal
  
  point = 0        ;
  while( *(nmeall + point) != '.') point++  ;
  
   //  Ecriture de la partie entière des degrés en fonction de l'offset du point
 
   if(type){                              // longitude ddmm.mmmm
    *latlong = *(nmeall + point - 5)      ;
    *(latlong+1) = *(nmeall + point - 4)  ;
    *(latlong+2) = *(nmeall + point - 3)  ;
    *(latlong+3) = ','                    ;
    pdec = 4   ;                          // position du point dans la chaine finale   
   }
   else{                                  // latitude dddmm.mmmm
    *latlong = *(nmeall + point - 4)      ;
    *(latlong+1) = *(nmeall + point - 3)  ;
    *(latlong+2) = ','                    ;
    pdec = 3  ;
   }
   
    
  //  decim1[] = chiffres exprimant la partie decimale   'mmmmmm'
  //  (sans le point !)commune à  la latitude et à  la longitude
  
  decim1[0] = *(nmeall + point - 2)  ;
  decim1[1] = *(nmeall + point - 1)  ;
  point++  ;
  for(i=0;i<4;i++)
  decim1[2+i] = *(nmeall + point+i )  ;
  decim1[6] = 0  ;
  
  //  conversion ascii -> unsigned long
  
  decimal = ascToLong(decim1)   ;
  
  decimal = decimal/60          ;
  
  //  conversion unsigned long -> ascii
  
  longToAsc(decimal,decim2)      ;
  
  //  mise en forme finale
  
  i =0                            ;
  j = pdec                       ;
  do{
    latlong[j++] = decim2[i++]    ;
  } while(decim2[i])              ;
  latlong[j] = '°'                ;
  latlong[j+1] = 0                ;
}

Expression en degrés, minutes, secondes

Principe

Si l'on pose d = valeur numérique codée par la partie fractionnaire des minutes ".mmmm"
alors d < 1 et le nombre de secondes vaut 60*d .
Exemple. 4921.4466 donnent 49 degrés, 21 minutes et d = .4466 .
Ainsi le nombre de secondes = 60*d vaut 26.79 ( 26 secondes 79 centièmes de secondes).

Mise en oeuvre pratique

L'extraction de dd (resp ddd) fournit les degrés et l'extraction de mm (de mm.mmmm) les minutes.
Soit donc D = valeur numérique entière exprimée par "mmmm" .( D < 10000)
La routine ascToUnsigned() permet la conversion de la chaine "mmmm" vers la valeur D.

La valeur en secondes vaut (60*D)/10000 soit (6*D)/1000.
En pratique ,comme nous ne retenons pas la partie fractionnaire des secondes
pour des raisons de précision , il suffit de multiplier D par 6 et de ne retenir des 5 chiffres qui l'expriment que les 2 chiffres de plus fort poids qui constituent la partie entière des secondes.
Exemple : ".4466" . D = 4466 et 6*D = 26796 et la valeur en secondes est de 26.
La chaine "26796" est donnée par la routine de conversion unsignedToAsc().
Nota: 6*D s'exprime sur 5 chiffres car 6*D < 60000.


void decodeDegreMinSec(int type, char *nmeall, char *latlong){
  
  //  type = 0 latitude ; type = 1 longitude
  //  nmeall :  chaine latitude (resp longitude) brute extraite de la trame nmea
  //  latlong : chaine exprimant la latitude (resp longitude) 
  //  en degre, minutes, secondes
  
  int  point ,i         ;
  char sec[5]           ;
  char sec2[7]          ;
  unsigned int second   ; 
  
  //  determination de  l'offset du  point decimal
  point = 0                     ;
  while( *(nmeall + point) != '.') point++  ;
  
  //  sec[] = chiffres exprimant la partie decimale  des minutes 'mmmm'
  
  for(i = 0; i< 4 ; i++)
    sec[i] = *(nmeall + point + i + 1)  ;
  sec[4] = 0                    ;
  
  //  conversion ascii -> undigned int 
  
  second = ascToUnsigned(sec)   ;
  second =  second *6           ;
  
  //  conversion unsigned int -> ascii 
  
  UnsignedToAsc(second , sec)       ;
  
  // mise en forme finale 
     
  if(!type){
    
    //  latitude
    
    *latlong = *(nmeall + point - 4)         ;
    *(latlong+1) = *(nmeall + point - 3)     ;
    *(latlong+2) = '°'                       ;
    *(latlong+3) = ' '                       ;
    *(latlong+4) = *(nmeall + point - 2 )    ;
    *(latlong+5) = *(nmeall + point - 1 )    ;
    *(latlong+6) = 'm'                       ;
    *(latlong+7) = ' '                       ;
    for(i=0;  i< 2 ; i++)
      *(latlong + 8 + i) = sec[i]            ; // partie entière des secondes
    *(latlong + 14) = 's'                    ;
    *(latlong+15) = 0                        ;
  }
  
  else{
    
    //  longitude
    
    *latlong     = *(nmeall + point - 5)    ;
    *(latlong+1) = *(nmeall + point - 4)    ;
    *(latlong+2) = *(nmeall + point - 3)    ;
    *(latlong+3) = '°' ;
    *(latlong+4) = ' '  ;
    *(latlong+5) = *(nmeall + point - 2 )    ;
    *(latlong+6) = *(nmeall + point - 1 )    ;
    *(latlong+7) = 'm'                       ;
    *(latlong+8) = ' '                       ;
    for(i=0;  i< 2 ; i++)
      *(latlong + 9 + i) = sec[i]            ;
    *(latlong + 15) = 's'                    ;
    *(latlong+16) = 0                        ;
  }
}