Subversion Repositories eFlore/Projets.eflore-projets

Rev

Rev 727 | Rev 873 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
727 alex 1
<?php
2
 
747 alex 3
/**
4
 * Classe qui genere la carte SVG pour les parametres de la requete qui a ete utilisee pour appeler
5
 * le web service
6
 *
7
 * @package framework-0.4
8
 * @author Alexandre GALIBERT <alexandre.galibert@tela-botanica.org>
9
 * @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
10
 * @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
11
 * @version $Id$
12
 * @copyright 2013 Tela Botanica (accueil@tela-botanica.org)
13
 *
14
 */
15
 
16
 
727 alex 17
class FormateurSVG {
18
 
19
	private $documentXML;
20
	private $coordonnees = array();
21
	private $grille = null;
22
 
23
	private $largeur  = 0;
24
	private $hauteur  = 0;
25
	private $typeMime = '';
26
	private $format   = 0;
27
	private $sources  = array();
28
 
29
	private $image = null;
30
 
31
	const ORIGINE = 20037508.342789244;
32
	const MIME_MAP = 'text/html';
33
 
34
 
35
	public function __construct($nomFichierSVG, $sources, $typeMime, $format) {
36
		$this->chargerSVG($nomFichierSVG);
37
		$this->chargerCoordonnees();
38
		$this->construireParametresRetour($typeMime, $format);
39
		$this->creerStyleSources();
40
		$this->sources = $sources;
41
	}
42
 
43
	private function chargerSVG($nomFichierSVG) {
44
		$this->documentXML = new DOMDocument("1.0", "UTF-8");
45
		$this->documentXML->load($nomFichierSVG);
46
	}
47
 
48
	private function chargerCoordonnees() {
49
		$viewbox = $this->recupererNoeuds('qgisviewbox');
50
		$this->coordonnees = array(
51
			'xMin' => $viewbox->attributes->getNamedItem('xMin')->value,
52
			'xMax' => $viewbox->attributes->getNamedItem('xMax')->value,
53
			'yMin' => $viewbox->attributes->getNamedItem('yMin')->value,
54
			'yMax' => $viewbox->attributes->getNamedItem('yMax')->value
55
		);
56
	}
57
 
58
	private function recupererNoeuds($nomCouche) {
59
		$contenuSVG = $this->documentXML->documentElement->childNodes;
60
		$noeudCouche = null;
61
		$index = 0;
62
		while ($index < $contenuSVG->length && is_null($noeudCouche)) {
63
			$id = $contenuSVG->item($index)->attributes->getNamedItem('id');
64
			if ($id->value == $nomCouche) {
65
				$noeudCouche = $contenuSVG->item($index);
66
			}
67
			$index ++;
68
		}
69
		$noeuds = null;
70
		if (!is_null($noeudCouche)) {
71
			$noeuds = $noeudCouche->firstChild;
72
		}
73
		return $noeuds;
74
	}
75
 
76
	private function construireParametresRetour($typeMime, $format) {
77
		$viewBox = $this->documentXML->documentElement->attributes->getNamedItem('viewBox');
78
		$limitesPixels = explode(' ',$viewBox->value);
79
		$this->largeur = intval($limitesPixels[2]);
80
		$this->hauteur = intval($limitesPixels[3]);
81
		$this->typeMime = $typeMime;
82
		$this->format = intval($format);
83
	}
84
 
85
	private function creerStyleSources() {
86
		$couleurs = $this->recupererCouleursSources();
87
		$reglesCss = array();
88
		foreach ($couleurs as $codeSource => $codeCouleur) {
89
			$reglesCss[] = ".{$codeSource} {\nfill:{$codeCouleur}\n}\n";
90
		}
91
		$texteCss = $this->documentXML->createCDATASection(implode(' ', $reglesCss));
92
		$noeudStyle = new DomElement('style', '');
93
		$this->documentXML->documentElement->appendChild($noeudStyle);
94
		$noeudStyle->appendChild($texteCss);
95
	}
96
 
97
	private function recupererCouleursSources() {
98
		$sourcesDonnees = Config::get('sourcesDonnees');
99
		$codesSources = str_replace('floradata', 'cel', $sourcesDonnees).',tout';
100
		$codes = explode(',', $codesSources);
101
		for ($index = 0; $index < count($codes);  $index ++) {
102
			$codes[$index] = "'".$codes[$index]."'";
103
		}
104
		$codesSources = implode(',', $codes);
105
		$bdd = new Bdd();
106
		$requete = "SELECT code, SUBSTR(complements,9) AS couleur FROM ".Config::get('bdd_table_ontologies')." WHERE code IN ({$codesSources})";
107
		$couleurs = $bdd->recupererTous($requete);
108
		$listeCouleurs = array();
109
		foreach ($couleurs as $couleur) {
110
			$couleur['code'] = $couleur['code'] == 'cel' ? 'floradata' : $couleur['code'];
111
			$listeCouleurs[$couleur['code']] = $couleur['couleur'];
112
		}
113
		return $listeCouleurs;
114
	}
115
 
116
 
117
 
118
	public function formaterCarte($taxon) {
119
		$limitesCarte = $this->renvoyerLimitesCarte();
747 alex 120
		$sourceDonnees = new SourceDonnees($limitesCarte, $taxon);
727 alex 121
		foreach ($this->sources as $source) {
747 alex 122
			$nomMethode = "recupererStations".($source == 'floradata' ? 'Floradata' : 'Moissonnage');
123
			$stations = $sourceDonnees->$nomMethode($source);
727 alex 124
			$this->ajouterStations($stations, $source);
125
		}
126
		$this->supprimerMaillesVides();
127
	}
128
 
129
	public function renvoyerLimitesCarte() {
130
		$limites = array();
131
		list($limites['ouest'], $limites['sud']) = $this->convertirMetresEnPixels(
132
			$this->coordonnees['xMin'], $this->coordonnees['yMin']);
133
		list($limites['est'], $limites['nord']) = $this->convertirMetresEnPixels(
134
				$this->coordonnees['xMax'], $this->coordonnees['yMax']);
135
		return $limites;
136
	}
137
 
138
	private function convertirMetresEnPixels($x, $y) {
139
		$longitude = ($x / self::ORIGINE) * 180;
140
		$latitude = ($y / self::ORIGINE) * 180;
141
		$latitude = 180 / M_PI * (2 * atan(exp($latitude * M_PI / 180.0)) - M_PI / 2.0);
142
		return array(round($longitude, 6), round($latitude, 6));
143
	}
144
 
145
	private function ajouterStations($stations, $source) {
146
		$grille = $this->recupererNoeuds('grille')->childNodes;
147
		$index = 0;
148
		$maille = $grille->item($index);
149
		foreach ($stations as $station) {
747 alex 150
			if (!isset($station['lat']) || !isset($station['lng']) || !isset($station['commune'])) {
151
				continue;
152
			}
727 alex 153
			$idMaille = $maille->attributes->getNamedItem('id')->value;
154
			$bbox = explode('_', substr($idMaille, 5));
155
			$bbox[0] = floatval($bbox[0]);
156
			$bbox[1] = floatval($bbox[1]);
157
			while ($index < $grille->length && (
158
				$bbox[1] > $station['lat'] || ($bbox[1] == $station['lat'] && $bbox[0] < $station['lng'])
159
			)) {
160
				$maille = $grille->item($index ++);
161
				$idMaille = $maille->attributes->getNamedItem('id')->value;
162
				$bbox = explode('_', substr($idMaille, 5));
163
				$bbox[0] = floatval($bbox[0]);
164
				$bbox[1] = floatval($bbox[1]);
165
			}
166
			if ($bbox[1] == $station['lat'] && $bbox[0] == $station['lng']) {
747 alex 167
				$this->ajouterCommentaire($station, $source, $maille);
727 alex 168
				$this->appliquerStyleMaille($source, $maille);
169
			}
170
			if ($index == $grille->length) {
171
				break;
172
			}
173
		}
174
	}
175
 
176
	private function supprimerMaillesVides() {
177
		$grille = $this->recupererNoeuds('grille')->childNodes;
178
		$index = 0;
179
		while ($index < $grille->length) {
180
			if (!$grille->item($index)->hasAttribute('title')) {
181
				$grille->item($index)->parentNode->removeChild($grille->item($index));
182
			} else {
183
				$index ++;
184
			}
185
		}
186
	}
187
 
188
	private function appliquerStyleMaille($source, & $maille) {
747 alex 189
		if ($maille->hasAttribute('class') && $maille->attributes->getNamedItem('class')->value != $source) {
190
			$maille->setAttribute('class', 'tout');
191
		} elseif (!$maille->hasAttribute('class')) {
192
			$maille->setAttribute('class', $source);
193
		}
727 alex 194
	}
195
 
747 alex 196
	private function ajouterCommentaire($station, $source, & $maille) {
197
		$commentaires = array();
727 alex 198
		if ($maille->hasAttribute('title')) {
747 alex 199
			$commentaires = explode("; ", $maille->attributes->getNamedItem('title')->value);
200
		}
201
		$commentaire = ucfirst($source)." : {$station['commune']}, ";
202
		if (strlen($station['date']) == 4) {
203
			$commentaire .= "en {$station['date']} par {$station['auteur']}";
727 alex 204
		} else {
747 alex 205
			$date = preg_replace("/(\d{4})-(\d{2})-(\d{2})/", "$3/$2/$1", $station['date']);
206
			$commentaire .= "le {$date} par {$station['auteur']}";
727 alex 207
		}
747 alex 208
		$commentaires[] = trim($commentaire);
209
		$maille->setAttribute('title', implode('; ', $commentaires));
727 alex 210
	}
211
 
212
 
213
 
214
	public function renvoyerCarte() {
215
		$this->documentXML->documentElement->setAttribute("width", $this->format);
216
		$this->documentXML->documentElement->setAttribute("height", $this->hauteur * $this->format / $this->largeur);
217
		$retour = '';
218
		if ($this->typeMime == self::MIME_MAP) {
219
			$retour = $this->documentXML->saveHTML();
220
		} else {
221
			$retour = $this->convertirEnPng();
222
		}
223
		return $retour;
224
	}
225
 
226
	private function convertirEnPng() {
227
		$this->image = imagecreatetruecolor($this->format,  $this->hauteur * $this->format / $this->largeur);
228
		imagefill($this->image, 0, 0, imagecolorallocate($this->image, 255, 255, 255));
229
		$this->transformerLignesEnPng('departements');
230
		$this->transformerPolygonesEnPng('grille');
231
 
232
		// stocker le contenu encode de l'image generee dans une chaine de caracteres
233
		ob_start();
234
		imagepng($this->image);
235
		$png = ob_get_contents();
236
		ob_end_clean();
237
		return $png;
238
	}
239
 
240
	private function transformerLignesEnPng($nomCouche) {
241
		$facteur = floatval($this->format) / floatval($this->largeur);
242
		$noeudCouche = $this->recupererNoeuds($nomCouche);
243
		$couleurContour = $noeudCouche->attributes->getNamedItem('stroke')->value;
244
		for ($index = 0; $index < $noeudCouche->childNodes->length; $index ++) {
245
			$noeudLigne = $noeudCouche->childNodes->item($index);
246
			for ($indexPath = 0; $indexPath < $noeudLigne->childNodes->length; $indexPath ++) {
247
				$coordonneesSvg = $noeudLigne->childNodes->item($indexPath)->attributes->getNamedItem('points')->value;
248
				preg_match_all('/\d+.\d/', $coordonneesSvg, $coordonnees);
249
				$coordonnees = current($coordonnees);
250
				foreach ($coordonnees as $indexCoord => $valeur) {
251
					$coordonnees[$indexCoord] = intval(floatval($valeur) * $facteur);
252
				}
253
				if ($couleurContour != 'none') {
254
					for ($i = 0; $i < count($coordonnees) - 2; $i += 2) {
255
						imageline($this->image, $coordonnees[$i], $coordonnees[$i+1], $coordonnees[$i+2],
256
							$coordonnees[$i+3], $this->allouerCouleur($couleurContour));
257
					}
258
				}
259
			}
260
		}
261
	}
262
 
263
	private function transformerPolygonesEnPng($nomCouche) {
264
		$couleurs = $this->recupererCouleursSources();
265
		$facteur = floatval($this->format) / floatval($this->largeur);
266
		$noeudCouche = $this->recupererNoeuds($nomCouche);
267
		$couleurRemplissage = $noeudCouche->attributes->getNamedItem('fill')->value;
268
		$couleurContour = $noeudCouche->attributes->getNamedItem('stroke')->value;
269
		for ($index = 0; $index < $noeudCouche->childNodes->length; $index ++) {
270
			$noeudPolygone = $noeudCouche->childNodes->item($index);
271
			$couleurPolygone = 'none';
272
			if ($noeudPolygone->hasAttribute('class')) {
273
				$couleurPolygone = $couleurs[$noeudPolygone->attributes->getNamedItem('class')->value];
274
			}
275
			for ($indexPath = 0; $indexPath < $noeudPolygone->childNodes->length; $indexPath ++) {
276
				$coordonneesSvg = $noeudPolygone->childNodes->item($indexPath)->attributes->getNamedItem('points')->value;
277
				preg_match_all('/\d+.\d/', $coordonneesSvg, $coordonnees);
278
				$coordonnees = current($coordonnees);
279
				foreach ($coordonnees as $indexCoord => $valeur) {
280
					$coordonnees[$indexCoord] = intval(floatval($valeur) * $facteur);
281
				}
282
				if ($couleurRemplissage != 'none') {
283
					imagefilledpolygon($this->image, $coordonnees, count($coordonnees) / 2, $this->allouerCouleur($couleurRemplissage));
284
				}
285
				if ($couleurContour != 'none') {
286
					imagepolygon($this->image, $coordonnees, count($coordonnees) / 2, $this->allouerCouleur($couleurContour));
287
				}
288
				if ($couleurPolygone != 'none') {
289
					$contourGrille = "rgba(255,255,255,".($this->format >= 300 ? 0.4 : 0).")";
290
					imagefilledrectangle($this->image, $coordonnees[0], $coordonnees[1], $coordonnees[4], $coordonnees[5],
291
						$this->allouerCouleur($couleurPolygone));
292
					imagerectangle($this->image, $coordonnees[0], $coordonnees[1], $coordonnees[4], $coordonnees[5],
293
						$this->allouerCouleur($contourGrille));
294
				}
295
			}
296
		}
297
	}
298
 
299
	private function allouerCouleur($couleurTexte) {
300
		preg_match_all('/\d+/', $couleurTexte, $valeurs);
301
		$rouge = $valeurs[0][0];
302
		$vert  = $valeurs[0][1];
303
		$bleu  = $valeurs[0][2];
304
		$alpha = 0;
305
		if (count($valeurs[0]) > 3) {
306
			$valeurAlpha = floatval($valeurs[0][3].".".$valeurs[0][4]);
307
			$alpha = intval((1.0 - $valeurAlpha) * 127.0);
308
		}
309
		return imagecolorallocatealpha($this->image, $rouge, $vert, $bleu, $alpha);
310
	}
311
 
312
}
313
 
314
?>