Subversion Repositories eFlore/Projets.eflore-projets

Rev

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

Rev Author Line No. Line
736 alex 1
<?php
743 alex 2
/**
3
 * Classe unique du web service nasa-srtm qui détermine l'altitude d'un point à partir de ses coordonnees
4
 * Les coordonnees sont definies dans des fichiers au format HGT dans un dossier specifique
5
 * (dont le chemin est defini dans le fichier de configuration propre au web service).
6
 * Les ressources utilisees sont les donnees issues du programme SRTM-3 de la NASA qui couvre
7
 * l'ensemble terrestre du monde. La precision des points dont on renvoie l'altitude est de 90 metres.
8
 * Chaque fichier couvre un secteur de 1 degre sur 1 degre et contient un tableau de 1201 lignes
9
 * (axe des latitudes) sur 1201 colonnes (axe des longitudes) contenant l'altitude en metres
10
 * correspondant a des point precis. L'ecart entre chaque entree des tableaux est constant, ce qui
11
 * permet de calculer la latitude et la longitude de chaque point. L'altitude du point le plus proche
12
 * de celui passe en parametres sera renvoyee au client.
1121 jpm 13
 *
743 alex 14
 * Parametres du web service :
15
 *   - latitude : latitude du point dont on recherche les coordonnees
16
 *   - longitude : longitude du point dont on recherche les coordonnees
1121 jpm 17
 *
743 alex 18
 * @package framework-0.4
19
 * @author Alexandre GALIBERT <alexandre.galibert@tela-botanica.org>
20
 * @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
21
 * @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
22
 * @version $Id$
23
 * @copyright 2013 Tela Botanica (accueil@tela-botanica.org)
24
 *
25
 */
