Subversion Repositories eFlore/Projets.eflore-projets

Rev

Rev 1058 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1058 jpm 1
<?php
2
/**
3
 * Réparation des polygones incomplets :
4
 *
5
 * Exemple de lancement du script :
6
 * /opt/lampp/bin/php -d memory_limit=8000M cli.php osm -a ordonnerPolygoneInc -m manuel -v 3
7
 *
8
 * /opt/lampp/bin/php -d memory_limit=8000M cli.php osm -a remplirPolygoneInc -m manuel -v 3
9
 *
10
 * /opt/lampp/bin/php -d memory_limit=8000M cli.php osm -a renommer -m manuel -v 3
11
 *
12
 */
13
class PolygoneReparateur {
14
	private $conteneur;
15
	private $bdd;
16
	private $messages;
17
	private $mode;
18
 
19
	public function __construct($conteneur) {
20
		$this->conteneur = $conteneur;
21
		$this->bdd = $this->conteneur->getBdd();
22
		$this->messages = $this->conteneur->getMessages();
23
		$this->mode = $this->conteneur->getParametre('m');
24
	}
25
 
26
	/**
27
	 * Fonction qui parcourt tous les ways les noeuds de chaque relation en prenant en considération l'ordre et
28
	 * le sens de chaque ways concaténés ensemble (séparés par des virgules). Update du champ polygone de chaque
29
	 * relation dans la table `osm_relations`
30
	 */
31
	public function executer() {
32
		// Lancement de l'action demandée
33
		$cmd = $this->conteneur->getParametre('a');
34
		switch ($cmd) {
35
			case 'ordonnerPolygoneInc' :
36
				$this->ordonnerRelationsAuPolygoneIncomplet();
37
				break;
38
			case 'remplirPolygoneInc' :
39
				$this->remplirRelationsAuPolygoneIncomplet();
40
				break;
41
			case 'renommer' :
42
				$this->renommerEnPolygoneIncomplet();
43
				break;
44
			default :
45
				$msgTpl = "Erreur : la commande '%s' n'est pas prise en compte par la classe %s !";
46
				$msg = sprintf($msgTpl, $cmd, get_class($this));
47
				throw new Exception($msg);
48
		}
49
		print "\n";// Pour ramener à la ligne en fin de script
50
	}
51
 
52
	/**
53
	 * Fonction qui récupère les relations des polygones incomplets et appelle pour chaque relation la fonction
54
	 * ordonnerPolygoneIncomplet($ordre,$tour,$idRelation,$nombrePolygone)
55
	 */
56
	private function ordonnerRelationsAuPolygoneIncomplet() {
57
		$relations = $this->getRelationsAuPolygoneIncomplet();
58
		foreach ($relations as $relation) {
59
			$idRelation = $relation['id_relation'];
60
			$this->ordonnerCheminsMultiPolygone($idRelation);
61
 
62
			if ($this->mode == 'manuel') {
63
				$this->messages->afficherAvancement("Réparation du polygone incomplet : ", 1);
64
			}
65
		}
66
	}
67
 
68
	/**
69
	 * Fonction récursive qui exécute la même tâche que la fonction ordonnerWays() pour chaque polygone d'un
70
	 * multipolygone et remplie le champ NbPoly dans la table `osm_relation_a_chemins` qui correspond au nombre de polygone fermé
71
	 * dans le multipolygone
72
	 */
73
	private function ordonnerCheminsMultiPolygone($idRelation, $numPolygone = 1, $ordre = 1, $tour = 1) {
74
		$chemins = $this->getChemins($idRelation);
75
		$nbreCheminsTotal = count($chemins);
76
 
77
		// premier élément du tableau
78
		$idPremierChemin = $chemins[0]['id_chemin'];
79
		$idChemin = $idPremierChemin;
80
 
81
		$this->mettreAJourChemin($idRelation, $idPremierChemin, $ordre, 'directe', $numPolygone);
82
		//selection dernier noeud
83
		$nodes = $this->getNoeuds($idPremierChemin);
84
		$nombreNodes = count($nodes);
85
		$premierNoeud = $nodes[0]['id_noeud'];
86
		$dernierNoeud = $nodes[$nombreNodes - 1]['id_noeud'];
87
		$noeudActuel = $dernierNoeud;
88
 
89
		//Condition pour laquelle la boucle while continue à tourner; tant que le premier noeud du polygone n'est
90
		//égale au dernier et tant qu'il reste des ways à gérer
91
		while (($premierNoeud != $noeudActuel) && (($ordre % 1000) < $nbreCheminsTotal)) {
92
			//select le way qui possède le dernier noeud du précédent way et écarter l'actuel
93
			$ordre++;
94
 
95
			$chemins = $this->getCheminsAOrdonner($idRelation, $idChemin, $noeudActuel);
96
			if (isset($chemins[0])) {
97
				$idChemin = $chemins[0]['id_chemin'];
98
				$nodes = $this->getNoeuds($idChemin);
99
				$nombreNodes = count($nodes);
100
				if (strcmp($nodes[0]['id_noeud'], $noeudActuel ) == 0) {
101
					$sens = 'directe';
102
					$noeudActuel = $nodes[$nombreNodes-1]['id_noeud'];
103
				} else {
104
					$sens = 'indirecte';
105
					$noeudActuel = $nodes[0]['id_noeud'];
106
				}
107
				$this->mettreAJourChemin($idRelation, $idChemin, $ordre, $sens, $numPolygone);
108
			}
109
		}
110
		$ordre = 1000 * $tour; //différencier chaque polygone: pour chaque polygone on a un multiple de mille
111
		if ($this->getNombreChemins($idRelation) != 0) {
112
			//appelle de la méthode récursivement
113
			$this->ordonnerCheminsMultiPolygone($idRelation, ++$numPolygone, $ordre, ++$tour);
114
		}
115
	}
116
 
117
	private function getRelationsAuPolygoneIncomplet() {
118
		$requete = 'SELECT id_relation '.
119
			'FROM osm_communes '.
120
			"WHERE notes = 'Polygone incomplet' ".
121
			' -- '.__FILE__.' : '.__LINE__;
122
		$relations = $this->bdd->recupererTous($requete);
123
		return $relations;
124
	}
125
 
126
	private function getChemins($idRelation) {
127
		$requete = 'SELECT id_chemin '.
128
			'FROM osm_relation_a_chemins '.
129
			"WHERE id_relation = $idRelation ".
130
			"AND ordre IS NULL ".
131
			' -- '.__FILE__.' : '.__LINE__;
132
		$chemins = $this->bdd->recupererTous($requete);
133
		return $chemins;
134
	}
135
	/**
136
	 * Select des ways qui n'ont pas été ordonnés: on obtient à chaque itération les ways qui restent à ordonner
137
	 */
138
	private function getCheminsAOrdonner($idRelation, $idChemin, $idNoeud) {
139
		$requete = 'SELECT cn.id_chemin '.
140
			'FROM osm_relation_a_chemins AS rc '.
141
			'	INNER JOIN osm_chemin_a_noeuds AS cn ON (rc.id_chemin = cn.id_chemin) '.
142
			"WHERE cn.id_noeud = $idNoeud ".
143
			"AND cn.id_chemin != $idChemin ".
144
			"AND rc.id_relation = $idRelation ".
145
			"AND rc.ordre IS NULL ".
146
			' -- '.__FILE__.' : '.__LINE__;
147
		$chemins = $this->bdd->recupererTous($requete);
148
		return $chemins;
149
	}
150
 
151
	private function getNoeuds($idChemin) {
152
		$requete = 'SELECT id_noeud '.
153
			'FROM osm_chemin_a_noeuds '.
154
			"WHERE id_chemin = $idChemin ".
155
			'ORDER BY ordre '.
156
			' -- '.__FILE__.' : '.__LINE__;
157
		$noeuds = $this->bdd->recupererTous($requete);
158
		return $noeuds;
159
	}
160
 
161
	private function getNombreChemins($idRelation) {
162
		$requete = 'SELECT COUNT(id_chemin) AS nbre '.
163
			'FROM osm_relation_a_chemins '.
164
			"WHERE id_relation = $idRelation ".
165
			'AND ordre = 0 '.
166
			' -- '.__FILE__.' : '.__LINE__;
167
		$infos = $this->bdd->recuperer($requete);
168
		return $infos['nbre'];
169
	}
170
 
171
	private function mettreAJourChemin($idRelation, $idChemin, $ordre, $sens, $nbrePoly) {
172
		$requete = 'UPDATE osm_relation_a_chemins '.
173
			"SET ordre = '$ordre', sens = '$sens', num_poly = $nbrePoly ".
174
			"WHERE id_relation = $idRelation ".
175
			"AND id_chemin = $idChemin ".
176
			' -- '.__FILE__.' : '.__LINE__;
177
		$this->bdd->requeter($requete);
178
	}
179
 
180
	/**
181
	 * Fonction qui récupère les relations des polygones incomplets et appelle pour chaque relation la fonction
182
	 * remplirPolygoneIncomplet($idRelation);
183
	 */
184
	private function remplirRelationsAuPolygoneIncomplet() {
185
		$relations = $this->getRelationsAuPolygoneIncomplet();
186
		foreach ($relations as $relation) {
187
			$this->remplirPolygoneIncomplet($relation['id_relation']);
188
			if ($this->mode == 'manuel') {
189
				$this->messages->afficherAvancement("Création du polygone incomplet : ", 1);
190
			}
191
		}
192
	}
193
 
194
	/**
195
	 * Fonction qui exécute la même tâche que la fonction remplirPolygone() pour chaque polygone d'un multipolygone
196
	 * et renvoie un tableau MultiPolygone[] où chaque case contient un polygone fermé. Puis met à jour le polygone
197
	 * de la commune.
198
	 */
199
	private function remplirPolygoneIncomplet($idRelation) {
200
		// Tableau multipolygone qui contient tous les polygones d'un multipolygone
201
		$multiPolygone = array();
202
		// Tableau roles qui contient les différents roles des chemins de la relation
203
		$roles = array();
204
		// Sélectionner le nombre de polygones qui existe dans un multipolygone
205
		$nbPoly = $this->getNombrePoly($idRelation);
206
		//boucle for qui parcourt chaque polygone du multipolygone
207
		for ($numPoly = 1; $numPoly <= $nbPoly; $numPoly++) {
208
			$polygone = array();
209
			$chemins = $this->getCheminsParPolygone($idRelation, $numPoly);
210
			foreach ($chemins as $chemin) {
211
				$role = $chemin['role'];
212
				$roles[$role] = (isset($roles[$role])) ? $roles[$role]++ : 1;
213
				$noeuds = $this->getNoeudsPourCheminEtSens($chemin['id_chemin'], $chemin['sens']);
214
				$polygone = array_merge($polygone, $noeuds);
215
			}
216
			$multiPolygone[] = implode(', ', $polygone);
217
		}
218
		$this->mettreAJourMultiPolygone($multiPolygone, $roles, $idRelation, $nbPoly);
219
	}
220
 
221
	private function getNombrePoly($idRelation) {
222
		$requete = 'SELECT MAX(num_poly) AS num_poly '.
223
			'FROM osm_relation_a_chemins '.
224
			"WHERE id_relation = $idRelation ".
225
			' -- '.__FILE__.' : '.__LINE__;
226
		$resultat = $this->bdd->recuperer($requete);
227
		return $resultat['num_poly'];
228
	}
229
 
230
	private function getCheminsParPolygone($idRelation, $numPoly) {
231
		$requete = 'SELECT id_chemin, sens, role '.
232
			'FROM osm_relation_a_chemins '.
233
			"WHERE id_relation = $idRelation ".
234
			"AND num_poly = $numPoly ".
235
			'ORDER BY ordre '.
236
			' -- '.__FILE__.' : '.__LINE__;
237
		$chemins = $this->bdd->recupererTous($requete);
238
		return $chemins;
239
	}
240
 
241
	private function getNoeudsPourCheminEtSens($idChemin, $sens) {
242
		$tri = ($sens == 'directe') ? 'ASC' : 'DESC';
243
		$requete = 'SELECT NLL.id_noeud, NLL.lat, NLL.`long` '.
244
			'FROM osm_chemin_a_noeuds AS WN '.
245
			'	INNER JOIN osm_noeuds AS NLL ON (WN.id_noeud = NLL.id_noeud) '.
246
			"WHERE WN.id_chemin = $idChemin ".
247
			"ORDER BY WN.ordre $tri ".
248
			' -- '.__FILE__.' : '.__LINE__;
249
		$noeuds = $this->bdd->recupererTous($requete);
250
		$latLng = array();
251
		foreach ($noeuds as $noeud) {
252
			$latLng[] = $noeud['lat'].' '.$noeud['long'];
253
		}
254
		return $latLng;
255
	}
256
 
257
	/**
258
	 * Remplie le champ polygone à partir du tableau MultiPolygone
259
	 */
260
	private function mettreAJourMultiPolygone($multiPolygone, $roles, $idRelation, $nbPoly) {
261
		// Présence d'une enclave contenue dans cette entité administrative mais qui appartient à une autre entité administrative
262
		if ((isset($roles['inner']) || isset($roles['enclave']))) {
263
			if ($nbPoly == 2) {
264
				$multiPoly = implode('),(', $multiPolygone);
265
			} else {
266
				$multiPoly = null;
267
				$msgTpl = "La relation '%s' possède plus de 2 polygones de type enclaves.";
268
				$this->messages->traiterErreur($msgTpl, array($idRelation));
269
			}
270
		} else {
271
			// Tous les autres cas
272
			$multiPoly = implode(')),((', $multiPolygone);
273
		}
274
		if (isset($multiPoly)) {
275
			$this->mettreAJourCommune($idRelation, $multiPoly);
276
		}
277
	}
278
 
279
	private function mettreAJourCommune($idRelation, $multiPoly) {
280
		$requete = 'UPDATE osm_communes '.
281
			"SET polygone = MPOLYFROMTEXT('MULTIPOLYGON((($multiPoly)))'), ".
282
			"notes = 'Polygone complet' ".
283
			"WHERE id_relation = $idRelation ".
284
			' -- '.__FILE__.' : '.__LINE__;
285
		$this->bdd->requeter($requete);
286
	}
287
 
288
	/**
289
	 * Renomme la note des polygones vides d'un polygone complet en polygone incomplet
290
	 */
291
	private function renommerEnPolygoneIncomplet() {
292
		$requete = 'UPDATE osm_communes '.
293
			"SET notes = 'Polygone incomplet' ".
294
			"WHERE ASTEXT(polygone) IS NULL ".
295
			' -- '.__FILE__.' : '.__LINE__;
296
 
297
		$retour = $this->bdd->requeter($requete);
298
		$this->messages->traiterInfo("Nombre de polygones définis à incomplet : ".$retour->rowCount());
299
	}
300
}