Subversion Repositories eFlore/Projets.eflore-projets

Rev

Blame | 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());
        }
}