You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gis/gis_fonctions.php

263 lines
8.2 KiB
PHP

<?php
if (!defined("_ECRIRE_INC_VERSION")) return;
/**
* Filtre dec_to_dms, http://www.statemaster.com/encyclopedia/Geographic-coordinate-conversion
*
* @param decimal $coord
* @return string
*/
function dec_to_dms($coord) {
return sprintf(
"%0.0f° %2.3f",
floor(abs($coord)),
60*(abs($coord)-floor(abs($coord)))
);
}
/**
* Filtre dms_to_dec, http://www.statemaster.com/encyclopedia/Geographic-coordinate-conversion
*
* @param string $ref N, E, S, W
* @param int $deg
* @param int $min
* @param int $sec
* @return decimal
*/
function dms_to_dec($ref,$deg,$min,$sec) {
$arrLatLong = array();
$arrLatLong["N"] = 1;
$arrLatLong["E"] = 1;
$arrLatLong["S"] = -1;
$arrLatLong["W"] = -1;
return ($deg+((($min*60)+($sec))/3600)) * $arrLatLong[$ref];
}
/**
* Filtre distance pour renvoyer la distance entre deux points
* http://snipplr.com/view/2531/calculate-the-distance-between-two-coordinates-latitude-longitude/
* sinon voir ici : https://zone.spip.org/trac/spip-zone/browser/_plugins_/forms/geoforms/inc/gPoint.php
*
* @param int $from id_gis du point de référence
* @param int $ti id_gis du point distant
* @param bool $miles renvoyer le résultat en miles (kilomètres par défaut)
* @return
*/
function distance($from,$to,$miles=false) {
$from = sql_fetsel('lat,lon','spip_gis',"id_gis=$from");
$to = sql_fetsel('lat,lon','spip_gis',"id_gis=$to");
$pi80 = M_PI / 180;
$from['lat'] *= $pi80;
$from['lon'] *= $pi80;
$to['lat'] *= $pi80;
$to['lon'] *= $pi80;
$r = 6372.797; // mean radius of Earth in km
$dlat = $to['lat'] - $from['lat'];
$dlng = $to['lon'] - $from['lon'];
$a = sin($dlat / 2) * sin($dlat / 2) + cos($from['lat']) * cos($to['lat']) * sin($dlng / 2) * sin($dlng / 2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$km = $r * $c;
return ($miles ? ($km * 0.621371192) : $km);
}
/**
* Critere {gis distance<XX} pour filtrer une liste de points par rapport à la distance du point de l'env
*
* @param unknown_type $idb
* @param unknown_type $boucles
* @param unknown_type $crit
*/
function critere_gis_dist($idb, &$boucles, $crit) {
$boucle = &$boucles[$idb];
$id = $boucle->primary;
// exclure l'élément en cours des résultats
$id_gis = calculer_argument_precedent($idb,$id, $boucles);
$boucle->where[]= array("'!='", "'$boucle->id_table." . "$id'", $id_gis);
// récupérer les paramètres du critère
$op='';
$params = $crit->param;
$type = array_shift($params);
$type = $type[0]->texte;
if(preg_match(',^(\w+)([<>=]+)([0-9]+)$,',$type,$r)){
$type=$r[1];
$op=$r[2];
$op_val=$r[3];
}
if ($op)
$boucle->having[]= array("'".$op."'", "'".$type."'",$op_val);
// récupérer lat/lon du point de la boucle englobante
$lat = calculer_argument_precedent($idb,'lat', $boucles);
$lon = calculer_argument_precedent($idb,'lon', $boucles);
// http://www.awelty.fr/developpement-web/php/
// http://www.movable-type.co.uk/scripts/latlong-db.html
// http://code.google.com/intl/fr/apis/maps/articles/geospatial.html#geospatial
$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";
$order = "'distance'";
$boucle->select[]= $select;
$boucle->order[]= $order;
}
/**
* Balise #DISTANCE issue du critère {gis distance<XX}
* merci marcimant : http://formation.magraine.net/spip.php?article61
*
* @param unknown_type $p
*/
function balise_distance_dist($p) {
return rindex_pile($p, 'distance', 'gis');
}
function generer_url_ecrire_gis($id, $args='', $ancre='', $statut='', $connect='') {
$a = "id_gis=" . intval($id);
if (!$statut) {
$statut = sql_getfetsel('statut', 'spip_articles', $a,'','','','',$connect);
}
$h = generer_url_ecrire('gis', $a . ($args ? "&$args" : ''))
. ($ancre ? "#$ancre" : '');
return $h;
}
/**
* Définition de l'API à utiliser en prenant compte les defines
*/
function gis_api_utilisee(){
$defaut = 'openlayers';
if(defined('_GIS_APIS_FORCEE')){
return _GIS_APIS_FORCEE;
}else{
if(defined('_GIS_APIS_DEFAUT')){
$defaut = _GIS_APIS_DEFAUT;
}
$config = @unserialize($GLOBALS['meta']['gis']);
return $config['api'] ? $config['api'] : $defaut;
}
}
/**
* Définition du fond cartographique à utiliser en prenant compte les defines
*/
function gis_maptype_utilise(){
$defaut = 'ROAD';
if(defined('_GIS_MAPTYPES_FORCE')){
return _GIS_MAPTYPES_FORCE;
}else{
if(defined('_GIS_MAPTYPES_DEFAUT')){
$defaut = _GIS_MAPTYPES_DEFAUT;
}
$config = @unserialize($GLOBALS['meta']['gis']);
return $config['maptype'] ? $config['maptype'] : $defaut;
}
}
// Cluster côté serveur
// http://www.appelsiini.net/2008/11/introduction-to-marker-clustering-with-google-maps
define('OFFSET', 268435456);
define('RADIUS', 85445659.4471); /* $offset / pi() */
function lonToX($lon) {
return round(OFFSET + RADIUS * $lon * pi() / 180);
}
function latToY($lat) {
return round(OFFSET - RADIUS *
log((1 + sin($lat * pi() / 180)) /
(1 - sin($lat * pi() / 180))) / 2);
}
function pixelDistance($lat1, $lon1, $lat2, $lon2, $zoom) {
$x1 = lonToX($lon1);
$y1 = latToY($lat1);
$x2 = lonToX($lon2);
$y2 = latToY($lat2);
return sqrt(pow(($x1-$x2),2) + pow(($y1-$y2),2)) >> (21 - $zoom);
}
function filtre_gis_cluster($flux, $distance=40, $zoom=3) {
$json = json_decode($flux,true);
$markers = $json['features'];
spip_log("total markers avant cluster ".count($markers),"bb");
$clustered = array();
/* Loop until all markers have been compared. */
while (count($markers)) {
$marker = array_pop($markers);
$cluster = array();
/* Compare against all markers which are left. */
foreach ($markers as $key => $target) {
$pixels = pixelDistance($marker['geometry']['coordinates'][1], $marker['geometry']['coordinates'][0],
$target['geometry']['coordinates'][1], $target['geometry']['coordinates'][0],
$zoom);
/* If two markers are closer than given distance remove */
/* target marker from array and add it to cluster. */
if ($distance > $pixels) {
unset($markers[$key]);
$cluster[] = $target;
}
}
/* If a marker has been added to cluster, add also the one */
/* we were comparing to and remove the original from array. */
if (count($cluster) > 0) {
$cluster[] = $marker;
$clustered[] = $cluster;
} else {
$clustered[] = $marker;
}
}
$result = array();
spip_log("total markers apres cluster ".count($clustered),"bb");
// crer les markers pour les clusters
foreach ($clustered as $key => $cluster) {
if (is_array($cluster[0])) {
$nb_markers = count($cluster);
// le cluster est centré sur le dernier point du tableau
// car c'est le point de référence pour les calculs de distance
$result[$key] = array_pop($cluster);
// on colle le nombre de points du cluster dans le titre du marker
$result[$key]['properties']['title'] = json_encode($nb_markers);
// marquer les markers qui sont des clusters, attribut category dans mxn.addJSON()
$result[$key]['properties']['category'] = 'cluster';
// pas d'infoBubble pour les markers de cluster
$result[$key]['properties']['infoBubble'] = '';
// récupérer les bounds pour afficher l'enssemble des points du clusters
$bounds = array(
'sw_lat' => $result[$key]['geometry']['coordinates'][1],
'sw_lon' => $result[$key]['geometry']['coordinates'][0],
'ne_lat' => $result[$key]['geometry']['coordinates'][1],
'ne_lon' => $result[$key]['geometry']['coordinates'][0]
);
foreach ($cluster as $marker) {
if ($bounds['sw_lat'] > $marker['geometry']['coordinates'][1])
$bounds['sw_lat'] = $marker['geometry']['coordinates'][1];
if ($bounds['sw_lon'] > $marker['geometry']['coordinates'][0])
$bounds['sw_lon'] = $marker['geometry']['coordinates'][0];
if ($bounds['ne_lat'] < $marker['geometry']['coordinates'][1])
$bounds['ne_lat'] = $marker['geometry']['coordinates'][1];
if ($bounds['ne_lon'] < $marker['geometry']['coordinates'][0])
$bounds['ne_lon'] = $marker['geometry']['coordinates'][0];
}
// on passe les bounds du cluster dans le champ data du marker
$result[$key]['properties']['data'] = $bounds;
} else {
$result[$key] = $cluster;
}
}
$result = '{"type": "FeatureCollection", "features": ' . json_encode($result) .'}';
return $result;
}
?>