Subversion Repositories eFlore/Projets.eflore-projets

Rev

Rev 1091 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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