Subversion Repositories eFlore/Projets.eflore-projets

Rev

Go to most recent revision | Details | 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);
875 aurelien 121
		// modification temporaire pour lors de la selection d'un rang au dessus de famille on ne prenne que floradata
873 aurelien 122
		// (probleme de performance, qui sera réglé en reremplissant la table de moissonnage)
874 aurelien 123
		if($taxon['rang'] >= 180) {
873 aurelien 124
			foreach ($this->sources as $source) {
125
				$nomMethode = "recupererStations".($source == 'floradata' ? 'Floradata' : 'Moissonnage');
126
				$stations = $sourceDonnees->$nomMethode($source);
127
				$this->ajouterStations($stations, $source);
128
			}
129
		} else {
130
			$stations = $sourceDonnees->recupererStationsFloradata($source);
727 alex 131
			$this->ajouterStations($stations, $source);
132
		}
133
		$this->supprimerMaillesVides();
134
	}
135
 
136
	public function renvoyerLimitesCarte() {
137
		$limites = array();
138
		list($limites['ouest'], $limites['sud']) = $this->convertirMetresEnPixels(
139
			$this->coordonnees['xMin'], $this->coordonnees['yMin']);
140
		list($limites['est'], $limites['nord']) = $this->convertirMetresEnPixels(
141
				$this->coordonnees['xMax'], $this->coordonnees['yMax']);
142
		return $limites;
143
	}
144
 
145
	private function convertirMetresEnPixels($x, $y) {
146
		$longitude = ($x / self::ORIGINE) * 180;
147
		$latitude = ($y / self::ORIGINE) * 180;
148
		$latitude = 180 / M_PI * (2 * atan(exp($latitude * M_PI / 180.0)) - M_PI / 2.0);
149
		return array(round($longitude, 6), round($latitude, 6));
150
	}
151
 
152
	private function ajouterStations($stations, $source) {
153
		$grille = $this->recupererNoeuds('grille')->childNodes;
154
		$index = 0;
155
		$maille = $grille->item($index);
156
		foreach ($stations as $station) {
747 alex 157
			if (!isset($station['lat']) || !isset($station['lng']) || !isset($station['commune'])) {
158
				continue;
159
			}
727 alex 160
			$idMaille = $maille->attributes->getNamedItem('id')->value;
161
			$bbox = explode('_', substr($idMaille, 5));
162
			$bbox[0] = floatval($bbox[0]);
163
			$bbox[1] = floatval($bbox[1]);
164
			while ($index < $grille->length && (
165
				$bbox[1] > $station['lat'] || ($bbox[1] == $station['lat'] && $bbox[0] < $station['lng'])
166
			)) {
167
				$maille = $grille->item($index ++);
168
				$idMaille = $maille->attributes->getNamedItem('id')->value;
169
				$bbox = explode('_', substr($idMaille, 5));
170
				$bbox[0] = floatval($bbox[0]);
171
				$bbox[1] = floatval($bbox[1]);
172
			}
173
			if ($bbox[1] == $station['lat'] && $bbox[0] == $station['lng']) {
747 alex 174
				$this->ajouterCommentaire($station, $source, $maille);
727 alex 175
				$this->appliquerStyleMaille($source, $maille);
176
			}
177
			if ($index == $grille->length) {
178
				break;
179
			}
180
		}
181
	}
182
 
183
	private function supprimerMaillesVides() {
184
		$grille = $this->recupererNoeuds('grille')->childNodes;
185
		$index = 0;
186
		while ($index < $grille->length) {
187
			if (!$grille->item($index)->hasAttribute('title')) {
188
				$grille->item($index)->parentNode->removeChild($grille->item($index));
189
			} else {
190
				$index ++;
191
			}
192
		}
193
	}
194
 
195
	private function appliquerStyleMaille($source, & $maille) {
747 alex 196
		if ($maille->hasAttribute('class') && $maille->attributes->getNamedItem('class')->value != $source) {
197
			$maille->setAttribute('class', 'tout');
198
		} elseif (!$maille->hasAttribute('class')) {
199
			$maille->setAttribute('class', $source);
200
		}
727 alex 201
	}
202
 
747 alex 203
	private function ajouterCommentaire($station, $source, & $maille) {
204
		$commentaires = array();
727 alex 205
		if ($maille->hasAttribute('title')) {
747 alex 206
			$commentaires = explode("; ", $maille->attributes->getNamedItem('title')->value);
207
		}
208
		$commentaire = ucfirst($source)." : {$station['commune']}, ";
209
		if (strlen($station['date']) == 4) {
210
			$commentaire .= "en {$station['date']} par {$station['auteur']}";
727 alex 211
		} else {
747 alex 212
			$date = preg_replace("/(\d{4})-(\d{2})-(\d{2})/", "$3/$2/$1", $station['date']);
213
			$commentaire .= "le {$date} par {$station['auteur']}";
727 alex 214
		}
747 alex 215
		$commentaires[] = trim($commentaire);
216
		$maille->setAttribute('title', implode('; ', $commentaires));
727 alex 217
	}
218
 
219
 
220
 
221
	public function renvoyerCarte() {
222
		$this->documentXML->documentElement->setAttribute("width", $this->format);
223
		$this->documentXML->documentElement->setAttribute("height", $this->hauteur * $this->format / $this->largeur);
224
		$retour = '';
225
		if ($this->typeMime == self::MIME_MAP) {
226
			$retour = $this->documentXML->saveHTML();
227
		} else {
228
			$retour = $this->convertirEnPng();
229
		}
230
		return $retour;
231
	}
