PageSourceSearch

https://www.ea2cw.eus/locator/js/geocoding.js

js ea2cw.eus collected 2026-10-06 13:15:02 UTC 26,298 bytes, 857 lines download raw bytes

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.