Subversion Repositories eFlore/Applications.cel

Rev

Rev 977 | Rev 979 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 977 Rev 978
Line 1... Line 1...
1
<?php
1
<?php
2
class CartoGroupage {
2
class CartoGroupage {
-
 
3
 
3
	const OFFSET = 268435456;// Moitié de la circonférence de la terre au zoom 21
4
	private static $seuilClusterisation = 100;
-
 
5
	private static $zoomDefaut = 3;
4
	const RADIUS = 85445659.4471; /* $offset / pi() */
6
	private static $zoomMaxClustering = 12;
5
	private static $profondeurMax = 3;
7
	private static $pasZoomDefaut = 1;
6
	private static $pasCorrectionCentre = 1;
8
	private static $pasZoomMaxClustering = 0.05;
7
	private static $zoom = 1;
9
	private static $profondeurMin = 0;
8
	private static $seuilClusterisation = 180;
10
	private static $profondeurMax = 8;
9
	
11
	
10
	private static $debug = false;
12
	private static $pasCorrectionCentre = null;
-
 
13
	private static $coefficientReductionPas = null;	
-
 
14
	private static $coefficientProfondeurMax = null;
11
	
15
 
12
	private static $listeNoeudsSelectionnes = array();
16
	private static $listeNoeudsSelectionnes = array();
13
	
17
 
14
	private static $hilbert_map_1 = array ('a' => array (
-
 
15
									"0, 0" => array (0, 'd'),
-
 
16
									"0, 1" => array (1, 'a'), 
-
 
17
											"1, 0" => array (3, 'b'),
-
 
18
											"1, 1" => array (2, 'a')
-
 
19
									), 
18
	/*
20
									 'b' => array ( 
19
	  +---------+---------+
21
											 "0, 0" => array (2, 'b'), 
-
 
22
											 "0, 1" => array (1, 'b'), 
20
	  |         |         |
23
											 "1, 0" => array (3, 'a'),
21
	  |    A    |    B    |
24
											 "1, 1" => array (0, 'c')
22
	  |         |         |
25
									), 
-
 
26
									'c' => array ( 
23
	  +---------*---------+
27
											"0, 0" => array (2, 'c'),
-
 
28
											"0, 1" => array (3, 'd'),
24
	  |         |         |
29
											"1, 0" => array (1, 'c'),
25
	  |    D    |    C    |
30
											"1, 1" => array (0, 'b')
26
	  |         |         |
31
										), 
-
 
32
									'd' => array (
27
	  +---------+---------+
33
											"0, 0" => array (0, 'a'), 
-
 
34
											"0, 1" => array (3, 'c'), 
-
 
35
											"1, 0" => array (1, 'd'), 
-
 
36
											"1, 1" => array (2, 'd')
-
 
37
									),
-
 
38
								);
-
 
39
	
28
	  
40
	public static $cache = array('lat->y' => array(), 'lat->y' => array());
29
	  Quatres cadrans sont considérés par le quad tree
-
 
30
	  * = centre de la fenetre 
41
	
31
	 */
42
	public static function creerGroupesManhattan($markers, $zoom) {
32
	public static function creerGroupesQuadtree($markers, $neLat, $neLng, $swLat, $swLng, $zoom = 3) {
43
		$clustered = array();
-
 
44
		// Distance minimum entre deux marqueurs pour l'inclure dans un cluster à un niveau de zoom donné
-
 
45
		$groupeRayon = (10000000 >> $zoom) / 100000;
-
 
Line 46... Line -...
46
		
-
 
47
		/* Boucle permettant de définir les marqueurs de références. */
-
 
48
		while (count($markers)) {
33
		
49
			$marker  = array_shift($markers);
-
 
50
			$cluster = array();
34
		if(count($markers) > self::$seuilClusterisation) {
51
			
-
 
52
			/* Comparaison de la distance des autres marqueurs avec le marqueur de référence. */
35
						
53
			foreach ($markers as $key => $target) {
36
			self::calculerProfondeurMax($zoom);
Line -... Line 37...
-
 
37
			self::calculerPasCorrectionCentre($zoom);
54
				$cibleDistance = abs($marker['lat'] - $target['lat']) + abs($marker['lng'] - $target['lng']);
38
 
-
 
39
			$noeudRacine = array('nbrePoints' => count($markers), 'points' => $markers);
-
 
40
			self::attribuerAuCadran($noeudRacine, $neLat, $neLng, $swLat, $swLng);	
55
 
41
			
56
				if ($groupeRayon > $cibleDistance) {
42
		} else {
57
					unset($markers[$key]);
-
 
-
 
43
			foreach($markers as $marker) {
-
 
44
				$points = array($marker);
58
					$cluster['cibles'][] = $target;
45
				$noeudSimple = array('points' => $points, 'nbrePoints' => 1);
-
 
46
				self::$listeNoeudsSelectionnes[] = self::ajouterGroupeOuPoint($noeudSimple);
-
 
47
			}
-
 
48
		}
-
 
49
			
Line 59... Line 50...
59
				}
50
		return self::$listeNoeudsSelectionnes;
-
 
51
	}
-
 
52
	
60
			}
53
	private function calculerCoefficientReductionPas() {
Line 61... Line 54...
61
	
54
		if(self::$coefficientReductionPas == null) {
62
			$clustered[] = self::ajouterGroupe($cluster, $marker);
55
			self::$coefficientReductionPas = (self::$pasZoomMaxClustering - self::$pasZoomDefaut)/(self::$zoomMaxClustering - self::$zoomDefaut);
Line 63... Line -...
63
		}
-
 
64
		
-
 
65
		return $clustered;
56
		}
66
	}
-
 
67
	
-
 
68
	public static function creerGroupesPixel($markers, $zoom, $clusterDistance = 20) {
-
 
69
		$clustered = array();
-
 
70
		/* Loop until all markers have been compared. */
-
 
71
		while (count($markers)) {
-
 
72
			$marker  = array_shift($markers);
57
		
73
			$cluster = array();
-
 
74
			
-
 
75
			/* Compare against all markers which are left. */
-
 
76
			foreach ($markers as $key => $target) {
-
 
77
				$cibleDistance = self::pixelDistance($marker['lat'], $marker['lng'], $target['lat'], $target['lng'], $zoom);
-
 
78
 
-
 
79
				if ($clusterDistance > $cibleDistance) {
-
 
80
					//$m = "Distance entre %s,%s et %s,%s vaut %d pixels.\n";
-
 
81
					//printf($m, $marker['lat'], $marker['lng'], $target['lat'], $target['lng'], $pixels);
-
 
82
					unset($markers[$key]);
-
 
83
					$cluster['cibles'][] = $target;
-
 
84
					$cluster['latMax'] = ($cluster['latMax'] < $target['lat']) ? $target['lat'] : $cluster['latMax'];
-
 
85
					$cluster['lngMax'] = ($cluster['lngMax'] < $target['lng']) ? $target['lng'] : $cluster['lngMax'];  
-
 
86
				}
58
		return self::$coefficientReductionPas;
Line 87... Line 59...
87
			}
59
	}
88
			$clustered[] = self::ajouterGroupe($cluster, $marker);
-
 
89
		}
60
	
90
		return $clustered;
-
 
91
	}
-
 
92
	
-
 
93
	public static function ajouterGroupe($cluster, $marker) {
-
 
94
		$groupe = array();
-
 
95
		$nbreMarqueurs = count($cluster['cibles']);
-
 
96
		if ($nbreMarqueurs > 0) {
61
	private function calculerPasCorrectionCentre($zoom) {
97
			$groupe['id'] = 'GROUPE:'.$marker['lat'].';'.$marker['lng'];
-
 
98
			$groupe['lat'] = $marker['lat'];
-
 
99
			$groupe['lng'] = $marker['lng'];
-
 
100
			$groupe['latMax'] = $cluster['latMax'];
62
		self::$pasCorrectionCentre = ($zoom - self::$zoomDefaut) * self::calculerCoefficientReductionPas() + self::$pasZoomDefaut;
-
 
63
	}
101
			$groupe['lngMax'] = $cluster['lngMax'];
64
	
102
			// +1 car le marqueur servant de point de départ n'est pas ajouté au cluster
65
	private function calculerCoefficientProfondeurMax() {
Line 103... Line -...
103
			$groupe['nbreMarqueur'] = $nbreMarqueurs + 1;
-
 
104
		} else {
-
 
105
			$groupe = $marker;
66
		if(self::$coefficientProfondeurMax == null) {
106
		}
-
 
107
		return $groupe;
-
 
108
	}
-
 
109
	
67
			self::$coefficientProfondeurMax = (self::$profondeurMax - self::$profondeurMin)/(self::$zoomMaxClustering - self::$zoomDefaut);
110
	public static function creerGroupesQuadtree2($markers, $neLat, $neLng, $swLat, $swLng, $zoom = 3) {
-
 
111
		
-
 
112
		if(count($markers) > self::$seuilClusterisation) {
-
 
113
			
-
 
114
			//$_GET['debug'] = true;
-
 
115
			
-
 
116
			self::$zoom = $zoom;
68
		}
117
			self::$pasCorrectionCentre = 10/self::$zoom;
-
 
118
			
-
 
119
			self::$profondeurMax = round(pow($zoom,1.05),0) - 1;
-
 
120
			
-
 
121
			echo ($_GET['debug'] == true) ? '<pre>' : '';
-
 
122
			
69
		
123
			echo ($_GET['debug'] == true) ? 'zoom :'.$zoom.' profondeur max '.self::$profondeurMax : '';
-
 
124
			
70
		return self::$coefficientProfondeurMax;
125
			//echo "$neLat, $neLng, $swLat, $swLng";
-
 
126
			$noeud = array('coordCentre' => null,'nbrePoints' => count($markers), 'points' => $markers);
-
 
127
			self::attribuerAuCarre($noeud, $neLat, $neLng, $swLat, $swLng);	
-
 
128
			echo ($_GET['debug'] == true) ? '</pre>' : '';
71
	}
129
		} else {
-
 
130
			foreach($markers as $marker) {
-
 
131
				$points = array($marker);
72
	
Line 132... Line -...
132
				$noeud_fictif = array('points' => $points, 'nbrePoints' => 1);
-
 
133
				self::$listeNoeudsSelectionnes[] = self::ajouterGroupe2($noeud_fictif);
73
	private function calculerProfondeurMax($zoom) {	
134
			}
74
		if($zoom > self::$zoomDefaut) {	
135
		}
75
			self::$profondeurMax = round(($zoom - self::$zoomDefaut) * self::calculerCoefficientProfondeurMax() + self::$profondeurMin,0);
136
			
76
		} else {
137
		return self::$listeNoeudsSelectionnes;
77
			self::$profondeurMax = 1;
-
 
78
		}
-
 
79
	}
-
 
80
	
138
	}
81
	/**
139
	
82
	 * 
140
	private static function attribuerAuCarre(&$noeud, $neLat, $neLng, $swLat, $swLng, $profondeur = 0) {
-
 
141
		
83
	 * @param mixed $noeud Le noeud à traiter par le quadtree
142
		
84
	 * @param float $neLat Latitude du coin nord est de la fenetre 
143
		echo ($_GET['debug'] == true) ? "coordonnees parametres : $neLat, $neLng, $swLat, $swLng" : "";
85
	 * @param float $neLng Longitude du coin nord est de la fenetre 
144
		//$latCentre = $noeud['coordCentre']['lat'] = ($neLat+$swLat)/2;
86
	 * @param float $swLat Latitude du coin sud ouest de la fenetre 
145
		//$lngCentre = $noeud['coordCentre']['lng'] = ($neLng+$swLng)/2;
87
	 * @param float $swLng Longitude du coin sud ouest de la fenetre 
146
		
-
 
147
		$latCentre = $noeud['coordCentre']['lat'] = round((($neLat+$swLat)/2)/self::$pasCorrectionCentre,0)*self::$pasCorrectionCentre;
88
	 * @param int $profondeur profondeur courante de l'arbre
148
		$lngCentre = $noeud['coordCentre']['lng'] = round((($neLng+$swLng)/2)/self::$pasCorrectionCentre,0)*self::$pasCorrectionCentre;
-
 
149
				
-
 
150
		echo ($_GET['debug'] == true) ? "\n\n profondeur : $profondeur\n" : "";
-
 
151
		echo ($_GET['debug'] == true) ? "\t centre : $lngCentre  $latCentre \n" : "";
-
 
152
		
-
 
153
		foreach ($noeud['points'] as &$point) {
-
 
154
			if ($point['lng'] < $lngCentre) {
-
 
155
				if ($point['lat'] > $latCentre) {
-
 
156
					//Carré A
-
 
157
					$noeud['A']['points'][] = $point;
-
 
158
					$noeud['A']['nbrePoints']++;
-
 
159
					$noeud['A']['latMoyenne'] += $point['lat'];
-
 
160
					$noeud['A']['lngMoyenne'] += $point['lng'];
-
 
161
				} else {
-
 
162
					//Carré D
-
 
163
					$noeud['D']['points'][] = $point;	
-
 
164
					$noeud['D']['nbrePoints']++;
-
 
165
					$noeud['D']['latMoyenne'] += $point['lat'];
-
 
166
					$noeud['D']['lngMoyenne'] += $point['lng'];
-
 
167
				}
-
 
168
			} else {
-
 
169
				if ($point['lat'] > $latCentre) {
89
	 */
170
					//Carré B
-
 
171
					$noeud['B']['points'][] = $point;
-
 
172
					$noeud['B']['nbrePoints']++;
-
 
173
					$noeud['B']['latMoyenne'] += $point['lat'];
-
 
174
					$noeud['B']['lngMoyenne'] += $point['lng'];
-
 
175
				} else {
90
	private static function attribuerAuCadran(&$noeud, $neLat, $neLng, $swLat, $swLng, $profondeur = 0) {
Line 176... Line 91...
176
					//Carré C
91
			
Line 177... Line -...
177
					$noeud['C']['points'][] = $point;
-
 
178
					$noeud['C']['nbrePoints']++;
-
 
179
					$noeud['C']['latMoyenne'] += $point['lat'];
92
		$latCentre = round((($neLat+$swLat)/2)/self::$pasCorrectionCentre,0)*self::$pasCorrectionCentre;
180
					$noeud['C']['lngMoyenne'] += $point['lng'];
-
 
181
				}
93
		$lngCentre = round((($neLng+$swLng)/2)/self::$pasCorrectionCentre,0)*self::$pasCorrectionCentre;
182
			}
-
 
183
		}
94
						
184
		
-
 
185
		$profondeur++;
95
		foreach ($noeud['points'] as &$point) {
186
		
-
 
187
		$centreNoeud = array('id' => $latCentre.' '.$lngCentre, 'lat' => $latCentre, 'lng' => $lngCentre, 'nbreMarqueur' => 0); 
96
			$cadran = self::obtenirCadranPourPoint($latCentre, $lngCentre, $point);
188
		//self::$listeNoeudsSelectionnes[] = $centreNoeud;
97
			self::ajouterFils($noeud,$cadran,$point);
Line 189... Line 98...
189
		if($profondeur <= self::$profondeurMax) {	
98
		}
190
			//echo "noeud A\n";	
-
 
191
			($noeud['A'] != null) ? self::attribuerAuCarre($noeud['A'], $neLat, $lngCentre , $latCentre, $lngSw, $profondeur) : '';
99
		
192
			//echo "noeud B\n";
-
 
193
			($noeud['B'] != null) ? self::attribuerAuCarre($noeud['B'], $neLat, $neLng, $latCentre, $lngCentre, $profondeur) : '';
-
 
194
			//echo "noeud C\n";
100
		$profondeur++;
195
			($noeud['C'] != null) ? self::attribuerAuCarre($noeud['C'], $latCentre, $neLng, $swLat, $lngCentre, $profondeur) : '';
101
		
Line -... Line 102...
-
 
102
		if($profondeur <= self::$profondeurMax) {
-
 
103
			($noeud['A'] != null) ? self::attribuerAuCadran($noeud['A'], $neLat, $lngCentre , $latCentre, $lngSw, $profondeur) : '';
-
 
104
			($noeud['B'] != null) ? self::attribuerAuCadran($noeud['B'], $neLat, $neLng, $latCentre, $lngCentre, $profondeur) : '';
-
 
105
			($noeud['C'] != null) ? self::attribuerAuCadran($noeud['C'], $latCentre, $neLng, $swLat, $lngCentre, $profondeur) : '';
-
 
106
			($noeud['D'] != null) ? self::attribuerAuCadran($noeud['D'], $latCentre, $lngCentre, $swLat, $swLng, $profondeur) : '';
-
 
107
		}
-
 
108
		
-
 
109
		if(self::estUnParentFeuilles($noeud)) {
-
 
110
			self::$listeNoeudsSelectionnes[] = self::ajouterGroupeOuPoint($noeud);
-
 
111
		}
-
 
112
	}
-
 
113
	
-
 
114
	private function obtenirCadranPourPoint($latCentre,$lngCentre, &$point) {
-
 
115
		if ($point['lng'] < $lngCentre) {
-
 
116
			if ($point['lat'] > $latCentre) {
-
 
117
					$cadran = 'A';
-
 
118
				} else {
-
 
119
					$cadran = 'D';
-
 
120
				}
-
 
121
		} else {
-
 
122
			if ($point['lat'] > $latCentre) {
-
 
123
				$cadran = 'B';
-
 
124
			} else {
-
 
125
				$cadran = 'C';
196
			//echo "noeud D\n";
126
			}
197
			($noeud['D'] != null) ? self::attribuerAuCarre($noeud['D'], $latCentre, $lngCentre, $swLat, $swLng, $profondeur) : '';
127
		}		
198
		}
128
		return $cadran;
199
		
-
 
200
		//self::$listeNoeudsSelectionnes[] = self::ajouterGroupe2($noeud);
-
 
201
		if(self::estUneFeuille($noeud['A']) && self::estUneFeuille($noeud['B']) && self::estUneFeuille($noeud['C']) && self::estUneFeuille($noeud['D'])) {
129
	}
202
			self::$listeNoeudsSelectionnes[] = self::ajouterGroupe2($noeud);
130
	
203
		} else {
131
	private static function ajouterFils(&$noeud, $cadran, &$point) {	
204
			//self::$listeNoeudsSelectionnes[] = self::ajouterGroupe2($noeud);
132
		$noeud[$cadran]['points'][] = $point;
205
		}
-
 
206
	}