232
 
233
	private function convertirEnPng() {
234
		$this->image = imagecreatetruecolor($this->format,  $this->hauteur * $this->format / $this->largeur);
235
		imagefill($this->image, 0, 0, imagecolorallocate($this->image, 255, 255, 255));
236
		$this->transformerLignesEnPng('departements');
237
		$this->transformerPolygonesEnPng('grille');
238
 
239
		// stocker le contenu encode de l'image generee dans une chaine de caracteres
240
		ob_start();
241
		imagepng($this->image);
242
		$png = ob_get_contents();
243
		ob_end_clean();
244
		return $png;
245
	}
246
 
247
	private function transformerLignesEnPng($nomCouche) {
248
		$facteur = floatval($this->format) / floatval($this->largeur);
249
		$noeudCouche = $this->recupererNoeuds($nomCouche);
250
		$couleurContour = $noeudCouche->attributes->getNamedItem('stroke')->value;
1035 aurelien 251
		$couleurContour = ($this->format >= 300 ? $couleurContour : "rgb(192,192,192)");
727 alex 252
		for ($index = 0; $index < $noeudCouche->childNodes->length; $index ++) {
253
			$noeudLigne = $noeudCouche->childNodes->item($index);
254
			for ($indexPath = 0; $indexPath < $noeudLigne->childNodes->length; $indexPath ++) {
255
				$coordonneesSvg = $noeudLigne->childNodes->item($indexPath)->attributes->getNamedItem('points')->value;
256
				preg_match_all('/\d+.\d/', $coordonneesSvg, $coordonnees);
257
				$coordonnees = current($coordonnees);
258
				foreach ($coordonnees as $indexCoord => $valeur) {
259
					$coordonnees[$indexCoord] = intval(floatval($valeur) * $facteur);
260
				}
261
				if ($couleurContour != 'none') {
262
					for ($i = 0; $i < count($coordonnees) - 2; $i += 2) {
263
						imageline($this->image, $coordonnees[$i], $coordonnees[$i+1], $coordonnees[$i+2],
264
							$coordonnees[$i+3], $this->allouerCouleur($couleurContour));
265
					}
266
				}
267
			}
268
		}
269
	}
270
 
271
	private function transformerPolygonesEnPng($nomCouche) {
272
		$couleurs = $this->recupererCouleursSources();
273
		$facteur = floatval($this->format) / floatval($this->largeur);
274
		$noeudCouche = $this->recupererNoeuds($nomCouche);
275
		$couleurRemplissage = $noeudCouche->attributes->getNamedItem('fill')->value;
276
		$couleurContour = $noeudCouche->attributes->getNamedItem('stroke')->value;
277
		for ($index = 0; $index < $noeudCouche->childNodes->length; $index ++) {
278
			$noeudPolygone = $noeudCouche->childNodes->item($index);
279
			$couleurPolygone = 'none';
280
			if ($noeudPolygone->hasAttribute('class')) {
281
				$couleurPolygone = $couleurs[$noeudPolygone->attributes->getNamedItem('class')->value];
282
			}
283
			for ($indexPath = 0; $indexPath < $noeudPolygone->childNodes->length; $indexPath ++) {
284
				$coordonneesSvg = $noeudPolygone->childNodes->item($indexPath)->attributes->getNamedItem('points')->value;
285
				preg_match_all('/\d+.\d/', $coordonneesSvg, $coordonnees);
286
				$coordonnees = current($coordonnees);
287
				foreach ($coordonnees as $indexCoord => $valeur) {
288
					$coordonnees[$indexCoord] = intval(floatval($valeur) * $facteur);
289
				}
290
				if ($couleurRemplissage != 'none') {
291
					imagefilledpolygon($this->image, $coordonnees, count($coordonnees) / 2, $this->allouerCouleur($couleurRemplissage));
292
				}
293
				if ($couleurContour != 'none') {
294
					imagepolygon($this->image, $coordonnees, count($coordonnees) / 2, $this->allouerCouleur($couleurContour));
295
				}
296
				if ($couleurPolygone != 'none') {
297
					$contourGrille = "rgba(255,255,255,".($this->format >= 300 ? 0.4 : 0).")";
298
					imagefilledrectangle($this->image, $coordonnees[0], $coordonnees[1], $coordonnees[4], $coordonnees[5],
299
						$this->allouerCouleur($couleurPolygone));
300
					imagerectangle($this->image, $coordonnees[0], $coordonnees[1], $coordonnees[4], $coordonnees[5],
301
						$this->allouerCouleur($contourGrille));
302
				}
303
			}
304
		}
305
	}
306
 
307
	private function allouerCouleur($couleurTexte) {
308
		preg_match_all('/\d+/', $couleurTexte, $valeurs);
309
		$rouge = $valeurs[0][0];
310
		$vert  = $valeurs[0][1];
311
		$bleu  = $valeurs[0][2];
312
		$alpha = 0;
313
		if (count($valeurs[0]) > 3) {
314
			$valeurAlpha = floatval($valeurs[0][3].".".$valeurs[0][4]);
315
			$alpha = intval((1.0 - $valeurAlpha) * 127.0);
316
		}
317
		return imagecolorallocatealpha($this->image, $rouge, $vert, $bleu, $alpha);
318
	}
319
 
320
}
321
 
322
?>