Subversion Repositories eFlore/Projets.eflore-projets

Rev

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

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