Subversion Repositories eFlore/Projets.eflore-projets

Rev

Rev 1224 | 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
		$bdd = new Bdd();
1192 delphine 99
		$requete = "SELECT code, SUBSTR(complements,9) AS couleur FROM ".Config::get('bdd_table_ontologies')." WHERE classe_id = 10";
727 alex 100
		$couleurs = $bdd->recupererTous($requete);
101
		$listeCouleurs = array();
102
		foreach ($couleurs as $couleur) {
103
			$couleur['code'] = $couleur['code'] == 'cel' ? 'floradata' : $couleur['code'];
1192 delphine 104
			$couleur['code'] = $couleur['code'] == 'VF' ? 'vigie_flore' : $couleur['code'];
1204 delphine 105
			$couleur['code'] = $couleur['code'] == 'PF' ? 'photoflora' : $couleur['code'];
727 alex 106
			$listeCouleurs[$couleur['code']] = $couleur['couleur'];
107
		}
108
		return $listeCouleurs;
109
	}
110
 
111
 
112
 
113
	public function formaterCarte($taxon) {
114
		$limitesCarte = $this->renvoyerLimitesCarte();
747 alex 115
		$sourceDonnees = new SourceDonnees($limitesCarte, $taxon);
875 aurelien 116
		// modification temporaire pour lors de la selection d'un rang au dessus de famille on ne prenne que floradata
873 aurelien 117
		// (probleme de performance, qui sera réglé en reremplissant la table de moissonnage)
874 aurelien 118
		if($taxon['rang'] >= 180) {
873 aurelien 119
			foreach ($this->sources as $source) {
1192 delphine 120
				switch ($source) {
121
					case 'floradata' : $nomMethode = "recupererStationsFloradata"; break;
122
					case 'vigie_flore' : $nomMethode = "recupererStationsVigieFlore"; break;
1204 delphine 123
					case 'photoflora' : $nomMethode = "recupererStationsPhotoflora"; break;
1192 delphine 124
					default : $nomMethode = "recupererStationsMoissonnage"; break;
125
				}
873 aurelien 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'])) {
1192 delphine 158
				continue;
747 alex 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
		}
1224 delphine 208
 
747 alex 209
		$commentaire = ucfirst($source)." : {$station['commune']}, ";
210
		if (strlen($station['date']) == 4) {
211
			$commentaire .= "en {$station['date']} par {$station['auteur']}";
727 alex 212
		} else {
747 alex 213
			$date = preg_replace("/(\d{4})-(\d{2})-(\d{2})/", "$3/$2/$1", $station['date']);
214
			$commentaire .= "le {$date} par {$station['auteur']}";
727 alex 215
		}
1192 delphine 216
		$commentaires[] = trim($commentaire);//print_r($commentaires);echo "<br /><br />";
1224 delphine 217
		$titre = $this->documentXML->createElement('title', implode('; ', $commentaires));
218
		if ($maille->hasChildNodes() && $maille->childNodes->length > 1) {
219
			$maille->replaceChild($titre, $maille->childNodes->item(1)); //print_r($maille->childNodes->item(1));echo "<br /><br />";
220
		} else {
221
			$maille->appendChild($titre);
222
		}
747 alex 223
		$maille->setAttribute('title', implode('; ', $commentaires));
727 alex 224
	}
225
 
226
 
227
 
228
	public function renvoyerCarte() {
229
		$this->documentXML->documentElement->setAttribute("width", $this->format);
230
		$this->documentXML->documentElement->setAttribute("height", $this->hauteur * $this->format / $this->largeur);
231
		$retour = '';
232
		if ($this->typeMime == self::MIME_MAP) {
233
			$retour = $this->documentXML->saveHTML();
234
		} else {
235
			$retour = $this->convertirEnPng();
236
		}
237
		return $retour;
238
	}
239
 
240
	private function convertirEnPng() {
241
		$this->image = imagecreatetruecolor($this->format,  $this->hauteur * $this->format / $this->largeur);
242
		imagefill($this->image, 0, 0, imagecolorallocate($this->image, 255, 255, 255));
243
		$this->transformerLignesEnPng('departements');
244
		$this->transformerPolygonesEnPng('grille');
245
 
246
		// stocker le contenu encode de l'image generee dans une chaine de caracteres
247
		ob_start();
248
		imagepng($this->image);
249
		$png = ob_get_contents();
250
		ob_end_clean();
251
		return $png;
252
	}
253
 
254
	private function transformerLignesEnPng($nomCouche) {
255
		$facteur = floatval($this->format) / floatval($this->largeur);
256
		$noeudCouche = $this->recupererNoeuds($nomCouche);
257
		$couleurContour = $noeudCouche->attributes->getNamedItem('stroke')->value;
1035 aurelien 258
		$couleurContour = ($this->format >= 300 ? $couleurContour : "rgb(192,192,192)");
727 alex 259
		for ($index = 0; $index < $noeudCouche->childNodes->length; $index ++) {
260
			$noeudLigne = $noeudCouche->childNodes->item($index);
261
			for ($indexPath = 0; $indexPath < $noeudLigne->childNodes->length; $indexPath ++) {
262
				$coordonneesSvg = $noeudLigne->childNodes->item($indexPath)->attributes->getNamedItem('points')->value;
263
				preg_match_all('/\d+.\d/', $coordonneesSvg, $coordonnees);
264
				$coordonnees = current($coordonnees);
265
				foreach ($coordonnees as $indexCoord => $valeur) {
266
					$coordonnees[$indexCoord] = intval(floatval($valeur) * $facteur);
267
				}
268
				if ($couleurContour != 'none') {
269
					for ($i = 0; $i < count($coordonnees) - 2; $i += 2) {
270
						imageline($this->image, $coordonnees[$i], $coordonnees[$i+1], $coordonnees[$i+2],
271
							$coordonnees[$i+3], $this->allouerCouleur($couleurContour));
272
					}
273
				}
274
			}
275
		}
276
	}
277
 
278
	private function transformerPolygonesEnPng($nomCouche) {
279
		$couleurs = $this->recupererCouleursSources();
280
		$facteur = floatval($this->format) / floatval($this->largeur);
281
		$noeudCouche = $this->recupererNoeuds($nomCouche);
282
		$couleurRemplissage = $noeudCouche->attributes->getNamedItem('fill')->value;
283
		$couleurContour = $noeudCouche->attributes->getNamedItem('stroke')->value;
284
		for ($index = 0; $index < $noeudCouche->childNodes->length; $index ++) {
285
			$noeudPolygone = $noeudCouche->childNodes->item($index);
286
			$couleurPolygone = 'none';
287
			if ($noeudPolygone->hasAttribute('class')) {
288
				$couleurPolygone = $couleurs[$noeudPolygone->attributes->getNamedItem('class')->value];
289
			}
290
			for ($indexPath = 0; $indexPath < $noeudPolygone->childNodes->length; $indexPath ++) {
291
				$coordonneesSvg = $noeudPolygone->childNodes->item($indexPath)->attributes->getNamedItem('points')->value;
292
				preg_match_all('/\d+.\d/', $coordonneesSvg, $coordonnees);
293
				$coordonnees = current($coordonnees);
294
				foreach ($coordonnees as $indexCoord => $valeur) {
295
					$coordonnees[$indexCoord] = intval(floatval($valeur) * $facteur);
296
				}
297
				if ($couleurRemplissage != 'none') {
298
					imagefilledpolygon($this->image, $coordonnees, count($coordonnees) / 2, $this->allouerCouleur($couleurRemplissage));
299
				}
300
				if ($couleurContour != 'none') {
301
					imagepolygon($this->image, $coordonnees, count($coordonnees) / 2, $this->allouerCouleur($couleurContour));
302
				}
1296 delphine 303
				if (is_array($coordonnees) && $couleurPolygone != 'none') {
727 alex 304
					$contourGrille = "rgba(255,255,255,".($this->format >= 300 ? 0.4 : 0).")";
305
					imagefilledrectangle($this->image, $coordonnees[0], $coordonnees[1], $coordonnees[4], $coordonnees[5],
306
						$this->allouerCouleur($couleurPolygone));
307
					imagerectangle($this->image, $coordonnees[0], $coordonnees[1], $coordonnees[4], $coordonnees[5],
308
						$this->allouerCouleur($contourGrille));
309
				}
310
			}
311
		}
312
	}
313
 
314
	private function allouerCouleur($couleurTexte) {
315
		preg_match_all('/\d+/', $couleurTexte, $valeurs);
316
		$rouge = $valeurs[0][0];
317
		$vert  = $valeurs[0][1];
318
		$bleu  = $valeurs[0][2];
319
		$alpha = 0;
320
		if (count($valeurs[0]) > 3) {
321
			$valeurAlpha = floatval($valeurs[0][3].".".$valeurs[0][4]);
322
			$alpha = intval((1.0 - $valeurAlpha) * 127.0);
323
		}
324
		return imagecolorallocatealpha($this->image, $rouge, $vert, $bleu, $alpha);
325
	}
326
 
327
}
328
 
329
?>