Rev 1058 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php
/**
* Réparation des polygones incomplets :
*
* Exemple de lancement du script :
* /opt/lampp/bin/php -d memory_limit=8000M cli.php osm -a ordonnerPolygoneInc -m manuel -v 3
*
* /opt/lampp/bin/php -d memory_limit=8000M cli.php osm -a remplirPolygoneInc -m manuel -v 3
*
* /opt/lampp/bin/php -d memory_limit=8000M cli.php osm -a renommer -m manuel -v 3
*
*/
class PolygoneReparateur {
private $conteneur;
private $bdd;
private $messages;
private $mode;
public function __construct($conteneur) {
$this->conteneur = $conteneur;
$this->bdd = $this->conteneur->getBdd();
$this->messages = $this->conteneur->getMessages();
$this->mode = $this->conteneur->getParametre('m');
}
/**
* Fonction qui parcourt tous les ways les noeuds de chaque relation en prenant en considération l'ordre et
* le sens de chaque ways concaténés ensemble (séparés par des virgules). Update du champ polygone de chaque
* relation dans la table `osm_relations`
*/
public function executer() {
// Lancement de l'action demandée
$cmd = $this->conteneur->getParametre('a');
switch ($cmd) {
case 'ordonnerPolygoneInc' :
$this->ordonnerRelationsAuPolygoneIncomplet();
break;
case 'remplirPolygoneInc' :
$this->remplirRelationsAuPolygoneIncomplet();
break;
case 'renommer' :
$this->renommerEnPolygoneIncomplet();
break;
default :
$msgTpl = "Erreur : la commande '%s' n'est pas prise en compte par la classe %s !";
$msg = sprintf($msgTpl, $cmd, get_class($this));
throw new Exception($msg);
}
print "\n";// Pour ramener à la ligne en fin de script
}
/**
* Fonction qui récupère les relations des polygones incomplets et appelle pour chaque relation la fonction
* ordonnerPolygoneIncomplet($ordre,$tour,$idRelation,$nombrePolygone)
*/
private function ordonnerRelationsAuPolygoneIncomplet() {
$relations = $this->getRelationsAuPolygoneIncomplet();
foreach ($relations as $relation) {
$idRelation = $relation['id_relation'];
$this->ordonnerCheminsMultiPolygone($idRelation);
if ($this->mode == 'manuel') {
$this->messages->afficherAvancement("Réparation du polygone incomplet : ", 1);
}
}
}
/**
* Fonction récursive qui exécute la même tâche que la fonction ordonnerWays() pour chaque polygone d'un
* multipolygone et remplie le champ NbPoly dans la table `osm_relation_a_chemins` qui correspond au nombre de polygone fermé
* dans le multipolygone
*/
private function ordonnerCheminsMultiPolygone($idRelation, $numPolygone = 1, $ordre = 1, $tour = 1) {
$chemins = $this->getChemins($idRelation);
$nbreCheminsTotal = count($chemins);
// premier élément du tableau
$idPremierChemin = $chemins[0]['id_chemin'];
$idChemin = $idPremierChemin;
$this->mettreAJourChemin($idRelation, $idPremierChemin, $ordre, 'directe', $numPolygone);
//selection dernier noeud
$nodes = $this->getNoeuds($idPremierChemin);
$nombreNodes = count($nodes);
$premierNoeud = $nodes[0]['id_noeud'];
$dernierNoeud = $nodes[$nombreNodes - 1]['id_noeud'];
$noeudActuel = $dernierNoeud;
//Condition pour laquelle la boucle while continue à tourner; tant que le premier noeud du polygone n'est
//égale au dernier et tant qu'il reste des ways à gérer
while (($premierNoeud != $noeudActuel) && (($ordre % 1000) < $nbreCheminsTotal)) {
//select le way qui possède le dernier noeud du précédent way et écarter l'actuel
$ordre++;
$chemins = $this->getCheminsAOrdonner($idRelation, $idChemin, $noeudActuel);
if (isset($chemins[0])) {
$idChemin = $chemins[0]['id_chemin'];
$nodes = $this->getNoeuds($idChemin);
$nombreNodes = count($nodes);
if (strcmp($nodes[0]['id_noeud'], $noeudActuel ) == 0) {
$sens = 'directe';
$noeudActuel = $nodes[$nombreNodes-1]['id_noeud'];
} else {
$sens = 'indirecte';
$noeudActuel = $nodes[0]['id_noeud'];
}
$this->mettreAJourChemin($idRelation, $idChemin, $ordre, $sens, $numPolygone);
}
}
$ordre = 1000 * $tour; //différencier chaque polygone: pour chaque polygone on a un multiple de mille
if ($this->getNombreChemins($idRelation) != 0) {
//appelle de la méthode récursivement
$this->ordonnerCheminsMultiPolygone($idRelation, ++$numPolygone, $ordre, ++$tour);
}
}
private function getRelationsAuPolygoneIncomplet() {
$requete = 'SELECT id_relation '.
'FROM osm_communes '.
"WHERE notes = 'Polygone incomplet' ".
' -- '.__FILE__.' : '.__LINE__;
$relations = $this->bdd->recupererTous($requete);
return $relations;
}
private function getChemins($idRelation) {
$requete = 'SELECT id_chemin '.
'FROM osm_relation_a_chemins '.
"WHERE id_relation = $idRelation ".
"AND ordre IS NULL ".
' -- '.__FILE__.' : '.__LINE__;
$chemins = $this->bdd->recupererTous($requete);
return $chemins;
}
/**
* Select des ways qui n'ont pas été ordonnés: on obtient à chaque itération les ways qui restent à ordonner
*/
private function getCheminsAOrdonner($idRelation, $idChemin, $idNoeud) {
$requete = 'SELECT cn.id_chemin '.
'FROM osm_relation_a_chemins AS rc '.
' INNER JOIN osm_chemin_a_noeuds AS cn ON (rc.id_chemin = cn.id_chemin) '.
"WHERE cn.id_noeud = $idNoeud ".
"AND cn.id_chemin != $idChemin ".
"AND rc.id_relation = $idRelation ".
"AND rc.ordre IS NULL ".
' -- '.__FILE__.' : '.__LINE__;
$chemins = $this->bdd->recupererTous($requete);
return $chemins;
}
private function getNoeuds($idChemin) {
$requete = 'SELECT id_noeud '.
'FROM osm_chemin_a_noeuds '.
"WHERE id_chemin = $idChemin ".
'ORDER BY ordre '.
' -- '.__FILE__.' : '.__LINE__;
$noeuds = $this->bdd->recupererTous($requete);
return $noeuds;
}
private function getNombreChemins($idRelation) {
$requete = 'SELECT COUNT(id_chemin) AS nbre '.
'FROM osm_relation_a_chemins '.
"WHERE id_relation = $idRelation ".
'AND ordre = 0 '.
' -- '.__FILE__.' : '.__LINE__;
$infos = $this->bdd->recuperer($requete);
return $infos['nbre'];
}
private function mettreAJourChemin($idRelation, $idChemin, $ordre, $sens, $nbrePoly) {
$requete = 'UPDATE osm_relation_a_chemins '.
"SET ordre = '$ordre', sens = '$sens', num_poly = $nbrePoly ".
"WHERE id_relation = $idRelation ".
"AND id_chemin = $idChemin ".
' -- '.__FILE__.' : '.__LINE__;
$this->bdd->requeter($requete);
}
/**
* Fonction qui récupère les relations des polygones incomplets et appelle pour chaque relation la fonction
* remplirPolygoneIncomplet($idRelation);
*/
private function remplirRelationsAuPolygoneIncomplet() {
$relations = $this->getRelationsAuPolygoneIncomplet();
foreach ($relations as $relation) {
$this->remplirPolygoneIncomplet($relation['id_relation']);
if ($this->mode == 'manuel') {
$this->messages->afficherAvancement("Création du polygone incomplet : ", 1);
}
}
}
/**
* Fonction qui exécute la même tâche que la fonction remplirPolygone() pour chaque polygone d'un multipolygone
* et renvoie un tableau MultiPolygone[] où chaque case contient un polygone fermé. Puis met à jour le polygone
* de la commune.
*/
private function remplirPolygoneIncomplet($idRelation) {
// Tableau multipolygone qui contient tous les polygones d'un multipolygone
$multiPolygone = array();
// Tableau roles qui contient les différents roles des chemins de la relation
$roles = array();
// Sélectionner le nombre de polygones qui existe dans un multipolygone
$nbPoly = $this->getNombrePoly($idRelation);
//boucle for qui parcourt chaque polygone du multipolygone
for ($numPoly = 1; $numPoly <= $nbPoly; $numPoly++) {
$polygone = array();
$chemins = $this->getCheminsParPolygone($idRelation, $numPoly);
foreach ($chemins as $chemin) {
$role = $chemin['role'];
$roles[$role] = (isset($roles[$role])) ? $roles[$role]++ : 1;
$noeuds = $this->getNoeudsPourCheminEtSens($chemin['id_chemin'], $chemin['sens']);
$polygone = array_merge($polygone, $noeuds);
}
$multiPolygone[] = implode(', ', $polygone);
}
$this->mettreAJourMultiPolygone($multiPolygone, $roles, $idRelation, $nbPoly);
}
private function getNombrePoly($idRelation) {
$requete = 'SELECT MAX(num_poly) AS num_poly '.
'FROM osm_relation_a_chemins '.
"WHERE id_relation = $idRelation ".
' -- '.__FILE__.' : '.__LINE__;
$resultat = $this->bdd->recuperer($requete);
return $resultat['num_poly'];
}
private function getCheminsParPolygone($idRelation, $numPoly) {
$requete = 'SELECT id_chemin, sens, role '.
'FROM osm_relation_a_chemins '.
"WHERE id_relation = $idRelation ".
"AND num_poly = $numPoly ".
'ORDER BY ordre '.
' -- '.__FILE__.' : '.__LINE__;
$chemins = $this->bdd->recupererTous($requete);
return $chemins;
}
private function getNoeudsPourCheminEtSens($idChemin, $sens) {
$tri = ($sens == 'directe') ? 'ASC' : 'DESC';
$requete = 'SELECT NLL.id_noeud, NLL.lat, NLL.`long` '.
'FROM osm_chemin_a_noeuds AS WN '.
' INNER JOIN osm_noeuds AS NLL ON (WN.id_noeud = NLL.id_noeud) '.
"WHERE WN.id_chemin = $idChemin ".
"ORDER BY WN.ordre $tri ".
' -- '.__FILE__.' : '.__LINE__;
$noeuds = $this->bdd->recupererTous($requete);
$latLng = array();
foreach ($noeuds as $noeud) {
$latLng[] = $noeud['lat'].' '.$noeud['long'];
}
return $latLng;
}
/**
* Remplie le champ polygone à partir du tableau MultiPolygone
*/
private function mettreAJourMultiPolygone($multiPolygone, $roles, $idRelation, $nbPoly) {
// Présence d'une enclave contenue dans cette entité administrative mais qui appartient à une autre entité administrative
if ((isset($roles['inner']) || isset($roles['enclave']))) {
if ($nbPoly == 2) {
$multiPoly = implode('),(', $multiPolygone);
} else {
$multiPoly = null;
$msgTpl = "La relation '%s' possède plus de 2 polygones de type enclaves.";
$this->messages->traiterErreur($msgTpl, array($idRelation));
}
} else {
// Tous les autres cas
$multiPoly = implode(')),((', $multiPolygone);
}
if (isset($multiPoly)) {
$this->mettreAJourCommune($idRelation, $multiPoly);
}
}
private function mettreAJourCommune($idRelation, $multiPoly) {
$requete = 'UPDATE osm_communes '.
"SET polygone = MPOLYFROMTEXT('MULTIPOLYGON((($multiPoly)))'), ".
"notes = 'Polygone complet' ".
"WHERE id_relation = $idRelation ".
' -- '.__FILE__.' : '.__LINE__;
$this->bdd->requeter($requete);
}
/**
* Renomme la note des polygones vides d'un polygone complet en polygone incomplet
*/
private function renommerEnPolygoneIncomplet() {
$requete = 'UPDATE osm_communes '.
"SET notes = 'Polygone incomplet' ".
"WHERE ASTEXT(polygone) IS NULL ".
' -- '.__FILE__.' : '.__LINE__;
$retour = $this->bdd->requeter($requete);
$this->messages->traiterInfo("Nombre de polygones définis à incomplet : ".$retour->rowCount());
}
}