Rev 875 | Rev 1204 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php/*** Classe qui genere la carte SVG pour les parametres de la requete qui a ete utilisee pour appeler* le web service** @package framework-0.4* @author Alexandre GALIBERT <alexandre.galibert@tela-botanica.org>* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>* @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>* @version $Id$* @copyright 2013 Tela Botanica (accueil@tela-botanica.org)**/class FormateurSVG {private $documentXML;private $coordonnees = array();private $grille = null;private $largeur = 0;private $hauteur = 0;private $typeMime = '';private $format = 0;private $sources = array();private $image = null;const ORIGINE = 20037508.342789244;const MIME_MAP = 'text/html';public function __construct($nomFichierSVG, $sources, $typeMime, $format) {$this->chargerSVG($nomFichierSVG);$this->chargerCoordonnees();$this->construireParametresRetour($typeMime, $format);$this->creerStyleSources();$this->sources = $sources;}private function chargerSVG($nomFichierSVG) {$this->documentXML = new DOMDocument("1.0", "UTF-8");$this->documentXML->load($nomFichierSVG);}private function chargerCoordonnees() {$viewbox = $this->recupererNoeuds('qgisviewbox');$this->coordonnees = array('xMin' => $viewbox->attributes->getNamedItem('xMin')->value,'xMax' => $viewbox->attributes->getNamedItem('xMax')->value,'yMin' => $viewbox->attributes->getNamedItem('yMin')->value,'yMax' => $viewbox->attributes->getNamedItem('yMax')->value);}private function recupererNoeuds($nomCouche) {$contenuSVG = $this->documentXML->documentElement->childNodes;$noeudCouche = null;$index = 0;while ($index < $contenuSVG->length && is_null($noeudCouche)) {$id = $contenuSVG->item($index)->attributes->getNamedItem('id');if ($id->value == $nomCouche) {$noeudCouche = $contenuSVG->item($index);}$index ++;}$noeuds = null;if (!is_null($noeudCouche)) {$noeuds = $noeudCouche->firstChild;}return $noeuds;}private function construireParametresRetour($typeMime, $format) {$viewBox = $this->documentXML->documentElement->attributes->getNamedItem('viewBox');$limitesPixels = explode(' ',$viewBox->value);$this->largeur = intval($limitesPixels[2]);$this->hauteur = intval($limitesPixels[3]);$this->typeMime = $typeMime;$this->format = intval($format);}private function creerStyleSources() {$couleurs = $this->recupererCouleursSources();$reglesCss = array();foreach ($couleurs as $codeSource => $codeCouleur) {$reglesCss[] = ".{$codeSource} {\nfill:{$codeCouleur}\n}\n";}$texteCss = $this->documentXML->createCDATASection(implode(' ', $reglesCss));$noeudStyle = new DomElement('style', '');$this->documentXML->documentElement->appendChild($noeudStyle);$noeudStyle->appendChild($texteCss);}private function recupererCouleursSources() {$sourcesDonnees = Config::get('sourcesDonnees');$codesSources = str_replace('floradata', 'cel', $sourcesDonnees).',tout';$codes = explode(',', $codesSources);for ($index = 0; $index < count($codes); $index ++) {$codes[$index] = "'".$codes[$index]."'";}$codesSources = implode(',', $codes);$bdd = new Bdd();$requete = "SELECT code, SUBSTR(complements,9) AS couleur FROM ".Config::get('bdd_table_ontologies')." WHERE code IN ({$codesSources})";$couleurs = $bdd->recupererTous($requete);$listeCouleurs = array();foreach ($couleurs as $couleur) {$couleur['code'] = $couleur['code'] == 'cel' ? 'floradata' : $couleur['code'];$listeCouleurs[$couleur['code']] = $couleur['couleur'];}return $listeCouleurs;}public function formaterCarte($taxon) {$limitesCarte = $this->renvoyerLimitesCarte();$sourceDonnees = new SourceDonnees($limitesCarte, $taxon);// modification temporaire pour lors de la selection d'un rang au dessus de famille on ne prenne que floradata// (probleme de performance, qui sera réglé en reremplissant la table de moissonnage)if($taxon['rang'] >= 180) {foreach ($this->sources as $source) {$nomMethode = "recupererStations".($source == 'floradata' ? 'Floradata' : 'Moissonnage');$stations = $sourceDonnees->$nomMethode($source);$this->ajouterStations($stations, $source);}} else {$stations = $sourceDonnees->recupererStationsFloradata($source);$this->ajouterStations($stations, $source);}$this->supprimerMaillesVides();}public function renvoyerLimitesCarte() {$limites = array();list($limites['ouest'], $limites['sud']) = $this->convertirMetresEnPixels($this->coordonnees['xMin'], $this->coordonnees['yMin']);list($limites['est'], $limites['nord']) = $this->convertirMetresEnPixels($this->coordonnees['xMax'], $this->coordonnees['yMax']);return $limites;}private function convertirMetresEnPixels($x, $y) {$longitude = ($x / self::ORIGINE) * 180;$latitude = ($y / self::ORIGINE) * 180;$latitude = 180 / M_PI * (2 * atan(exp($latitude * M_PI / 180.0)) - M_PI / 2.0);return array(round($longitude, 6), round($latitude, 6));}private function ajouterStations($stations, $source) {$grille = $this->recupererNoeuds('grille')->childNodes;$index = 0;$maille = $grille->item($index);foreach ($stations as $station) {if (!isset($station['lat']) || !isset($station['lng']) || !isset($station['commune'])) {continue;}$idMaille = $maille->attributes->getNamedItem('id')->value;$bbox = explode('_', substr($idMaille, 5));$bbox[0] = floatval($bbox[0]);$bbox[1] = floatval($bbox[1]);while ($index < $grille->length && ($bbox[1] > $station['lat'] || ($bbox[1] == $station['lat'] && $bbox[0] < $station['lng']))) {$maille = $grille->item($index ++);$idMaille = $maille->attributes->getNamedItem('id')->value;$bbox = explode('_', substr($idMaille, 5));$bbox[0] = floatval($bbox[0]);$bbox[1] = floatval($bbox[1]);}if ($bbox[1] == $station['lat'] && $bbox[0] == $station['lng']) {$this->ajouterCommentaire($station, $source, $maille);$this->appliquerStyleMaille($source, $maille);}if ($index == $grille->length) {break;}}}private function supprimerMaillesVides() {$grille = $this->recupererNoeuds('grille')->childNodes;$index = 0;while ($index < $grille->length) {if (!$grille->item($index)->hasAttribute('title')) {$grille->item($index)->parentNode->removeChild($grille->item($index));} else {$index ++;}}}private function appliquerStyleMaille($source, & $maille) {if ($maille->hasAttribute('class') && $maille->attributes->getNamedItem('class')->value != $source) {$maille->setAttribute('class', 'tout');} elseif (!$maille->hasAttribute('class')) {$maille->setAttribute('class', $source);}}private function ajouterCommentaire($station, $source, & $maille) {$commentaires = array();if ($maille->hasAttribute('title')) {$commentaires = explode("; ", $maille->attributes->getNamedItem('title')->value);}$commentaire = ucfirst($source)." : {$station['commune']}, ";if (strlen($station['date']) == 4) {$commentaire .= "en {$station['date']} par {$station['auteur']}";} else {$date = preg_replace("/(\d{4})-(\d{2})-(\d{2})/", "$3/$2/$1", $station['date']);$commentaire .= "le {$date} par {$station['auteur']}";}$commentaires[] = trim($commentaire);$maille->setAttribute('title', implode('; ', $commentaires));}public function renvoyerCarte() {$this->documentXML->documentElement->setAttribute("width", $this->format);$this->documentXML->documentElement->setAttribute("height", $this->hauteur * $this->format / $this->largeur);$retour = '';if ($this->typeMime == self::MIME_MAP) {$retour = $this->documentXML->saveHTML();} else {$retour = $this->convertirEnPng();}return $retour;}private function convertirEnPng() {$this->image = imagecreatetruecolor($this->format, $this->hauteur * $this->format / $this->largeur);imagefill($this->image, 0, 0, imagecolorallocate($this->image, 255, 255, 255));$this->transformerLignesEnPng('departements');$this->transformerPolygonesEnPng('grille');// stocker le contenu encode de l'image generee dans une chaine de caracteresob_start();imagepng($this->image);$png = ob_get_contents();ob_end_clean();return $png;}private function transformerLignesEnPng($nomCouche) {$facteur = floatval($this->format) / floatval($this->largeur);$noeudCouche = $this->recupererNoeuds($nomCouche);$couleurContour = $noeudCouche->attributes->getNamedItem('stroke')->value;$couleurContour = ($this->format >= 300 ? $couleurContour : "rgb(192,192,192)");for ($index = 0; $index < $noeudCouche->childNodes->length; $index ++) {$noeudLigne = $noeudCouche->childNodes->item($index);for ($indexPath = 0; $indexPath < $noeudLigne->childNodes->length; $indexPath ++) {$coordonneesSvg = $noeudLigne->childNodes->item($indexPath)->attributes->getNamedItem('points')->value;preg_match_all('/\d+.\d/', $coordonneesSvg, $coordonnees);$coordonnees = current($coordonnees);foreach ($coordonnees as $indexCoord => $valeur) {$coordonnees[$indexCoord] = intval(floatval($valeur) * $facteur);}if ($couleurContour != 'none') {for ($i = 0; $i < count($coordonnees) - 2; $i += 2) {imageline($this->image, $coordonnees[$i], $coordonnees[$i+1], $coordonnees[$i+2],$coordonnees[$i+3], $this->allouerCouleur($couleurContour));}}}}}private function transformerPolygonesEnPng($nomCouche) {$couleurs = $this->recupererCouleursSources();$facteur = floatval($this->format) / floatval($this->largeur);$noeudCouche = $this->recupererNoeuds($nomCouche);$couleurRemplissage = $noeudCouche->attributes->getNamedItem('fill')->value;$couleurContour = $noeudCouche->attributes->getNamedItem('stroke')->value;for ($index = 0; $index < $noeudCouche->childNodes->length; $index ++) {$noeudPolygone = $noeudCouche->childNodes->item($index);$couleurPolygone = 'none';if ($noeudPolygone->hasAttribute('class')) {$couleurPolygone = $couleurs[$noeudPolygone->attributes->getNamedItem('class')->value];}for ($indexPath = 0; $indexPath < $noeudPolygone->childNodes->length; $indexPath ++) {$coordonneesSvg = $noeudPolygone->childNodes->item($indexPath)->attributes->getNamedItem('points')->value;preg_match_all('/\d+.\d/', $coordonneesSvg, $coordonnees);$coordonnees = current($coordonnees);foreach ($coordonnees as $indexCoord => $valeur) {$coordonnees[$indexCoord] = intval(floatval($valeur) * $facteur);}if ($couleurRemplissage != 'none') {imagefilledpolygon($this->image, $coordonnees, count($coordonnees) / 2, $this->allouerCouleur($couleurRemplissage));}if ($couleurContour != 'none') {imagepolygon($this->image, $coordonnees, count($coordonnees) / 2, $this->allouerCouleur($couleurContour));}if ($couleurPolygone != 'none') {$contourGrille = "rgba(255,255,255,".($this->format >= 300 ? 0.4 : 0).")";imagefilledrectangle($this->image, $coordonnees[0], $coordonnees[1], $coordonnees[4], $coordonnees[5],$this->allouerCouleur($couleurPolygone));imagerectangle($this->image, $coordonnees[0], $coordonnees[1], $coordonnees[4], $coordonnees[5],$this->allouerCouleur($contourGrille));}}}}private function allouerCouleur($couleurTexte) {preg_match_all('/\d+/', $couleurTexte, $valeurs);$rouge = $valeurs[0][0];$vert = $valeurs[0][1];$bleu = $valeurs[0][2];$alpha = 0;if (count($valeurs[0]) > 3) {$valeurAlpha = floatval($valeurs[0][3].".".$valeurs[0][4]);$alpha = intval((1.0 - $valeurAlpha) * 127.0);}return imagecolorallocatealpha($this->image, $rouge, $vert, $bleu, $alpha);}}?>