Subversion Repositories eFlore/Applications.cel

Rev

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