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
 
3
class FormateurSVG {
4
 
5
	private $documentXML;
6
	private $coordonnees = array();
7
	private $grille = null;
8
 
9
	private $largeur  = 0;
10
	private $hauteur  = 0;
11
	private $typeMime = '';
12
	private $format   = 0;
13
	private $sources  = array();
14
 
15
	private $image = null;
16
 
17
	const ORIGINE = 20037508.342789244;
18
	const MIME_MAP = 'text/html';
19
 
20
 
21
	public function __construct($nomFichierSVG, $sources, $typeMime, $format) {
22
		$this->chargerSVG($nomFichierSVG);
23
		$this->chargerCoordonnees();
24
		$this->construireParametresRetour($typeMime, $format);
25
		$this->creerStyleSources();
26
		$this->sources = $sources;
27
	}
28
 
29
	private function chargerSVG($nomFichierSVG) {
30
		$this->documentXML = new DOMDocument("1.0", "UTF-8");
31
		$this->documentXML->load($nomFichierSVG);
32
		$this->supprimerNoeudsInutiles($this->documentXML->documentElement);
33
	}
34
 
35
	private function supprimerNoeudsInutiles(& $noeud) {
36
		$index = 0;
37
		while ($index < $noeud->childNodes->length) {
38
			if (get_class($noeud->childNodes->item($index)) != 'DOMElement') {
39
				$noeud->removeChild($noeud->childNodes->item($index));
40
			} else {
41
				$fils = $noeud->childNodes->item($index);
42
				$this->supprimerNoeudsInutiles($fils);
43
				$index ++;
44
			}
45
		}
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();
120
		foreach ($this->sources as $source) {
121
			$nomClasse = $source == 'floradata' ? 'DonneesFloradata' : 'DonneesMoissonnage';
122
			$rechercheBdd = new $nomClasse($limitesCarte, $taxon, $source);
123
			$stations = $rechercheBdd->recupererStations();
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) {
150
			$idMaille = $maille->attributes->getNamedItem('id')->value;
151
			$bbox = explode('_', substr($idMaille, 5));
152
			$bbox[0] = floatval($bbox[0]);
153
			$bbox[1] = floatval($bbox[1]);
154
			while ($index < $grille->length && (
155
				$bbox[1] > $station['lat'] || ($bbox[1] == $station['lat'] && $bbox[0] < $station['lng'])
156
			)) {
157
				$maille = $grille->item($index ++);
158
				$idMaille = $maille->attributes->getNamedItem('id')->value;
159
				$bbox = explode('_', substr($idMaille, 5));
160
				$bbox[0] = floatval($bbox[0]);
161
				$bbox[1] = floatval($bbox[1]);
162
			}
163
			if ($bbox[1] == $station['lat'] && $bbox[0] == $station['lng']) {
164
				$this->genererTitreMaille($station['nb_observations'], $source, $maille);
165
				$this->appliquerStyleMaille($source, $maille);
166
				$maille = $grille->item($index ++);
167
			}
168
			if ($index == $grille->length) {
169
				break;
170
			}
171
		}
172
	}
173
 
174
	private function supprimerMaillesVides() {
175
		$grille = $this->recupererNoeuds('grille')->childNodes;
176
		$index = 0;
177
		while ($index < $grille->length) {
178
			if (!$grille->item($index)->hasAttribute('title')) {
179
				$grille->item($index)->parentNode->removeChild($grille->item($index));
180
			} else {
181
				$index ++;
182
			}
183
		}
184
	}
185
 
186
	private function appliquerStyleMaille($source, & $maille) {
187
		$style = $maille->hasAttribute('class') ? 'tout' : $source;
188
		$maille->setAttribute('class', $style);
189
	}
190
 
191
	private function genererTitreMaille($observations, $source, & $maille) {
192
		$texte = '';
193
		if ($maille->hasAttribute('title')) {
194
			$texte = $maille->attributes->getNamedItem('title')->value."\n$source : $observations observations";
195
		} else {
196
			$texte = "$source : $observations observations";
197
		}
198
		$maille->setAttribute('title', $texte);
199
	}
200
 
201
 
202
 
203
	public function renvoyerCarte() {
204
		$this->documentXML->documentElement->setAttribute("width", $this->format);
205
		$this->documentXML->documentElement->setAttribute("height", $this->hauteur * $this->format / $this->largeur);
206
		$retour = '';
207
		if ($this->typeMime == self::MIME_MAP) {
208
			$retour = $this->documentXML->saveHTML();
209
		} else {
210
			$retour = $this->convertirEnPng();
211
		}
212
		return $retour;
213
	}
214
 
215
	private function convertirEnPng() {
216
		$this->image = imagecreatetruecolor($this->format,  $this->hauteur * $this->format / $this->largeur);
217
		imagefill($this->image, 0, 0, imagecolorallocate($this->image, 255, 255, 255));
218
		$this->transformerLignesEnPng('departements');
219
		$this->transformerPolygonesEnPng('grille');
220
 
221
		// stocker le contenu encode de l'image generee dans une chaine de caracteres
222
		ob_start();
223
		imagepng($this->image);
224
		$png = ob_get_contents();
225
		ob_end_clean();
226
		return $png;
227
	}
228
 
229
	private function transformerLignesEnPng($nomCouche) {
230
		$facteur = floatval($this->format) / floatval($this->largeur);
231
		$noeudCouche = $this->recupererNoeuds($nomCouche);
232
		$couleurContour = $noeudCouche->attributes->getNamedItem('stroke')->value;
233
		for ($index = 0; $index < $noeudCouche->childNodes->length; $index ++) {
234
			$noeudLigne = $noeudCouche->childNodes->item($index);
235
			for ($indexPath = 0; $indexPath < $noeudLigne->childNodes->length; $indexPath ++) {
236
				$coordonneesSvg = $noeudLigne->childNodes->item($indexPath)->attributes->getNamedItem('points')->value;
237
				preg_match_all('/\d+.\d/', $coordonneesSvg, $coordonnees);
238
				$coordonnees = current($coordonnees);
239
				foreach ($coordonnees as $indexCoord => $valeur) {
240
					$coordonnees[$indexCoord] = intval(floatval($valeur) * $facteur);
241
				}
242
				if ($couleurContour != 'none') {
243
					for ($i = 0; $i < count($coordonnees) - 2; $i += 2) {
244
						imageline($this->image, $coordonnees[$i], $coordonnees[$i+1], $coordonnees[$i+2],
245
							$coordonnees[$i+3], $this->allouerCouleur($couleurContour));
246
					}
247
				}
248
			}
249
		}
250
	}
251
 
252
	private function transformerPolygonesEnPng($nomCouche) {
253
		$couleurs = $this->recupererCouleursSources();
254
		$facteur = floatval($this->format) / floatval($this->largeur);
255
		$noeudCouche = $this->recupererNoeuds($nomCouche);
256
		$couleurRemplissage = $noeudCouche->attributes->getNamedItem('fill')->value;
257
		$couleurContour = $noeudCouche->attributes->getNamedItem('stroke')->value;
258
		for ($index = 0; $index < $noeudCouche->childNodes->length; $index ++) {
259
			$noeudPolygone = $noeudCouche->childNodes->item($index);
260
			$couleurPolygone = 'none';
261
			if ($noeudPolygone->hasAttribute('class')) {
262
				$couleurPolygone = $couleurs[$noeudPolygone->attributes->getNamedItem('class')->value];
263
			}
264
			for ($indexPath = 0; $indexPath < $noeudPolygone->childNodes->length; $indexPath ++) {
265
				$coordonneesSvg = $noeudPolygone->childNodes->item($indexPath)->attributes->getNamedItem('points')->value;
266
				preg_match_all('/\d+.\d/', $coordonneesSvg, $coordonnees);
267
				$coordonnees = current($coordonnees);
268
				foreach ($coordonnees as $indexCoord => $valeur) {
269
					$coordonnees[$indexCoord] = intval(floatval($valeur) * $facteur);
270
				}
271
				if ($couleurRemplissage != 'none') {
272
					imagefilledpolygon($this->image, $coordonnees, count($coordonnees) / 2, $this->allouerCouleur($couleurRemplissage));
273
				}
274
				if ($couleurContour != 'none') {
275
					imagepolygon($this->image, $coordonnees, count($coordonnees) / 2, $this->allouerCouleur($couleurContour));
276
				}
277
				if ($couleurPolygone != 'none') {
278
					$contourGrille = "rgba(255,255,255,".($this->format >= 300 ? 0.4 : 0).")";
279
					imagefilledrectangle($this->image, $coordonnees[0], $coordonnees[1], $coordonnees[4], $coordonnees[5],
280
						$this->allouerCouleur($couleurPolygone));
281
					imagerectangle($this->image, $coordonnees[0], $coordonnees[1], $coordonnees[4], $coordonnees[5],
282
						$this->allouerCouleur($contourGrille));
283
				}
284
			}
285
		}
286
	}
287
 
288
	private function allouerCouleur($couleurTexte) {
289
		preg_match_all('/\d+/', $couleurTexte, $valeurs);
290
		$rouge = $valeurs[0][0];
291
		$vert  = $valeurs[0][1];
292
		$bleu  = $valeurs[0][2];
293
		$alpha = 0;
294
		if (count($valeurs[0]) > 3) {
295
			$valeurAlpha = floatval($valeurs[0][3].".".$valeurs[0][4]);
296
			$alpha = intval((1.0 - $valeurAlpha) * 127.0);
297
		}
298
		return imagecolorallocatealpha($this->image, $rouge, $vert, $bleu, $alpha);
299
	}
300
 
301
}
302
 
303
?>