source: spip-zone/_plugins_/gis_geometries/gisgeom_fonctions.php @ 104889

Last change on this file since 104889 was 104889, checked in by marcimat@…, 3 years ago

Ajout de filtres & d’un critère pour pouvoir sélectionner des points proches d’un tracé.
Nécessite Mysql 5.6+ ou Mariadb pour être utilisés.

# Filtre zoner_geometrie

zoner_geometrie($geometrie, $type[, $distance[, $tolerance]])

Pour une géométrie donnée, au format $type (json, wkt, ...), calcule une zone (un polygone) qui couvre la géométrie à une distance donnée (0.05 par défaut ici).
En d’autre terme, applique la fonction Mysql ST_Buffer() sur la géométrie en entrée. La distance est exprimée en degré décimal d’angle si la géométrie a des points latitude/longitude (en tout cas c'est ce que j’en comprends).
Pour que le polygone calculé ne contienne pas une immensité de points, on simplifie le polygone d’entrée et le polygone de sortie (ça réduit le nombre de points). La réduction prend en compte un paramètre de tolérance, qui vaut par défaut $distance/20.

# Filtre simplifier_geometrie

simplifier_geometrie($geometrie, $type, $tolerance)

Simplifie le nombre de points d’une géométrie, en utilisant la tolérance indiquée (en degré décimal d’angle je suppute, si la géométrie est en latitude/longitude).
Elle est utilisée automatiquement par la fonction zone_geometrie().

# Critère geometrie_dans_polygone

{geometrie_dans_polygone #GET{polygone}

Pour un polygone calculé, par exemple avec zoner_geometrie() tel que
#SET{polygone,#GEOMETRY|zoner_geometrie{wkt,0.05} dans une boucle GIS, récupère les géométries qui sont contenues dans le polygone.

Exemple, récupérer les Points (et pas d’autre forme, mais ce serait possible) dans une zone :
<BOUCLE_points_proches(GIS){type=Point}{geometrie_dans_polygone #GET{poly}}>

  • Property svn:executable set to *
File size: 6.8 KB
Line 
1<?php
2
3if (!defined('_ECRIRE_INC_VERSION')) {
4        return;
5}
6
7/**
8 * Balise GEOMETRY pour afficher le champ geo de la table spip_gis au format WKT
9 *
10 * @param $p
11 * @return mixed
12 */
13function balise_geometry_dist($p) {
14        $p->code = '$Pile[$SP][\'geometry\']';
15        return $p;
16}
17
18/**
19 * Balise GEOMETRY_STYLES pour afficher la représentation JSON des styles
20 *
21 * @param $p
22 * @return mixed
23 */
24function balise_geometry_styles_dist($p) {
25        $p->code = '$Pile[$SP][\'geometry_styles\']';
26        return $p;
27}
28
29/**
30 * Filtre wkt_to_json converti une chaine au format WKT en GeoJSON
31 *
32 * @param string $wkt
33 * @return string
34 */
35function wkt_to_json($wkt) {
36        if (!$wkt) {
37                return false;
38        }
39        // include_spip cherche les fichier .php, on utilise find_in_path avec l'option $include à true
40        find_in_path(_DIR_LIB_GEOPHP.'geoPHP.inc', '', true);
41        $geometry = geoPHP::load($wkt, 'wkt');
42        return $geometry->out('json');
43}
44
45/**
46 * Filtre json_to_wkt converti une chaine au format GeoJSON en WKT
47 *
48 * @param string $json
49 * @return string
50 */
51function json_to_wkt($json) {
52        if (!$json) {
53                return false;
54        }
55        find_in_path(_DIR_LIB_GEOPHP.'geoPHP.inc', '', true);
56        $geometry = geoPHP::load($json, 'json');
57        return $geometry->out('wkt');
58}
59
60/**
61 * Filtre wkt_to_kml converti une chaine au format WKT en KML
62 *
63 * @param string $wkt
64 * @return string
65 */
66function wkt_to_kml($wkt) {
67        if (!$wkt) {
68                return false;
69        }
70        // include_spip cherche les fichier .php, on utilise find_in_path avec l'option $include à true
71        find_in_path(_DIR_LIB_GEOPHP.'geoPHP.inc', '', true);
72        $geometry = geoPHP::load($wkt, 'wkt');
73        return $geometry->out('kml');
74}
75
76/**
77 * Filtre wkt_to_gpx converti une chaine au format WKT en GPX
78 *
79 * @param string $wkt
80 * @return string
81 */
82function wkt_to_gpx($wkt) {
83        if (!$wkt) {
84                return false;
85        }
86        // include_spip cherche les fichier .php, on utilise find_in_path avec l'option $include à true
87        find_in_path(_DIR_LIB_GEOPHP.'geoPHP.inc', '', true);
88        $geometry = geoPHP::load($wkt, 'wkt');
89        return $geometry->out('gpx');
90}
91
92/**
93 * Filtre geometry_styles_to_json converti une chaine de valeurs séparées par des virugles au format JSON
94 *
95 * @param string $geometry_styles
96 * @return string
97 */
98function geometry_styles_to_json($geometry_styles) {
99        $values = explode(',', $geometry_styles);
100        if (count(array_filter($values)) < 1) {
101                return false;
102        }
103        $styles = array();
104        $keys = array('color', 'weight', 'opacity', 'fillColor', 'fillOpacity');
105        foreach ($keys as $index => $key) {
106                if (strlen($values[$index])) {
107                        $styles[$key] = $values[$index];
108                }
109        }
110        return json_encode($styles);
111}
112
113
114
115/**
116 * Renvoie une géométrie couvrant tous les points à une distance donnée de la géométrie d'entrée.
117 *
118 * Cela permet de calculer une zone autour d’un point, d’une ligne ou d’un polygone, à une certaine distance.
119 * Retourne une géométrie (polygone) simplifiée.
120 *
121 * @filtre
122 * @example
123 *     ```
124 *     Dans une boucle GIS :
125 *     #SET{poly,#GEOMETRY|zoner_geometrie{wkt,0.05}}
126 *     #SET{poly,#GEOMETRY|zoner_geometrie{wkt,0.05,0.005}}
127 *     ```
128 *
129 * @note
130 *     Nécessite Mysql 5.6+ ou Mariadb.
131 *
132 * @param string $geometrie
133 *     Géométrie
134 * @param float $distance
135 *     En degrés décimal (si l’unité de géométrie est latitude / longitude…)
136 * @param float|null $tolerance
137 *     Tolérance de simplification des tracés (null, appliquera la valeur par défaut ($distance/20)),
138 *     en degré décimal (si l’unité de géométrie est latitude / longitude…) ;
139 * @return mixed
140 */
141function zoner_geometrie($geometrie, $type = 'wkt', $distance = 0.05, $tolerance = null) {
142        // tolérance… à peu près 1/20 de l’unité de distance (pifomètre)
143        if (is_null($tolerance)) {
144                $tolerance = $distance / 20;
145        }
146
147        // Simplifier le tracé d’origine… le récupérer en wkt
148        $geometrie = simplifier_geometrie($geometrie, $type, $tolerance, 'wkt');
149
150        // Obtenir le zonage demandé
151        $select = 'GeomFromText(' . sql_quote($geometrie) . ')';
152        $select = 'ST_Buffer(' . $select . ', ' . floatval($distance) . ')';
153        #$select = 'ST_Simplify(' . $select . ', ' . floatval($tolerance) . ')'; // mysql 5.7+ (non testé)
154        $select = 'ST_AsText(' . $select . ')';
155        $zone = sql_getfetsel($select);
156
157        // Simplifié le tracé de la zone, le récupérer au format d’entrée
158        $zone = simplifier_geometrie($zone, 'wkt', $tolerance, $type);
159        return $zone;
160}
161
162/**
163 * Simplifier une forme géométrique
164 *
165 * Diminue le nombre de points d’une forme géométrique (lignes, polygones, ...)
166 *
167 * @param mixed $data
168 *     Forme à simplifer, pouvant être lue par geoPHP (json, wkt, ...)
169 * @param string $type
170 *     Type d’entrée de `$data` (json, wkt, ...)
171 * @param float|null $tolerance
172 *     Tolérance de la réduction (en degré décimal si les unités sont latitude/longitude)
173 * @param string $type_sortie
174 *     Type de sortie de la simplification de `$data` (json, wkt, ...)
175 *     Par défaut, le type indiqué en entrée.
176 * @retrun mixed
177 *     Forme simplifiée, dans le même format qu’en entrée.
178 */
179function simplifier_geometrie($data, $type = 'wkt', $tolerance = null, $type_sortie = null) {
180        if (!class_exists('geoPHP_Simplify')) {
181                include_spip('inc/geoPHP_Simplify');
182        }
183        $geometry = geoPHP::load($data, $type);
184        $geometry = geoPHP::geometryReduce($geometry);
185        $geometry = geoPHP_Simplify::geometrySimplify($geometry, $tolerance);
186        $data = $geometry->out($type_sortie ? $type_sortie : $type);
187        return $data;
188}
189
190
191/**
192 * Compile le critère `geometrie_dans_polygone` qui sélectionne des points contenus dans un polygone donné.
193 *
194 * @critere
195 * @see zoner_geometrie() pour créer une zone (polygone) à partir d’un tracé.
196 * @example
197 *     ```
198 *     Dans une boucle GIS : #SET{poly,#GEOMETRY|zoner_geometrie{wkt,0.05}}
199 *     Puis :
200 *     <BOUCLE_points_proches(GIS){type=Point}{geometrie_dans_polygone #GET{poly}}> ...
201 *     ```
202 * @note
203 *     - Nécessite Mysql 5.6 ou Mariadb
204 *     - Si le polygone est trop complexe (nombreux points, le calcul peut être trop long),
205 *       c'est pour cela que zoner_geometrie() simplifie le tracé automatiquement.
206 *
207 * @param string $idb Identifiant de la boucle
208 * @param array $boucles AST du squelette
209 * @param Critere $crit Paramètres du critère dans cette boucle
210 * @return void
211 **/
212function critere_geometrie_dans_polygone_dist($idb, &$boucles, $crit) {
213        $not = $crit->not;
214        $boucle = &$boucles[$idb];
215
216        // prendre en priorite un identifiant en parametre {branche XX}
217        if (isset($crit->param[0])) {
218                $polygon = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
219                // sinon on le prend chez une boucle parente
220        } else {
221                return array('zbug_critere_inconnu', array('critere' => $crit->op));
222        }
223
224        $polygon = kwote($polygon, $boucle->sql_serveur, 'TEXT');
225        if ($not) {
226                $boucle->where[] = array("'='", "'ST_WITHIN(gis.geo, GeomFromText(' . $polygon . '))'", "'0'");
227        } else {
228                $boucle->where[] = array("'='", "'ST_WITHIN(gis.geo, GeomFromText(' . $polygon . '))'", "'1'");
229        }
230
231}
Note: See TracBrowser for help on using the repository browser.