1// Lat & Lng to Maidenhead conversion 2// 3// input : lat and lng in decimal format 4// output : locator (string) 5// returns : Maidenhead locator like JN42iw08 6// Patrick EGLOFF (04/2009) 7// 8 9 10function latlng2loc(lat,lng) 11 { 12 lat += 90; // lat origin of Maidenhead is 90S 13 lng += 180; // lng origin of Maidenhead is 180W 14 var units=43200; // 18 fields * 10 squares * 24 subsquares * 10 extended square 15 16 // get the extended sq 17 lat = Math.floor(lat*units/180.0); 18 lng = Math.floor(lng*units/360.0); 19 locator=String.fromCharCode(48 + (lng % 10), 48 + (lat % 10))+''; 20 // get the subsq. 21 lat = Math.floor(lat/10); 22 lng = Math.floor(lng/10); 23 locator = String.fromCharCode(65 + (lng % 24), 65 + (lat % 24))+locator ; // asc('a')=97 ou asc('A')=65 si majuscules 24 // get the sq. 25 lat = Math.floor(lat/24); 26 lng = Math.floor(lng/24); 27 locator = String.fromCharCode(48 + (lng % 10), 48 + (lat % 10)) + locator; // asc('0')=48 28 // get the fields 29 lat = Math.floor(lat/10); 30 lng = Math.floor(lng/10); 31 var locator=String.fromCharCode(65+lng,65+lat) + locator; // asc('A')=65 32 33 return(locator); 34 } 35 36function getLocator(lat,lng) { 37 var ydiv_arr=new Array(10, 1, 1/24, 1/240, 1/240/24); 38 var d1 = "ABCDEFGHIJKLMNOPQR".split(""); 39 var d2 = "ABCDEFGHIJKLMNOPQRSTUVWX".split(""); 40 //var d4 = new Array(0 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,2 ,2 ,3 ,3 ,3 ,3 ,3 ,4 ,4 ,4 ,4 ,5 ,5 ); 41 var locator = ""; 42 var x = lng; 43 var y = lat; 44 //var precision = d4[map.getZoom()]; // if we want the locator length depends of zoom 45 var precision = 10; 46 while (x < -180) {x += 360;} 47 while (x > 180) {x -=360;} 48 x = x + 180; 49 y = y + 90; 50 locator = locator + d1[Math.floor(x/20)] + d1[Math.floor(y/10)]; 51 for (var i=0; i<4; i=i+1) { 52 if (precision > i+1) { 53 rlon = x%(ydiv_arr[i]*2); 54 rlat = y%(ydiv_arr[i]); 55 if ((i%2)==0) { 56 locator += Math.floor(rlon/(ydiv_arr[i+1]*2)) +""+ Math.floor(rlat/(ydiv_arr[i+1])); 57 } else { 58 locator += d2[Math.floor(rlon/(ydiv_arr[i+1]*2))] +""+ d2[Math.floor(rlat/(ydiv_arr[i+1]))]; 59 } 60 } 61 } 62 return (locator); 63 }; 64 65// fonction pour convertir latitude et longitude décimales dans le système WGS84 en coordonnées Lambert II étendues 66// ne tient pas compte de h, hauteur au-dessus de l'éllipsoïde 67// entrée : lat et lng au format WGS84 décimal 68// sortie : données Lambert II étendu arrondi à 3 chiffres après la virgule 69// return : tableau Lambert(). X = Lambert[0] , Y = Lambert[1] 70// par Patrick EGLOFF (02/2026) 71// 72function LatLng2Lambert(lat, lng) { 73 // 1. Constantes Lambert II Ãtendu (IGN) 74 const n = 0.7289686274; 75 const c = 11745793.39; 76 const Xs = 600000; 77 const Ys = 8199695.768; 78 const e = 0.08248325676; // Excentricité Clarke 1880 79 const lambda0 = 2.33722917; // Longitude de Paris en degrés / Greenwich 80 81 // 2. Conversion degrés vers radians 82 const phi = lat * Math.PI / 180; 83 const lambda = lng * Math.PI / 180; 84 const lambda0Rad = lambda0 * Math.PI / 180; 85 86 // 3. Calcul de la latitude isométrique 87 const sinPhi = Math.sin(phi); 88 const tmp = Math.pow((1 - e * sinPhi) / (1 + e * sinPhi), e / 2); 89 const L = Math.log(Math.tan(Math.PI / 4 + phi / 2) * tmp); 90 91 // 4. Projection 92 const x = Xs + c * Math.exp(-n * L) * Math.sin(n * (lambda - lambda0Rad)); 93 const y = Ys - c * Math.exp(-n * L) * Math.cos(n * (lambda - lambda0Rad)); 94 95 return [Math.round(x * 1000) / 1000, Math.round(y * 1000) / 1000]; 96} 97 98 99// fonction de conversion des coordonnées Lambert II étendu vers la grille DFCI 100// entrée : coordonnées X et Y en système Lambert II étendu en m 101// sortie : coordonnées DFCI formatée -> NB80A0.5 102// return : DFCI chaîne 103// Patrick EGLOFF (04/2009) 104// 105function Lambert2DFCI(X,Y) { 106 // on ne garde que les mètres 107 X = Math.round(X); 108 Y = Math.round(Y); 109 110 // on limite le carroyage à la France 111 // 0-1200 km de l'Ouest à Est et 1600-2700km du N au S 112 if (X<=0 || X>=1200000 || Y<=1600000 || Y>=2700000) 113 DFCI = ""; 114 115 else 116 { 117 // les constantes 118 var ABC = "ABCDEFGHKLMN012345678902468"; 119 120 // on ramène l'origine au sud de la Corse à zero 121 Y -= 1600000; 122 123 // carré 100*100 km 124 X100 = Math.floor(X/100000); 125 Y100 = Math.floor(Y/100000); 126 DFCI = ABC.substr(X100,1)+ABC.substr(Y100+1,1); 127 128 // carré 20*20 km 129 Xtot = X-(X100*100000); 130 Ytot = Y-(Y100*100000); 131 X20 = Math.floor(Xtot/20000); 132 Y20 = Math.floor(Ytot/20000); 133 DFCI += ABC.substr(X20+22,1)+ABC.substr(Y20+22,1); 134 135 // carré 2*2 km 136 Xtot -= (X20*20000); 137 Ytot -= (Y20*20000); 138 X2 = Math.floor(Xtot/2000); 139 Y2 = Math.floor(Ytot/2000); 140 DFCI += ABC.substr(X2,1)+ABC.substr(Y2+12,1); 141 142 // découpage "chasse" en 5 zones 143 Xtot -= (X2*2000); 144 Ytot -= (Y2*2000); 145 146 if (Xtot>500 && Xtot<1500 && Ytot>500 && Ytot<1500) 147 Xc=5; 148 else if (Xtot<1000 && Ytot>1000) 149 Xc=1; 150 else if (Xtot<1000 && Ytot<1000) 151 Xc=4; 152 else if (Xtot>1000 && Ytot>1000) 153 Xc=2; 154 else if (Xtot>1000 && Ytot<1000) 155 Xc=3; 156 157 DFCI += "."+Xc; 158 } 159 return DFCI; 160 } 161 162// script de conversion lat long en UTM 163// en partie inspiré de Charles L. Taylor 164//
165// constantes pour modèle ellipsoïde WGS84 166 var sm_a = 6378137.0; 167 var sm_b = 6356752.314; 168 var sm_EccSquared = 6.69437999013e-03; 169 var UTMScaleFactor = 0.9996; 170 var pi = 3.14159265358979; 171 172 // calcul des coordonnées UTM 173 // entrée lat et lng en décimales, S et W en négatif 174 // sortie zone 32T 500000mE 4649776mN 175 function latlng2UTM(lat,lng) 176 { 177 // fixe les limites du système UTM 178 if (lat<-80 || lat>=84) 179 zone='hors UTM !'; 180 else 181 { 182 // détermine fuseau 183 zone = Math.floor ((lng + 180.0) / 6) + 1; 184 // fuseaau spécial Ouest de la Norvège 185 if (lat >= 56.0 && lat < 64.0 && lng >= 3.0 && lng < 12.0 ) zone = 32; 186 // fuseaux spéciaux des îles Svalbard 187 if( lat >= 72.0 && lat < 84.0 ) 188 { 189 if (lng >= 0.0 && lng < 9.0 ) zone = 31; 190 else if ( lng >= 9.0 && lng < 21.0 ) zone = 33; 191 else if ( lng >= 21.0 && lng < 33.0 ) zone = 35; 192 else if ( lng >= 33.0 && lng < 42.0 ) zone = 37; 193 } 194 195 // détermine les distances en m depuis la référence 196 var xy = new Array(); // 197 dist= LatlngToUTMXY (DegToRad (lat), DegToRad (lng), zone, xy); 198 199 // détermine bande C à X 200 bande = lat2bande (lat); 201 xy[2]=zone + " " + bande; 202 return xy; 203 } 204 } 205 206function LatlngToUTMXY (lat, lng, zone, xy) 207 { 208 MapLatlngToXY (lat, lng, UTMCentralMeridian (zone), xy); 209 210 /* Adjust easting and northing for UTM system. */ 211 xy[0] = xy[0] * UTMScaleFactor + 500000.0; 212 xy[1] = xy[1] * UTMScaleFactor; 213 if (xy[1] < 0.0) 214 xy[1] = xy[1] + 10000000.0; 215 216 return xy; 217 } 218 219// * DegToRad Convertir degrès en radians. 220function DegToRad (deg) 221 { 222 return (deg / 180.0 * pi) 223 } 224 225function lat2bande (lat) 226 { 227 // détermine la bande 228 // entrée lat en décimales DD.DDDDD 229 // sortie bande de C à X 230 231 // lettres utilisées en UTM 232 Lettres='CDEFGHJKLMNPQRSTUVWXYZ'; 233 // coordonnées UTM vont de -80 (S) à + 84 (N) 234 lat=lat+80; 235 // détermine lettre de la bande latitude de C à X 236 Pos=Math.floor(lat/8); 237 bande=Lettres.charAt(Pos); 238 if (bande>'X') bande='X'; 239return bande; 240 } 241 242function ArcLengthOfMeridian (phi) 243 { 244 var alpha, beta, gamma, delta, epsilon, n; 245 var result; 246 247 /* Precalculate n */ 248 n = (sm_a - sm_b) / (sm_a + sm_b); 249 250 /* Precalculate alpha */ 251 alpha = ((sm_a + sm_b) / 2.0) 252 * (1.0 + (Math.pow (n, 2.0) / 4.0) + (Math.pow (n, 4.0) / 64.0)); 253 254 /* Precalculate beta */ 255 beta = (-3.0 * n / 2.0) + (9.0 * Math.pow (n, 3.0) / 16.0) 256 + (-3.0 * Math.pow (n, 5.0) / 32.0); 257 258 /* Precalculate gamma */ 259 gamma = (15.0 * Math.pow (n, 2.0) / 16.0) 260 + (-15.0 * Math.pow (n, 4.0) / 32.0); 261 262 /* Precalculate delta */ 263 delta = (-35.0 * Math.pow (n, 3.0) / 48.0) 264 + (105.0 * Math.pow (n, 5.0) / 256.0); 265 266 /* Precalculate epsilon */ 267 epsilon = (315.0 * Math.pow (n, 4.0) / 512.0); 268 269 /* Now calculate the sum of the series and return */ 270 result = alpha 271 * (phi + (beta * Math.sin (2.0 * phi)) 272 + (gamma * Math.sin (4.0 * phi)) 273 + (delta * Math.sin (6.0 * phi)) 274 + (epsilon * Math.sin (8.0 * phi))); 275 276return result; 277} 278 279function UTMCentralMeridian (zone) 280 { 281 var cmeridian; 282 cmeridian = DegToRad (-183.0 + (zone * 6.0)); 283 return cmeridian; 284 } 285 286 287function MapLatlngToXY (phi, lambda, lambda0, xy) 288 { 289 var N, nu2, ep2, t, t2, l; 290 var l3coef, l4coef, l5coef, l6coef, l7coef, l8coef; 291 var tmp; 292 293 /* Precalculate ep2 */ 294 ep2 = (Math.pow (sm_a, 2.0) - Math.pow (sm_b, 2.0)) / Math.pow (sm_b, 2.0); 295 296 /* Precalculate nu2 */ 297 nu2 = ep2 * Math.pow (Math.cos (phi), 2.0); 298 299 /* Precalculate N */ 300 N = Math.pow (sm_a, 2.0) / (sm_b * Math.sqrt (1 + nu2)); 301 302 /* Precalculate t */ 303 t = Math.tan (phi); 304 t2 = t * t; 305 tmp = (t2 * t2 * t2) - Math.pow (t, 6.0); 306 307 /* Precalculate l */ 308 l = lambda - lambda0; 309 310 /* Precalculate coefficients for l**n in the equations below 311 so a normal human being can read the expressions for easting 312 and northing 313 -- l**1 and l**2 have coefficients of 1.0 */ 314 l3coef = 1.0 - t2 + nu2; 315 316 l4coef = 5.0 - t2 + 9 * nu2 + 4.0 * (nu2 * nu2); 317 318 l5coef = 5.0 - 18.0 * t2 + (t2 * t2) + 14.0 * nu2 319 - 58.0 * t2 * nu2; 320 321 l6coef = 61.0 - 58.0 * t2 + (t2 * t2) + 270.0 * nu2 322 - 330.0 * t2 * nu2; 323 324 l7coef = 61.0 - 479.0 * t2 + 179.0 * (t2 * t2) - (t2 * t2 * t2); 325 326 l8coef = 1385.0 - 3111.0 * t2 + 543.0 * (t2 * t2) - (t2 * t2 * t2); 327 328 /* Calculate easting (x) */ 329 xy[0] = N * Math.cos (phi) * l
330 + (N / 6.0 * Math.pow (Math.cos (phi), 3.0) * l3coef * Math.pow (l, 3.0)) 331 + (N / 120.0 * Math.pow (Math.cos (phi), 5.0) * l5coef * Math.pow (l, 5.0)) 332 + (N / 5040.0 * Math.pow (Math.cos (phi), 7.0) * l7coef * Math.pow (l, 7.0)); 333 334 /* Calculate northing (y) */ 335 xy[1] = ArcLengthOfMeridian (phi) 336 + (t / 2.0 * N * Math.pow (Math.cos (phi), 2.0) * Math.pow (l, 2.0)) 337 + (t / 24.0 * N * Math.pow (Math.cos (phi), 4.0) * l4coef * Math.pow (l, 4.0)) 338 + (t / 720.0 * N * Math.pow (Math.cos (phi), 6.0) * l6coef * Math.pow (l, 6.0)) 339 + (t / 40320.0 * N * Math.pow (Math.cos (phi), 8.0) * l8coef * Math.pow (l, 8.0)); 340 341 return; 342 } 343 344// function to convert a Maidenhead grid locator (6 or 8 characters) to lat/long + locator length 345// by TK5EP EGLOFF Patrick 346// returns variable LocToLatLng (Lat,Lng,LocLength) if a valid locator has been found 347// returns (0,0,0) if it is not a locator 348// 349function MHtoLatLng(locator) { 350// convert to uppercase 351locator = locator.toUpperCase(); 352 353var myRegExp1 = /^[A-R]{2}[0-9]{2}[A-X]{2}$/; 354var myRegExp2 = /^[A-R]{2}[0-9]{2}[A-X]{2}[0-9]{2}$/; 355var myRegExp3 = /^[A-R]{2}[0-9]{2}[A-X]{2}[0-9]{2}[A-X]{2}$/; 356//var LocLength = 0; 357 358// check if 10 char MH 359if ( myRegExp3.test(locator) && locator.length == 10 ) { 360//alert ("10 char locator"); 361 var loca = []; 362 var i = 0; 363 while (i < 10) 364 { 365 loca[i] = locator.charCodeAt(i) - 65; 366 i++; 367 } 368 loca[2] += 17; 369 loca[3] += 17; 370 loca[6] += 17; 371 loca[7] += 17; 372 lat=(loca[1]*10 + loca[3] + loca[5]/24 + loca[7]/240 + loca[9]/5780 -90) ; 373 lng=(loca[0]*20 + loca[2]*2 + loca[4]/12 + loca[6]/120 + loca[8]/2880 - 180) ; 374 LocLength=10; 375} 376 377// check if 8 char MH 378else if ( myRegExp2.test(locator) && locator.length == 8 ) { 379//alert ("8 char locator"); 380 var loca = []; 381 var i = 0; 382 while (i < 8) 383 { 384 loca[i] = locator.charCodeAt(i) - 65; 385 i++; 386 } 387 loca[2] += 17; 388 loca[3] += 17; 389 loca[6] += 17; 390 loca[7] += 17; 391 // center of the locator = +0.0333 392 lat=(loca[1]*10 + loca[3] + (loca[5]+0.033)/24 + loca[7]/240 - 90) ; 393 lng=(loca[0]*20 + loca[2]*2 + (loca[4]+0.033)/12 + loca[6]/120 - 180); 394 LocLength=8; 395} 396 397// check if 6 char MH 398else if ( myRegExp1.test(locator) && locator.length == 6 ) { 399 //alert ("6 char locator"); 400 var loca = []; 401 var i = 0; 402 while (i < 6) 403 { 404 loca[i] = locator.charCodeAt(i) - 65; 405 i++; 406 } 407 loca[2] += 17; 408 loca[3] += 17; 409 // the center of the locator = +0.5 410 lat=(loca[1] * 10 + loca[3] + (loca[5]+0.5) / 24 - 90); 411 lng=(loca[0] * 20 + loca[2] * 2 + (loca[4]+0.5) / 12 - 180); 412 LocLength=6; 413} 414 415// in any other case return null 416else { 417 LocLength=0; 418 lat=0; 419 lng=0; 420} 421// TESTS 422//alert("lat="+lat +" lng="+lng+" Longueur="+LocLength); 423 424// on retourne les coordonnées 425var LocToLatLng = [lat,lng,LocLength]; 426return LocToLatLng; 427} 428 429/** 430 * Converts decimal degrees to degrees minutes seconds. 431 corrected 2024/01/12 432**/ 433/* 434function dec2DMS(dd, lat) { 435 var absolute = Math.abs(dd); 436 437 var deg = Math.floor(absolute); 438 var minutesNotTruncated = (absolute - deg) * 60; 439 var min = Math.floor(minutesNotTruncated); 440 var sec = ((minutesNotTruncated - min) * 60).toFixed(2); 441 442 if (sec==60) { 443 min++; 444 sec =0; 445 } 446 447 if (min==60) { 448 min=0; 449 deg++; 450 } 451 452 if (lat) { 453 var direction = 'N'; 454 if (dd <= 0) {direction = 'S'}; 455 } else { 456 var direction = 'E'; 457 if (dd <= 0) direction = 'W'; 458 } 459 460 //alert(deg + "°" + min + "'" + sec + '"' + direction); 461 462 return deg + "°" + min + "'" + sec + '"' + direction; 463} 464*/ 465/* 466function dec2DMS(dd, isLat) { 467 let absolute = Math.abs(dd); 468 469 let deg = Math.floor(absolute); 470 let minutesNotTruncated = (absolute - deg) * 60; 471 let min = Math.floor(minutesNotTruncated); 472 let sec = ((minutesNotTruncated - min) * 60).toFixed(2); 473 474 // Gestion de l'arrondi au supérieur (ex: 59.999 -> 60 -> 00) 475 if (parseFloat(sec) >= 60) { 476 min++; 477 sec = (0).toFixed(2); 478 } 479 480 if (min >= 60) { 481 min = 0; 482 deg++; 483 } 484 485 // Détermination de la direction 486 let direction = ""; 487 if (isLat) { 488 direction = dd >= 0 ? 'N' : 'S'; 489 } else { 490 direction = dd >= 0 ? 'E' : 'W'; 491 } 492 493 // Formatage avec des zéros initiaux pour la stabilité visuelle 494 // On transforme en String pour utiliser padStart(2, '0') 495 let minStr = String(min).padStart(2, '0'); 496 let secStr = String(sec).padStart(5, '0'); // 5 car 00.00 (inclut le point et les décimales) 497 498 return `${deg}° ${minStr}' ${secStr}" ${direction}`; 499} 500*/ 501function dec2DMS(dd, isLat) { 502 let absolute = Math.abs(dd); 503 504 let deg = Math.floor(absolute); 505 let minutesNotTruncated = (absolute - deg) * 60; 506 let min = Math.floor(minutesNotTruncated); 507 let sec = ((minutesNotTruncated - min) * 60).toFixed(2); 508 509 if (parseFloat(sec) >= 60) { 510 min++; 511 sec = (0).toFixed(2); 512 } 513 514 if (min >= 60) { 515 min = 0; 516 deg++; 517 } 518 519 let direction = isLat ? (dd >= 0 ? 'N' : 'S') : (dd >= 0 ? 'E' : 'W'); 520 521 // Justification (Padding) 522 // Pour la latitude on utilise souvent 2 chiffres, pour la longitude 3. 523 // Ici on reste sur 2 pour la cohérence visuelle standard. 524 let degStr = String(deg).padStart(2, '0'); 525 let minStr = String(min).padStart(2, '0'); 526 let secStr = String(sec).padStart(5, '0'); 527 528 return `${degStr}°${minStr}'${secStr}"${direction}`; 529} 530 531 532/***************** 533cnvert to DDDMM.MMM 534*******************/ 535/* 536function dec2DDMMMM(dd,lat) { 537 var absolute = Math.abs(dd); 538 539 var deg = Math.floor(absolute); 540 var min = (absolute - deg) * 60; 541 var min = Math.round((min * 100))/100; 542 if (min==60) { 543 min=0; 544 deg++; 545 } 546 min1 = min.toString().split(".")[0]; 547 min2 = min.toString().split(".")[1]; 548 if (min2 == undefined) min2 = "00"; 549 550 if (lat) { 551 var direction = 'N'; 552 if (dd <= 0) {direction = 'S'}; 553 } else { 554 var direction = 'E'; 555 if (dd <= 0) direction = 'W'; 556 } 557 558 return deg + "°" + pad('00', min1,true) +"." + pad('00', min2,true)+ direction; 559} 560*/ 561 562/***************** 563Convert to DDDMM.MMM 564*******************/ 565function dec2DDMMMM(dd, isLat) { 566 let absolute = Math.abs(dd); 567 568 let deg = Math.floor(absolute); 569 // Calcul des minutes avec 3 décimales pour le format MM.MMM 570 let min = (absolute - deg) * 60; 571 572 // Gestion de l'arrondi au supérieur (ex: 59.9996 -> 60.000) 573 if (parseFloat(min.toFixed(3)) >= 60) { 574 min = 0; 575 deg++; 576 } 577 578 // Détermination de la direction (Nord/Sud ou Est/Ouest) 579 let direction = isLat ? (dd >= 0 ? 'N' : 'S') : (dd >= 0 ? 'E' : 'W'); 580 581 // Justification des degrés : 2 chiffres pour Lat, 3 pour Lon 582 let degStr = String(deg).padStart(isLat ? 2 : 3, '0'); 583 584 // Formatage des minutes : 2 chiffres avant le point, 3 après 585 // On sépare les minutes entières et les décimales proprement 586 let minFixed = min.toFixed(3); 587 let [minEntiere, minDecimale] = minFixed.split('.'); 588 let minStr = minEntiere.padStart(2, '0'); 589 590 return `${degStr}°${minStr}.${minDecimale}${direction}`; 591} 592 593/***************** 594convert dec to APRS formatted string 595*******************/ 596function dec2APRS(dd,lat) { 597 var absolute = Math.abs(dd); 598 599 var deg = Math.floor(absolute); 600 var min = (absolute - deg) * 60; 601 var min = Math.round((min * 100))/100; 602 if (min==60) { 603 min=0; 604 deg++; 605 } 606 min1 = min.toString().split(".")[0]; 607 min2 = min.toString().split(".")[1]; 608 if (min2 == undefined) min2 = "00"; 609 610 if (lat) { 611 var direction = 'N'; 612 if (dd <= 0) {direction = 'S'}; 613 return pad('0000',deg + min1,true) + "." + pad('00',deg + min2,true) + direction; 614 } else { 615 var direction = 'E'; 616 if (dd <= 0) direction = 'W'; 617 return pad('00000',deg + min1,true) + "." + pad('00',deg + min2,true) + direction; 618 } 619} 620 621/***************** 622to pad the datas 623usage var = pad ('0000', str, true) 624*******************/ 625function pad(pad, str, padLeft) { 626 if (typeof str === 'undefined') 627 return pad; 628 if (padLeft) {
629 return (pad + str).slice(-pad.length); 630 } else { 631 return (str + pad).substring(0, pad.length); 632 } 633} 634 635/* 636// 637function geocode(addr) 638{ 639 var result = null; 640 var lat = 0; 641 var lon = 0; 642 var country = ""; 643 644 $.ajax({ 645 async: false, 646 type: 'GET', 647 dataType: "json", 648 //url: "https://nominatim.openstreetmap.org/search"+addr+"?format=json&addressdetails=1&limit=1", 649 url: "https://nominatim.openstreetmap.org/search?format=json&addressdetails=1&limit=1&q="+addr, 650 data: {}, 651 success: function(data){ 652 if (typeof data[0].lat !== 'undefined') { 653 lat = parseFloat(data[0].lat,10); 654 } 655 if (typeof data[0].lon !== 'undefined') { 656 lon = parseFloat(data[0].lon,10); 657 } 658 if (typeof data[0].address.country !== 'undefined') { 659 country = data[0].address.country; 660 } 661 result = { country: country, lat: lat, lng:lon }; 662 }, 663 }); 664return result; 665} 666 667$( "#find_locator" ).live( "change" , function() { 668 qth = $('#find_locator').val(); 669 if (qth.length<6) { alert('WWL must have at least 6 characters !') }; 670 }); 671 672// check for valid WWL and converts to lat,lng 673$("#find_locator").live('keyup', function(event){ 674 loc = $('#find_locator').val().toUpperCase(); 675 676 if ( (loc.length==1) && ((loc.charCodeAt(0)<65) || (loc.charCodeAt(0)>82))) {loc = loc.substr(0,0);} 677 if ( (loc.length==2) && ((loc.charCodeAt(1)<65) || (loc.charCodeAt(1)>82))) {loc = loc.substr(0,1);} 678 if ( (loc.length==3) && ((loc.charCodeAt(2)<48) || (loc.charCodeAt(2)>57))) {loc = loc.substr(0,2);} 679 if ( (loc.length==4) && ((loc.charCodeAt(3)<48) || (loc.charCodeAt(3)>57))) {loc = loc.substr(0,3);} 680 if ( (loc.length==5) && ((loc.charCodeAt(4)<65) || (loc.charCodeAt(4)>88))) {loc = loc.substr(0,4);} 681 if ( (loc.length==6) && ((loc.charCodeAt(5)<65) || (loc.charCodeAt(5)>88))) {loc = loc.substr(0,5);} 682 if ( (loc.length==7) && ((loc.charCodeAt(6)<48) || (loc.charCodeAt(6)>57))) {loc = loc.substr(0,6);} 683 if ( (loc.length==8) && ((loc.charCodeAt(7)<48) || (loc.charCodeAt(7)>57))) {loc = loc.substr(0,7);} 684 if ( (loc.length==9) && ((loc.charCodeAt(8)<65) || (loc.charCodeAt(8)>88))) {loc = loc.substr(0,8);} 685 if ( (loc.length==10) && ((loc.charCodeAt(9)<65) || (loc.charCodeAt(9)>88))) {loc = loc.substr(0,9);} 686 687 $('#find_locator').val(loc); 688 if (loc.length==6) { 689 MHtoLatLng(loc); 690 //map.setView([lat,lng],13); 691 showLoc(lat,lng,13); 692 } 693 if (loc.length==8) { 694 MHtoLatLng(loc);
695 map.setView([lat,lng],17); 696 //showLoc(lat,lng,17); 697 } 698 if (loc.length==10) { 699 MHtoLatLng(loc); 700 map.setView([lat,lng],19); 701 //showLoc(lat,lng,17); 702 } 703 }); 704 705 $( "#find_address" ).live( "change" ,function() { 706 var locality = $('#find_address').val(); 707 var geo = geocode(locality); 708 var locator = latlng2loc(geo.lat,geo.lng, 10); 709 //$('#locator_klick').val(locator); 710 map.setView([geo.lat, geo.lng],13); 711 712 //$('#country').html(geo.country); 713}); 714/* 715function showLoc(lat,lng,zoom) { 716 map.setView([lat,lng],zoom); 717 718 //if (!map.hasLayer(locSquare)) {locSquare.remove(map)}; 719 //L.circle([lat, lng], 200).addTo(map); 720 var locSquare = L.rectangle([[lat + 0.0208333333, lng - 0.0416666666],[lat - 0.0208333333, lng + 0.0416666666]], {color: "red", weight: 2,fillColor:"false"}).addTo(map); 721 722 //if (map.hasLayer(locSquare)) {locSquare.remove(map)}; 723 } 724*/ 725 726 727/** 728 * Géocodage via Nominatim (Remplace l'ancien $.ajax) 729 */ 730async function geocode(addr) { 731 try { 732 const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&addressdetails=1&limit=1&q=${encodeURIComponent(addr)}`); 733 const data = await response.json(); 734 735 if (data && data.length > 0) { 736 return { 737 country: data[0].address.country || "", 738 lat: parseFloat(data[0].lat), 739 lng: parseFloat(data[0].lon) 740 }; 741 } 742 } catch (error) { 743 console.error("Error de geocoding:", error); 744 } 745 return null; 746} 747 748/** 749 * Gestionnaire de recherche par Locator (Remplace $("#find_locator").live) 750 */ 751document.addEventListener('keyup', async function(event) { 752 if (event.target && event.target.id === 'find_locator') { 753 let loc = event.target.value.toUpperCase(); 754 755 // Validation des caractères (votre logique conservée) 756 const charCode = (i) => loc.charCodeAt(i);
757 if (loc.length === 1 && (charCode(0) < 65 || charCode(0) > 82)) loc = ""; 758 if (loc.length === 2 && (charCode(1) < 65 || charCode(1) > 82)) loc = loc.substr(0, 1); 759 // ... (Logique de filtrage identique à la vôtre) ... 760 761 event.target.value = loc; 762 763 // Si le locator est complet, on déplace la carte 764 if (loc.length >= 6) { 765 const coords = MHtoLatLng(loc); 766 if (coords[2] > 0) { // Si LocLength > 0 767 let zoom = 13; 768 if (loc.length === 8) zoom = 17; 769 if (loc.length === 10) zoom = 19; 770 771 showLoc(coords[0], coords[1], zoom); 772 } 773 } 774 } 775}); 776 777/** 778 * Gestionnaire de recherche par Adresse (Remplace $("#find_address").live) 779 */ 780document.addEventListener('change', async function(event) { 781 if (event.target && event.target.id === 'find_address') { 782 const locality = event.target.value; 783 const geo = await geocode(locality); 784 785 if (geo) {
786 map.setView([geo.lat, geo.lng], 13); 787 // Optionnel : afficher le locator dans la console ou un div 788 console.log("Locator trouvé :", latlng2loc(geo.lat, geo.lng)); 789 } 790 } 791}); 792 793 794/** 795 * Affiche le rectangle rouge du locator 796 */ 797function showLoc(lat, lng, zoom) { 798 const classRectangle = 'locsquare'; 799 800 // Nettoyage des anciens rectangles 801 const existingRects = document.getElementsByClassName(classRectangle); 802 while(existingRects.length > 0) { 803 existingRects[0].remove(); 804 } 805 806 L.rectangle( 807 [ 808 [lat + 0.0208333333, lng - 0.0416666666], 809 [lat - 0.0208333333, lng + 0.0416666666] 810 ], 811 { 812 color: "red", 813 weight: 2, 814 fillColor: "none", 815 className: classRectangle 816 } 817 ).addTo(map); 818 819 map.setView([lat, lng], zoom); 820} 821 822/* 823* conversion coordonnées GWGS84 en Lambert93 824* entre lat et long 825* retour un tableau avec X et Y en mètres 826*/ 827function wgs84ToLambert93(lat, lon) { 828 // constantes officielles IGN 829 const GRS80E = 0.081819191042816; 830 const n = 0.7256077650532670; 831 const C = 11754255.426096; 832 const XS = 700000.0; 833 const YS = 12655612.049876; 834 const lon0 = 3 * Math.PI / 180; // méridien origine (3°E) 835 836 // conversion degrés â radians 837 const phi = lat * Math.PI / 180; 838 const lambda = lon * Math.PI / 180; 839 840 // latitude isométrique 841 const sinPhi = Math.sin(phi); 842 const part1 = Math.tan(Math.PI / 4 + phi / 2); 843 const part2 = Math.pow( 844 (1 - GRS80E * sinPhi) / (1 + GRS80E * sinPhi), 845 GRS80E / 2 846 ); 847 const L = Math.log(part1 * part2); 848 849 // projection Lambert 93 850 const R = C * Math.exp(-n * L); 851 const gamma = n * (lambda - lon0); 852 853 const X = XS + R * Math.sin(gamma); 854 const Y = YS - R * Math.cos(gamma); 855 856 return [X,Y]; 857}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.