source: spip-zone/_plugins_/gis/trunk/gis_fonctions.php @ 80095

Last change on this file since 80095 was 80095, checked in by brunobergot@…, 7 years ago

Version 4.15.0 : simplification des squelettes JSON, filtre |gis_icon_properties

  • Nouveau filtre |gis_icon_properties qui renvoie les propriétés JSON de l'icône d'un point.
  • Petit changement de comportement pour les logo des points. Si le logo ne dépasse pas 44px de largeur, on ne le retaille pas. Ainsi on permet aux utilisateurs d'utiliser des marqueurs persos en respectant leur taille et transparence.
  • Property svn:executable set to *
File size: 13.5 KB
Line 
1<?php
2
3if (!defined('_ECRIRE_INC_VERSION')) return;
4
5include_spip('inc/config');
6include_spip('inc/json');
7
8/**
9 * Filtre dec_to_dms, http://www.statemaster.com/encyclopedia/Geographic-coordinate-conversion
10 *
11 * @param decimal $coord
12 * @return string
13 */
14function dec_to_dms($coord) {
15        return sprintf(
16                "%0.0f° %2.3f",
17                floor(abs($coord)),
18                60*(abs($coord)-floor(abs($coord)))
19        );
20}
21
22/**
23 * Filtre dms_to_dec, http://www.statemaster.com/encyclopedia/Geographic-coordinate-conversion
24 *
25 * @param string $ref N, E, S, W
26 * @param int $deg
27 * @param int $min
28 * @param int $sec
29 * @return decimal
30 */
31function dms_to_dec($ref,$deg,$min,$sec) {
32
33        $arrLatLong = array();
34        $arrLatLong["N"] = 1;
35        $arrLatLong["E"] = 1;
36        $arrLatLong["S"] = -1;
37        $arrLatLong["W"] = -1;
38
39        return ($deg+((($min*60)+($sec))/3600)) * $arrLatLong[$ref];
40}
41
42/**
43 * Filtre distance pour renvoyer la distance entre deux points
44 * http://snipplr.com/view/2531/calculate-the-distance-between-two-coordinates-latitude-longitude/
45 * sinon voir ici : http://zone.spip.org/trac/spip-zone/browser/_plugins_/forms/geoforms/inc/gPoint.php
46 *
47 * @param int|array $from
48 *     id_gis du point de référence ou tableau de coordonnées
49 * @param int|array $to
50 *     id_gis du point distant ou tableau de coordonnées
51 * @param bool $miles
52 *     Renvoyer le résultat en miles (kilomètres par défaut)
53 * @return float
54 *     Retourne la distance en kilomètre ou en miles
55 */
56function distance($from, $to, $miles=false) {
57        // On ne travaille que si on a toutes les infos
58        if (
59                // Le départ est soit un tableau soit un entier
60                (
61                        (is_array($from) and isset($from['lat']) and isset($from['lon']))
62                        or
63                        ($from = intval($from) and $from > 0 and $from = sql_fetsel('lat,lon','spip_gis',"id_gis=$from"))
64                )
65                and
66                // Le distant est soit un tableau soit un entier
67                (
68                        (is_array($to) and isset($to['lat']) and isset($to['lon']))
69                        or
70                        ($to = intval($to) and $to > 0 and $to = sql_fetsel('lat,lon','spip_gis',"id_gis=$to"))
71                )
72        ){
73                $pi80 = M_PI / 180;
74                $from['lat'] *= $pi80;
75                $from['lon'] *= $pi80;
76                $to['lat'] *= $pi80;
77                $to['lon'] *= $pi80;
78
79                $r = 6372.797; // mean radius of Earth in km
80                $dlat = $to['lat'] - $from['lat'];
81                $dlng = $to['lon'] - $from['lon'];
82                $a = sin($dlat / 2) * sin($dlat / 2) + cos($from['lat']) * cos($to['lat']) * sin($dlng / 2) * sin($dlng / 2);
83                $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
84                $km = $r * $c;
85
86                return ($miles ? ($km * 0.621371192) : $km);
87        }
88       
89        return false;
90}
91
92/**
93 * Compilation du critère {distancefrom}
94 *
95 * Critère {distancefrom} qui permet de ne sélectionner que les objets se trouvant à une distance comparée avec un point de repère.
96 * On doit lui passer 3 paramètres obligatoires :
97 * - le point de repère qui est un tableau avec les clés "lat" et "lon" ou un id_gis
98 * - l'opérateur de comparaison
99 * - la distance à comparer, en kilomètres
100 * Cela donne par exemple :
101 *   {distancefrom #ARRAY{lat,#LAT,lon,#LON},<,30}
102 *   {distancefrom #ARRAY{lat,#ENV{lat},lon,#ENV{lon}},<=,#ENV{distance}}
103 *
104 * @param unknown $idb
105 * @param unknown &$boucles
106 * @param unknown $crit
107 */
108function critere_distancefrom_dist($idb, &$boucles, $crit) {
109        $boucle = &$boucles[$idb];
110        $id_table = $boucle->id_table; // articles
111        $primary = $boucle->primary; // id_article
112        $objet = objet_type($id_table); // article
113       
114        if (
115                // Soit depuis une boucle (GIS) soit un autre objet mais avec {gis}
116                ($id_table == 'gis' or isset($boucle->join['gis']))
117                // Il faut aussi qu'il y ait 3 critères obligatoires
118                and count($crit->param) == 3
119        ){
120                $point_reference = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
121                $operateur = calculer_liste($crit->param[1], array(), $boucles, $boucles[$idb]->id_parent);
122                $distance = calculer_liste($crit->param[2], array(), $boucles, $boucles[$idb]->id_parent);
123
124                // Si le point de référence est un entier, on essaye de récupérer les coordonnées du point GIS
125                // Et si on a toujours pas de tableau correct, on met false
126                $boucle->hierarchie .= '$point_reference = '.$point_reference.';';
127                $boucle->hierarchie .= 'if (is_numeric($point_reference)){ $point_reference = sql_fetsel("lat,lon", "spip_gis", "id_gis = ".intval($point_reference)); }';
128                $boucle->hierarchie .= 'if (!is_array($point_reference) or !isset($point_reference["lat"]) or !isset($point_reference["lon"])){ $point_reference = false; }';
129                // L'opérateur doit exister dans une liste précise
130                $boucle->hierarchie .= '$operateur_distance = trim('.$operateur.');';
131                $boucle->hierarchie .= 'if (!in_array($operateur_distance, array("=","<",">","<=",">="))){ $operateur_distance = false; }';
132                $boucle->hierarchie .= '$distance = '.$distance.';';
133               
134                $boucle->select[] = '".(!$point_reference ? "\'\' as distance" : "(6371 * acos( cos( radians(".$point_reference["lat"].") ) * cos( radians( gis.lat ) ) * cos( radians( gis.lon ) - radians(".$point_reference["lon"].") ) + sin( radians(".$point_reference["lat"].") ) * sin( radians( gis.lat ) ) ) ) AS distance")."';
135                $boucle->having[] = '((!$point_reference or !$operateur_distance or !$distance) ? "1=1" : "distance $operateur_distance ".sql_quote($distance))';
136        }
137}
138
139/**
140 * Critere {gis distance<XX} pour filtrer une liste de points par rapport à la distance du point de l'env
141 *
142 * @param unknown_type $idb
143 * @param unknown_type $boucles
144 * @param unknown_type $crit
145 */
146function critere_gis_dist($idb, &$boucles, $crit) {
147        $boucle = &$boucles[$idb];
148        $id_table = $boucle->id_table; // articles
149        $primary = $boucle->primary; // id_article
150        $objet = objet_type($id_table); // article
151       
152        if ($id_table == 'gis') {
153                // exclure l'élément en cours des résultats
154                $id_gis = calculer_argument_precedent($idb,$primary, $boucles);
155                $boucle->where[]= array("'!='", "'$boucle->id_table." . "$primary'", $id_gis);
156               
157                // récupérer les paramètres du critère
158                $op='';
159                $params = $crit->param;
160                $type = array_shift($params);
161                $type = $type[0]->texte;
162                if(preg_match(',^(\w+)([<>=]+)([0-9]+)$,',$type,$r)){
163                        $type=$r[1];
164                        $op=$r[2];
165                        $op_val=$r[3];
166                }
167                if ($op)
168                        $boucle->having[]= array("'".$op."'", "'".$type."'",$op_val);
169               
170                // récupérer lat/lon du point de la boucle englobante
171                $lat = calculer_argument_precedent($idb,'lat', $boucles);
172                $lon = calculer_argument_precedent($idb,'lon', $boucles);
173               
174                // http://www.awelty.fr/developpement-web/php/
175                // http://www.movable-type.co.uk/scripts/latlong-db.html
176                // http://code.google.com/intl/fr/apis/maps/articles/geospatial.html#geospatial
177                $select = "(6371 * acos( cos( radians(\".$lat.\") ) * cos( radians( gis.lat ) ) * cos( radians( gis.lon ) - radians(\".$lon.\") ) + sin( radians(\".$lat.\") ) * sin( radians( gis.lat ) ) ) ) AS distance";
178                $order = "'distance'";
179               
180                $boucle->select[]= $select;
181                $boucle->order[]= $order;
182        } else {
183                // ajouter tous les champs du point au select
184                // et les suffixer pour lever toute ambiguite avec des champs homonymes
185                $boucle->select[]= 'gis.titre AS titre_gis';
186                $boucle->select[]= 'gis.descriptif AS descriptif_gis';
187                $boucle->select[]= 'gis.adresse AS adresse_gis';
188                $boucle->select[]= 'gis.pays AS pays_gis';
189                $boucle->select[]= 'gis.code_pays AS code_pays_gis';
190                $boucle->select[]= 'gis.region AS region_gis';
191                $boucle->select[]= 'gis.ville AS ville_gis';
192                $boucle->select[]= 'gis.code_postal AS code_postal_gis';
193                // jointure sur spip_gis_liens/spip_gis
194                // cf plugin notation
195                // $boucle->join["surnom (as) table de liaison"] = array("surnom de la table a lier", "cle primaire de la table de liaison", "identifiant a lier", "type d'objet de l'identifiant");
196                $boucle->from['gis_liens'] = 'spip_gis_liens';
197                $boucle->join['gis_liens']= array("'$id_table'","'id_objet'","'$primary'","'gis_liens.objet='.sql_quote('$objet')");
198                $boucle->from['gis'] = 'spip_gis';
199                $boucle->join['gis']= array("'gis_liens'","'id_gis'");
200                // bien renvoyer tous les points qui son attachés à l'objet
201                // mais attention, si on trouve en amont un groupement portant sur un champ *de GIS*,
202                // alors cela signifie que la personne veut faire une opération de groupement sur les points donc là on n'ajoute pas id_gis
203                $tous_les_points = true;
204                foreach ($boucle->group as $champ){
205                        if (in_array($champ, array('ville', 'code_postal', 'pays', 'code_pays', 'region'))) {
206                                $tous_les_points = false;
207                        }
208                }
209                if ($tous_les_points) {
210                        $boucle->group[] = 'gis_liens.id_gis';
211                }
212                // ajouter gis aux jointures et spécifier les jointures explicites pour pouvoir utiliser les balises de la table de jointure
213                // permet de passer dans trouver_champ_exterieur() depuis index_tables_en_pile()
214                // cf http://article.gmane.org/gmane.comp.web.spip.zone/6628
215                $boucle->jointures[] = 'gis';
216                if (empty($boucle->jointures_explicites)){
217                        $boucle->jointures_explicites = 'gis_liens gis';
218                }
219                else{
220                        $boucle->jointures_explicites .= ' gis_liens gis';
221                }
222        }
223}
224
225/**
226 * Balise #DISTANCE issue du critère {gis distance<XX}
227 * merci marcimant : http://formation.magraine.net/spip.php?article61
228 *
229 * @param unknown_type $p
230 */
231function balise_distance_dist($p) {
232        return rindex_pile($p, 'distance', 'gis');
233}
234
235/**
236 * Balise #TITRE_GIS : retourne le titre du point
237 * Necessite le critere {gis} sur la boucle
238 *
239 * @param unknown_type $p
240 */
241function balise_titre_gis_dist($p) {
242        return rindex_pile($p, 'titre_gis', 'gis');
243}
244
245/**
246 * Balise #DESCRIPTIF_GIS : retourne le descriptif du point
247 * Necessite le critere {gis} sur la boucle
248 *
249 * @param unknown_type $p
250 */
251function balise_descriptif_gis_dist($p) {
252        return rindex_pile($p, 'descriptif_gis', 'gis');
253}
254
255/**
256 * Balise #ADRESSE_GIS : retourne l'adresse du point
257 * Necessite le critere {gis} sur la boucle
258 *
259 * @param unknown_type $p
260 */
261function balise_adresse_gis_dist($p) {
262        return rindex_pile($p, 'adresse_gis', 'gis');
263}
264
265/**
266 * Balise #PAYS_GIS : retourne le pays du point
267 * Necessite le critere {gis} sur la boucle
268 *
269 * @param unknown_type $p
270 */
271function balise_pays_gis_dist($p) {
272        return rindex_pile($p, 'pays_gis', 'gis');
273}
274
275/**
276 * Balise #CODE_PAYS_GIS : retourne le code pays du point
277 * Necessite le critere {gis} sur la boucle
278 *
279 * @param unknown_type $p
280 */
281function balise_code_pays_gis_dist($p) {
282        return rindex_pile($p, 'code_pays_gis', 'gis');
283}
284
285/**
286 * Balise #VILLE_GIS : retourne la ville du point
287 * Necessite le critere {gis} sur la boucle
288 *
289 * @param unknown_type $p
290 */
291function balise_ville_gis_dist($p) {
292        return rindex_pile($p, 'ville_gis', 'gis');
293}
294
295/**
296 * Balise #REGION_GIS : retourne la région du point
297 * Necessite le critere {gis} sur la boucle
298 *
299 * @param unknown_type $p
300 */
301function balise_region_gis_dist($p) {
302        return rindex_pile($p, 'region_gis', 'gis');
303}
304
305/**
306 * Balise #CODE_POSTAL_GIS : retourne le code postal du point
307 * Necessite le critere {gis} sur la boucle
308 *
309 * @param unknown_type $p
310 */
311function balise_code_postal_gis_dist($p) {
312        return rindex_pile($p, 'code_postal_gis', 'gis');
313}
314
315/**
316 * Définition du fond de carte à utiliser par défaut en prenant compte les defines
317 */
318function gis_layer_defaut(){
319        $defaut = 'openstreetmap_mapnik';
320        if(defined('_GIS_LAYER_DEFAUT_FORCE')){
321                return _GIS_LAYER_DEFAUT_FORCE;
322        }else{
323                if(defined('_GIS_LAYER_DEFAUT')){
324                        $defaut = _GIS_LAYER_DEFAUT;
325                }
326                $config = lire_config('gis/layer_defaut');
327                return $config ? $config : $defaut;
328        }
329}
330
331/**
332 * Recuperer les cles primaires du env pour l'appel a l'url json des points
333 * @param $env
334 * @return array
335 */
336function gis_modele_url_json_env($env){
337        $contexte = array();
338        if (is_string($env))
339                $env = unserialize($env);
340        if ($env){
341                // d'abord toutes les cles primaires connues
342                $tables_sql = lister_tables_objets_sql();
343                foreach (array_keys($tables_sql) as $table){
344                        $primary = id_table_objet($table);
345                        if (isset($env[$primary]))
346                                $contexte[$primary] = $env[$primary];
347                }
348                // puis cas particuliers et ceux ajoutés par le pipeline
349                $keys = pipeline('gis_modele_parametres_autorises', array("id_objet","id_secteur","id_parent","media","recherche","mots","pays","code_pays","region","ville","code_postal","adresse"));
350                foreach ($keys as $key){
351                        if (isset($env[$key]))
352                                $contexte[$key] = $env[$key];
353                }
354        }
355        return $contexte;
356}
357
358/**
359 * Transformer le tableau de kml en tableau d'urls :
360 *   si numerique c'est un id de document
361 *   si chaine c'est une url qu'on rapatrie en local
362 * @param array $kml
363 * @return array
364 */
365function gis_kml_to_urls($kml){
366        if ($kml AND count($kml)){
367                include_spip("inc/filtres_mini");
368                include_spip("inc/distant");
369                foreach($kml as $k=>$v){
370                        if (is_numeric($v)){
371                                $kml[$k] = url_absolue(generer_url_entite($v,"document"));
372                        }
373                        else
374                                $kml[$k] = _DIR_RACINE.copie_locale($kml[$k]);
375                }
376        }
377        return $kml;
378}
379
380/**
381 * Retourne les propriétés JSON de l'icône d'un point
382 *
383 * @param string $img
384 *     Balise HTML `<img ... />` ou chemin de l'image (qui peut être une URL distante).
385 * @return string
386 *     Les propriétés de l'icône
387**/
388function gis_icon_properties($img=''){
389        $props = $icon = '';
390       
391        if ($img) {
392                if (largeur($img) >= 44)
393                        $icon = extraire_attribut(filtrer('image_graver',filtrer('image_recadre',filtrer('image_passe_partout',$img,32,32),32,32,'center','transparent')),'src');
394                else
395                        $icon = extraire_attribut($img,'src');
396        }
397        else
398                $icon = find_in_path('images/marker_defaut.png');
399       
400        if ($icon) {
401                $props .= ",\n\"icon\": ". json_encode(url_absolue($icon)).",";
402                list($h,$w) = taille_image($icon);
403                $props .= "\n\"icon_size\": ". json_encode(array($w,$h)).",";
404                $props .= "\n\"icon_anchor\": ". json_encode(array($w/2,$h)).",";
405                $props .= "\n\"popup_anchor\": ". json_encode(array(1,$h/1.2));
406        }
407       
408        if ($shadow = find_in_path('images/marker_defaut_shadow.png'))
409                $props .= ",\n\"shadow\": ". json_encode(url_absolue($shadow));
410       
411        return $props;
412}
413
414?>
Note: See TracBrowser for help on using the repository browser.