-
 
207
	
133
		$noeud[$cadran]['nbrePoints']++;
208
	public static function ajouterGroupe2($noeud) {
-
 
209
		$groupe = array();
134
		$noeud[$cadran]['latMoyenne'] += $point['lat'];
210
		if ($noeud['nbrePoints'] > 1) {
135
		$noeud[$cadran]['lngMoyenne'] += $point['lng'];
211
			$groupe['id'] = 'GROUPE:'.$noeud['coordCentre']['lat'].';'.$noeud['coordCentre']['lng'];
136
	}
212
			// TODO changer la génération de l'id
137
	
Line 213... Line 138...
213
			$groupe['lat'] = $noeud['latMoyenne']/$noeud['nbrePoints'];
138
	private static function ajouterGroupeOuPoint($noeud) {
214
			$groupe['lng'] = $noeud['lngMoyenne']/$noeud['nbrePoints'];
-
 
215
			echo ($_GET['debug'] == true) ? "\ncentre moyenne ".$groupe['lat']."  ".$groupe['lng'] : "";
-
 
216
			$groupe['nbreMarqueur'] = $noeud['nbrePoints'];
-
 
217
			//$groupe['latMax'] = $cluster['latMax'];
-
 
218
			//$groupe['lngMax'] = $cluster['lngMax'];
-
 
219
		} else {
-
 
220
			//echo '<pre>'.print_r($noeud['points'][0],true).'</pre>';
-
 
221
			$groupe = $noeud['points'][0];
139
		$groupe = array();
222
		}
140
		if ($noeud['nbrePoints'] > 1) {
223
		return $groupe;
-
 
224
	}
-
 
225
	
-
 
226
	private static function estUneFeuille($noeud) {		
-
 
227
		return $noeud == null || ($noeud['A'] == null && $noeud['B'] == null && $noeud['C'] == null && $noeud['D'] == null);
-
 
228
	}
-
 
229
	
-
 
230
	public static function creerGroupesQuadtree($markers, $zoom) {
141
			$groupe['lat'] = $noeud['latMoyenne']/$noeud['nbrePoints'];
231
		$ordre = $zoom - 3;
142
			$groupe['lng'] = $noeud['lngMoyenne']/$noeud['nbrePoints'];
232
		$clustered = array();
-
 
233
		foreach ($markers as $key => $marker) {
-
 
234
			$x = self::lonToX($marker['lng']);
-
 
235
			$y = self::latToY($marker['lat']);
-
 
236
			$payload = self::pointToQuadtree($x, $y, $ordre);
-
 
237
			
-
 
238
			if (isset($clustered[$payload])) {
-
 
239
				$clustered[$payload]['nbreMarqueur']++;
-
 
240
			} else {
-
 
241
				$cluster = array();
-
 
242
				$cluster['id'] = 'GROUPE';
-
 
243
				$cluster['lat'] = $marker['lat'];
-
 
244
				$cluster['lng'] = $marker['lng'];
-
 
245
				$cluster['nbreMarqueur'] = 1;
-
 
246
				$clustered[$payload] = $cluster;
-
 
247
			} 
-
 
248
		}
-
 
249
		return array_values($clustered);
-
 
250
	}
-
 
251
	
-
 
252
	private static function pixelDistance($lat1, $lon1, $lat2, $lon2, $zoom) {
-
 
253
		$x1 = self::lonToX($lon1);
-
 
254
		$y1 = self::latToY($lat1);
-
 
255
 
-
 
256
		$x2 = self::lonToX($lon2);
-
 
257
		$y2 = self::latToY($lat2);
-
 
258
        
-
 
259
		return sqrt(pow(($x1 - $x2), 2) + pow(($y1 - $y2), 2)) >> (21 - $zoom);
-
 
260
	}
-
 
261
	
-
 
262
	private static function lonToX($lon) {
143
			$groupe['id'] = 'GROUPE:'.$groupe['lat'].';'.$groupe['lng'];
Line 263... Line -...
263
		if (! isset(self::$cache['lng->x'][$lon])) {
-
 
264
			self::$cache['lng->x'][$lon] = round(self::OFFSET + self::RADIUS * $lon * pi() / 180);
-
 
265
		}
-
 
266
		return self::$cache['lng->x'][$lon];        
-
 
267
	}
-
 
268
	
-
 
269
	private static function latToY($lat) {
-
 
270
		if (! isset(self::$cache['lat->y'][$lat])) {
-
 
271
			$logLat = log((1 + sin($lat * pi() / 180)) / (1 - sin($lat * pi() / 180)));
-
 
272
			self::$cache['lat->y'][$lat] = round(self::OFFSET - self::RADIUS * $logLat / 2);
-
 
273
		}
144
			$groupe['nbreMarqueur'] = $noeud['nbrePoints'];
274
		return self::$cache['lat->y'][$lat];
-
 
275
	}
-
 
276
	
-
 
277
	public static function haversineDistance($lat1, $lon1, $lat2, $lon2) {
-
 
278
		$latd = deg2rad($lat2 - $lat1);
-
 
279
		$lond = deg2rad($lon2 - $lon1);
145
		} else {
280
		$a = sin($latd / 2) * sin($latd / 2) +
-
 
281
			cos(deg2rad($lat1)) * cos(deg2rad($lat2)) *
-
 
282
			sin($lond / 2) * sin($lond / 2);
-
 
283
			$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
146
			$groupe = $noeud['points'][0];
284
		return 6371.0 * $c;
-
 
285
	}
-
 
286
	
147
		}
287
	private static function pointToQuadtree($x, $y, $order=16) {		
148
		return $groupe;
288
		$current_square = 'a' ;
149
	}