1121 jpm 26
class Altitude {
743 alex 27
 
736 alex 28
	private $parametres = array();
29
	private $ressources = array();
30
	private $coordonnees = null;
31
	private $fichierSrtm = '';
1121 jpm 32
 
736 alex 33
	const LONGUEUR_COTE = 1201;
34
	const OFFSET = 2;
1121 jpm 35
 
36
 
736 alex 37
	public function consulter($ressources, $parametres) {
38
		$this->ressources = $ressources;
39
		$this->parametres = $parametres;
40
		$retour = null;
41
		try {
42
			$this->traiterCoordonnees();
43
			$this->rechercherFichierSrtm();
44
			$this->recupererAltitude();
45
			$retour = $this->coordonnees;
46
		} catch (Exception $erreur) {
47
			$retour = $erreur->getMessage();
48
		}
49
		return $retour;
50
	}
1121 jpm 51
 
736 alex 52
	private function traiterCoordonnees() {
743 alex 53
		if ($this->estParametreExistant('lat') && $this->estParametreExistant('lon')) {
54
			$longitude = $this->parametres['lon'];
55
			$latitude  = $this->parametres['lat'];
736 alex 56
			if ($this->estUnFloat($longitude) && $this->estUnFloat($latitude)) {
57
				$this->verifierValiditeCoordonnees($longitude, $latitude);
58
			} else {
59
				$message = "La valeur des coordonnées longitude ou latitude n'est pas correcte. ".
60
				" Elle doit être pour les deux paramètres une valeur décimale.";
61
				throw new Exception($message, RestServeur::HTTP_CODE_MAUVAISE_REQUETE);
62
			}
63
		} else {
64
			$message = "Tous les paramètres passés dans l'URL ne correspondent pas à ceux attendus. ".
65
			"Le web service nécessite de lui fournir une longitude et une latitude pour son bon fonctionnement.";
66
			throw new Exception($message, RestServeur::HTTP_CODE_CONTENU_REQUIS);
67
		}
68
	}
1121 jpm 69
 
736 alex 70
	private function estParametreExistant($nomParametre) {
71
		return in_array($nomParametre, array_keys($this->parametres));
72
	}
1121 jpm 73
 
736 alex 74
	private function estUnFloat($variable) {
75
		return (preg_match("/^(-)?\d+(\.\d+)?$/", $variable) == 1);
76
	}
1121 jpm 77
 
736 alex 78
	private function verifierValiditeCoordonnees($longitude, $latitude) {
79
		$longitude = floatval($longitude);
80
		$latitude  = floatval($latitude);
81
		$longitudeMax = Config::get("limite_longitude");
82
		$latitudeMax  = Config::get("limite_latitude");
83
		if (abs($longitude) > $longitudeMax || abs($latitude) > $latitudeMax) {
84
			$message = "Les coordonnées passées en paramètres désignent un point qui se trouve ".
85
			"en dehors des limites du monde. Elles doivent être comprises entre -{$longitudeMax} ".
86
			"et $longitudeMax sur l'axe des longitudes, et entre -{$latitudeMax} et {$latitudeMax} ".
87
			"sur l'axe des latitudes.";
88
			throw new Exception($message, RestServeur::HTTP_CODE_MAUVAISE_REQUETE);
89
		} else {
90
			$this->coordonnees = new StdClass();
91
			$this->coordonnees->longitude = $longitude;
92
			$this->coordonnees->latitude  = $latitude;
93
		}
94
	}
1121 jpm 95
 
736 alex 96
	private function rechercherFichierSrtm() {
97
		$nomFichierSrtm = $this->construireNomFichierSrtm();
98
		if (!file_exists($nomFichierSrtm)) {
1121 jpm 99
			$message = "Erreur interne : la ressource « $nomFichierSrtm » demandée n'a pas pu être trouvée sur le serveur.";
736 alex 100
			throw new Exception($message, restServeur::HTTP_CODE_ERREUR);
101
		} else {
102
			$this->fichierSrtm = $nomFichierSrtm;
103
		}
104
	}
1121 jpm 105
 
736 alex 106
	private function construireNomFichierSrtm() {
107
		$latitudeEntier = abs(floor($this->coordonnees->latitude));
108
		if ($latitudeEntier < 10) {
109
			$latitudeEntier = "0".$latitudeEntier;
110
		}
111
		$suffixeLatitude = $this->coordonnees->latitude < 0 ? "S" : "N";
112
		$longitudeEntier = abs(floor($this->coordonnees->longitude));
113
		if ($longitudeEntier < 10) {
114
			$longitudeEntier = "00".$longitudeEntier;
115
		} elseif ($longitudeEntier < 100) {
116
			$longitudeEntier = "0".$longitudeEntier;
117
		}
118
		$suffixeLongitude = $this->coordonnees->longitude < 0 ? "W" : "E";
119
		$dossierSrtm = Config::get('dossier_srtm').DS;
120
		$nomFichierSrtm = $dossierSrtm.$suffixeLatitude.$latitudeEntier.$suffixeLongitude.$longitudeEntier.".hgt.zip";
121
		return $nomFichierSrtm;
122
	}
1121 jpm 123
 
736 alex 124
	private function recupererAltitude() {
125
		$zip = zip_open($this->fichierSrtm);
126
		$fichier = zip_read($zip);
127
		$donnees = zip_entry_read($fichier, zip_entry_filesize($fichier));
128
		zip_close($zip);
1121 jpm 129
 
736 alex 130
		$xDepart = floor($this->coordonnees->longitude);
131
		$yDepart = floor($this->coordonnees->latitude);
132
		$longitude = $this->coordonnees->longitude;
133
		$latitude = $this->coordonnees->latitude;
134
		$positionX = (self::LONGUEUR_COTE-1) * ($longitude - $xDepart);
135
		$positionY = (self::LONGUEUR_COTE-1) * (1 - $latitude + $yDepart);
136
		$positionX = ($positionX + 0.5 > ceil($positionX)) ? ceil($positionX) : floor($positionX);
137
		$positionY = ($positionY + 0.5 > ceil($positionY)) ? ceil($positionY) : floor($positionY);
1121 jpm 138
 
736 alex 139
		$binaire = substr($donnees, ($positionY * self::LONGUEUR_COTE + $positionX) * self::OFFSET, self::OFFSET);
140
		$this->coordonnees->altitude = current(unpack("n*", $binaire));
141
		if (!$this->coordonnees->altitude) {
142
			$this->coordonnees->altitude = 0;
143
		}
144
	}
145
 
1121 jpm 146
}