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

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

Version 4.12.0 : ajout d'un pipeline gis_modele_parametres_autorises dans la fonction gis_modele_url_json_env() pour permettre d'enrichir la liste des noms de paramètres que l'on peut passer au modèle (sur une idée de rasta et troon http://contrib.spip.net/GIS-4#forum472416).

  • Property svn:executable set to *
File size: 12.4 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?>
Note: See TracBrowser for help on using the repository browser.