* @license GPL v3 * @license CECILL v2 * @version $Id$ * @copyright 2013 Tela Botanica (accueil@tela-botanica.org) * */ class Altitude { private $parametres = array(); private $ressources = array(); private $coordonnees = null; private $fichierSrtm = ''; const LONGUEUR_COTE = 1201; const OFFSET = 2; public function consulter($ressources, $parametres) { $this->ressources = $ressources; $this->parametres = $parametres; $retour = null; try { $this->traiterCoordonnees(); $this->rechercherFichierSrtm(); $this->recupererAltitude(); $retour = $this->coordonnees; } catch (Exception $erreur) { $retour = $erreur->getMessage(); } return $retour; } private function traiterCoordonnees() { if ($this->estParametreExistant('lat') && $this->estParametreExistant('lon')) { $longitude = $this->parametres['lon']; $latitude = $this->parametres['lat']; if ($this->estUnFloat($longitude) && $this->estUnFloat($latitude)) { $this->verifierValiditeCoordonnees($longitude, $latitude); } else { $message = "La valeur des coordonnées longitude ou latitude n'est pas correcte. ". " Elle doit être pour les deux paramètres une valeur décimale."; throw new Exception($message, RestServeur::HTTP_CODE_MAUVAISE_REQUETE); } } else { $message = "Tous les paramètres passés dans l'URL ne correspondent pas à ceux attendus. ". "Le web service nécessite de lui fournir une longitude et une latitude pour son bon fonctionnement."; throw new Exception($message, RestServeur::HTTP_CODE_CONTENU_REQUIS); } } private function estParametreExistant($nomParametre) { return in_array($nomParametre, array_keys($this->parametres)); } private function estUnFloat($variable) { return (preg_match("/^(-)?\d+(\.\d+)?$/", $variable) == 1); } private function verifierValiditeCoordonnees($longitude, $latitude) { $longitude = floatval($longitude); $latitude = floatval($latitude); $longitudeMax = Config::get("limite_longitude"); $latitudeMax = Config::get("limite_latitude"); if (abs($longitude) > $longitudeMax || abs($latitude) > $latitudeMax) { $message = "Les coordonnées passées en paramètres désignent un point qui se trouve ". "en dehors des limites du monde. Elles doivent être comprises entre -{$longitudeMax} ". "et $longitudeMax sur l'axe des longitudes, et entre -{$latitudeMax} et {$latitudeMax} ". "sur l'axe des latitudes."; throw new Exception($message, RestServeur::HTTP_CODE_MAUVAISE_REQUETE); } else { $this->coordonnees = new StdClass(); $this->coordonnees->longitude = $longitude; $this->coordonnees->latitude = $latitude; } } private function rechercherFichierSrtm() { $nomFichierSrtm = $this->construireNomFichierSrtm(); if (!file_exists($nomFichierSrtm)) { $message = "Erreur interne : certaines ressources demandées n'ont pas pu être trouvées sur le serveur."; throw new Exception($message, restServeur::HTTP_CODE_ERREUR); } else { $this->fichierSrtm = $nomFichierSrtm; } } private function construireNomFichierSrtm() { $latitudeEntier = abs(floor($this->coordonnees->latitude)); if ($latitudeEntier < 10) { $latitudeEntier = "0".$latitudeEntier; } $suffixeLatitude = $this->coordonnees->latitude < 0 ? "S" : "N"; $longitudeEntier = abs(floor($this->coordonnees->longitude)); if ($longitudeEntier < 10) { $longitudeEntier = "00".$longitudeEntier; } elseif ($longitudeEntier < 100) { $longitudeEntier = "0".$longitudeEntier; } $suffixeLongitude = $this->coordonnees->longitude < 0 ? "W" : "E"; $dossierSrtm = Config::get('dossier_srtm').DS; $nomFichierSrtm = $dossierSrtm.$suffixeLatitude.$latitudeEntier.$suffixeLongitude.$longitudeEntier.".hgt.zip"; return $nomFichierSrtm; } private function recupererAltitude() { $zip = zip_open($this->fichierSrtm); $fichier = zip_read($zip); $donnees = zip_entry_read($fichier, zip_entry_filesize($fichier)); zip_close($zip); $xDepart = floor($this->coordonnees->longitude); $yDepart = floor($this->coordonnees->latitude); $longitude = $this->coordonnees->longitude; $latitude = $this->coordonnees->latitude; $positionX = (self::LONGUEUR_COTE-1) * ($longitude - $xDepart); $positionY = (self::LONGUEUR_COTE-1) * (1 - $latitude + $yDepart); $positionX = ($positionX + 0.5 > ceil($positionX)) ? ceil($positionX) : floor($positionX); $positionY = ($positionY + 0.5 > ceil($positionY)) ? ceil($positionY) : floor($positionY); $binaire = substr($donnees, ($positionY * self::LONGUEUR_COTE + $positionX) * self::OFFSET, self::OFFSET); $this->coordonnees->altitude = current(unpack("n*", $binaire)); if (!$this->coordonnees->altitude) { $this->coordonnees->altitude = 0; } } } ?>