mirror of
https://github.com/Dolibarr/dolibarr.git
synced 2025-02-20 13:46:52 +01:00
NEW add geometrics extrafield (#28239)
* add extrafield point * wip * wip * wip * input * input * output values * update values * update values * update values * update values * update values * wip * add geomapeditor * add geomapeditor * add linestring and polygon * add linestring and polygon * add linestring and polygon * add linestring and polygon * wip * wip * can store and retrieve linestring * can store and retrieve linestring * coordinates are inverted * coordinates are inverted * add multipoints * use text instead binary * auto center map * wip wip * doc * fix * wip * wip * translation dynamic --------- Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
This commit is contained in:
parent
26920d2cb3
commit
7ea6a406bd
|
|
@ -3669,6 +3669,10 @@ EditWithEditor
|
|||
ElementId
|
||||
ElementType
|
||||
ErrorABatchShouldNotContainsSpaces
|
||||
ExtrafieldLinestringGeo
|
||||
ExtrafieldMultiPointGeo
|
||||
ExtrafieldPointGeo
|
||||
ExtrafieldPolygonGeo
|
||||
ImageGeneration
|
||||
ModelTemplate
|
||||
ModuleWebPortalDesc
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ if ($action == 'add') {
|
|||
|
||||
// Visibility: -1=not visible by default in list, 1=visible, 0=hidden
|
||||
$visibility = GETPOST('list', 'alpha');
|
||||
if ($type == 'separate') {
|
||||
if (in_array($type, ['separate', 'point', 'linestrg', 'polygon'])) {
|
||||
$visibility = 3;
|
||||
}
|
||||
|
||||
|
|
@ -360,7 +360,7 @@ if ($action == 'update') {
|
|||
|
||||
// Visibility: -1=not visible by default in list, 1=visible, 0=hidden
|
||||
$visibility = GETPOST('list', 'alpha');
|
||||
if ($type == 'separate') {
|
||||
if (in_array($type, ['separate', 'point', 'linestrg', 'polygon'])) {
|
||||
$visibility = 3;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6323,9 +6323,22 @@ abstract class CommonObject
|
|||
if (is_array($optionsArray) && count($optionsArray) > 0) {
|
||||
$sql = "SELECT rowid";
|
||||
foreach ($optionsArray as $name => $label) {
|
||||
if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] != 'separate') {
|
||||
if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || (!in_array($extrafields->attributes[$this->table_element]['type'][$name], ['separate', 'point', 'multipts', 'linestrg','polygon']))) {
|
||||
$sql .= ", ".$name;
|
||||
}
|
||||
// use geo sql fonction to read as text
|
||||
if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] == 'point') {
|
||||
$sql .= ", ST_AsWKT(".$name.") as ".$name;
|
||||
}
|
||||
if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] == 'multipts') {
|
||||
$sql .= ", ST_AsWKT(".$name.") as ".$name;
|
||||
}
|
||||
if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] == 'linestrg') {
|
||||
$sql .= ", ST_AsWKT(".$name.") as ".$name;
|
||||
}
|
||||
if (empty($extrafields->attributes[$this->table_element]['type'][$name]) || $extrafields->attributes[$this->table_element]['type'][$name] == 'polygon') {
|
||||
$sql .= ", ST_AsWKT(".$name.") as ".$name;
|
||||
}
|
||||
}
|
||||
$sql .= " FROM ".$this->db->prefix().$table_element."_extrafields";
|
||||
$sql .= " WHERE fk_object = ".((int) $rowid);
|
||||
|
|
@ -6671,13 +6684,41 @@ abstract class CommonObject
|
|||
foreach ($new_array_options as $key => $value) {
|
||||
$attributeKey = substr($key, 8); // Remove 'options_' prefix
|
||||
// Add field of attribute
|
||||
if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] != 'separate') { // Only for other type than separator)
|
||||
if (!in_array($extrafields->attributes[$this->table_element]['type'][$attributeKey], ['separate', 'point', 'multipts', 'linestrg', 'polygon'])) { // Only for other type than separator)
|
||||
if ($new_array_options[$key] != '' || $new_array_options[$key] == '0') {
|
||||
$sql .= ",'".$this->db->escape($new_array_options[$key])."'";
|
||||
} else {
|
||||
$sql .= ",null";
|
||||
}
|
||||
}
|
||||
if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] == 'point') { // for point type
|
||||
if (!empty($new_array_options[$key])) {
|
||||
$sql .= ",ST_PointFromText('".$this->db->escape($new_array_options[$key])."')";
|
||||
} else {
|
||||
$sql .= ",null";
|
||||
}
|
||||
}
|
||||
if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] == 'multipts') { // for point type
|
||||
if (!empty($new_array_options[$key])) {
|
||||
$sql .= ",ST_MultiPointFromText('".$this->db->escape($new_array_options[$key])."')";
|
||||
} else {
|
||||
$sql .= ",null";
|
||||
}
|
||||
}
|
||||
if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] == 'linestrg') { // for linestring type
|
||||
if (!empty($new_array_options[$key])) {
|
||||
$sql .= ",ST_LineFromText('".$this->db->escape($new_array_options[$key])."')";
|
||||
} else {
|
||||
$sql .= ",null";
|
||||
}
|
||||
}
|
||||
if ($extrafields->attributes[$this->table_element]['type'][$attributeKey] == 'polygon') { // for polygon type
|
||||
if (!empty($new_array_options[$key])) {
|
||||
$sql .= ",ST_PolyFromText('".$this->db->escape($new_array_options[$key])."')";
|
||||
} else {
|
||||
$sql .= ",null";
|
||||
}
|
||||
}
|
||||
}
|
||||
// We must insert a default value for fields for other entities that are mandatory to avoid not null error
|
||||
if (!empty($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities']) && is_array($extrafields->attributes[$this->table_element]['mandatoryfieldsofotherentities'])) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
* Copyright (C) 2015-2023 Charlene BENKE <charlene@patas-monkey.com>
|
||||
* Copyright (C) 2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
|
||||
* Copyright (C) 2017 Nicolas ZABOURI <info@inovea-conseil.com>
|
||||
* Copyright (C) 2018-2022 Frédéric France <frederic.france@netlogic.fr>
|
||||
* Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
|
||||
* Copyright (C) 2022 Antonin MARCHAL <antonin@letempledujeu.fr>
|
||||
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
|
||||
*
|
||||
|
|
@ -47,7 +47,7 @@ class ExtraFields
|
|||
/**
|
||||
* @var array<string,array{label:array<string,string>,type:array<string,string>,size:array<string,string>,default:array<string,string>,computed:array<string,string>,unique:array<string,int>,required:array<string,int>,param:array<string,mixed>,perms:array<string,mixed[]>,list:array<string,int|string>,pos:array<string,int>,totalizable:array<string,int>,help:array<string,string>,printable:array<string,int>,enabled:array<string,int>,langfile:array<string,string>,css:array<string,string>,csslist:array<string,string>,hidden:array<string,int>,mandatoryfieldsofotherentities:array<string,string>,loaded?:int,count:int}> New array to store extrafields definition Note: count set as present to avoid static analysis notices
|
||||
*/
|
||||
public $attributes;
|
||||
public $attributes = array();
|
||||
|
||||
/**
|
||||
* @var array<string,bool> Array with boolean of status of groups
|
||||
|
|
@ -96,6 +96,10 @@ class ExtraFields
|
|||
'checkbox' => 'ExtrafieldCheckBox',
|
||||
'chkbxlst' => 'ExtrafieldCheckBoxFromList',
|
||||
'link' => 'ExtrafieldLink',
|
||||
'point' => 'ExtrafieldPointGeo',
|
||||
'multipts' => 'ExtrafieldMultiPointGeo',
|
||||
'linestrg' => 'ExtrafieldLinestringGeo',
|
||||
'polygon' => 'ExtrafieldPolygonGeo',
|
||||
'separate' => 'ExtrafieldSeparator',
|
||||
);
|
||||
|
||||
|
|
@ -107,9 +111,6 @@ class ExtraFields
|
|||
public function __construct($db)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->error = '';
|
||||
$this->errors = array();
|
||||
$this->attributes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -312,6 +313,18 @@ class ExtraFields
|
|||
} elseif ($type == 'link') {
|
||||
$typedb = 'int';
|
||||
$lengthdb = '11';
|
||||
} elseif ($type == 'point') {
|
||||
$typedb = 'point';
|
||||
$lengthdb = '';
|
||||
} elseif ($type == 'multipts') {
|
||||
$typedb = 'multipoint';
|
||||
$lengthdb = '';
|
||||
} elseif ($type == 'linestrg') {
|
||||
$typedb = 'linestring';
|
||||
$lengthdb = '';
|
||||
} elseif ($type == 'polygon') {
|
||||
$typedb = 'polygon';
|
||||
$lengthdb = '';
|
||||
} elseif ($type == 'html') {
|
||||
$typedb = 'text';
|
||||
$lengthdb = $length;
|
||||
|
|
@ -670,6 +683,18 @@ class ExtraFields
|
|||
} elseif ($type == 'link') {
|
||||
$typedb = 'int';
|
||||
$lengthdb = '11';
|
||||
} elseif ($type == 'point') {
|
||||
$typedb = 'point';
|
||||
$lengthdb = '';
|
||||
} elseif ($type == 'multipts') {
|
||||
$typedb = 'multipoint';
|
||||
$lengthdb = '';
|
||||
} elseif ($type == 'linestrg') {
|
||||
$typedb = 'linestring';
|
||||
$lengthdb = '';
|
||||
} elseif ($type == 'polygon') {
|
||||
$typedb = 'polygon';
|
||||
$lengthdb = '';
|
||||
} elseif ($type == 'password') {
|
||||
$typedb = 'varchar';
|
||||
$lengthdb = '128';
|
||||
|
|
@ -1686,6 +1711,24 @@ class ExtraFields
|
|||
|
||||
//$out = $form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss, '', 0, 0, '');
|
||||
$out = $form->selectForForms($tmparray[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss, '', 0, 0, '', $element.':options_'.$key);
|
||||
} elseif (in_array($type, ['point', 'multipts', 'linestrg', 'polygon'])) {
|
||||
require_once DOL_DOCUMENT_ROOT.'/includes/geoPHP/geoPHP.inc.php';
|
||||
$geojson = '{}';
|
||||
$centroidjson = getDolGlobalString('MAIN_INFO_SOCIETE_GEO_COORDINATES', '{}');
|
||||
if (!empty($value)) {
|
||||
$geom = geoPHP::load($value, 'wkt');
|
||||
$geojson = $geom->out('json');
|
||||
$centroid = $geom->getCentroid();
|
||||
$centroidjson = $centroid->out('json');
|
||||
}
|
||||
if (!preg_match('/search_/', $keyprefix)) {
|
||||
require_once DOL_DOCUMENT_ROOT.'/core/class/geomapeditor.class.php';
|
||||
$geomapeditor = new GeoMapEditor();
|
||||
$out .= $geomapeditor->getHtml($keyprefix.$key.$keysuffix, $geojson, $centroidjson, $type);
|
||||
} else {
|
||||
// If keyprefix is search_ or search_options_, we must just use a simple text field
|
||||
$out = ''; // @phan-suppress-current-line PhanPluginRedundantAssignment
|
||||
}
|
||||
} elseif ($type == 'password') {
|
||||
// If prefix is 'search_', field is used as a filter, we use a common text field.
|
||||
$out = '<input style="display:none" type="text" name="fakeusernameremembered">'; // Hidden field to reduce impact of evil Google Chrome autopopulate bug.
|
||||
|
|
@ -2050,6 +2093,22 @@ class ExtraFields
|
|||
return 'Error bad setup of extrafield';
|
||||
}
|
||||
}
|
||||
} elseif ($type == 'point') {
|
||||
require_once DOL_DOCUMENT_ROOT.'/includes/geoPHP/geoPHP.inc.php';
|
||||
if (!empty($value)) {
|
||||
$geom = geoPHP::load($value, 'wkt');
|
||||
$value = $geom->x().' '.$geom->y();
|
||||
} else {
|
||||
$value = '';
|
||||
}
|
||||
} elseif (in_array($type, ['multipts','linestrg', 'polygon'])) {
|
||||
require_once DOL_DOCUMENT_ROOT.'/includes/geoPHP/geoPHP.inc.php';
|
||||
if (!empty($value)) {
|
||||
$geom = geoPHP::load($value, 'wkt');
|
||||
$value = get_class($geom) . ' : '. $geom->numPoints() . ' Points';
|
||||
} else {
|
||||
$value = '';
|
||||
}
|
||||
} elseif ($type == 'text') {
|
||||
$value = dol_htmlentitiesbr($value);
|
||||
} elseif ($type == 'html') {
|
||||
|
|
@ -2233,7 +2292,7 @@ class ExtraFields
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!empty($onlykey) && $onlykey == '@GETPOSTISSET' && !GETPOSTISSET('options_'.$key) && (! in_array($this->attributes[$object->table_element]['type'][$key], array('boolean', 'checkbox', 'chkbxlst')))) {
|
||||
if (!empty($onlykey) && $onlykey == '@GETPOSTISSET' && !GETPOSTISSET('options_'.$key) && (! in_array($this->attributes[$object->table_element]['type'][$key], array('boolean', 'checkbox', 'chkbxlst', 'point', 'multipts', 'linestrg', 'polygon')))) {
|
||||
//when unticking boolean field, it's not set in POST
|
||||
continue;
|
||||
}
|
||||
|
|
@ -2319,6 +2378,16 @@ class ExtraFields
|
|||
$value_key = price2num(GETPOST("options_".$key, 'alpha')).':'.GETPOST("options_".$key."currency_id", 'alpha');
|
||||
} elseif (in_array($key_type, array('html'))) {
|
||||
$value_key = GETPOST("options_".$key, 'restricthtml');
|
||||
} elseif (in_array($key_type, ['point', 'multipts', 'linestrg', 'polygon'])) {
|
||||
// construct point
|
||||
require_once DOL_DOCUMENT_ROOT.'/includes/geoPHP/geoPHP.inc.php';
|
||||
$geojson = GETPOST("options_".$key, 'restricthtml');
|
||||
if ($geojson != '{}') {
|
||||
$geom = geoPHP::load($geojson, 'json');
|
||||
$value_key = $geom->out('wkt');
|
||||
} else {
|
||||
$value_key = '';
|
||||
}
|
||||
} elseif (in_array($key_type, array('text'))) {
|
||||
$label_security_check = 'alphanohtml';
|
||||
// by default 'alphanohtml' (better security); hidden conf MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML allows basic html
|
||||
|
|
|
|||
231
htdocs/core/class/geomapeditor.class.php
Normal file
231
htdocs/core/class/geomapeditor.class.php
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
<?php
|
||||
/* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
* or see https://www.gnu.org/
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file htdocs/core/class/geomapeditor.class.php
|
||||
* \brief Class to manage a leaflet map width geometrics objects
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to manage a Leaflet map width geometrics objects
|
||||
*/
|
||||
class GeoMapEditor
|
||||
{
|
||||
/**
|
||||
* __contruct
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* getHtml
|
||||
*
|
||||
* @param string $htmlname htmlname
|
||||
* @param string $geojson json of geometric objects
|
||||
* @param string $centroidjson json of geometric center of object
|
||||
* @param string $markertype type of marker, point, multipts, linestrg, polygon
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHtml($htmlname, $geojson, $centroidjson, $markertype)
|
||||
{
|
||||
global $langs;
|
||||
|
||||
$out = '<input id="' . $htmlname . '" name="' . $htmlname . '" size="100" value="' . htmlentities($geojson, ENT_QUOTES) . '"/>';
|
||||
$out .= '<div id="map_' . $htmlname . '" style="width: 600px; height: 350px;"></div>';
|
||||
if ($geojson != '{}') {
|
||||
// OpenLayers it's "longitude, latitude".
|
||||
// inverting coordinates
|
||||
$tmp = json_decode($geojson);
|
||||
$tmp2 = new stdClass();
|
||||
$tmp2->type = $tmp->type;
|
||||
$tmp2->coordinates = [];
|
||||
if ($tmp->type == 'Point') {
|
||||
$tmp2->coordinates = [$tmp->coordinates[1], $tmp->coordinates[0]];
|
||||
} elseif ($tmp->type == 'Polygon') {
|
||||
foreach ($tmp->coordinates as $polygon) {
|
||||
$polyg = [];
|
||||
foreach ($polygon as $key => $value) {
|
||||
$polyg[] = [$value[1], $value[0]];
|
||||
}
|
||||
$tmp2->coordinates[] = $polyg;
|
||||
}
|
||||
} else {
|
||||
foreach ($tmp->coordinates as $key => $value) {
|
||||
$tmp2->coordinates[] = [$value[1], $value[0]];
|
||||
}
|
||||
}
|
||||
$geojson = json_encode($tmp2);
|
||||
}
|
||||
if ($centroidjson != '{}') {
|
||||
if (null === json_decode($centroidjson)) {
|
||||
$centroidjson = '{}';
|
||||
} else {
|
||||
// OpenLayers it's "longitude, latitude".
|
||||
// inverting coordinates
|
||||
$tmp = json_decode($centroidjson);
|
||||
$tmp2 = new stdClass();
|
||||
$tmp2->type = $tmp->type;
|
||||
$tmp2->coordinates = [];
|
||||
if ($tmp->type == 'Point') {
|
||||
$tmp2->coordinates = [$tmp->coordinates[1], $tmp->coordinates[0]];
|
||||
} else {
|
||||
foreach ($tmp->coordinates as $key => $value) {
|
||||
$tmp2->coordinates[] = [$value[1], $value[0]];
|
||||
}
|
||||
}
|
||||
$centroidjson = json_encode($tmp2);
|
||||
}
|
||||
}
|
||||
$out .= '
|
||||
<script>
|
||||
var geoms = JSON.parse(\'' . $geojson . '\');
|
||||
var centroid = JSON.parse(\'' . $centroidjson . '\');
|
||||
var markerType = "' . $markertype . '";
|
||||
var map = L.map("map_' . $htmlname . '");
|
||||
console.log(markerType);
|
||||
console.log(geoms);
|
||||
map.pm.addControls({
|
||||
position: \'topleft\',
|
||||
dragMode: false,
|
||||
drawMarker: false,
|
||||
drawCircle:false,
|
||||
drawCircleMarker: false,
|
||||
drawText: false,
|
||||
drawRectangle: false,
|
||||
editMode: true,
|
||||
removalMode: true,
|
||||
rotateMode: false,
|
||||
customControls: false,
|
||||
});
|
||||
console.log(centroid);
|
||||
if (centroid.type == "Point") {
|
||||
map.setView(centroid.coordinates, 11);
|
||||
} else {
|
||||
map.setView([48.852, 2.351], 12);
|
||||
}
|
||||
if (markerType == "point" && Object.keys(geoms).length != 0) {
|
||||
//map.setView(geoms.coordinates, 17);
|
||||
L.marker(geoms.coordinates).addTo(map);
|
||||
// disableMarkers();
|
||||
map.pm.addControls({
|
||||
drawMarker: false,
|
||||
drawPolyline: false,
|
||||
drawPolygon: false,
|
||||
});
|
||||
} else if (markerType == "multipts" && Object.keys(geoms).length != 0) {
|
||||
L.multipoint(geoms.coordinates).addTo(map);
|
||||
} else if (markerType == "linestrg" && Object.keys(geoms).length != 0) {
|
||||
L.polyline(geoms.coordinates).addTo(map);
|
||||
} else if (markerType == "polygon" && Object.keys(geoms).length != 0) {
|
||||
L.polygon(geoms.coordinates).addTo(map);
|
||||
} else if (Object.keys(geoms).length === 0) {
|
||||
// map.setView([48.852, 2.351], 12);
|
||||
}
|
||||
var tiles = L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||
maxZoom: 19,
|
||||
attribution: \'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>\'
|
||||
}).addTo(map);
|
||||
map.pm.setLang("' . ($langs->shortlang ?? 'en') . '");
|
||||
|
||||
enableMarker(markerType);
|
||||
// if (geoms && geoms.type == "Point") {
|
||||
// L.marker([geoms.coordinates[1], geoms.coordinates[0]]).addTo(map);
|
||||
// disableMarkers();
|
||||
// }
|
||||
map.on("pm:drawend", (e) => {
|
||||
disableMarkers();
|
||||
generateGeoJson();
|
||||
console.log("pm:drawend");
|
||||
console.log(e);
|
||||
});
|
||||
map.on("pm:markerdragend", (e) => {
|
||||
disableMarkers();
|
||||
generateGeoJson();
|
||||
console.log("pm:markerdragend");
|
||||
console.log(e);
|
||||
});
|
||||
map.on("pm:remove", (e) => {
|
||||
enableMarker();
|
||||
console.log(e);
|
||||
$("#' . $htmlname . '").val ("{}");
|
||||
});
|
||||
map.on("pm:edit", (e) => {
|
||||
console.log("pm:edit");
|
||||
generateGeoJson();
|
||||
});
|
||||
map.on("pm:create", (e) => {
|
||||
console.log("pm:create");
|
||||
generateGeoJson();
|
||||
});
|
||||
map.on("pm:globaleditmodetoggled", (e) => {
|
||||
generateGeoJson();
|
||||
console.log(e);
|
||||
});
|
||||
function enableMarker(type) {
|
||||
console.log("enable : " + type);
|
||||
if (type == "point") {
|
||||
map.pm.addControls({
|
||||
drawMarker: true
|
||||
});
|
||||
};
|
||||
}
|
||||
function disableMarkers(){
|
||||
map.pm.addControls({
|
||||
drawMarker: false,
|
||||
drawPolyline: false,
|
||||
drawPolygon: false,
|
||||
});
|
||||
}
|
||||
|
||||
function generateGeoJson(){
|
||||
var fg = L.featureGroup();
|
||||
var layers = findLayers(map);
|
||||
layers.forEach(function(layer){
|
||||
fg.addLayer(layer);
|
||||
});
|
||||
console.log(fg.toGeoJSON());
|
||||
$("#' . $htmlname . '").val (JSON.stringify(fg.toGeoJSON().features[0].geometry));
|
||||
}
|
||||
function findLayers(map) {
|
||||
// https://stackoverflow.com/questions/62887120/leafletjs-geoman-into-json-data
|
||||
var layers = [];
|
||||
map.eachLayer(layer => {
|
||||
if (
|
||||
layer instanceof L.Polyline || // Don"t worry about Polygon and Rectangle they are included in Polyline
|
||||
layer instanceof L.Marker ||
|
||||
layer instanceof L.Circle ||
|
||||
layer instanceof L.CircleMarker
|
||||
) {
|
||||
layers.push(layer);
|
||||
}
|
||||
});
|
||||
// filter out layers that don"t have the leaflet-geoman instance
|
||||
layers = layers.filter(layer => !!layer.pm);
|
||||
// filter out everything that"s leaflet-geoman specific temporary stuff
|
||||
layers = layers.filter(layer => !layer._pmTempLayer);
|
||||
return layers;
|
||||
}
|
||||
</script>';
|
||||
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
|
|
@ -4593,6 +4593,11 @@ function getPictoForType($key)
|
|||
'checkbox' => 'check-square',
|
||||
'chkbxlst' => 'check-square',
|
||||
'link' => 'link',
|
||||
'icon' => "question",
|
||||
'point' => "country",
|
||||
'multipts' => 'country',
|
||||
'linestrg' => "country",
|
||||
'polygon' => "country",
|
||||
'separate' => 'minus'
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php<br>Contact:con
|
|||
else if (type == 'checkbox') { size.val('').prop('disabled', true); unique.removeAttr('checked').prop('disabled', true); jQuery("#value_choice").show(); jQuery(".spanforparamtooltip").hide(); jQuery("#helpselect").show();}
|
||||
else if (type == 'chkbxlst') { size.val('').prop('disabled', true); unique.removeAttr('checked').prop('disabled', true); jQuery("#value_choice").show(); jQuery(".spanforparamtooltip").hide(); jQuery("#helpchkbxlst").show();}
|
||||
else if (type == 'link') { size.val('').prop('disabled', true); unique.removeAttr('disabled'); jQuery("#value_choice").show(); jQuery(".spanforparamtooltip").hide(); jQuery("#helplink").show();}
|
||||
else if (type == 'point') { size.val('').prop('disabled', true); unique.removeAttr('disabled'); jQuery("#value_choice").show(); jQuery(".spanforparamtooltip").hide(); jQuery("#helplink").show();}
|
||||
else if (type == 'linestrg') { size.val('').prop('disabled', true); unique.removeAttr('disabled'); jQuery("#value_choice").show(); jQuery(".spanforparamtooltip").hide(); jQuery("#helplink").show();}
|
||||
else if (type == 'polygon') { size.val('').prop('disabled', true); unique.removeAttr('disabled'); jQuery("#value_choice").show(); jQuery(".spanforparamtooltip").hide(); jQuery("#helplink").show();}
|
||||
else if (type == 'separate') {
|
||||
langfile.val('').prop('disabled',true);size.val('').prop('disabled', true); unique.removeAttr('checked').prop('disabled', true); required.val('').prop('disabled', true);
|
||||
jQuery("#value_choice").show();
|
||||
|
|
@ -114,7 +117,7 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php<br>Contact:con
|
|||
unique.removeAttr('disabled');
|
||||
}
|
||||
|
||||
if (type == 'separate')
|
||||
if (type == 'separate' || type == 'point' || type == 'linestrg' || type == 'polygon')
|
||||
{
|
||||
required.removeAttr('checked').prop('disabled', true); alwayseditable.removeAttr('checked').prop('disabled', true); list.removeAttr('checked').prop('disabled', true);
|
||||
jQuery('#size, #default_value, #langfile').val('').prop('disabled', true);
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php<br>Contact:con
|
|||
print 'jQuery("#value_choice").hide();';
|
||||
}
|
||||
|
||||
if (GETPOST('type', 'alpha') == "separate") {
|
||||
if (in_array(GETPOST('type', 'alpha'), ["separate", 'point', 'linestrg', 'polygon'])) {
|
||||
print "jQuery('#size, #default_value, #langfile').val('').prop('disabled', true);";
|
||||
print 'jQuery("#value_choice").hide();';
|
||||
}
|
||||
|
|
@ -113,7 +113,7 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php<br>Contact:con
|
|||
unique.removeAttr('disabled');
|
||||
}
|
||||
|
||||
if (type == 'separate')
|
||||
if (type == 'separate' || type == 'point' || type == 'linestrg' || type == 'polygon')
|
||||
{
|
||||
required.removeAttr('checked').prop('disabled', true); alwayseditable.removeAttr('checked').prop('disabled', true); list.removeAttr('checked').prop('disabled', true);
|
||||
jQuery('#size, #default_value, #langfile').val('').prop('disabled', true);
|
||||
|
|
|
|||
1
htdocs/includes/geoPHP/.gitignore
vendored
Normal file
1
htdocs/includes/geoPHP/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/vendor
|
||||
29
htdocs/includes/geoPHP/.travis.yml
Normal file
29
htdocs/includes/geoPHP/.travis.yml
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# docs available at http://docs.travis-ci.com/user/languages/php/
|
||||
# example available at https://github.com/travis-ci/travis-ci-php-example
|
||||
language: php
|
||||
|
||||
before_script:
|
||||
- composer self-update
|
||||
|
||||
env: GEOPHP_RUN_TESTS=1
|
||||
|
||||
install:
|
||||
- composer install
|
||||
# TODO Install geos library -- as a matrix test
|
||||
# TODO optionally set up a postgis database for testing
|
||||
|
||||
script:
|
||||
- cd tests
|
||||
- phpunit --verbose --colors --stderr tests
|
||||
- php test.php
|
||||
|
||||
# run tests on the following versions
|
||||
php:
|
||||
- 5.6
|
||||
- 5.5
|
||||
- 5.4
|
||||
- 5.3
|
||||
- hhvm
|
||||
|
||||
matrix:
|
||||
fast_finish: false
|
||||
370
htdocs/includes/geoPHP/LICENSE
Normal file
370
htdocs/includes/geoPHP/LICENSE
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
Copyright (c) 2011, Patrick Hayes and contributors
|
||||
|
||||
This program is dual-licensed under both the GPL version 2 (or later) and
|
||||
Modified BSD License. Either license may be used at your option.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Modified BSD License
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of the contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
155
htdocs/includes/geoPHP/README.md
Normal file
155
htdocs/includes/geoPHP/README.md
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
[](https://travis-ci.org/phayes/geoPHP)
|
||||
|
||||
[geophp.net](https://geophp.net "GeoPHP homepage")
|
||||
|
||||
|
||||
GeoPHP is a open-source native PHP library for doing geometry operations. It is written entirely in PHP and
|
||||
can therefore run on shared hosts. It can read and write a wide variety of formats: WKT (including EWKT), WKB (including EWKB), GeoJSON,
|
||||
KML, GPX, and GeoRSS. It works with all Simple-Feature geometries (Point, LineString, Polygon, GeometryCollection etc.)
|
||||
and can be used to get centroids, bounding-boxes, area, and a wide variety of other useful information.
|
||||
|
||||
geoPHP also helpfully wraps the GEOS php extension so that applications can get a transparent performance
|
||||
increase when GEOS is installed on the server. When GEOS is installed, geoPHP also becomes
|
||||
fully compliant with the OpenGIS® Implementation Standard for Geographic information. With GEOS you get the
|
||||
full-set of openGIS functions in PHP like Union, IsWithin, Touches etc. This means that applications
|
||||
get a useful "core-set" of geometry operations that work in all environments, and an "extended-set"of operations
|
||||
for environments that have GEOS installed.
|
||||
|
||||
See the 'getting started' section below for references and examples of everything that geoPHP can do.
|
||||
|
||||
This project is currently looking for co-maintainers. If you think you can help out, please send me a
|
||||
message. Forks are also welcome, please issue pull requests and I will merge them into the main branch.
|
||||
|
||||
Getting Started
|
||||
-----------------------
|
||||
|
||||
* The lastest stable version can always be downloaded at: <https://phayes.github.io/bin/current/geoPHP/geoPHP.tar.gz>
|
||||
* Read the API Reference at: <https://geophp.net/api.html>
|
||||
* Examples
|
||||
* Using geoPHP as a GIS format converter: <http://github.com/phayes/geoPHP/wiki/Example-format-converter>
|
||||
* Other Interesting Links:
|
||||
* Learn about GEOS integration at: <https://geophp.net/geos.html>
|
||||
|
||||
Example usage
|
||||
-------------------------------------------------
|
||||
|
||||
```php
|
||||
<?php
|
||||
include_once('geoPHP.inc');
|
||||
|
||||
// Polygon WKT example
|
||||
$polygon = geoPHP::load('POLYGON((1 1,5 1,5 5,1 5,1 1),(2 2,2 3,3 3,3 2,2 2))','wkt');
|
||||
$area = $polygon->getArea();
|
||||
$centroid = $polygon->getCentroid();
|
||||
$centX = $centroid->getX();
|
||||
$centY = $centroid->getY();
|
||||
|
||||
print "This polygon has an area of ".$area." and a centroid with X=".$centX." and Y=".$centY;
|
||||
|
||||
// MultiPoint json example
|
||||
print "<br/>";
|
||||
$json =
|
||||
'{
|
||||
"type": "MultiPoint",
|
||||
"coordinates": [
|
||||
[100.0, 0.0], [101.0, 1.0]
|
||||
]
|
||||
}';
|
||||
|
||||
$multipoint = geoPHP::load($json, 'json');
|
||||
$multipoint_points = $multipoint->getComponents();
|
||||
$first_wkt = $multipoint_points[0]->out('wkt');
|
||||
|
||||
print "This multipoint has ".$multipoint->numGeometries()." points. The first point has a wkt representation of ".$first_wkt;
|
||||
```
|
||||
=======
|
||||
|
||||
More Examples
|
||||
-------------------------------------------------
|
||||
|
||||
The Well Known Text (WKT) and Well Known Binary (WKB) support is ideal for integrating with MySQL's or PostGIS's spatial capability.
|
||||
Once you have SELECTed your data with `'AsText('geo_field')'` or `'AsBinary('geo_field')'`, you can put it straight into
|
||||
geoPHP (can be wkt or wkb, but must be the same as how you extracted it from your database):
|
||||
|
||||
$geom = geoPHP::load($dbRow,'wkt');
|
||||
|
||||
You can collect multiple geometries into one (note that you must use wkt for this):
|
||||
|
||||
$geom = geoPHP::load("GEOMETRYCOLLECTION(".$dbString1.",".$dbString2.")",'wkt');
|
||||
|
||||
Calling get components returns the sub-geometries within a geometry as an array.
|
||||
|
||||
$geom2 = geoPHP::load("GEOMETRYCOLLECTION(LINESTRING(1 1,5 1,5 5,1 5,1 1),LINESTRING(2 2,2 3,3 3,3 2,2 2))");
|
||||
$geomComponents = $geom2->getComponents(); //an array of the two linestring geometries
|
||||
$linestring1 = $geomComponents[0]->getComponents(); //an array of the first linestring's point geometries
|
||||
$linestring2 = $geomComponents[1]->getComponents();
|
||||
echo $linestring1[0]->x() . ", " . $linestring1[0]->y(); //outputs '1, 1'
|
||||
|
||||
An alternative is to use the `asArray()` method. Using the above geometry collection of two linestrings,
|
||||
|
||||
$geometryArray = $geom2->asArray();
|
||||
echo $geometryArray[0][0][0] . ", " . $geometryArray[0][0][1]; //outputs '1, 1'
|
||||
|
||||
Clearly, more complex analysis is possible.
|
||||
|
||||
echo $geom2->envelope()->area();
|
||||
|
||||
|
||||
Working with PostGIS
|
||||
---------------------
|
||||
geoPHP, through it's EWKB adapter, has good integration with postGIS. Here's an example of reading and writing postGIS geometries
|
||||
|
||||
```php
|
||||
<?php
|
||||
include_once('geoPHP.inc');
|
||||
$host = 'localhost';
|
||||
$database = 'phayes';
|
||||
$table = 'test';
|
||||
$column = 'geom';
|
||||
$user = 'phayes';
|
||||
$pass = 'supersecret';
|
||||
|
||||
$connection = pg_connect("host=$host dbname=$database user=$user password=$pass");
|
||||
|
||||
// Working with PostGIS and Extended-WKB
|
||||
// ----------------------------
|
||||
|
||||
// Using asBinary and GeomFromWKB in PostGIS
|
||||
$result = pg_fetch_all(pg_query($connection, "SELECT asBinary($column) as geom FROM $table"));
|
||||
foreach ($result as $item) {
|
||||
$wkb = pg_unescape_bytea($item['geom']); // Make sure to unescape the hex blob
|
||||
$geom = geoPHP::load($wkb, 'ewkb'); // We now a full geoPHP Geometry object
|
||||
|
||||
// Let's insert it back into the database
|
||||
$insert_string = pg_escape_bytea($geom->out('ewkb'));
|
||||
pg_query($connection, "INSERT INTO $table ($column) values (GeomFromWKB('$insert_string'))");
|
||||
}
|
||||
|
||||
// Using a direct SELECT and INSERTs in PostGIS without using wrapping functions
|
||||
$result = pg_fetch_all(pg_query($connection, "SELECT $column as geom FROM $table"));
|
||||
foreach ($result as $item) {
|
||||
$wkb = pack('H*',$item['geom']); // Unpacking the hex blob
|
||||
$geom = geoPHP::load($wkb, 'ewkb'); // We now have a geoPHP Geometry
|
||||
|
||||
// To insert directly into postGIS we need to unpack the WKB
|
||||
$unpacked = unpack('H*', $geom->out('ewkb'));
|
||||
$insert_string = $unpacked[1];
|
||||
pg_query($connection, "INSERT INTO $table ($column) values ('$insert_string')");
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Credit
|
||||
-------------------------------------------------
|
||||
|
||||
Maintainer: Patrick Hayes
|
||||
|
||||
Additional Contributors:
|
||||
|
||||
* GeoMemes Research (<http://www.geomemes.com>)
|
||||
* HighWire Press (<http://www.highwire.org>) and GeoScienceWorld (<http://www.geoscienceworld.org>)
|
||||
* Arnaud Renevier (gisconverter.php) <https://github.com/arenevier/gisconverter.php>
|
||||
* Dave Tarc <https://github.com/dtarc>
|
||||
* Elliott Hunston (documentation) <https://github.com/ejh>
|
||||
|
||||
This library is open-source and dual-licensed under both the Modified BSD License and GPLv2. Either license may be used at your option.
|
||||
18
htdocs/includes/geoPHP/composer.json
Normal file
18
htdocs/includes/geoPHP/composer.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "phayes/geophp",
|
||||
"license": "GPL-2 or New-BSD",
|
||||
"type": "library",
|
||||
"description": "GeoPHP is a open-source native PHP library for doing geometry operations. It is written entirely in PHP and can therefore run on shared hosts. It can read and write a wide variety of formats: WKT (including EWKT), WKB (including EWKB), GeoJSON, KML, GPX, GeoRSS). It works with all Simple-Feature geometries (Point, LineString, Polygon, GeometryCollection etc.) and can be used to get centroids, bounding-boxes, area, and a wide variety of other useful information.",
|
||||
"homepage": "https://github.com/phayes/geoPHP",
|
||||
"autoload": {
|
||||
"classmap": ["geoPHP.inc"]
|
||||
},
|
||||
"authors":[
|
||||
{
|
||||
"name":"Patrick Hayes"
|
||||
}
|
||||
],
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.1.*"
|
||||
}
|
||||
}
|
||||
734
htdocs/includes/geoPHP/doc/api.html
Normal file
734
htdocs/includes/geoPHP/doc/api.html
Normal file
|
|
@ -0,0 +1,734 @@
|
|||
<div id="wiki-wrapper" class="page">
|
||||
<div id="head">
|
||||
<h1 class="instapaper_title">API Reference</h1>
|
||||
<ul class="wiki-actions readability-extra">
|
||||
<li class="gollum-minibutton">
|
||||
<a href="/phayes/geoPHP/wiki/API-Reference/_history"
|
||||
class="minibutton bigger action-page-history">
|
||||
<span>Page History</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="wiki-content">
|
||||
<div class="wrap">
|
||||
<div id="wiki-body" class="gollum-mediawiki-content instapaper_body">
|
||||
<div class="markdown-body">
|
||||
<table class="toc" summary="Contents">
|
||||
<tr>
|
||||
<td>
|
||||
<div>Table of Contents</div>
|
||||
<ul>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#wiki-geoPHP_static_class" rel="nofollow">geoPHP static class</a>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#wiki-Example" rel="nofollow">Example</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#wiki-Static_Methods" rel="nofollow">Static Methods</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#wiki-Adapters" rel="nofollow">Adapters</a>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#wiki-Class_Hierarchy" rel="nofollow">Class Hierarchy</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#wiki-Example-2" rel="nofollow">Example</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#wiki-Methods" rel="nofollow">Methods</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#wiki-Geometries" rel="nofollow">Geometries</a>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#wiki-Class_Hierarchy-2" rel="nofollow">Class Hierarchy</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#wiki-Example-3" rel="nofollow">Example</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#wiki-Methods-2" rel="nofollow">Methods</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2>
|
||||
<span class="mw-headline">
|
||||
<a name="wiki-geoPHP_static_class" rel="nofollow">geoPHP static class</a>
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<p>geoPHP provides a static class that contains useful utility functions. All methods must
|
||||
be called statically. </p>
|
||||
<h3>
|
||||
<span class="mw-headline">
|
||||
<a name="wiki-Example" rel="nofollow">Example</a>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<pre>$geometry = geoPHP::load('MULTILINESTRING((10 10,20 20,10 40))','wkt');</pre>
|
||||
<pre>$reduced_geometry = geoPHP::geometryReduce($geometry);</pre>
|
||||
|
||||
<h3>
|
||||
<span class="mw-headline">
|
||||
<a name="wiki-Static_Methods" rel="nofollow">Static Methods</a>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Method</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Description</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Returns</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> version </td>
|
||||
<td> Provides the current geoPHP version. Useful if you need to check compatablity </td>
|
||||
<td> Numeric String </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> load </td>
|
||||
<td> Load from an adapter format (like wkt) into a geometry. The first argument is the
|
||||
data, the second one is the format of the data
|
||||
('wkt','wkb','json','kml','gpx','google_geocode'). All additional arguments are
|
||||
passed along to the read method of the relevant adapte </td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> getAdapterMap </td>
|
||||
<td> Get a list of adapters as an array keyed by the value that should be passed to
|
||||
geoPHP::load </td>
|
||||
<td> Array </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> geometryList </td>
|
||||
<td> List all geometry types </td>
|
||||
<td> Array </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> geosToGeometry </td>
|
||||
<td> Given a GEOSGeometry, get a geoPHP geometry </td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> geometryReduce </td>
|
||||
<td> Reduce a geometry, or an array of geometries, into their \'lowest\' available
|
||||
common geometry. For example a GeometryCollection of only points will become a
|
||||
MultiPoint, while a multi-point containing a single point will return a point. An
|
||||
array of geometries can be passed and they will be compiled into a single geometry. </td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> geosInstalled </td>
|
||||
<td> Check if the GEOS php extension is installed and working </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2>
|
||||
<span class="mw-headline">
|
||||
<a name="wiki-Adapters" rel="nofollow">Adapters</a>
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<p>Adapters are responsible for getting data in and out of geoPHP Geometries. Generally
|
||||
you will use an adapter to load data into a geoPHP geometry, do various manipulations on
|
||||
the geometry, then use another adapter to write it out to another (or the same) format.
|
||||
You can also use adapters by themselves to simply do conversion from one format to
|
||||
another (See <a class="internal present"
|
||||
href="/phayes/geoPHP/wiki/Example-format-converter" rel="nofollow"
|
||||
>example-format-converter</a> for an example of this). Adapters should be instantiated
|
||||
and not called statically. </p>
|
||||
<h3>
|
||||
<span class="mw-headline">
|
||||
<a name="wiki-Class_Hierarchy" rel="nofollow">Class Hierarchy</a>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>GeoAdapter Abtract Class<ul>
|
||||
<li>WKT Enables reading and writing WKT (Well Known Text)</li>
|
||||
<li>WKB Enables reading and writing WKB (Well Known Binary). This is very fast.</li>
|
||||
<li>GeoJSON Enables reading and writing GeoJSON</li>
|
||||
<li>KML Enables reading and writing KML (Google Earth)</li>
|
||||
<li>GoogleGeocode Enables geocoding and reverse-geocoding via google geocoding
|
||||
API</li>
|
||||
<li>GPX Enables reading and writing GPX (from handheld GPS devices)</li>
|
||||
<li>GeoRSS Enables reading and writing of GeoRSS</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
<span class="mw-headline">
|
||||
<a name="wiki-Example-2" rel="nofollow">Example</a>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<pre>$wkb_reader = new WKB();</pre>
|
||||
<pre>$geometry = $wkb_reader->read('0101000000000000000000f03f000000000000f03f',TRUE);</pre>
|
||||
<pre>$wkt_writer = new wkt();</pre>
|
||||
<pre>$wkt = $wkt_writer->write($geometry);</pre>
|
||||
|
||||
<h3>
|
||||
<span class="mw-headline">
|
||||
<a name="wiki-Methods" rel="nofollow">Methods</a>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Method</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Description</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Returns</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> read </td>
|
||||
<td> Read in input (generally a string) and return a Geometry </td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> write </td>
|
||||
<td> Write out the given geometry into the adapter formater </td>
|
||||
<td> String </td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2>
|
||||
<span class="mw-headline">
|
||||
<a name="wiki-Geometries" rel="nofollow">Geometries</a>
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<p>Geometries form the heart of the geoPHP library. Once you have loaded your data into a
|
||||
Geometry object, you have access to all the various methods detailed below for doing
|
||||
conversions, transformations, and operations. While generally you would use an adapter
|
||||
to get a Geometry object, they can also be built by hand. See the constructor methods in
|
||||
the classes to see how to do this. GEOS-php extension needs to be installed in order to
|
||||
use some of the advanced methods (detailed below). </p>
|
||||
<h3>
|
||||
<span class="mw-headline">
|
||||
<a name="wiki-Class_Hierarchy-2" rel="nofollow">Class Hierarchy</a>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<ul>
|
||||
<li>Geometry<ul>
|
||||
<li>Point</li>
|
||||
<li>Collection<ul>
|
||||
<li>LineString</li>
|
||||
<li>Polygon</li>
|
||||
<li>MultiLineString</li>
|
||||
<li>MultiPoint</li>
|
||||
<li>MultiPolygon</li>
|
||||
<li>GeometryCollection</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
<span class="mw-headline">
|
||||
<a name="wiki-Example-3" rel="nofollow">Example</a>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<pre>$poly1 = $geoPHP::load('POLYGON((30 10,10 20,20 40,40 40,30 10))','wkt');</pre>
|
||||
<pre>$poly2 = $geoPHP::load('POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30, 35 35, 30 20, 20 30))','wkt');</pre>
|
||||
<pre>$combined_poly = $poly1->union($poly2);</pre>
|
||||
<pre>$kml = $combined_poly->out('kml');</pre>
|
||||
|
||||
<h3>
|
||||
<span class="mw-headline">
|
||||
<a name="wiki-Methods-2" rel="nofollow">Methods</a>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<p>
|
||||
<b>Common Methods</b>
|
||||
</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Method</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Description</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Returns</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> out </td>
|
||||
<td> Outputs the geometry into the specified adapter format. Available formats are
|
||||
<i>wkt</i>, <i>wkb</i>, <i>json</i>, <i>kml</i>, <i>gpx</i>, <i>google_geocode</i>
|
||||
</td>
|
||||
<td> String </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> area </td>
|
||||
<td> The area of this Polygon (or GeometryCollection), as measured in the spatial
|
||||
reference system of the geometry </td>
|
||||
<td> Float </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> boundary </td>
|
||||
<td> Returns the closure of the combinatorial boundary of this geometric object. </td>
|
||||
<td> LinearRing </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> envelope </td>
|
||||
<td> The minimum bounding box for this Geometry, returned as a Geometry. </td>
|
||||
<td> Polygon </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> getBBox </td>
|
||||
<td> The minimum bounding box for this Geometry, returned as an array. Also see
|
||||
envelope() </td>
|
||||
<td> Array </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> centroid </td>
|
||||
<td> The mathematical centroid for this geometry as a Point. For polygons, the result
|
||||
is not guaranteed to be interior. </td>
|
||||
<td> Point </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> length </td>
|
||||
<td> The length of this Curve in its associated spatial reference. </td>
|
||||
<td> Float </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> y </td>
|
||||
<td> The y-coordinate value for this Point. </td>
|
||||
<td> Float </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> x </td>
|
||||
<td> The x-coordinate value for this Point. </td>
|
||||
<td> Float </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> numGeometries </td>
|
||||
<td> The number of component geometries in this collection </td>
|
||||
<td> Integer </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> geometryN </td>
|
||||
<td> Returns the geometry N in this collection. Note that the index starts at 1. </td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> startPoint </td>
|
||||
<td> The start Point of this LineString </td>
|
||||
<td> Point </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> endPoint </td>
|
||||
<td> The end Point of this LineString </td>
|
||||
<td> Point </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> isRing </td>
|
||||
<td> Returns 1 (TRUE) if this Curve is closed() and this Curve isSimple(). </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> isClosed </td>
|
||||
<td> Returns 1 (TRUE) if this Curve is closed. StartPoint() == EndPoint(). </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> getComponents </td>
|
||||
<td> Get all sub-geometry components of the geometry </td>
|
||||
<td> Array of geometries </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> numPoints </td>
|
||||
<td> The number of Points in this LineString </td>
|
||||
<td> Integer </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> pointN </td>
|
||||
<td> Returns the specified Point N in this LineString. Note that the index starts at
|
||||
1. </td>
|
||||
<td> Point </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> exteriorRing </td>
|
||||
<td> Returns the exterior ring of this Polygon. </td>
|
||||
<td> LineString </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> numInteriorRings </td>
|
||||
<td> Returns the number of interior rings in this Polygon. </td>
|
||||
<td> Integer </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> interiorRingN </td>
|
||||
<td> Returns the Nth interior ring for this Polygon as a LineString. Note that the
|
||||
index starts at 1. </td>
|
||||
<td> LineString </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> dimension </td>
|
||||
<td> The inherent dimension of this geometric object. In non-homogeneous collections,
|
||||
this will return the largest topological dimension of the contained objects. </td>
|
||||
<td> Integer </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> geometryType </td>
|
||||
<td> Returns the name of the instantiable subtype of Geometry of which this geometric
|
||||
object is an instantiable member. The name of the subtype of Geometry is returned as
|
||||
a string. </td>
|
||||
<td> String </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> SRID </td>
|
||||
<td> Returns the Spatial Reference System ID for this geometric object. </td>
|
||||
<td> integer </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> setSRID </td>
|
||||
<td> Set the Spatial Reference System ID for this geometric object. </td>
|
||||
<td> NULL </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> asArray </td>
|
||||
<td> Get the given geometry as an array of components (recursive) </td>
|
||||
<td> Array </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> getGeoInterface </td>
|
||||
<td> Get the geometryType and Coordinates as an array </td>
|
||||
<td> Array </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
<b>Aliases</b>
|
||||
</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Method</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Description</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Returns</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> getCentroid </td>
|
||||
<td> Alias for centroid() </td>
|
||||
<td> Point </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> getArea </td>
|
||||
<td> Alias for area() </td>
|
||||
<td> Float </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> getX </td>
|
||||
<td> Alias for x() </td>
|
||||
<td> Float </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> getY </td>
|
||||
<td> Alias for y() </td>
|
||||
<td> Float </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> getGeos </td>
|
||||
<td> Alias for geos() </td>
|
||||
<td> GEOSGeometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> getGeomType </td>
|
||||
<td> Alias for geometryType() </td>
|
||||
<td> String </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> getSRID </td>
|
||||
<td> Alias for SRID() </td>
|
||||
<td> Integer </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> asText </td>
|
||||
<td> Alias for <i>$this->out('wkt')</i>
|
||||
</td>
|
||||
<td> String </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> asBinary </td>
|
||||
<td> Alias for <i>$this->out('wkb')</i>
|
||||
</td>
|
||||
<td> String </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
<b>Advanced Methods</b>
|
||||
</p>
|
||||
<p>The <a class="internal present" href="/phayes/geoPHP/wiki/GEOS" rel="nofollow">GEOS-php
|
||||
extension</a> needs to be installed for these functions to be available </p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Method</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Description</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Returns</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> geos </td>
|
||||
<td> Return a GEOSGeometry object representing this geometry </td>
|
||||
<td> GEOSGeometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> setGeos </td>
|
||||
<td> Set a GEOSGeometry object representing this geometry </td>
|
||||
<td> NULL </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> pointOnSurface </td>
|
||||
<td> A Point guaranteed to be within a polygon </td>
|
||||
<td> Point </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> equals </td>
|
||||
<td> Returns 1 (TRUE) if this geometry is “spatially equal” to another Geometry </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> equalsExact </td>
|
||||
<td> Returns 1 (TRUE) if this gemometric object is exactly the same as another object,
|
||||
including the ordering of component parts </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> relate </td>
|
||||
<td> Returns 1 (TRUE) if this geometric object is spatially related to anotherGeometry
|
||||
by testing for intersections between the interior, boundary and exterior of the two
|
||||
geometric objects as specified by the values in the intersectionPatternMatrix. This
|
||||
returns FALSE if all the tested intersections are empty except exterior (this)
|
||||
intersect exterior (another). </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> checkValidity </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> isSimple </td>
|
||||
<td> Returns 1 (TRUE) if this geometry does not pass through the same point in space
|
||||
more than once </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> project </td>
|
||||
<td> Project the geometry from from one SRID to another </td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> buffer </td>
|
||||
<td> Returns a geometric object that represents all Points whose distance from this
|
||||
geometric object is less than or equal to distance. Calculations are in the spatial
|
||||
reference system of this geometric object. Because of the limitations of linear
|
||||
interpolation, there will often be some relatively small error in this distance, but
|
||||
it should be near the resolution of the coordinates used. </td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> intersection </td>
|
||||
<td> Returns a geometric object that represents the Point set intersection of this
|
||||
geometric object with anotherGeometry. See <a
|
||||
href="http://en.wikipedia.org/wiki/Intersection_(set_theory)" rel="nofollow"
|
||||
>http://en.wikipedia.org/wiki/Intersection_(set_theory)</a>
|
||||
</td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> convexHull </td>
|
||||
<td> Returns a geometric object that represents the convex hull of this geometric
|
||||
object. See <a href="http://en.wikipedia.org/wiki/Convex_hull" rel="nofollow"
|
||||
>http://en.wikipedia.org/wiki/Convex_hull</a>
|
||||
</td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> difference </td>
|
||||
<td> Returns a geometric object that represents the Point set difference of this
|
||||
geometric object with anotherGeometry. </td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> symDifference </td>
|
||||
<td> Returns a geometric object that represents the Point set symmetric difference of
|
||||
this geometric object with another Geometry. See <a
|
||||
href="http://en.wikipedia.org/wiki/Symmetric_difference" rel="nofollow"
|
||||
>http://en.wikipedia.org/wiki/Symmetric_difference</a>
|
||||
</td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> union </td>
|
||||
<td> Returns a geometric object that represents the Point set union of this geometric
|
||||
object with anotherGeometry. See <a
|
||||
href="http://en.wikipedia.org/wiki/Union_(set_theory)" rel="nofollow"
|
||||
>http://en.wikipedia.org/wiki/Union_(set_theory)</a>
|
||||
</td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> simplify </td>
|
||||
<td> Simplify the geometry </td>
|
||||
<td> Geometry </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> disjoint </td>
|
||||
<td> Returns 1 (TRUE) if this geometric object is “spatially disjoint” from another
|
||||
Geometry. </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> touches </td>
|
||||
<td> Returns 1 (TRUE) if this geometric object “spatially touches” another Geometry. </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> intersects </td>
|
||||
<td> Returns 1 (TRUE) if this geometric object “spatially intersects” another
|
||||
Geometry. </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> crosses </td>
|
||||
<td> Returns 1 (TRUE) if this geometric object “spatially crosses? another Geometry. </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> within </td>
|
||||
<td> Returns 1 (TRUE) if this geometric object is “spatially within” another Geometry. </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> contains </td>
|
||||
<td> Returns 1 (TRUE) if this geometric object “spatially contains” another Geometry. </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> overlaps </td>
|
||||
<td> Returns 1 (TRUE) if this geometric object “spatially overlaps” another Geometry. </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> covers </td>
|
||||
<td> Alias for contains() </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> coveredBy </td>
|
||||
<td> Alias for within() </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> distance </td>
|
||||
<td> Returns the shortest distance between any two Points in the two geometric objects
|
||||
as calculated in the spatial reference system of this geometric object. Because the
|
||||
geometries are closed, it is possible to find a point on each geometric object
|
||||
involved, such that the distance between these 2 points is the returned distance
|
||||
between their geometric objects. </td>
|
||||
<td> Float </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> hausdorffDistance </td>
|
||||
<td> See <a href="http://en.wikipedia.org/wiki/Hausdorff_distance" rel="nofollow"
|
||||
>http://en.wikipedia.org/wiki/Hausdorff_distance</a>
|
||||
</td>
|
||||
<td> Float </td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
<b>Placeholders</b>
|
||||
</p>
|
||||
<p>These methods are part of the specification, but are not really supported by geoPHP. </p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<b>Method</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Description</b>
|
||||
</td>
|
||||
<td>
|
||||
<b>Returns</b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> hasZ </td>
|
||||
<td> returns FALSE. geoPHP does not support Z values at the moment. </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> is3D </td>
|
||||
<td> returns FALSE. geoPHP does not support 3D geometries at the moment. </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> isMeasured </td>
|
||||
<td> returns FALSE. geoPHP does not yet support M values </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> isEmpty </td>
|
||||
<td> returns FALSE. geoPHP does not yet support empty geometries </td>
|
||||
<td> Boolean </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> coordinateDimension </td>
|
||||
<td> returns 2. geoPHP only supports 2-dimentional space </td>
|
||||
<td> Integer </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> z </td>
|
||||
<td> returns NULL. geoPHP does not support Z values at the moment </td>
|
||||
<td> NULL </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> m </td>
|
||||
<td> returns NULL. geoPHP does not support M values </td>
|
||||
<td> NULL </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
303
htdocs/includes/geoPHP/geoPHP.inc.php
Normal file
303
htdocs/includes/geoPHP/geoPHP.inc.php
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
<?php
|
||||
/*
|
||||
* (c) Patrick Hayes
|
||||
*
|
||||
* This code is open-source and licenced under the Modified BSD License.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// Adapters
|
||||
include_once "lib/adapters/GeoAdapter.class.php"; // Abtract class
|
||||
include_once "lib/adapters/GeoJSON.class.php";
|
||||
include_once "lib/adapters/WKT.class.php";
|
||||
include_once "lib/adapters/EWKT.class.php";
|
||||
include_once "lib/adapters/WKB.class.php";
|
||||
include_once "lib/adapters/EWKB.class.php";
|
||||
include_once "lib/adapters/KML.class.php";
|
||||
include_once "lib/adapters/GPX.class.php";
|
||||
include_once "lib/adapters/GeoRSS.class.php";
|
||||
include_once "lib/adapters/GoogleGeocode.class.php";
|
||||
include_once "lib/adapters/GeoHash.class.php";
|
||||
|
||||
// Geometries
|
||||
include_once "lib/geometry/Geometry.class.php"; // Abtract class
|
||||
include_once "lib/geometry/Point.class.php";
|
||||
include_once "lib/geometry/Collection.class.php"; // Abtract class
|
||||
include_once "lib/geometry/LineString.class.php";
|
||||
include_once "lib/geometry/MultiPoint.class.php";
|
||||
include_once "lib/geometry/Polygon.class.php";
|
||||
include_once "lib/geometry/MultiLineString.class.php";
|
||||
include_once "lib/geometry/MultiPolygon.class.php";
|
||||
include_once "lib/geometry/GeometryCollection.class.php";
|
||||
|
||||
class geoPHP
|
||||
{
|
||||
|
||||
static function version()
|
||||
{
|
||||
return '1.2';
|
||||
}
|
||||
|
||||
// geoPHP::load($data, $type, $other_args);
|
||||
// if $data is an array, all passed in values will be combined into a single geometry
|
||||
static function load()
|
||||
{
|
||||
$args = func_get_args();
|
||||
|
||||
$data = array_shift($args);
|
||||
$type = array_shift($args);
|
||||
|
||||
$type_map = geoPHP::getAdapterMap();
|
||||
|
||||
// Auto-detect type if needed
|
||||
if (!$type) {
|
||||
// If the user is trying to load a Geometry from a Geometry... Just pass it back
|
||||
if (is_object($data)) {
|
||||
if ($data instanceOf Geometry) return $data;
|
||||
}
|
||||
|
||||
$detected = geoPHP::detectFormat($data);
|
||||
if (!$detected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$format = explode(':', $detected);
|
||||
$type = array_shift($format);
|
||||
$args = $format;
|
||||
}
|
||||
|
||||
$processor_type = $type_map[$type];
|
||||
|
||||
if (!$processor_type) {
|
||||
throw new exception('geoPHP could not find an adapter of type '.htmlentities($type));
|
||||
}
|
||||
|
||||
$processor = new $processor_type();
|
||||
|
||||
// Data is not an array, just pass it normally
|
||||
if (!is_array($data)) {
|
||||
$result = call_user_func_array(array($processor, "read"), array_merge(array($data), $args));
|
||||
}
|
||||
// Data is an array, combine all passed in items into a single geometry
|
||||
else {
|
||||
$geoms = array();
|
||||
foreach ($data as $item) {
|
||||
$geoms[] = call_user_func_array(array($processor, "read"), array_merge(array($item), $args));
|
||||
}
|
||||
$result = geoPHP::geometryReduce($geoms);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
static function getAdapterMap()
|
||||
{
|
||||
return array (
|
||||
'wkt' => 'WKT',
|
||||
'ewkt' => 'EWKT',
|
||||
'wkb' => 'WKB',
|
||||
'ewkb' => 'EWKB',
|
||||
'json' => 'GeoJSON',
|
||||
'geojson' => 'GeoJSON',
|
||||
'kml' => 'KML',
|
||||
'gpx' => 'GPX',
|
||||
'georss' => 'GeoRSS',
|
||||
'google_geocode' => 'GoogleGeocode',
|
||||
'geohash' => 'GeoHash',
|
||||
);
|
||||
}
|
||||
|
||||
static function geometryList()
|
||||
{
|
||||
return array(
|
||||
'point' => 'Point',
|
||||
'linestring' => 'LineString',
|
||||
'polygon' => 'Polygon',
|
||||
'multipoint' => 'MultiPoint',
|
||||
'multilinestring' => 'MultiLineString',
|
||||
'multipolygon' => 'MultiPolygon',
|
||||
'geometrycollection' => 'GeometryCollection',
|
||||
);
|
||||
}
|
||||
|
||||
static function geosInstalled($force = null)
|
||||
{
|
||||
static $geos_installed = null;
|
||||
if ($force !== null) $geos_installed = $force;
|
||||
if ($geos_installed !== null) {
|
||||
return $geos_installed;
|
||||
}
|
||||
$geos_installed = class_exists('GEOSGeometry');
|
||||
return $geos_installed;
|
||||
}
|
||||
|
||||
static function geosToGeometry($geos)
|
||||
{
|
||||
if (!geoPHP::geosInstalled()) {
|
||||
return null;
|
||||
}
|
||||
$wkb_writer = new GEOSWKBWriter();
|
||||
$wkb = $wkb_writer->writeHEX($geos);
|
||||
$geometry = geoPHP::load($wkb, 'wkb', true);
|
||||
if ($geometry) {
|
||||
$geometry->setGeos($geos);
|
||||
return $geometry;
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce a geometry, or an array of geometries, into their 'lowest' available common geometry.
|
||||
// For example a GeometryCollection of only points will become a MultiPoint
|
||||
// A multi-point containing a single point will return a point.
|
||||
// An array of geometries can be passed and they will be compiled into a single geometry
|
||||
static function geometryReduce($geometry)
|
||||
{
|
||||
// If it's an array of one, then just parse the one
|
||||
if (is_array($geometry)) {
|
||||
if (empty($geometry)) return false;
|
||||
if (count($geometry) == 1) return geoPHP::geometryReduce(array_shift($geometry));
|
||||
}
|
||||
|
||||
// If the geometry cannot even theoretically be reduced more, then pass it back
|
||||
if (gettype($geometry) == 'object') {
|
||||
$passbacks = array('Point','LineString','Polygon');
|
||||
if (in_array($geometry->geometryType(), $passbacks)) {
|
||||
return $geometry;
|
||||
}
|
||||
}
|
||||
|
||||
// If it is a mutlti-geometry, check to see if it just has one member
|
||||
// If it does, then pass the member, if not, then just pass back the geometry
|
||||
if (gettype($geometry) == 'object') {
|
||||
$simple_collections = array('MultiPoint','MultiLineString','MultiPolygon');
|
||||
if (in_array(get_class($geometry), $passbacks)) {
|
||||
$components = $geometry->getComponents();
|
||||
if (count($components) == 1) {
|
||||
return $components[0];
|
||||
} else {
|
||||
return $geometry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// So now we either have an array of geometries, a GeometryCollection, or an array of GeometryCollections
|
||||
if (!is_array($geometry)) {
|
||||
$geometry = array($geometry);
|
||||
}
|
||||
|
||||
$geometries = array();
|
||||
$geom_types = array();
|
||||
|
||||
$collections = array('MultiPoint','MultiLineString','MultiPolygon','GeometryCollection');
|
||||
|
||||
foreach ($geometry as $item) {
|
||||
if ($item) {
|
||||
if (in_array(get_class($item), $collections)) {
|
||||
foreach ($item->getComponents() as $component) {
|
||||
$geometries[] = $component;
|
||||
$geom_types[] = $component->geometryType();
|
||||
}
|
||||
} else {
|
||||
$geometries[] = $item;
|
||||
$geom_types[] = $item->geometryType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$geom_types = array_unique($geom_types);
|
||||
|
||||
if (empty($geom_types)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count($geom_types) == 1) {
|
||||
if (count($geometries) == 1) {
|
||||
return $geometries[0];
|
||||
} else {
|
||||
$class = 'Multi'.$geom_types[0];
|
||||
return new $class($geometries);
|
||||
}
|
||||
} else {
|
||||
return new GeometryCollection($geometries);
|
||||
}
|
||||
}
|
||||
|
||||
// Detect a format given a value. This function is meant to be SPEEDY.
|
||||
// It could make a mistake in XML detection if you are mixing or using namespaces in weird ways (ie, KML inside an RSS feed)
|
||||
static function detectFormat(&$input)
|
||||
{
|
||||
$mem = fopen('php://memory', 'r+');
|
||||
fwrite($mem, $input, 11); // Write 11 bytes - we can detect the vast majority of formats in the first 11 bytes
|
||||
fseek($mem, 0);
|
||||
|
||||
$bytes = unpack("c*", fread($mem, 11));
|
||||
|
||||
// If bytes is empty, then we were passed empty input
|
||||
if (empty($bytes)) return false;
|
||||
|
||||
// First char is a tab, space or carriage-return. trim it and try again
|
||||
if ($bytes[1] == 9 || $bytes[1] == 10 || $bytes[1] == 32) {
|
||||
$ltinput = ltrim($input);
|
||||
return geoPHP::detectFormat($ltinput);
|
||||
}
|
||||
|
||||
// Detect WKB or EWKB -- first byte is 1 (little endian indicator)
|
||||
if ($bytes[1] == 1) {
|
||||
// If SRID byte is TRUE (1), it's EWKB
|
||||
if ($bytes[5]) return 'ewkb';
|
||||
else return 'wkb';
|
||||
}
|
||||
|
||||
// Detect HEX encoded WKB or EWKB (PostGIS format) -- first byte is 48, second byte is 49 (hex '01' => first-byte = 1)
|
||||
if ($bytes[1] == 48 && $bytes[2] == 49) {
|
||||
// The shortest possible WKB string (LINESTRING EMPTY) is 18 hex-chars (9 encoded bytes) long
|
||||
// This differentiates it from a geohash, which is always shorter than 18 characters.
|
||||
if (strlen($input) >= 18) {
|
||||
//@@TODO: Differentiate between EWKB and WKB -- check hex-char 10 or 11 (SRID bool indicator at encoded byte 5)
|
||||
return 'ewkb:1';
|
||||
}
|
||||
}
|
||||
|
||||
// Detect GeoJSON - first char starts with {
|
||||
if ($bytes[1] == 123) {
|
||||
return 'json';
|
||||
}
|
||||
|
||||
// Detect EWKT - first char is S
|
||||
if ($bytes[1] == 83) {
|
||||
return 'ewkt';
|
||||
}
|
||||
|
||||
// Detect WKT - first char starts with P (80), L (76), M (77), or G (71)
|
||||
$wkt_chars = array(80, 76, 77, 71);
|
||||
if (in_array($bytes[1], $wkt_chars)) {
|
||||
return 'wkt';
|
||||
}
|
||||
|
||||
// Detect XML -- first char is <
|
||||
if ($bytes[1] == 60) {
|
||||
// grab the first 256 characters
|
||||
$string = substr($input, 0, 256);
|
||||
if (strpos($string, '<kml') !== false) return 'kml';
|
||||
if (strpos($string, '<coordinate') !== false) return 'kml';
|
||||
if (strpos($string, '<gpx') !== false) return 'gpx';
|
||||
if (strpos($string, '<georss') !== false) return 'georss';
|
||||
if (strpos($string, '<rss') !== false) return 'georss';
|
||||
if (strpos($string, '<feed') !== false) return 'georss';
|
||||
}
|
||||
|
||||
// We need an 8 byte string for geohash and unpacked WKB / WKT
|
||||
fseek($mem, 0);
|
||||
$string = trim(fread($mem, 8));
|
||||
|
||||
// Detect geohash - geohash ONLY contains lowercase chars and numerics
|
||||
preg_match('/[a-z0-9]+/', $string, $matches);
|
||||
if ($matches[0] == $string) {
|
||||
return 'geohash';
|
||||
}
|
||||
|
||||
// What do you get when you cross an elephant with a rhino?
|
||||
// http://youtu.be/RCBn5J83Poc
|
||||
return false;
|
||||
}
|
||||
}
|
||||
95
htdocs/includes/geoPHP/lib/adapters/EWKB.class.php
Normal file
95
htdocs/includes/geoPHP/lib/adapters/EWKB.class.php
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
/**
|
||||
* EWKB (Extended Well Known Binary) Adapter
|
||||
*/
|
||||
class EWKB extends WKB
|
||||
{
|
||||
|
||||
/**
|
||||
* Read WKB binary string into geometry objects
|
||||
*
|
||||
* @param string $wkb An Extended-WKB binary string
|
||||
*
|
||||
* @return Geometry
|
||||
*/
|
||||
public function read($wkb, $is_hex_string = false)
|
||||
{
|
||||
if ($is_hex_string) {
|
||||
$wkb = pack('H*', $wkb);
|
||||
}
|
||||
|
||||
// Open the wkb up in memory so we can examine the SRID
|
||||
$mem = fopen('php://memory', 'r+');
|
||||
fwrite($mem, $wkb);
|
||||
fseek($mem, 0);
|
||||
$base_info = unpack("corder/ctype/cz/cm/cs", fread($mem, 5));
|
||||
if ($base_info['s']) {
|
||||
$srid = current(unpack("Lsrid", fread($mem, 4)));
|
||||
} else {
|
||||
$srid = null;
|
||||
}
|
||||
fclose($mem);
|
||||
|
||||
// Run the wkb through the normal WKB reader to get the geometry
|
||||
$wkb_reader = new WKB();
|
||||
$geom = $wkb_reader->read($wkb);
|
||||
|
||||
// If there is an SRID, add it to the geometry
|
||||
if ($srid) {
|
||||
$geom->setSRID($srid);
|
||||
}
|
||||
|
||||
return $geom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize geometries into an EWKB binary string.
|
||||
*
|
||||
* @param Geometry $geometry
|
||||
*
|
||||
* @return string The Extended-WKB binary string representation of the input geometries
|
||||
*/
|
||||
public function write(Geometry $geometry, $write_as_hex = false)
|
||||
{
|
||||
// We always write into NDR (little endian)
|
||||
$wkb = pack('c', 1);
|
||||
|
||||
switch ($geometry->getGeomType()) {
|
||||
case 'Point';
|
||||
$wkb .= pack('L', 1);
|
||||
$wkb .= $this->writePoint($geometry);
|
||||
break;
|
||||
case 'LineString';
|
||||
$wkb .= pack('L', 2);
|
||||
$wkb .= $this->writeLineString($geometry);
|
||||
break;
|
||||
case 'Polygon';
|
||||
$wkb .= pack('L', 3);
|
||||
$wkb .= $this->writePolygon($geometry);
|
||||
break;
|
||||
case 'MultiPoint';
|
||||
$wkb .= pack('L', 4);
|
||||
$wkb .= $this->writeMulti($geometry);
|
||||
break;
|
||||
case 'MultiLineString';
|
||||
$wkb .= pack('L', 5);
|
||||
$wkb .= $this->writeMulti($geometry);
|
||||
break;
|
||||
case 'MultiPolygon';
|
||||
$wkb .= pack('L', 6);
|
||||
$wkb .= $this->writeMulti($geometry);
|
||||
break;
|
||||
case 'GeometryCollection';
|
||||
$wkb .= pack('L', 7);
|
||||
$wkb .= $this->writeMulti($geometry);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($write_as_hex) {
|
||||
$unpacked = unpack('H*', $wkb);
|
||||
return $unpacked[1];
|
||||
} else {
|
||||
return $wkb;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
htdocs/includes/geoPHP/lib/adapters/EWKT.class.php
Normal file
27
htdocs/includes/geoPHP/lib/adapters/EWKT.class.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* EWKT (Extended Well Known Text) Adapter
|
||||
*/
|
||||
class EWKT extends WKT
|
||||
{
|
||||
|
||||
/**
|
||||
* Serialize geometries into an EWKT string.
|
||||
*
|
||||
* @param Geometry $geometry
|
||||
*
|
||||
* @return string The Extended-WKT string representation of the input geometries
|
||||
*/
|
||||
public function write(Geometry $geometry)
|
||||
{
|
||||
$srid = $geometry->SRID();
|
||||
$wkt = '';
|
||||
if ($srid) {
|
||||
$wkt = 'SRID=' . $srid . ';';
|
||||
$wkt .= $geometry->out('wkt');
|
||||
return $wkt;
|
||||
} else {
|
||||
return $geometry->out('wkt');
|
||||
}
|
||||
}
|
||||
}
|
||||
191
htdocs/includes/geoPHP/lib/adapters/GPX.class.php
Normal file
191
htdocs/includes/geoPHP/lib/adapters/GPX.class.php
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
<?php
|
||||
/*
|
||||
* Copyright (c) Patrick Hayes
|
||||
*
|
||||
* This code is open-source and licenced under the Modified BSD License.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHP Geometry/GPX encoder/decoder
|
||||
*/
|
||||
class GPX extends GeoAdapter
|
||||
{
|
||||
private $namespace = false;
|
||||
private $nss = ''; // Name-space string. eg 'georss:'
|
||||
|
||||
/**
|
||||
* Read GPX string into geometry objects
|
||||
*
|
||||
* @param string $gpx A GPX string
|
||||
*
|
||||
* @return Geometry|GeometryCollection
|
||||
*/
|
||||
public function read($gpx)
|
||||
{
|
||||
return $this->geomFromText($gpx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize geometries into a GPX string.
|
||||
*
|
||||
* @param Geometry $geometry
|
||||
*
|
||||
* @return string The GPX string representation of the input geometries
|
||||
*/
|
||||
public function write(Geometry $geometry, $namespace = false)
|
||||
{
|
||||
if ($geometry->isEmpty()) return null;
|
||||
if ($namespace) {
|
||||
$this->namespace = $namespace;
|
||||
$this->nss = $namespace.':';
|
||||
}
|
||||
return '<'.$this->nss.'gpx creator="geoPHP" version="1.0">'.$this->geometryToGPX($geometry).'</'.$this->nss.'gpx>';
|
||||
}
|
||||
|
||||
public function geomFromText($text)
|
||||
{
|
||||
// Change to lower-case and strip all CDATA
|
||||
$text = strtolower($text);
|
||||
$text = preg_replace('/<!\[cdata\[(.*?)\]\]>/s', '', $text);
|
||||
|
||||
// Load into DOMDocument
|
||||
$xmlobj = new DOMDocument();
|
||||
@$xmlobj->loadXML($text);
|
||||
if ($xmlobj === false) {
|
||||
throw new Exception("Invalid GPX: ". $text);
|
||||
}
|
||||
|
||||
$this->xmlobj = $xmlobj;
|
||||
try {
|
||||
$geom = $this->geomFromXML();
|
||||
} catch (InvalidText $e) {
|
||||
throw new Exception("Cannot Read Geometry From GPX: ". $text);
|
||||
} catch (Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $geom;
|
||||
}
|
||||
|
||||
protected function geomFromXML()
|
||||
{
|
||||
$geometries = array();
|
||||
$geometries = array_merge($geometries, $this->parseWaypoints());
|
||||
$geometries = array_merge($geometries, $this->parseTracks());
|
||||
$geometries = array_merge($geometries, $this->parseRoutes());
|
||||
|
||||
if (empty($geometries)) {
|
||||
throw new Exception("Invalid / Empty GPX");
|
||||
}
|
||||
|
||||
return geoPHP::geometryReduce($geometries);
|
||||
}
|
||||
|
||||
protected function childElements($xml, $nodename = '')
|
||||
{
|
||||
$children = array();
|
||||
foreach ($xml->childNodes as $child) {
|
||||
if ($child->nodeName == $nodename) {
|
||||
$children[] = $child;
|
||||
}
|
||||
}
|
||||
return $children;
|
||||
}
|
||||
|
||||
protected function parseWaypoints()
|
||||
{
|
||||
$points = array();
|
||||
$wpt_elements = $this->xmlobj->getElementsByTagName('wpt');
|
||||
foreach ($wpt_elements as $wpt) {
|
||||
$lat = $wpt->attributes->getNamedItem("lat")->nodeValue;
|
||||
$lon = $wpt->attributes->getNamedItem("lon")->nodeValue;
|
||||
$points[] = new Point($lon, $lat);
|
||||
}
|
||||
return $points;
|
||||
}
|
||||
|
||||
protected function parseTracks()
|
||||
{
|
||||
$lines = array();
|
||||
$trk_elements = $this->xmlobj->getElementsByTagName('trk');
|
||||
foreach ($trk_elements as $trk) {
|
||||
$components = array();
|
||||
foreach ($this->childElements($trk, 'trkseg') as $trkseg) {
|
||||
foreach ($this->childElements($trkseg, 'trkpt') as $trkpt) {
|
||||
$lat = $trkpt->attributes->getNamedItem("lat")->nodeValue;
|
||||
$lon = $trkpt->attributes->getNamedItem("lon")->nodeValue;
|
||||
$components[] = new Point($lon, $lat);
|
||||
}
|
||||
}
|
||||
if ($components) {$lines[] = new LineString($components);}
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
protected function parseRoutes()
|
||||
{
|
||||
$lines = array();
|
||||
$rte_elements = $this->xmlobj->getElementsByTagName('rte');
|
||||
foreach ($rte_elements as $rte) {
|
||||
$components = array();
|
||||
foreach ($this->childElements($rte, 'rtept') as $rtept) {
|
||||
$lat = $rtept->attributes->getNamedItem("lat")->nodeValue;
|
||||
$lon = $rtept->attributes->getNamedItem("lon")->nodeValue;
|
||||
$components[] = new Point($lon, $lat);
|
||||
}
|
||||
$lines[] = new LineString($components);
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
protected function geometryToGPX($geom)
|
||||
{
|
||||
$type = strtolower($geom->getGeomType());
|
||||
switch ($type) {
|
||||
case 'point':
|
||||
return $this->pointToGPX($geom);
|
||||
break;
|
||||
case 'linestring':
|
||||
return $this->linestringToGPX($geom);
|
||||
break;
|
||||
case 'polygon':
|
||||
case 'multipoint':
|
||||
case 'multilinestring':
|
||||
case 'multipolygon':
|
||||
case 'geometrycollection':
|
||||
return $this->collectionToGPX($geom);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function pointToGPX($geom)
|
||||
{
|
||||
return '<'.$this->nss.'wpt lat="'.$geom->getY().'" lon="'.$geom->getX().'" />';
|
||||
}
|
||||
|
||||
private function linestringToGPX($geom)
|
||||
{
|
||||
$gpx = '<'.$this->nss.'trk><'.$this->nss.'trkseg>';
|
||||
|
||||
foreach ($geom->getComponents() as $comp) {
|
||||
$gpx .= '<'.$this->nss.'trkpt lat="'.$comp->getY().'" lon="'.$comp->getX().'" />';
|
||||
}
|
||||
|
||||
$gpx .= '</'.$this->nss.'trkseg></'.$this->nss.'trk>';
|
||||
|
||||
return $gpx;
|
||||
}
|
||||
|
||||
public function collectionToGPX($geom)
|
||||
{
|
||||
$gpx = '';
|
||||
$components = $geom->getComponents();
|
||||
foreach ($geom->getComponents() as $comp) {
|
||||
$gpx .= $this->geometryToGPX($comp);
|
||||
}
|
||||
|
||||
return $gpx;
|
||||
}
|
||||
}
|
||||
30
htdocs/includes/geoPHP/lib/adapters/GeoAdapter.class.php
Normal file
30
htdocs/includes/geoPHP/lib/adapters/GeoAdapter.class.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/*
|
||||
* (c) Patrick Hayes 2011
|
||||
*
|
||||
* This code is open-source and licenced under the Modified BSD License.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GeoAdapter : abstract class which represents an adapter
|
||||
* for reading and writing to and from Geomtry objects
|
||||
*
|
||||
*/
|
||||
abstract class GeoAdapter
|
||||
{
|
||||
/**
|
||||
* Read input and return a Geomtry or GeometryCollection
|
||||
*
|
||||
* @return Geometry|GeometryCollection
|
||||
*/
|
||||
abstract public function read($input);
|
||||
|
||||
/**
|
||||
* Write out a Geomtry or GeometryCollection in the adapter's format
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function write(Geometry $geometry);
|
||||
}
|
||||
253
htdocs/includes/geoPHP/lib/adapters/GeoHash.class.php
Normal file
253
htdocs/includes/geoPHP/lib/adapters/GeoHash.class.php
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
<?php
|
||||
/**
|
||||
* PHP Geometry GeoHash encoder/decoder.
|
||||
*
|
||||
* @author prinsmc
|
||||
* @see http://en.wikipedia.org/wiki/Geohash
|
||||
*
|
||||
*/
|
||||
class GeoHash extends GeoAdapter
|
||||
{
|
||||
|
||||
/**
|
||||
* base32 encoding character map.
|
||||
*/
|
||||
private $table = "0123456789bcdefghjkmnpqrstuvwxyz";
|
||||
|
||||
/**
|
||||
* array of neighbouring hash character maps.
|
||||
*/
|
||||
private $neighbours = array (
|
||||
// north
|
||||
'top' => array (
|
||||
'even' => 'p0r21436x8zb9dcf5h7kjnmqesgutwvy',
|
||||
'odd' => 'bc01fg45238967deuvhjyznpkmstqrwx'
|
||||
),
|
||||
// east
|
||||
'right' => array (
|
||||
'even' => 'bc01fg45238967deuvhjyznpkmstqrwx',
|
||||
'odd' => 'p0r21436x8zb9dcf5h7kjnmqesgutwvy'
|
||||
),
|
||||
// west
|
||||
'left' => array (
|
||||
'even' => '238967debc01fg45kmstqrwxuvhjyznp',
|
||||
'odd' => '14365h7k9dcfesgujnmqp0r2twvyx8zb'
|
||||
),
|
||||
// south
|
||||
'bottom' => array (
|
||||
'even' => '14365h7k9dcfesgujnmqp0r2twvyx8zb',
|
||||
'odd' => '238967debc01fg45kmstqrwxuvhjyznp'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* array of bordering hash character maps.
|
||||
*/
|
||||
private $borders = array (
|
||||
// north
|
||||
'top' => array (
|
||||
'even' => 'prxz',
|
||||
'odd' => 'bcfguvyz'
|
||||
),
|
||||
// east
|
||||
'right' => array (
|
||||
'even' => 'bcfguvyz',
|
||||
'odd' => 'prxz'
|
||||
),
|
||||
// west
|
||||
'left' => array (
|
||||
'even' => '0145hjnp',
|
||||
'odd' => '028b'
|
||||
),
|
||||
// south
|
||||
'bottom' => array (
|
||||
'even' => '028b',
|
||||
'odd' => '0145hjnp'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Convert the geohash to a Point. The point is 2-dimensional.
|
||||
* @return Point the converted geohash
|
||||
* @param string $hash a geohash
|
||||
* @see GeoAdapter::read()
|
||||
*/
|
||||
public function read($hash, $as_grid = false)
|
||||
{
|
||||
$ll = $this->decode($hash);
|
||||
if (!$as_grid) {
|
||||
return new Point($ll['medlon'], $ll['medlat']);
|
||||
} else {
|
||||
return new Polygon(array(
|
||||
new LineString(array(
|
||||
new Point($ll['minlon'], $ll['maxlat']),
|
||||
new Point($ll['maxlon'], $ll['maxlat']),
|
||||
new Point($ll['maxlon'], $ll['minlat']),
|
||||
new Point($ll['minlon'], $ll['minlat']),
|
||||
new Point($ll['minlon'], $ll['maxlat']),
|
||||
))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the geometry to geohash.
|
||||
* @return string the geohash or null when the $geometry is not a Point
|
||||
* @param Point $geometry
|
||||
* @see GeoAdapter::write()
|
||||
*/
|
||||
public function write(Geometry $geometry, $precision = null)
|
||||
{
|
||||
if ($geometry->isEmpty()) return '';
|
||||
|
||||
if ($geometry->geometryType() === 'Point') {
|
||||
return $this->encodePoint($geometry, $precision);
|
||||
} else {
|
||||
// The geohash is the hash grid ID that fits the envelope
|
||||
$envelope = $geometry->envelope();
|
||||
$geohashes = array();
|
||||
$geohash = '';
|
||||
foreach ($envelope->getPoints() as $point) {
|
||||
$geohashes[] = $this->encodePoint($point, 0.0000001);
|
||||
}
|
||||
$i = 0;
|
||||
while ($i < strlen($geohashes[0])) {
|
||||
$char = $geohashes[0][$i];
|
||||
foreach ($geohashes as $hash) {
|
||||
if ($hash[$i] != $char) {
|
||||
return $geohash;
|
||||
}
|
||||
}
|
||||
$geohash .= $char;
|
||||
$i++;
|
||||
}
|
||||
return $geohash;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string geohash
|
||||
* @param Point $point
|
||||
* @author algorithm based on code by Alexander Songe <a@songe.me>
|
||||
* @see https://github.com/asonge/php-geohash/issues/1
|
||||
*/
|
||||
private function encodePoint($point, $precision = null)
|
||||
{
|
||||
if ($precision === null) {
|
||||
$lap = strlen($point->y())-strpos($point->y(), ".");
|
||||
$lop = strlen($point->x())-strpos($point->x(), ".");
|
||||
$precision = pow(10, -max($lap-1, $lop-1, 0))/2;
|
||||
}
|
||||
|
||||
$minlat = -90;
|
||||
$maxlat = 90;
|
||||
$minlon = -180;
|
||||
$maxlon = 180;
|
||||
$latE = 90;
|
||||
$lonE = 180;
|
||||
$i = 0;
|
||||
$error = 180;
|
||||
$hash='';
|
||||
while ($error>=$precision) {
|
||||
$chr = 0;
|
||||
for ($b=4;$b>=0;--$b) {
|
||||
if ((1&$b) == (1&$i)) {
|
||||
// even char, even bit OR odd char, odd bit...a lon
|
||||
$next = ($minlon+$maxlon)/2;
|
||||
if ($point->x()>$next) {
|
||||
$chr |= pow(2, $b);
|
||||
$minlon = $next;
|
||||
} else {
|
||||
$maxlon = $next;
|
||||
}
|
||||
$lonE /= 2;
|
||||
} else {
|
||||
// odd char, even bit OR even char, odd bit...a lat
|
||||
$next = ($minlat+$maxlat)/2;
|
||||
if ($point->y()>$next) {
|
||||
$chr |= pow(2, $b);
|
||||
$minlat = $next;
|
||||
} else {
|
||||
$maxlat = $next;
|
||||
}
|
||||
$latE /= 2;
|
||||
}
|
||||
}
|
||||
$hash .= $this->table[$chr];
|
||||
$i++;
|
||||
$error = min($latE, $lonE);
|
||||
}
|
||||
return $hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $hash a geohash
|
||||
* @author algorithm based on code by Alexander Songe <a@songe.me>
|
||||
* @see https://github.com/asonge/php-geohash/issues/1
|
||||
*/
|
||||
private function decode($hash)
|
||||
{
|
||||
$ll = array();
|
||||
$minlat = -90;
|
||||
$maxlat = 90;
|
||||
$minlon = -180;
|
||||
$maxlon = 180;
|
||||
$latE = 90;
|
||||
$lonE = 180;
|
||||
for ($i=0,$c=strlen($hash);$i<$c;$i++) {
|
||||
$v = strpos($this->table, $hash[$i]);
|
||||
if (1&$i) {
|
||||
if (16&$v)$minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2;
|
||||
if (8&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2;
|
||||
if (4&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2;
|
||||
if (2&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2;
|
||||
if (1&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2;
|
||||
$latE /= 8;
|
||||
$lonE /= 4;
|
||||
} else {
|
||||
if (16&$v)$minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2;
|
||||
if (8&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2;
|
||||
if (4&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2;
|
||||
if (2&$v) $minlat = ($minlat+$maxlat)/2; else $maxlat = ($minlat+$maxlat)/2;
|
||||
if (1&$v) $minlon = ($minlon+$maxlon)/2; else $maxlon = ($minlon+$maxlon)/2;
|
||||
$latE /= 4;
|
||||
$lonE /= 8;
|
||||
}
|
||||
}
|
||||
$ll['minlat'] = $minlat;
|
||||
$ll['minlon'] = $minlon;
|
||||
$ll['maxlat'] = $maxlat;
|
||||
$ll['maxlon'] = $maxlon;
|
||||
$ll['medlat'] = round(($minlat+$maxlat)/2, max(1, -round(log10($latE)))-1);
|
||||
$ll['medlon'] = round(($minlon+$maxlon)/2, max(1, -round(log10($lonE)))-1);
|
||||
return $ll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the adjacent geohash of the geohash in the specified direction.
|
||||
* This algorithm is available in various ports that seem to point back to
|
||||
* geohash-js by David Troy under MIT notice.
|
||||
*
|
||||
*
|
||||
* @see https://github.com/davetroy/geohash-js
|
||||
* @see https://github.com/lyokato/objc-geohash
|
||||
* @see https://github.com/lyokato/libgeohash
|
||||
* @see https://github.com/masuidrive/pr_geohash
|
||||
* @see https://github.com/sunng87/node-geohash
|
||||
* @see https://github.com/davidmoten/geo
|
||||
*
|
||||
* @param string $hash the geohash (lowercase)
|
||||
* @param string $direction the direction of the neighbor (top, bottom, left or right)
|
||||
* @return string the geohash of the adjacent cell
|
||||
*/
|
||||
public function adjacent($hash, $direction)
|
||||
{
|
||||
$last = substr($hash, -1);
|
||||
$type = (strlen($hash) % 2)? 'odd': 'even';
|
||||
$base = substr($hash, 0, strlen($hash) - 1);
|
||||
if (strpos(($this->borders[$direction][$type]), $last) !== false) {
|
||||
$base = $this->adjacent($base, $direction);
|
||||
}
|
||||
return $base.$this->table[strpos($this->neighbours[$direction][$type], $last)];
|
||||
}
|
||||
}
|
||||
161
htdocs/includes/geoPHP/lib/adapters/GeoJSON.class.php
Normal file
161
htdocs/includes/geoPHP/lib/adapters/GeoJSON.class.php
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
/**
|
||||
* GeoJSON class : a geojson reader/writer.
|
||||
*
|
||||
* Note that it will always return a GeoJSON geometry. This
|
||||
* means that if you pass it a feature, it will return the
|
||||
* geometry of that feature strip everything else.
|
||||
*/
|
||||
class GeoJSON extends GeoAdapter
|
||||
{
|
||||
/**
|
||||
* Given an object or a string, return a Geometry
|
||||
*
|
||||
* @param mixed $input The GeoJSON string or object
|
||||
*
|
||||
* @return object Geometry
|
||||
*/
|
||||
public function read($input)
|
||||
{
|
||||
if (is_string($input)) {
|
||||
$input = json_decode($input);
|
||||
}
|
||||
if (!is_object($input)) {
|
||||
throw new Exception('Invalid JSON');
|
||||
}
|
||||
if (!is_string($input->type)) {
|
||||
throw new Exception('Invalid JSON');
|
||||
}
|
||||
|
||||
// Check to see if it's a FeatureCollection
|
||||
if ($input->type == 'FeatureCollection') {
|
||||
$geoms = array();
|
||||
foreach ($input->features as $feature) {
|
||||
$geoms[] = $this->read($feature);
|
||||
}
|
||||
return geoPHP::geometryReduce($geoms);
|
||||
}
|
||||
|
||||
// Check to see if it's a Feature
|
||||
if ($input->type == 'Feature') {
|
||||
return $this->read($input->geometry);
|
||||
}
|
||||
|
||||
// It's a geometry - process it
|
||||
return $this->objToGeom($input);
|
||||
}
|
||||
|
||||
private function objToGeom($obj)
|
||||
{
|
||||
$type = $obj->type;
|
||||
|
||||
if ($type == 'GeometryCollection') {
|
||||
return $this->objToGeometryCollection($obj);
|
||||
}
|
||||
$method = 'arrayTo' . $type;
|
||||
return $this->$method($obj->coordinates);
|
||||
}
|
||||
|
||||
private function arrayToPoint($array)
|
||||
{
|
||||
if (!empty($array)) {
|
||||
return new Point($array[0], $array[1]);
|
||||
} else {
|
||||
return new Point();
|
||||
}
|
||||
}
|
||||
|
||||
private function arrayToLineString($array)
|
||||
{
|
||||
$points = array();
|
||||
foreach ($array as $comp_array) {
|
||||
$points[] = $this->arrayToPoint($comp_array);
|
||||
}
|
||||
return new LineString($points);
|
||||
}
|
||||
|
||||
private function arrayToPolygon($array)
|
||||
{
|
||||
$lines = array();
|
||||
foreach ($array as $comp_array) {
|
||||
$lines[] = $this->arrayToLineString($comp_array);
|
||||
}
|
||||
return new Polygon($lines);
|
||||
}
|
||||
|
||||
private function arrayToMultiPoint($array)
|
||||
{
|
||||
$points = array();
|
||||
foreach ($array as $comp_array) {
|
||||
$points[] = $this->arrayToPoint($comp_array);
|
||||
}
|
||||
return new MultiPoint($points);
|
||||
}
|
||||
|
||||
private function arrayToMultiLineString($array)
|
||||
{
|
||||
$lines = array();
|
||||
foreach ($array as $comp_array) {
|
||||
$lines[] = $this->arrayToLineString($comp_array);
|
||||
}
|
||||
return new MultiLineString($lines);
|
||||
}
|
||||
|
||||
private function arrayToMultiPolygon($array)
|
||||
{
|
||||
$polys = array();
|
||||
foreach ($array as $comp_array) {
|
||||
$polys[] = $this->arrayToPolygon($comp_array);
|
||||
}
|
||||
return new MultiPolygon($polys);
|
||||
}
|
||||
|
||||
private function objToGeometryCollection($obj)
|
||||
{
|
||||
$geoms = array();
|
||||
if (empty($obj->geometries)) {
|
||||
throw new Exception('Invalid GeoJSON: GeometryCollection with no component geometries');
|
||||
}
|
||||
foreach ($obj->geometries as $comp_object) {
|
||||
$geoms[] = $this->objToGeom($comp_object);
|
||||
}
|
||||
return new GeometryCollection($geoms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes an object into a geojson string
|
||||
*
|
||||
*
|
||||
* @param Geometry $obj The object to serialize
|
||||
*
|
||||
* @return string The GeoJSON string
|
||||
*/
|
||||
public function write(Geometry $geometry, $return_array = false)
|
||||
{
|
||||
if ($return_array) {
|
||||
return $this->getArray($geometry);
|
||||
} else {
|
||||
return json_encode($this->getArray($geometry));
|
||||
}
|
||||
}
|
||||
|
||||
public function getArray($geometry)
|
||||
{
|
||||
if ($geometry->getGeomType() == 'GeometryCollection') {
|
||||
$component_array = array();
|
||||
foreach ($geometry->components as $component) {
|
||||
$component_array[] = array(
|
||||
'type' => $component->geometryType(),
|
||||
'coordinates' => $component->asArray(),
|
||||
);
|
||||
}
|
||||
return array(
|
||||
'type'=> 'GeometryCollection',
|
||||
'geometries'=> $component_array,
|
||||
);
|
||||
} else return array(
|
||||
'type'=> $geometry->getGeomType(),
|
||||
'coordinates'=> $geometry->asArray(),
|
||||
);
|
||||
}
|
||||
}
|
||||
255
htdocs/includes/geoPHP/lib/adapters/GeoRSS.class.php
Normal file
255
htdocs/includes/geoPHP/lib/adapters/GeoRSS.class.php
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
<?php
|
||||
/*
|
||||
* Copyright (c) Patrick Hayes
|
||||
*
|
||||
* This code is open-source and licenced under the Modified BSD License.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHP Geometry/GeoRSS encoder/decoder
|
||||
*/
|
||||
class GeoRSS extends GeoAdapter
|
||||
{
|
||||
private $namespace = false;
|
||||
private $nss = ''; // Name-space string. eg 'georss:'
|
||||
|
||||
/**
|
||||
* Read GeoRSS string into geometry objects
|
||||
*
|
||||
* @param string $georss - an XML feed containing geoRSS
|
||||
*
|
||||
* @return Geometry|GeometryCollection
|
||||
*/
|
||||
public function read($gpx)
|
||||
{
|
||||
return $this->geomFromText($gpx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize geometries into a GeoRSS string.
|
||||
*
|
||||
* @param Geometry $geometry
|
||||
*
|
||||
* @return string The georss string representation of the input geometries
|
||||
*/
|
||||
public function write(Geometry $geometry, $namespace = false)
|
||||
{
|
||||
if ($namespace) {
|
||||
$this->namespace = $namespace;
|
||||
$this->nss = $namespace.':';
|
||||
}
|
||||
return $this->geometryToGeoRSS($geometry);
|
||||
}
|
||||
|
||||
public function geomFromText($text)
|
||||
{
|
||||
// Change to lower-case, strip all CDATA, and de-namespace
|
||||
$text = strtolower($text);
|
||||
$text = preg_replace('/<!\[cdata\[(.*?)\]\]>/s', '', $text);
|
||||
|
||||
// Load into DOMDOcument
|
||||
$xmlobj = new DOMDocument();
|
||||
@$xmlobj->loadXML($text);
|
||||
if ($xmlobj === false) {
|
||||
throw new Exception("Invalid GeoRSS: ". $text);
|
||||
}
|
||||
|
||||
$this->xmlobj = $xmlobj;
|
||||
try {
|
||||
$geom = $this->geomFromXML();
|
||||
} catch (InvalidText $e) {
|
||||
throw new Exception("Cannot Read Geometry From GeoRSS: ". $text);
|
||||
} catch (Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $geom;
|
||||
}
|
||||
|
||||
protected function geomFromXML()
|
||||
{
|
||||
$geometries = array();
|
||||
$geometries = array_merge($geometries, $this->parsePoints());
|
||||
$geometries = array_merge($geometries, $this->parseLines());
|
||||
$geometries = array_merge($geometries, $this->parsePolygons());
|
||||
$geometries = array_merge($geometries, $this->parseBoxes());
|
||||
$geometries = array_merge($geometries, $this->parseCircles());
|
||||
|
||||
if (empty($geometries)) {
|
||||
throw new Exception("Invalid / Empty GeoRSS");
|
||||
}
|
||||
|
||||
return geoPHP::geometryReduce($geometries);
|
||||
}
|
||||
|
||||
protected function getPointsFromCoords($string)
|
||||
{
|
||||
$coords = array();
|
||||
|
||||
if (empty($string)) {
|
||||
return $coords;
|
||||
}
|
||||
|
||||
$latlon = explode(' ', $string);
|
||||
foreach ($latlon as $key => $item) {
|
||||
if (!($key % 2)) {
|
||||
// It's a latitude
|
||||
$lat = $item;
|
||||
} else {
|
||||
// It's a longitude
|
||||
$lon = $item;
|
||||
$coords[] = new Point($lon, $lat);
|
||||
}
|
||||
}
|
||||
return $coords;
|
||||
}
|
||||
|
||||
protected function parsePoints()
|
||||
{
|
||||
$points = array();
|
||||
$pt_elements = $this->xmlobj->getElementsByTagName('point');
|
||||
foreach ($pt_elements as $pt) {
|
||||
if ($pt->hasChildNodes()) {
|
||||
$point_array = $this->getPointsFromCoords(trim($pt->firstChild->nodeValue));
|
||||
}
|
||||
if (!empty($point_array)) {
|
||||
$points[] = $point_array[0];
|
||||
} else {
|
||||
$points[] = new Point();
|
||||
}
|
||||
}
|
||||
return $points;
|
||||
}
|
||||
|
||||
protected function parseLines()
|
||||
{
|
||||
$lines = array();
|
||||
$line_elements = $this->xmlobj->getElementsByTagName('line');
|
||||
foreach ($line_elements as $line) {
|
||||
$components = $this->getPointsFromCoords(trim($line->firstChild->nodeValue));
|
||||
$lines[] = new LineString($components);
|
||||
}
|
||||
return $lines;
|
||||
}
|
||||
|
||||
protected function parsePolygons()
|
||||
{
|
||||
$polygons = array();
|
||||
$poly_elements = $this->xmlobj->getElementsByTagName('polygon');
|
||||
foreach ($poly_elements as $poly) {
|
||||
if ($poly->hasChildNodes()) {
|
||||
$points = $this->getPointsFromCoords(trim($poly->firstChild->nodeValue));
|
||||
$exterior_ring = new LineString($points);
|
||||
$polygons[] = new Polygon(array($exterior_ring));
|
||||
} else {
|
||||
// It's an EMPTY polygon
|
||||
$polygons[] = new Polygon();
|
||||
}
|
||||
}
|
||||
return $polygons;
|
||||
}
|
||||
|
||||
// Boxes are rendered into polygons
|
||||
protected function parseBoxes()
|
||||
{
|
||||
$polygons = array();
|
||||
$box_elements = $this->xmlobj->getElementsByTagName('box');
|
||||
foreach ($box_elements as $box) {
|
||||
$parts = explode(' ', trim($box->firstChild->nodeValue));
|
||||
$components = array(
|
||||
new Point($parts[3], $parts[2]),
|
||||
new Point($parts[3], $parts[0]),
|
||||
new Point($parts[1], $parts[0]),
|
||||
new Point($parts[1], $parts[2]),
|
||||
new Point($parts[3], $parts[2]),
|
||||
);
|
||||
$exterior_ring = new LineString($components);
|
||||
$polygons[] = new Polygon(array($exterior_ring));
|
||||
}
|
||||
return $polygons;
|
||||
}
|
||||
|
||||
// Circles are rendered into points
|
||||
// @@TODO: Add good support once we have circular-string geometry support
|
||||
protected function parseCircles()
|
||||
{
|
||||
$points = array();
|
||||
$circle_elements = $this->xmlobj->getElementsByTagName('circle');
|
||||
foreach ($circle_elements as $circle) {
|
||||
$parts = explode(' ', trim($circle->firstChild->nodeValue));
|
||||
$points[] = new Point($parts[1], $parts[0]);
|
||||
}
|
||||
return $points;
|
||||
}
|
||||
|
||||
protected function geometryToGeoRSS($geom)
|
||||
{
|
||||
$type = strtolower($geom->getGeomType());
|
||||
switch ($type) {
|
||||
case 'point':
|
||||
return $this->pointToGeoRSS($geom);
|
||||
break;
|
||||
case 'linestring':
|
||||
return $this->linestringToGeoRSS($geom);
|
||||
break;
|
||||
case 'polygon':
|
||||
return $this->PolygonToGeoRSS($geom);
|
||||
break;
|
||||
case 'multipoint':
|
||||
case 'multilinestring':
|
||||
case 'multipolygon':
|
||||
case 'geometrycollection':
|
||||
return $this->collectionToGeoRSS($geom);
|
||||
break;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function pointToGeoRSS($geom)
|
||||
{
|
||||
$out = '<'.$this->nss.'point>';
|
||||
if (!$geom->isEmpty()) {
|
||||
$out .= $geom->getY().' '.$geom->getX();
|
||||
}
|
||||
$out .= '</'.$this->nss.'point>';
|
||||
return $out;
|
||||
}
|
||||
|
||||
private function linestringToGeoRSS($geom)
|
||||
{
|
||||
$output = '<'.$this->nss.'line>';
|
||||
foreach ($geom->getComponents() as $k => $point) {
|
||||
$output .= $point->getY().' '.$point->getX();
|
||||
if ($k < ($geom->numGeometries() -1)) $output .= ' ';
|
||||
}
|
||||
$output .= '</'.$this->nss.'line>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function polygonToGeoRSS($geom)
|
||||
{
|
||||
$output = '<'.$this->nss.'polygon>';
|
||||
$exterior_ring = $geom->exteriorRing();
|
||||
foreach ($exterior_ring->getComponents() as $k => $point) {
|
||||
$output .= $point->getY().' '.$point->getX();
|
||||
if ($k < ($exterior_ring->numGeometries() -1)) $output .= ' ';
|
||||
}
|
||||
$output .= '</'.$this->nss.'polygon>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function collectionToGeoRSS($geom)
|
||||
{
|
||||
$georss = '<'.$this->nss.'where>';
|
||||
$components = $geom->getComponents();
|
||||
foreach ($geom->getComponents() as $comp) {
|
||||
$georss .= $this->geometryToGeoRSS($comp);
|
||||
}
|
||||
|
||||
$georss .= '</'.$this->nss.'where>';
|
||||
|
||||
return $georss;
|
||||
}
|
||||
}
|
||||
170
htdocs/includes/geoPHP/lib/adapters/GoogleGeocode.class.php
Normal file
170
htdocs/includes/geoPHP/lib/adapters/GoogleGeocode.class.php
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
/*
|
||||
* (c) Camptocamp <info@camptocamp.com>
|
||||
* (c) Patrick Hayes
|
||||
*
|
||||
* This code is open-source and licenced under the Modified BSD License.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHP Google Geocoder Adapter
|
||||
*
|
||||
*
|
||||
* @package geoPHP
|
||||
* @author Patrick Hayes <patrick.d.hayes@gmail.com>
|
||||
*/
|
||||
class GoogleGeocode extends GeoAdapter
|
||||
{
|
||||
|
||||
/**
|
||||
* Read an address string or array geometry objects
|
||||
*
|
||||
* @param string - Address to geocode
|
||||
* @param string - Type of Geometry to return. Can either be 'points' or 'bounds' (polygon)
|
||||
* @param Geometry|bounds-array - Limit the search area to within this region. For example
|
||||
* by default geocoding "Cairo" will return the location of Cairo Egypt.
|
||||
* If you pass a polygon of illinois, it will return Cairo IL.
|
||||
* @param return_multiple - Return all results in a multipoint or multipolygon
|
||||
* @return Geometry|GeometryCollection
|
||||
*/
|
||||
public function read($address, $return_type = 'point', $bounds = false, $return_multiple = false)
|
||||
{
|
||||
if (is_array($address)) $address = join(',', $address);
|
||||
|
||||
if (gettype($bounds) == 'object') {
|
||||
$bounds = $bounds->getBBox();
|
||||
}
|
||||
if (gettype($bounds) == 'array') {
|
||||
$bounds_string = '&bounds='.$bounds['miny'].','.$bounds['minx'].'|'.$bounds['maxy'].','.$bounds['maxx'];
|
||||
} else {
|
||||
$bounds_string = '';
|
||||
}
|
||||
|
||||
$url = "http://maps.googleapis.com/maps/api/geocode/json";
|
||||
$url .= '?address='. urlencode($address);
|
||||
$url .= $bounds_string;
|
||||
$url .= '&sensor=false';
|
||||
$this->result = json_decode(@file_get_contents($url));
|
||||
|
||||
if ($this->result->status == 'OK') {
|
||||
if ($return_multiple == false) {
|
||||
if ($return_type == 'point') {
|
||||
return $this->getPoint();
|
||||
}
|
||||
if ($return_type == 'bounds' || $return_type == 'polygon') {
|
||||
return $this->getPolygon();
|
||||
}
|
||||
}
|
||||
if ($return_multiple == true) {
|
||||
if ($return_type == 'point') {
|
||||
$points = array();
|
||||
foreach ($this->result->results as $delta => $item) {
|
||||
$points[] = $this->getPoint($delta);
|
||||
}
|
||||
return new MultiPoint($points);
|
||||
}
|
||||
if ($return_type == 'bounds' || $return_type == 'polygon') {
|
||||
$polygons = array();
|
||||
foreach ($this->result->results as $delta => $item) {
|
||||
$polygons[] = $this->getPolygon($delta);
|
||||
}
|
||||
return new MultiPolygon($polygons);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($this->result->status) throw new Exception('Error in Google Geocoder: '.$this->result->status);
|
||||
else throw new Exception('Unknown error in Google Geocoder');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize geometries into a WKT string.
|
||||
*
|
||||
* @param Geometry $geometry
|
||||
* @param string $return_type Should be either 'string' or 'array'
|
||||
*
|
||||
* @return string Does a reverse geocode of the geometry
|
||||
*/
|
||||
public function write(Geometry $geometry, $return_type = 'string')
|
||||
{
|
||||
$centroid = $geometry->getCentroid();
|
||||
$lat = $centroid->getY();
|
||||
$lon = $centroid->getX();
|
||||
|
||||
$url = "http://maps.googleapis.com/maps/api/geocode/json";
|
||||
$url .= '?latlng='.$lat.','.$lon;
|
||||
$url .= '&sensor=false';
|
||||
$this->result = json_decode(@file_get_contents($url));
|
||||
|
||||
if ($this->result->status == 'OK') {
|
||||
if ($return_type == 'string') {
|
||||
return $this->result->results[0]->formatted_address;
|
||||
}
|
||||
if ($return_type == 'array') {
|
||||
return $this->result->results[0]->address_components;
|
||||
}
|
||||
} elseif ($this->result->status == 'ZERO_RESULTS') {
|
||||
if ($return_type == 'string') {
|
||||
return '';
|
||||
}
|
||||
if ($return_type == 'array') {
|
||||
return $this->result->results;
|
||||
}
|
||||
} else {
|
||||
if ($this->result->status) throw new Exception('Error in Google Reverse Geocoder: '.$this->result->status);
|
||||
else throw new Exception('Unknown error in Google Reverse Geocoder');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function getPoint($delta = 0)
|
||||
{
|
||||
$lat = $this->result->results[$delta]->geometry->location->lat;
|
||||
$lon = $this->result->results[$delta]->geometry->location->lng;
|
||||
return new Point($lon, $lat);
|
||||
}
|
||||
|
||||
private function getPolygon($delta = 0)
|
||||
{
|
||||
$points = array (
|
||||
$this->getTopLeft($delta),
|
||||
$this->getTopRight($delta),
|
||||
$this->getBottomRight($delta),
|
||||
$this->getBottomLeft($delta),
|
||||
$this->getTopLeft($delta),
|
||||
);
|
||||
$outer_ring = new LineString($points);
|
||||
return new Polygon(array($outer_ring));
|
||||
}
|
||||
|
||||
private function getTopLeft($delta = 0)
|
||||
{
|
||||
$lat = $this->result->results[$delta]->geometry->bounds->northeast->lat;
|
||||
$lon = $this->result->results[$delta]->geometry->bounds->southwest->lng;
|
||||
return new Point($lon, $lat);
|
||||
}
|
||||
|
||||
private function getTopRight($delta = 0)
|
||||
{
|
||||
$lat = $this->result->results[$delta]->geometry->bounds->northeast->lat;
|
||||
$lon = $this->result->results[$delta]->geometry->bounds->northeast->lng;
|
||||
return new Point($lon, $lat);
|
||||
}
|
||||
|
||||
private function getBottomLeft($delta = 0)
|
||||
{
|
||||
$lat = $this->result->results[$delta]->geometry->bounds->southwest->lat;
|
||||
$lon = $this->result->results[$delta]->geometry->bounds->southwest->lng;
|
||||
return new Point($lon, $lat);
|
||||
}
|
||||
|
||||
private function getBottomRight($delta = 0)
|
||||
{
|
||||
$lat = $this->result->results[$delta]->geometry->bounds->southwest->lat;
|
||||
$lon = $this->result->results[$delta]->geometry->bounds->northeast->lng;
|
||||
return new Point($lon, $lat);
|
||||
}
|
||||
}
|
||||
284
htdocs/includes/geoPHP/lib/adapters/KML.class.php
Normal file
284
htdocs/includes/geoPHP/lib/adapters/KML.class.php
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
<?php
|
||||
/*
|
||||
* Copyright (c) Patrick Hayes
|
||||
* Copyright (c) 2010-2011, Arnaud Renevier
|
||||
*
|
||||
* This code is open-source and licenced under the Modified BSD License.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHP Geometry/KML encoder/decoder
|
||||
*
|
||||
* Mainly inspired/adapted from OpenLayers( http://www.openlayers.org )
|
||||
* Openlayers/format/WKT.js
|
||||
*
|
||||
* @package sfMapFishPlugin
|
||||
* @subpackage GeoJSON
|
||||
* @author Camptocamp <info@camptocamp.com>
|
||||
*/
|
||||
class KML extends GeoAdapter
|
||||
{
|
||||
private $namespace = false;
|
||||
private $nss = ''; // Name-space string. eg 'georss:'
|
||||
|
||||
/**
|
||||
* Read KML string into geometry objects
|
||||
*
|
||||
* @param string $kml A KML string
|
||||
*
|
||||
* @return Geometry|GeometryCollection
|
||||
*/
|
||||
public function read($kml)
|
||||
{
|
||||
return $this->geomFromText($kml);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize geometries into a KML string.
|
||||
*
|
||||
* @param Geometry $geometry
|
||||
*
|
||||
* @return string The KML string representation of the input geometries
|
||||
*/
|
||||
public function write(Geometry $geometry, $namespace = false)
|
||||
{
|
||||
if ($namespace) {
|
||||
$this->namespace = $namespace;
|
||||
$this->nss = $namespace.':';
|
||||
}
|
||||
return $this->geometryToKML($geometry);
|
||||
}
|
||||
|
||||
public function geomFromText($text)
|
||||
{
|
||||
// Change to lower-case and strip all CDATA
|
||||
$text = mb_strtolower($text, mb_detect_encoding($text));
|
||||
$text = preg_replace('/<!\[cdata\[(.*?)\]\]>/s', '', $text);
|
||||
|
||||
// Load into DOMDocument
|
||||
$xmlobj = new DOMDocument();
|
||||
@$xmlobj->loadXML($text);
|
||||
if ($xmlobj === false) {
|
||||
throw new Exception("Invalid KML: ". $text);
|
||||
}
|
||||
|
||||
$this->xmlobj = $xmlobj;
|
||||
try {
|
||||
$geom = $this->geomFromXML();
|
||||
} catch (InvalidText $e) {
|
||||
throw new Exception("Cannot Read Geometry From KML: ". $text);
|
||||
} catch (Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $geom;
|
||||
}
|
||||
|
||||
protected function geomFromXML()
|
||||
{
|
||||
$geometries = array();
|
||||
$geom_types = geoPHP::geometryList();
|
||||
$placemark_elements = $this->xmlobj->getElementsByTagName('placemark');
|
||||
if ($placemark_elements->length) {
|
||||
foreach ($placemark_elements as $placemark) {
|
||||
foreach ($placemark->childNodes as $child) {
|
||||
// Node names are all the same, except for MultiGeometry, which maps to GeometryCollection
|
||||
$node_name = $child->nodeName == 'multigeometry' ? 'geometrycollection' : $child->nodeName;
|
||||
if (array_key_exists($node_name, $geom_types)) {
|
||||
$function = 'parse'.$geom_types[$node_name];
|
||||
$geometries[] = $this->$function($child);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The document does not have a placemark, try to create a valid geometry from the root element
|
||||
$node_name = $this->xmlobj->documentElement->nodeName == 'multigeometry' ? 'geometrycollection' : $this->xmlobj->documentElement->nodeName;
|
||||
if (array_key_exists($node_name, $geom_types)) {
|
||||
$function = 'parse'.$geom_types[$node_name];
|
||||
$geometries[] = $this->$function($this->xmlobj->documentElement);
|
||||
}
|
||||
}
|
||||
return geoPHP::geometryReduce($geometries);
|
||||
}
|
||||
|
||||
protected function childElements($xml, $nodename = '')
|
||||
{
|
||||
$children = array();
|
||||
if ($xml->childNodes) {
|
||||
foreach ($xml->childNodes as $child) {
|
||||
if ($child->nodeName == $nodename) {
|
||||
$children[] = $child;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $children;
|
||||
}
|
||||
|
||||
protected function parsePoint($xml)
|
||||
{
|
||||
$coordinates = $this->_extractCoordinates($xml);
|
||||
if (!empty($coordinates)) {
|
||||
return new Point($coordinates[0][0], $coordinates[0][1]);
|
||||
} else {
|
||||
return new Point();
|
||||
}
|
||||
}
|
||||
|
||||
protected function parseLineString($xml)
|
||||
{
|
||||
$coordinates = $this->_extractCoordinates($xml);
|
||||
$point_array = array();
|
||||
foreach ($coordinates as $set) {
|
||||
$point_array[] = new Point($set[0], $set[1]);
|
||||
}
|
||||
return new LineString($point_array);
|
||||
}
|
||||
|
||||
protected function parsePolygon($xml)
|
||||
{
|
||||
$components = array();
|
||||
|
||||
$outer_boundary_element_a = $this->childElements($xml, 'outerboundaryis');
|
||||
if (empty($outer_boundary_element_a)) {
|
||||
return new Polygon(); // It's an empty polygon
|
||||
}
|
||||
$outer_boundary_element = $outer_boundary_element_a[0];
|
||||
$outer_ring_element_a = $this->childElements($outer_boundary_element, 'linearring');
|
||||
$outer_ring_element = $outer_ring_element_a[0];
|
||||
$components[] = $this->parseLineString($outer_ring_element);
|
||||
|
||||
if (count($components) != 1) {
|
||||
throw new Exception("Invalid KML");
|
||||
}
|
||||
|
||||
$inner_boundary_element_a = $this->childElements($xml, 'innerboundaryis');
|
||||
if (count($inner_boundary_element_a)) {
|
||||
foreach ($inner_boundary_element_a as $inner_boundary_element) {
|
||||
foreach ($this->childElements($inner_boundary_element, 'linearring') as $inner_ring_element) {
|
||||
$components[] = $this->parseLineString($inner_ring_element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Polygon($components);
|
||||
}
|
||||
|
||||
protected function parseGeometryCollection($xml)
|
||||
{
|
||||
$components = array();
|
||||
$geom_types = geoPHP::geometryList();
|
||||
foreach ($xml->childNodes as $child) {
|
||||
$nodeName = ($child->nodeName == 'linearring') ? 'linestring' : $child->nodeName;
|
||||
if (array_key_exists($nodeName, $geom_types)) {
|
||||
$function = 'parse'.$geom_types[$nodeName];
|
||||
$components[] = $this->$function($child);
|
||||
}
|
||||
}
|
||||
return new GeometryCollection($components);
|
||||
}
|
||||
|
||||
protected function _extractCoordinates($xml)
|
||||
{
|
||||
$coord_elements = $this->childElements($xml, 'coordinates');
|
||||
$coordinates = array();
|
||||
if (count($coord_elements)) {
|
||||
$coord_sets = explode(' ', preg_replace('/[\r\n]+/', ' ', $coord_elements[0]->nodeValue));
|
||||
foreach ($coord_sets as $set_string) {
|
||||
$set_string = trim($set_string);
|
||||
if ($set_string) {
|
||||
$set_array = explode(',', $set_string);
|
||||
if (count($set_array) >= 2) {
|
||||
$coordinates[] = $set_array;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $coordinates;
|
||||
}
|
||||
|
||||
private function geometryToKML($geom)
|
||||
{
|
||||
$type = strtolower($geom->getGeomType());
|
||||
switch ($type) {
|
||||
case 'point':
|
||||
return $this->pointToKML($geom);
|
||||
break;
|
||||
case 'linestring':
|
||||
return $this->linestringToKML($geom);
|
||||
break;
|
||||
case 'polygon':
|
||||
return $this->polygonToKML($geom);
|
||||
break;
|
||||
case 'multipoint':
|
||||
case 'multilinestring':
|
||||
case 'multipolygon':
|
||||
case 'geometrycollection':
|
||||
return $this->collectionToKML($geom);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function pointToKML($geom)
|
||||
{
|
||||
$out = '<'.$this->nss.'Point>';
|
||||
if (!$geom->isEmpty()) {
|
||||
$out .= '<'.$this->nss.'coordinates>'.$geom->getX().",".$geom->getY().'</'.$this->nss.'coordinates>';
|
||||
}
|
||||
$out .= '</'.$this->nss.'Point>';
|
||||
return $out;
|
||||
}
|
||||
|
||||
private function linestringToKML($geom, $type = false)
|
||||
{
|
||||
if (!$type) {
|
||||
$type = $geom->getGeomType();
|
||||
}
|
||||
|
||||
$str = '<'.$this->nss . $type .'>';
|
||||
|
||||
if (!$geom->isEmpty()) {
|
||||
$str .= '<'.$this->nss.'coordinates>';
|
||||
$i=0;
|
||||
foreach ($geom->getComponents() as $comp) {
|
||||
if ($i != 0) $str .= ' ';
|
||||
$str .= $comp->getX() .','. $comp->getY();
|
||||
$i++;
|
||||
}
|
||||
|
||||
$str .= '</'.$this->nss.'coordinates>';
|
||||
}
|
||||
|
||||
$str .= '</'. $this->nss . $type .'>';
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
public function polygonToKML($geom)
|
||||
{
|
||||
$components = $geom->getComponents();
|
||||
$str = '';
|
||||
if (!empty($components)) {
|
||||
$str = '<'.$this->nss.'outerBoundaryIs>' . $this->linestringToKML($components[0], 'LinearRing') . '</'.$this->nss.'outerBoundaryIs>';
|
||||
foreach (array_slice($components, 1) as $comp) {
|
||||
$str .= '<'.$this->nss.'innerBoundaryIs>' . $this->linestringToKML($comp) . '</'.$this->nss.'innerBoundaryIs>';
|
||||
}
|
||||
}
|
||||
|
||||
return '<'.$this->nss.'Polygon>'. $str .'</'.$this->nss.'Polygon>';
|
||||
}
|
||||
|
||||
public function collectionToKML($geom)
|
||||
{
|
||||
$components = $geom->getComponents();
|
||||
$str = '<'.$this->nss.'MultiGeometry>';
|
||||
foreach ($geom->getComponents() as $comp) {
|
||||
$sub_adapter = new KML();
|
||||
$str .= $sub_adapter->write($comp);
|
||||
}
|
||||
|
||||
return $str .'</'.$this->nss.'MultiGeometry>';
|
||||
}
|
||||
}
|
||||
258
htdocs/includes/geoPHP/lib/adapters/WKB.class.php
Normal file
258
htdocs/includes/geoPHP/lib/adapters/WKB.class.php
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
<?php
|
||||
/*
|
||||
* (c) Patrick Hayes
|
||||
*
|
||||
* This code is open-source and licenced under the Modified BSD License.
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PHP Geometry/WKB encoder/decoder
|
||||
*
|
||||
*/
|
||||
class WKB extends GeoAdapter
|
||||
{
|
||||
|
||||
private $dimension = 2;
|
||||
private $z = false;
|
||||
private $m = false;
|
||||
|
||||
/**
|
||||
* Read WKB into geometry objects
|
||||
*
|
||||
* @param string $wkb
|
||||
* Well-known-binary string
|
||||
* @param bool $is_hex_string
|
||||
* If this is a hexedecimal string that is in need of packing
|
||||
*
|
||||
* @return Geometry
|
||||
*/
|
||||
public function read($wkb, $is_hex_string = false)
|
||||
{
|
||||
if ($is_hex_string) {
|
||||
$wkb = pack('H*', $wkb);
|
||||
}
|
||||
|
||||
if (empty($wkb)) {
|
||||
throw new Exception('Cannot read empty WKB geometry. Found ' . gettype($wkb));
|
||||
}
|
||||
|
||||
$mem = fopen('php://memory', 'r+');
|
||||
fwrite($mem, $wkb);
|
||||
fseek($mem, 0);
|
||||
|
||||
$geometry = $this->getGeometry($mem);
|
||||
fclose($mem);
|
||||
return $geometry;
|
||||
}
|
||||
|
||||
function getGeometry(&$mem)
|
||||
{
|
||||
$base_info = unpack("corder/ctype/cz/cm/cs", fread($mem, 5));
|
||||
if ($base_info['order'] !== 1) {
|
||||
throw new Exception('Only NDR (little endian) SKB format is supported at the moment');
|
||||
}
|
||||
|
||||
if ($base_info['z']) {
|
||||
$this->dimension++;
|
||||
$this->z = true;
|
||||
}
|
||||
if ($base_info['m']) {
|
||||
$this->dimension++;
|
||||
$this->m = true;
|
||||
}
|
||||
|
||||
// If there is SRID information, ignore it - use EWKB Adapter to get SRID support
|
||||
if ($base_info['s']) {
|
||||
fread($mem, 4);
|
||||
}
|
||||
|
||||
switch ($base_info['type']) {
|
||||
case 1:
|
||||
return $this->getPoint($mem);
|
||||
case 2:
|
||||
return $this->getLinstring($mem);
|
||||
case 3:
|
||||
return $this->getPolygon($mem);
|
||||
case 4:
|
||||
return $this->getMulti($mem, 'point');
|
||||
case 5:
|
||||
return $this->getMulti($mem, 'line');
|
||||
case 6:
|
||||
return $this->getMulti($mem, 'polygon');
|
||||
case 7:
|
||||
return $this->getMulti($mem, 'geometry');
|
||||
}
|
||||
}
|
||||
|
||||
function getPoint(&$mem)
|
||||
{
|
||||
$point_coords = unpack("d*", fread($mem, $this->dimension*8));
|
||||
if (!empty($point_coords)) {
|
||||
return new Point($point_coords[1], $point_coords[2]);
|
||||
} else {
|
||||
return new Point(); // EMPTY point
|
||||
}
|
||||
}
|
||||
|
||||
function getLinstring(&$mem)
|
||||
{
|
||||
// Get the number of points expected in this string out of the first 4 bytes
|
||||
$line_length = unpack('L', fread($mem, 4));
|
||||
|
||||
// Return an empty linestring if there is no line-length
|
||||
if (!$line_length[1]) return new LineString();
|
||||
|
||||
// Read the nubmer of points x2 (each point is two coords) into decimal-floats
|
||||
$line_coords = unpack('d*', fread($mem, $line_length[1]*$this->dimension*8));
|
||||
|
||||
// We have our coords, build up the linestring
|
||||
$components = array();
|
||||
$i = 1;
|
||||
$num_coords = count($line_coords);
|
||||
while ($i <= $num_coords) {
|
||||
$components[] = new Point($line_coords[$i], $line_coords[$i+1]);
|
||||
$i += 2;
|
||||
}
|
||||
return new LineString($components);
|
||||
}
|
||||
|
||||
function getPolygon(&$mem)
|
||||
{
|
||||
// Get the number of linestring expected in this poly out of the first 4 bytes
|
||||
$poly_length = unpack('L', fread($mem, 4));
|
||||
|
||||
$components = array();
|
||||
$i = 1;
|
||||
while ($i <= $poly_length[1]) {
|
||||
$components[] = $this->getLinstring($mem);
|
||||
$i++;
|
||||
}
|
||||
return new Polygon($components);
|
||||
}
|
||||
|
||||
function getMulti(&$mem, $type)
|
||||
{
|
||||
// Get the number of items expected in this multi out of the first 4 bytes
|
||||
$multi_length = unpack('L', fread($mem, 4));
|
||||
|
||||
$components = array();
|
||||
$i = 1;
|
||||
while ($i <= $multi_length[1]) {
|
||||
$components[] = $this->getGeometry($mem);
|
||||
$i++;
|
||||
}
|
||||
switch ($type) {
|
||||
case 'point':
|
||||
return new MultiPoint($components);
|
||||
case 'line':
|
||||
return new MultiLineString($components);
|
||||
case 'polygon':
|
||||
return new MultiPolygon($components);
|
||||
case 'geometry':
|
||||
return new GeometryCollection($components);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize geometries into WKB string.
|
||||
*
|
||||
* @param Geometry $geometry
|
||||
*
|
||||
* @return string The WKB string representation of the input geometries
|
||||
*/
|
||||
public function write(Geometry $geometry, $write_as_hex = false)
|
||||
{
|
||||
// We always write into NDR (little endian)
|
||||
$wkb = pack('c', 1);
|
||||
|
||||
switch ($geometry->getGeomType()) {
|
||||
case 'Point';
|
||||
$wkb .= pack('L', 1);
|
||||
$wkb .= $this->writePoint($geometry);
|
||||
break;
|
||||
case 'LineString';
|
||||
$wkb .= pack('L', 2);
|
||||
$wkb .= $this->writeLineString($geometry);
|
||||
break;
|
||||
case 'Polygon';
|
||||
$wkb .= pack('L', 3);
|
||||
$wkb .= $this->writePolygon($geometry);
|
||||
break;
|
||||
case 'MultiPoint';
|
||||
$wkb .= pack('L', 4);
|
||||
$wkb .= $this->writeMulti($geometry);
|
||||
break;
|
||||
case 'MultiLineString';
|
||||
$wkb .= pack('L', 5);
|
||||
$wkb .= $this->writeMulti($geometry);
|
||||
break;
|
||||
case 'MultiPolygon';
|
||||
$wkb .= pack('L', 6);
|
||||
$wkb .= $this->writeMulti($geometry);
|
||||
break;
|
||||
case 'GeometryCollection';
|
||||
$wkb .= pack('L', 7);
|
||||
$wkb .= $this->writeMulti($geometry);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($write_as_hex) {
|
||||
$unpacked = unpack('H*', $wkb);
|
||||
return $unpacked[1];
|
||||
} else {
|
||||
return $wkb;
|
||||
}
|
||||
}
|
||||
|
||||
function writePoint($point)
|
||||
{
|
||||
// Set the coords
|
||||
if (!$point->isEmpty()) {
|
||||
$wkb = pack('dd', $point->x(), $point->y());
|
||||
return $wkb;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function writeLineString($line)
|
||||
{
|
||||
// Set the number of points in this line
|
||||
$wkb = pack('L', $line->numPoints());
|
||||
|
||||
// Set the coords
|
||||
foreach ($line->getComponents() as $point) {
|
||||
$wkb .= pack('dd', $point->x(), $point->y());
|
||||
}
|
||||
|
||||
return $wkb;
|
||||
}
|
||||
|
||||
function writePolygon($poly)
|
||||
{
|
||||
// Set the number of lines in this poly
|
||||
$wkb = pack('L', $poly->numGeometries());
|
||||
|
||||
// Write the lines
|
||||
foreach ($poly->getComponents() as $line) {
|
||||
$wkb .= $this->writeLineString($line);
|
||||
}
|
||||
|
||||
return $wkb;
|
||||
}
|
||||
|
||||
function writeMulti($geometry)
|
||||
{
|
||||
// Set the number of components
|
||||
$wkb = pack('L', $geometry->numGeometries());
|
||||
|
||||
// Write the components
|
||||
foreach ($geometry->getComponents() as $component) {
|
||||
$wkb .= $this->write($component);
|
||||
}
|
||||
|
||||
return $wkb;
|
||||
}
|
||||
}
|
||||
265
htdocs/includes/geoPHP/lib/adapters/WKT.class.php
Normal file
265
htdocs/includes/geoPHP/lib/adapters/WKT.class.php
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
<?php
|
||||
/**
|
||||
* WKT (Well Known Text) Adapter
|
||||
*/
|
||||
class WKT extends GeoAdapter
|
||||
{
|
||||
|
||||
/**
|
||||
* Read WKT string into geometry objects
|
||||
*
|
||||
* @param string $WKT A WKT string
|
||||
*
|
||||
* @return Geometry
|
||||
*/
|
||||
public function read($wkt)
|
||||
{
|
||||
$wkt = trim($wkt);
|
||||
|
||||
// If it contains a ';', then it contains additional SRID data
|
||||
if (strpos($wkt, ';')) {
|
||||
$parts = explode(';', $wkt);
|
||||
$wkt = $parts[1];
|
||||
$eparts = explode('=', $parts[0]);
|
||||
$srid = $eparts[1];
|
||||
} else {
|
||||
$srid = null;
|
||||
}
|
||||
|
||||
// If geos is installed, then we take a shortcut and let it parse the WKT
|
||||
if (geoPHP::geosInstalled()) {
|
||||
$reader = new GEOSWKTReader();
|
||||
if ($srid) {
|
||||
$geom = geoPHP::geosToGeometry($reader->read($wkt));
|
||||
$geom->setSRID($srid);
|
||||
return $geom;
|
||||
} else {
|
||||
return geoPHP::geosToGeometry($reader->read($wkt));
|
||||
}
|
||||
}
|
||||
$wkt = str_replace(', ', ',', $wkt);
|
||||
|
||||
// For each geometry type, check to see if we have a match at the
|
||||
// beginning of the string. If we do, then parse using that type
|
||||
foreach (geoPHP::geometryList() as $geom_type) {
|
||||
$wkt_geom = strtoupper($geom_type);
|
||||
if (strtoupper(substr($wkt, 0, strlen($wkt_geom))) == $wkt_geom) {
|
||||
$data_string = $this->getDataString($wkt);
|
||||
$method = 'parse'.$geom_type;
|
||||
|
||||
if ($srid) {
|
||||
$geom = $this->$method($data_string);
|
||||
$geom->setSRID($srid);
|
||||
return $geom;
|
||||
} else {
|
||||
return $this->$method($data_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function parsePoint($data_string)
|
||||
{
|
||||
$data_string = $this->trimParens($data_string);
|
||||
|
||||
// If it's marked as empty, then return an empty point
|
||||
if ($data_string == 'EMPTY') return new Point();
|
||||
|
||||
$parts = explode(' ', $data_string);
|
||||
return new Point($parts[0], $parts[1]);
|
||||
}
|
||||
|
||||
private function parseLineString($data_string)
|
||||
{
|
||||
$data_string = $this->trimParens($data_string);
|
||||
|
||||
// If it's marked as empty, then return an empty line
|
||||
if ($data_string == 'EMPTY') return new LineString();
|
||||
|
||||
$parts = explode(',', $data_string);
|
||||
$points = array();
|
||||
foreach ($parts as $part) {
|
||||
$points[] = $this->parsePoint($part);
|
||||
}
|
||||
return new LineString($points);
|
||||
}
|
||||
|
||||
private function parsePolygon($data_string)
|
||||
{
|
||||
$data_string = $this->trimParens($data_string);
|
||||
|
||||
// If it's marked as empty, then return an empty polygon
|
||||
if ($data_string == 'EMPTY') return new Polygon();
|
||||
|
||||
$parts = explode('),(', $data_string);
|
||||
$lines = array();
|
||||
foreach ($parts as $part) {
|
||||
if (!$this->beginsWith($part, '(')) $part = '(' . $part;
|
||||
if (!$this->endsWith($part, ')')) $part = $part . ')';
|
||||
$lines[] = $this->parseLineString($part);
|
||||
}
|
||||
return new Polygon($lines);
|
||||
}
|
||||
|
||||
private function parseMultiPoint($data_string)
|
||||
{
|
||||
$data_string = $this->trimParens($data_string);
|
||||
|
||||
// If it's marked as empty, then return an empty MutiPoint
|
||||
if ($data_string == 'EMPTY') return new MultiPoint();
|
||||
|
||||
$parts = explode(',', $data_string);
|
||||
$points = array();
|
||||
foreach ($parts as $part) {
|
||||
$points[] = $this->parsePoint($part);
|
||||
}
|
||||
return new MultiPoint($points);
|
||||
}
|
||||
|
||||
private function parseMultiLineString($data_string)
|
||||
{
|
||||
$data_string = $this->trimParens($data_string);
|
||||
|
||||
// If it's marked as empty, then return an empty multi-linestring
|
||||
if ($data_string == 'EMPTY') return new MultiLineString();
|
||||
|
||||
$parts = explode('),(', $data_string);
|
||||
$lines = array();
|
||||
foreach ($parts as $part) {
|
||||
// Repair the string if the explode broke it
|
||||
if (!$this->beginsWith($part, '(')) $part = '(' . $part;
|
||||
if (!$this->endsWith($part, ')')) $part = $part . ')';
|
||||
$lines[] = $this->parseLineString($part);
|
||||
}
|
||||
return new MultiLineString($lines);
|
||||
}
|
||||
|
||||
private function parseMultiPolygon($data_string)
|
||||
{
|
||||
$data_string = $this->trimParens($data_string);
|
||||
|
||||
// If it's marked as empty, then return an empty multi-polygon
|
||||
if ($data_string == 'EMPTY') return new MultiPolygon();
|
||||
|
||||
$parts = explode(')),((', $data_string);
|
||||
$polys = array();
|
||||
foreach ($parts as $part) {
|
||||
// Repair the string if the explode broke it
|
||||
if (!$this->beginsWith($part, '((')) $part = '((' . $part;
|
||||
if (!$this->endsWith($part, '))')) $part = $part . '))';
|
||||
$polys[] = $this->parsePolygon($part);
|
||||
}
|
||||
return new MultiPolygon($polys);
|
||||
}
|
||||
|
||||
private function parseGeometryCollection($data_string)
|
||||
{
|
||||
$data_string = $this->trimParens($data_string);
|
||||
|
||||
// If it's marked as empty, then return an empty geom-collection
|
||||
if ($data_string == 'EMPTY') return new GeometryCollection();
|
||||
|
||||
$geometries = array();
|
||||
$matches = array();
|
||||
$str = preg_replace('/,\s*([A-Za-z])/', '|$1', $data_string);
|
||||
$components = explode('|', trim($str));
|
||||
|
||||
foreach ($components as $component) {
|
||||
$geometries[] = $this->read($component);
|
||||
}
|
||||
return new GeometryCollection($geometries);
|
||||
}
|
||||
|
||||
protected function getDataString($wkt)
|
||||
{
|
||||
$first_paren = strpos($wkt, '(');
|
||||
|
||||
if ($first_paren !== false) {
|
||||
return substr($wkt, $first_paren);
|
||||
} elseif (strstr($wkt, 'EMPTY')) {
|
||||
return 'EMPTY';
|
||||
} else return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim the parenthesis and spaces
|
||||
*/
|
||||
protected function trimParens($str)
|
||||
{
|
||||
$str = trim($str);
|
||||
|
||||
// We want to only strip off one set of parenthesis
|
||||
if ($this->beginsWith($str, '(')) {
|
||||
return substr($str, 1, -1);
|
||||
} else return $str;
|
||||
}
|
||||
|
||||
protected function beginsWith($str, $char)
|
||||
{
|
||||
if (substr($str, 0, strlen($char)) == $char) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
protected function endsWith($str, $char)
|
||||
{
|
||||
if (substr($str, (0 - strlen($char))) == $char) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize geometries into a WKT string.
|
||||
*
|
||||
* @param Geometry $geometry
|
||||
*
|
||||
* @return string The WKT string representation of the input geometries
|
||||
*/
|
||||
public function write(Geometry $geometry)
|
||||
{
|
||||
// If geos is installed, then we take a shortcut and let it write the WKT
|
||||
if (geoPHP::geosInstalled()) {
|
||||
$writer = new GEOSWKTWriter();
|
||||
$writer->setTrim(true);
|
||||
return $writer->write($geometry->geos());
|
||||
}
|
||||
|
||||
if ($geometry->isEmpty()) {
|
||||
return strtoupper($geometry->geometryType()).' EMPTY';
|
||||
} elseif ($data = $this->extractData($geometry)) {
|
||||
return strtoupper($geometry->geometryType()).' ('.$data.')';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract geometry to a WKT string
|
||||
*
|
||||
* @param Geometry $geometry A Geometry object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function extractData($geometry)
|
||||
{
|
||||
$parts = array();
|
||||
switch ($geometry->geometryType()) {
|
||||
case 'Point':
|
||||
return $geometry->getX().' '.$geometry->getY();
|
||||
case 'LineString':
|
||||
foreach ($geometry->getComponents() as $component) {
|
||||
$parts[] = $this->extractData($component);
|
||||
}
|
||||
return implode(', ', $parts);
|
||||
case 'Polygon':
|
||||
case 'MultiPoint':
|
||||
case 'MultiLineString':
|
||||
case 'MultiPolygon':
|
||||
foreach ($geometry->getComponents() as $component) {
|
||||
$parts[] = '('.$this->extractData($component).')';
|
||||
}
|
||||
return implode(', ', $parts);
|
||||
case 'GeometryCollection':
|
||||
foreach ($geometry->getComponents() as $component) {
|
||||
$parts[] = strtoupper($component->geometryType()).' ('.$this->extractData($component).')';
|
||||
}
|
||||
return implode(', ', $parts);
|
||||
}
|
||||
}
|
||||
}
|
||||
348
htdocs/includes/geoPHP/lib/geometry/Collection.class.php
Normal file
348
htdocs/includes/geoPHP/lib/geometry/Collection.class.php
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Collection: Abstract class for compound geometries
|
||||
*
|
||||
* A geometry is a collection if it is made up of other
|
||||
* component geometries. Therefore everything but a Point
|
||||
* is a Collection. For example a LingString is a collection
|
||||
* of Points. A Polygon is a collection of LineStrings etc.
|
||||
*/
|
||||
abstract class Collection extends Geometry
|
||||
{
|
||||
public $components = array();
|
||||
|
||||
/**
|
||||
* Constructor: Checks and sets component geometries
|
||||
*
|
||||
* @param array $components array of geometries
|
||||
*/
|
||||
public function __construct($components = array())
|
||||
{
|
||||
if (!is_array($components)) {
|
||||
throw new Exception("Component geometries must be passed as an array");
|
||||
}
|
||||
foreach ($components as $component) {
|
||||
if ($component instanceof Geometry) {
|
||||
$this->components[] = $component;
|
||||
} else {
|
||||
throw new Exception("Cannot create a collection with non-geometries");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Collection component geometries
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getComponents()
|
||||
{
|
||||
return $this->components;
|
||||
}
|
||||
|
||||
/*
|
||||
* Author : Adam Cherti
|
||||
*
|
||||
* inverts x and y coordinates
|
||||
* Useful for old data still using lng lat
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* */
|
||||
public function invertxy()
|
||||
{
|
||||
for ($i=0;$i<count($this->components);$i++) {
|
||||
if ( method_exists($this->components[$i], 'invertxy') )
|
||||
$this->components[$i]->invertxy();
|
||||
}
|
||||
}
|
||||
|
||||
public function centroid()
|
||||
{
|
||||
if ($this->isEmpty()) return null;
|
||||
|
||||
if ($this->geos()) {
|
||||
$geos_centroid = $this->geos()->centroid();
|
||||
if ($geos_centroid->typeName() == 'Point') {
|
||||
return geoPHP::geosToGeometry($this->geos()->centroid());
|
||||
}
|
||||
}
|
||||
|
||||
// As a rough estimate, we say that the centroid of a colletion is the centroid of it's envelope
|
||||
// @@TODO: Make this the centroid of the convexHull
|
||||
// Note: Outside of polygons, geometryCollections and the trivial case of points, there is no standard on what a "centroid" is
|
||||
$centroid = $this->envelope()->centroid();
|
||||
|
||||
return $centroid;
|
||||
}
|
||||
|
||||
public function getBBox()
|
||||
{
|
||||
if ($this->isEmpty()) return null;
|
||||
|
||||
if ($this->geos()) {
|
||||
$envelope = $this->geos()->envelope();
|
||||
if ($envelope->typeName() == 'Point') {
|
||||
return geoPHP::geosToGeometry($envelope)->getBBOX();
|
||||
}
|
||||
|
||||
$geos_ring = $envelope->exteriorRing();
|
||||
return array(
|
||||
'maxy' => $geos_ring->pointN(3)->getY(),
|
||||
'miny' => $geos_ring->pointN(1)->getY(),
|
||||
'maxx' => $geos_ring->pointN(1)->getX(),
|
||||
'minx' => $geos_ring->pointN(3)->getX(),
|
||||
);
|
||||
}
|
||||
|
||||
// Go through each component and get the max and min x and y
|
||||
$i = 0;
|
||||
foreach ($this->components as $component) {
|
||||
$component_bbox = $component->getBBox();
|
||||
|
||||
// On the first run through, set the bbox to the component bbox
|
||||
if ($i == 0) {
|
||||
$maxx = $component_bbox['maxx'];
|
||||
$maxy = $component_bbox['maxy'];
|
||||
$minx = $component_bbox['minx'];
|
||||
$miny = $component_bbox['miny'];
|
||||
}
|
||||
|
||||
// Do a check and replace on each boundary, slowly growing the bbox
|
||||
$maxx = $component_bbox['maxx'] > $maxx ? $component_bbox['maxx'] : $maxx;
|
||||
$maxy = $component_bbox['maxy'] > $maxy ? $component_bbox['maxy'] : $maxy;
|
||||
$minx = $component_bbox['minx'] < $minx ? $component_bbox['minx'] : $minx;
|
||||
$miny = $component_bbox['miny'] < $miny ? $component_bbox['miny'] : $miny;
|
||||
$i++;
|
||||
}
|
||||
|
||||
return array(
|
||||
'maxy' => $maxy,
|
||||
'miny' => $miny,
|
||||
'maxx' => $maxx,
|
||||
'minx' => $minx,
|
||||
);
|
||||
}
|
||||
|
||||
public function asArray()
|
||||
{
|
||||
$array = array();
|
||||
foreach ($this->components as $component) {
|
||||
$array[] = $component->asArray();
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function area()
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->area();
|
||||
}
|
||||
|
||||
$area = 0;
|
||||
foreach ($this->components as $component) {
|
||||
$area += $component->area();
|
||||
}
|
||||
return $area;
|
||||
}
|
||||
|
||||
// By default, the boundary of a collection is the boundary of it's components
|
||||
public function boundary()
|
||||
{
|
||||
if ($this->isEmpty()) return new LineString();
|
||||
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->boundary();
|
||||
}
|
||||
|
||||
$components_boundaries = array();
|
||||
foreach ($this->components as $component) {
|
||||
$components_boundaries[] = $component->boundary();
|
||||
}
|
||||
return geoPHP::geometryReduce($components_boundaries);
|
||||
}
|
||||
|
||||
public function numGeometries()
|
||||
{
|
||||
return count($this->components);
|
||||
}
|
||||
|
||||
// Note that the standard is 1 based indexing
|
||||
public function geometryN($n)
|
||||
{
|
||||
$n = intval($n);
|
||||
if (array_key_exists($n-1, $this->components)) {
|
||||
return $this->components[$n-1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function length()
|
||||
{
|
||||
$length = 0;
|
||||
foreach ($this->components as $delta => $component) {
|
||||
$length += $component->length();
|
||||
}
|
||||
return $length;
|
||||
}
|
||||
|
||||
public function greatCircleLength($radius = 6378137)
|
||||
{
|
||||
$length = 0;
|
||||
foreach ($this->components as $component) {
|
||||
$length += $component->greatCircleLength($radius);
|
||||
}
|
||||
return $length;
|
||||
}
|
||||
|
||||
public function haversineLength()
|
||||
{
|
||||
$length = 0;
|
||||
foreach ($this->components as $component) {
|
||||
$length += $component->haversineLength();
|
||||
}
|
||||
return $length;
|
||||
}
|
||||
|
||||
public function dimension()
|
||||
{
|
||||
$dimension = 0;
|
||||
foreach ($this->components as $component) {
|
||||
if ($component->dimension() > $dimension) {
|
||||
$dimension = $component->dimension();
|
||||
}
|
||||
}
|
||||
return $dimension;
|
||||
}
|
||||
|
||||
// A collection is empty if it has no components OR all it's components are empty
|
||||
public function isEmpty()
|
||||
{
|
||||
if (!count($this->components)) {
|
||||
return true;
|
||||
} else {
|
||||
foreach ($this->components as $component) {
|
||||
if (!$component->isEmpty()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function numPoints()
|
||||
{
|
||||
$num = 0;
|
||||
foreach ($this->components as $component) {
|
||||
$num += $component->numPoints();
|
||||
}
|
||||
return $num;
|
||||
}
|
||||
|
||||
public function getPoints()
|
||||
{
|
||||
$points = array();
|
||||
foreach ($this->components as $component) {
|
||||
$points = array_merge($points, $component->getPoints());
|
||||
}
|
||||
return $points;
|
||||
}
|
||||
|
||||
public function equals($geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->equals($geometry->geos());
|
||||
}
|
||||
|
||||
// To test for equality we check to make sure that there is a matching point
|
||||
// in the other geometry for every point in this geometry.
|
||||
// This is slightly more strict than the standard, which
|
||||
// uses Within(A,B) = true and Within(B,A) = true
|
||||
// @@TODO: Eventually we could fix this by using some sort of simplification
|
||||
// method that strips redundant vertices (that are all in a row)
|
||||
|
||||
$this_points = $this->getPoints();
|
||||
$other_points = $geometry->getPoints();
|
||||
|
||||
// First do a check to make sure they have the same number of vertices
|
||||
if (count($this_points) != count($other_points)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this_points as $point) {
|
||||
$found_match = false;
|
||||
foreach ($other_points as $key => $test_point) {
|
||||
if ($point->equals($test_point)) {
|
||||
$found_match = true;
|
||||
unset($other_points[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found_match) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// All points match, return TRUE
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isSimple()
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->isSimple();
|
||||
}
|
||||
|
||||
// A collection is simple if all it's components are simple
|
||||
foreach ($this->components as $component) {
|
||||
if (!$component->isSimple()) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function explode()
|
||||
{
|
||||
$parts = array();
|
||||
foreach ($this->components as $component) {
|
||||
$parts = array_merge($parts, $component->explode());
|
||||
}
|
||||
return $parts;
|
||||
}
|
||||
|
||||
// Not valid for this geometry type
|
||||
// --------------------------------
|
||||
public function x()
|
||||
{
|
||||
return null; }
|
||||
public function y()
|
||||
{
|
||||
return null; }
|
||||
public function startPoint()
|
||||
{
|
||||
return null; }
|
||||
public function endPoint()
|
||||
{
|
||||
return null; }
|
||||
public function isRing()
|
||||
{
|
||||
return null; }
|
||||
public function isClosed()
|
||||
{
|
||||
return null; }
|
||||
public function pointN($n)
|
||||
{
|
||||
return null; }
|
||||
public function exteriorRing()
|
||||
{
|
||||
return null; }
|
||||
public function numInteriorRings()
|
||||
{
|
||||
return null; }
|
||||
public function interiorRingN($n)
|
||||
{
|
||||
return null; }
|
||||
public function pointOnSurface()
|
||||
{
|
||||
return null; }
|
||||
}
|
||||
388
htdocs/includes/geoPHP/lib/geometry/Geometry.class.php
Normal file
388
htdocs/includes/geoPHP/lib/geometry/Geometry.class.php
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Geometry abstract class
|
||||
*/
|
||||
abstract class Geometry
|
||||
{
|
||||
private $geos = null;
|
||||
protected $srid = null;
|
||||
protected $geom_type;
|
||||
|
||||
// Abtract: Standard
|
||||
// -----------------
|
||||
abstract public function area();
|
||||
abstract public function boundary();
|
||||
abstract public function centroid();
|
||||
abstract public function length();
|
||||
abstract public function y();
|
||||
abstract public function x();
|
||||
abstract public function numGeometries();
|
||||
abstract public function geometryN($n);
|
||||
abstract public function startPoint();
|
||||
abstract public function endPoint();
|
||||
abstract public function isRing(); // Mssing dependancy
|
||||
abstract public function isClosed(); // Missing dependancy
|
||||
abstract public function numPoints();
|
||||
abstract public function pointN($n);
|
||||
abstract public function exteriorRing();
|
||||
abstract public function numInteriorRings();
|
||||
abstract public function interiorRingN($n);
|
||||
abstract public function dimension();
|
||||
abstract public function equals($geom);
|
||||
abstract public function isEmpty();
|
||||
abstract public function isSimple();
|
||||
|
||||
// Abtract: Non-Standard
|
||||
// ---------------------
|
||||
abstract public function getBBox();
|
||||
abstract public function asArray();
|
||||
abstract public function getPoints();
|
||||
abstract public function explode();
|
||||
abstract public function greatCircleLength(); //meters
|
||||
abstract public function haversineLength(); //degrees
|
||||
|
||||
|
||||
// Public: Standard -- Common to all geometries
|
||||
// --------------------------------------------
|
||||
public function SRID()
|
||||
{
|
||||
return $this->srid;
|
||||
}
|
||||
|
||||
public function setSRID($srid)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
$this->geos()->setSRID($srid);
|
||||
}
|
||||
$this->srid = $srid;
|
||||
}
|
||||
|
||||
public function envelope()
|
||||
{
|
||||
if ($this->isEmpty()) return new Polygon();
|
||||
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->envelope());
|
||||
}
|
||||
|
||||
$bbox = $this->getBBox();
|
||||
$points = array (
|
||||
new Point($bbox['maxx'], $bbox['miny']),
|
||||
new Point($bbox['maxx'], $bbox['maxy']),
|
||||
new Point($bbox['minx'], $bbox['maxy']),
|
||||
new Point($bbox['minx'], $bbox['miny']),
|
||||
new Point($bbox['maxx'], $bbox['miny']),
|
||||
);
|
||||
|
||||
$outer_boundary = new LineString($points);
|
||||
return new Polygon(array($outer_boundary));
|
||||
}
|
||||
|
||||
public function geometryType()
|
||||
{
|
||||
return $this->geom_type;
|
||||
}
|
||||
|
||||
// Public: Non-Standard -- Common to all geometries
|
||||
// ------------------------------------------------
|
||||
|
||||
// $this->out($format, $other_args);
|
||||
public function out()
|
||||
{
|
||||
$args = func_get_args();
|
||||
|
||||
$format = array_shift($args);
|
||||
$type_map = geoPHP::getAdapterMap();
|
||||
$processor_type = $type_map[$format];
|
||||
$processor = new $processor_type();
|
||||
|
||||
array_unshift($args, $this);
|
||||
$result = call_user_func_array(array($processor, 'write'), $args);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
// Public: Aliases
|
||||
// ---------------
|
||||
public function getCentroid()
|
||||
{
|
||||
return $this->centroid();
|
||||
}
|
||||
|
||||
public function getArea()
|
||||
{
|
||||
return $this->area();
|
||||
}
|
||||
|
||||
public function getX()
|
||||
{
|
||||
return $this->x();
|
||||
}
|
||||
|
||||
public function getY()
|
||||
{
|
||||
return $this->y();
|
||||
}
|
||||
|
||||
public function getGeos()
|
||||
{
|
||||
return $this->geos();
|
||||
}
|
||||
|
||||
public function getGeomType()
|
||||
{
|
||||
return $this->geometryType();
|
||||
}
|
||||
|
||||
public function getSRID()
|
||||
{
|
||||
return $this->SRID();
|
||||
}
|
||||
|
||||
public function asText()
|
||||
{
|
||||
return $this->out('wkt');
|
||||
}
|
||||
|
||||
public function asBinary()
|
||||
{
|
||||
return $this->out('wkb');
|
||||
}
|
||||
|
||||
// Public: GEOS Only Functions
|
||||
// ---------------------------
|
||||
public function geos()
|
||||
{
|
||||
// If it's already been set, just return it
|
||||
if ($this->geos && geoPHP::geosInstalled()) {
|
||||
return $this->geos;
|
||||
}
|
||||
// It hasn't been set yet, generate it
|
||||
if (geoPHP::geosInstalled()) {
|
||||
$reader = new GEOSWKBReader();
|
||||
$this->geos = $reader->readHEX($this->out('wkb', true));
|
||||
} else {
|
||||
$this->geos = false;
|
||||
}
|
||||
return $this->geos;
|
||||
}
|
||||
|
||||
public function setGeos($geos)
|
||||
{
|
||||
$this->geos = $geos;
|
||||
}
|
||||
|
||||
public function pointOnSurface()
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->pointOnSurface());
|
||||
}
|
||||
}
|
||||
|
||||
public function equalsExact(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->equalsExact($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function relate(Geometry $geometry, $pattern = null)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
if ($pattern) {
|
||||
return $this->geos()->relate($geometry->geos(), $pattern);
|
||||
} else {
|
||||
return $this->geos()->relate($geometry->geos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function checkValidity()
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->checkValidity();
|
||||
}
|
||||
}
|
||||
|
||||
public function buffer($distance)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->buffer($distance));
|
||||
}
|
||||
}
|
||||
|
||||
public function intersection(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->intersection($geometry->geos()));
|
||||
}
|
||||
}
|
||||
|
||||
public function convexHull()
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->convexHull());
|
||||
}
|
||||
}
|
||||
|
||||
public function difference(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->difference($geometry->geos()));
|
||||
}
|
||||
}
|
||||
|
||||
public function symDifference(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->symDifference($geometry->geos()));
|
||||
}
|
||||
}
|
||||
|
||||
// Can pass in a geometry or an array of geometries
|
||||
public function union(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
if (is_array($geometry)) {
|
||||
$geom = $this->geos();
|
||||
foreach ($geometry as $item) {
|
||||
$geom = $geom->union($item->geos());
|
||||
}
|
||||
return geoPHP::geosToGeometry($geom);
|
||||
} else {
|
||||
return geoPHP::geosToGeometry($this->geos()->union($geometry->geos()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function simplify($tolerance, $preserveTopology = false)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->simplify($tolerance, $preserveTopology));
|
||||
}
|
||||
}
|
||||
|
||||
public function disjoint(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->disjoint($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function touches(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->touches($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function intersects(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->intersects($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function crosses(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->crosses($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function within(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->within($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function contains(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->contains($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function overlaps(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->overlaps($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function covers(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->covers($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function coveredBy(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->coveredBy($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function distance(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->distance($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function hausdorffDistance(Geometry $geometry)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->hausdorffDistance($geometry->geos());
|
||||
}
|
||||
}
|
||||
|
||||
public function project(Geometry $point, $normalized = null)
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->project($point->geos(), $normalized);
|
||||
}
|
||||
}
|
||||
|
||||
// Public - Placeholders
|
||||
// ---------------------
|
||||
public function hasZ()
|
||||
{
|
||||
// geoPHP does not support Z values at the moment
|
||||
return false;
|
||||
}
|
||||
|
||||
public function is3D()
|
||||
{
|
||||
// geoPHP does not support 3D geometries at the moment
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isMeasured()
|
||||
{
|
||||
// geoPHP does not yet support M values
|
||||
return false;
|
||||
}
|
||||
|
||||
public function coordinateDimension()
|
||||
{
|
||||
// geoPHP only supports 2-dimensional space
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function z()
|
||||
{
|
||||
// geoPHP only supports 2-dimensional space
|
||||
return null;
|
||||
}
|
||||
|
||||
public function m()
|
||||
{
|
||||
// geoPHP only supports 2-dimensional space
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
/**
|
||||
* GeometryCollection: A heterogenous collection of geometries
|
||||
*/
|
||||
class GeometryCollection extends Collection
|
||||
{
|
||||
protected $geom_type = 'GeometryCollection';
|
||||
|
||||
// We need to override asArray. Because geometryCollections are heterogeneous
|
||||
// we need to specify which type of geometries they contain. We need to do this
|
||||
// because, for example, there would be no way to tell the difference between a
|
||||
// MultiPoint or a LineString, since they share the same structure (collection
|
||||
// of points). So we need to call out the type explicitly.
|
||||
public function asArray()
|
||||
{
|
||||
$array = array();
|
||||
foreach ($this->components as $component) {
|
||||
$array[] = array(
|
||||
'type' => $component->geometryType(),
|
||||
'components' => $component->asArray(),
|
||||
);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
// Not valid for this geomettry
|
||||
public function boundary()
|
||||
{
|
||||
return null; }
|
||||
public function isSimple()
|
||||
{
|
||||
return null; }
|
||||
}
|
||||
204
htdocs/includes/geoPHP/lib/geometry/LineString.class.php
Normal file
204
htdocs/includes/geoPHP/lib/geometry/LineString.class.php
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
<?php
|
||||
/**
|
||||
* LineString. A collection of Points representing a line.
|
||||
* A line can have more than one segment.
|
||||
*/
|
||||
class LineString extends Collection
|
||||
{
|
||||
protected $geom_type = 'LineString';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $points An array of at least two points with
|
||||
* which to build the LineString
|
||||
*/
|
||||
public function __construct($points = array())
|
||||
{
|
||||
if (count($points) == 1) {
|
||||
throw new Exception("Cannot construct a LineString with a single point");
|
||||
}
|
||||
|
||||
// Call the Collection constructor to build the LineString
|
||||
parent::__construct($points);
|
||||
}
|
||||
|
||||
// The boundary of a linestring is itself
|
||||
public function boundary()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function startPoint()
|
||||
{
|
||||
return $this->pointN(1);
|
||||
}
|
||||
|
||||
public function endPoint()
|
||||
{
|
||||
$last_n = $this->numPoints();
|
||||
return $this->pointN($last_n);
|
||||
}
|
||||
|
||||
public function isClosed()
|
||||
{
|
||||
return ($this->startPoint()->equals($this->endPoint()));
|
||||
}
|
||||
|
||||
public function isRing()
|
||||
{
|
||||
return ($this->isClosed() && $this->isSimple());
|
||||
}
|
||||
|
||||
public function numPoints()
|
||||
{
|
||||
return $this->numGeometries();
|
||||
}
|
||||
|
||||
public function pointN($n)
|
||||
{
|
||||
return $this->geometryN($n);
|
||||
}
|
||||
|
||||
public function dimension()
|
||||
{
|
||||
if ($this->isEmpty()) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function area()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function length()
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->length();
|
||||
}
|
||||
$length = 0;
|
||||
foreach ($this->getPoints() as $delta => $point) {
|
||||
$previous_point = $this->geometryN($delta);
|
||||
if ($previous_point) {
|
||||
$length += sqrt(pow(($previous_point->getX() - $point->getX()), 2) + pow(($previous_point->getY()- $point->getY()), 2));
|
||||
}
|
||||
}
|
||||
return $length;
|
||||
}
|
||||
|
||||
public function greatCircleLength($radius = 6378137)
|
||||
{
|
||||
$length = 0;
|
||||
$points = $this->getPoints();
|
||||
for ($i=0; $i<$this->numPoints()-1; $i++) {
|
||||
$point = $points[$i];
|
||||
$next_point = $points[$i+1];
|
||||
if (!is_object($next_point)) {continue;}
|
||||
// Great circle method
|
||||
$lat1 = deg2rad($point->getY());
|
||||
$lat2 = deg2rad($next_point->getY());
|
||||
$lon1 = deg2rad($point->getX());
|
||||
$lon2 = deg2rad($next_point->getX());
|
||||
$dlon = $lon2 - $lon1;
|
||||
$length +=
|
||||
$radius *
|
||||
atan2(
|
||||
sqrt(
|
||||
pow(cos($lat2) * sin($dlon), 2) +
|
||||
pow(cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($dlon), 2)
|
||||
),
|
||||
sin($lat1) * sin($lat2) +
|
||||
cos($lat1) * cos($lat2) * cos($dlon)
|
||||
);
|
||||
}
|
||||
// Returns length in meters.
|
||||
return $length;
|
||||
}
|
||||
|
||||
public function haversineLength()
|
||||
{
|
||||
$degrees = 0;
|
||||
$points = $this->getPoints();
|
||||
for ($i=0; $i<$this->numPoints()-1; $i++) {
|
||||
$point = $points[$i];
|
||||
$next_point = $points[$i+1];
|
||||
if (!is_object($next_point)) {continue;}
|
||||
$degree = rad2deg(
|
||||
acos(
|
||||
sin(deg2rad($point->getY())) * sin(deg2rad($next_point->getY())) +
|
||||
cos(deg2rad($point->getY())) * cos(deg2rad($next_point->getY())) *
|
||||
cos(deg2rad(abs($point->getX() - $next_point->getX())))
|
||||
)
|
||||
);
|
||||
$degrees += $degree;
|
||||
}
|
||||
// Returns degrees
|
||||
return $degrees;
|
||||
}
|
||||
|
||||
public function explode()
|
||||
{
|
||||
$parts = array();
|
||||
$points = $this->getPoints();
|
||||
|
||||
foreach ($points as $i => $point) {
|
||||
if (isset($points[$i+1])) {
|
||||
$parts[] = new LineString(array($point, $points[$i+1]));
|
||||
}
|
||||
}
|
||||
return $parts;
|
||||
}
|
||||
|
||||
public function isSimple()
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->isSimple();
|
||||
}
|
||||
|
||||
$segments = $this->explode();
|
||||
|
||||
foreach ($segments as $i => $segment) {
|
||||
foreach ($segments as $j => $check_segment) {
|
||||
if ($i != $j) {
|
||||
if ($segment->lineSegmentIntersect($check_segment)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Utility function to check if any line sigments intersect
|
||||
// Derived from http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
|
||||
public function lineSegmentIntersect($segment)
|
||||
{
|
||||
$p0_x = $this->startPoint()->x();
|
||||
$p0_y = $this->startPoint()->y();
|
||||
$p1_x = $this->endPoint()->x();
|
||||
$p1_y = $this->endPoint()->y();
|
||||
$p2_x = $segment->startPoint()->x();
|
||||
$p2_y = $segment->startPoint()->y();
|
||||
$p3_x = $segment->endPoint()->x();
|
||||
$p3_y = $segment->endPoint()->y();
|
||||
|
||||
$s1_x = $p1_x - $p0_x; $s1_y = $p1_y - $p0_y;
|
||||
$s2_x = $p3_x - $p2_x; $s2_y = $p3_y - $p2_y;
|
||||
|
||||
$fps = (-$s2_x * $s1_y) + ($s1_x * $s2_y);
|
||||
$fpt = (-$s2_x * $s1_y) + ($s1_x * $s2_y);
|
||||
|
||||
if ($fps == 0 || $fpt == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$s = (-$s1_y * ($p0_x - $p2_x) + $s1_x * ($p0_y - $p2_y)) / $fps;
|
||||
$t = ( $s2_x * ($p0_y - $p2_y) - $s2_y * ($p0_x - $p2_x)) / $fpt;
|
||||
|
||||
if ($s > 0 && $s < 1 && $t > 0 && $t < 1) {
|
||||
// Collision detected
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* MultiLineString: A collection of LineStrings
|
||||
*/
|
||||
class MultiLineString extends Collection
|
||||
{
|
||||
protected $geom_type = 'MultiLineString';
|
||||
|
||||
// MultiLineString is closed if all it's components are closed
|
||||
public function isClosed()
|
||||
{
|
||||
foreach ($this->components as $line) {
|
||||
if (!$line->isClosed()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
24
htdocs/includes/geoPHP/lib/geometry/MultiPoint.class.php
Normal file
24
htdocs/includes/geoPHP/lib/geometry/MultiPoint.class.php
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* MultiPoint: A collection Points
|
||||
*/
|
||||
class MultiPoint extends Collection
|
||||
{
|
||||
protected $geom_type = 'MultiPoint';
|
||||
|
||||
public function numPoints()
|
||||
{
|
||||
return $this->numGeometries();
|
||||
}
|
||||
|
||||
public function isSimple()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not valid for this geometry type
|
||||
// --------------------------------
|
||||
public function explode()
|
||||
{
|
||||
return null; }
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
/**
|
||||
* MultiPolygon: A collection of Polygons
|
||||
*/
|
||||
class MultiPolygon extends Collection
|
||||
{
|
||||
protected $geom_type = 'MultiPolygon';
|
||||
}
|
||||
236
htdocs/includes/geoPHP/lib/geometry/Point.class.php
Normal file
236
htdocs/includes/geoPHP/lib/geometry/Point.class.php
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Point: The most basic geometry type. All other geometries
|
||||
* are built out of Points.
|
||||
*/
|
||||
class Point extends Geometry
|
||||
{
|
||||
public $coords = array(2);
|
||||
protected $geom_type = 'Point';
|
||||
protected $dimension = 2;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param numeric $x The x coordinate (or longitude)
|
||||
* @param numeric $y The y coordinate (or latitude)
|
||||
* @param numeric $z The z coordinate (or altitude) - optional
|
||||
*/
|
||||
public function __construct($x = null, $y = null, $z = null)
|
||||
{
|
||||
|
||||
// Check if it's an empty point
|
||||
if ($x === null && $y === null) {
|
||||
$this->coords = array(null, null);
|
||||
$this->dimension = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Basic validation on x and y
|
||||
if (!is_numeric($x) || !is_numeric($y)) {
|
||||
throw new Exception("Cannot construct Point. x and y should be numeric");
|
||||
}
|
||||
|
||||
// Check to see if this is a 3D point
|
||||
if ($z !== null) {
|
||||
if (!is_numeric($z)) {
|
||||
throw new Exception("Cannot construct Point. z should be numeric");
|
||||
}
|
||||
$this->dimension = 3;
|
||||
}
|
||||
|
||||
// Convert to floatval in case they are passed in as a string or integer etc.
|
||||
$x = floatval($x);
|
||||
$y = floatval($y);
|
||||
$z = floatval($z);
|
||||
|
||||
// Add poitional elements
|
||||
if ($this->dimension == 2) {
|
||||
$this->coords = array($x, $y);
|
||||
}
|
||||
if ($this->dimension == 3) {
|
||||
$this->coords = array($x, $y, $z);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get X (longitude) coordinate
|
||||
*
|
||||
* @return float The X coordinate
|
||||
*/
|
||||
public function x()
|
||||
{
|
||||
return $this->coords[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Y (latitude) coordinate
|
||||
*
|
||||
* @return float The Y coordinate
|
||||
*/
|
||||
public function y()
|
||||
{
|
||||
return $this->coords[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Z (altitude) coordinate
|
||||
*
|
||||
* @return float The Z coordinate or NULL is not a 3D point
|
||||
*/
|
||||
public function z()
|
||||
{
|
||||
if ($this->dimension == 3) {
|
||||
return $this->coords[2];
|
||||
} else return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Author : Adam Cherti
|
||||
* inverts x and y coordinates
|
||||
* Useful with old applications still using lng lat
|
||||
*
|
||||
* @return void
|
||||
* */
|
||||
public function invertxy()
|
||||
{
|
||||
$x=$this->coords[0];
|
||||
$this->coords[0]=$this->coords[1];
|
||||
$this->coords[1]=$x;
|
||||
}
|
||||
|
||||
|
||||
// A point's centroid is itself
|
||||
public function centroid()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBBox()
|
||||
{
|
||||
return array(
|
||||
'maxy' => $this->getY(),
|
||||
'miny' => $this->getY(),
|
||||
'maxx' => $this->getX(),
|
||||
'minx' => $this->getX(),
|
||||
);
|
||||
}
|
||||
|
||||
public function asArray($assoc = false)
|
||||
{
|
||||
return $this->coords;
|
||||
}
|
||||
|
||||
public function area()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function length()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function greatCircleLength()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function haversineLength()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The boundary of a point is itself
|
||||
public function boundary()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function dimension()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function isEmpty()
|
||||
{
|
||||
if ($this->dimension == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function numPoints()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function getPoints()
|
||||
{
|
||||
return array($this);
|
||||
}
|
||||
|
||||
public function equals($geometry)
|
||||
{
|
||||
if (get_class($geometry) != 'Point') {
|
||||
return false;
|
||||
}
|
||||
if (!$this->isEmpty() && !$geometry->isEmpty()) {
|
||||
/**
|
||||
* @see: http://php.net/manual/en/function.bccomp.php
|
||||
* @see: http://php.net/manual/en/language.types.float.php
|
||||
* @see: http://tubalmartin.github.io/spherical-geometry-php/#LatLng
|
||||
*/
|
||||
return (abs($this->x() - $geometry->x()) <= 1.0E-9 && abs($this->y() - $geometry->y()) <= 1.0E-9);
|
||||
} elseif ($this->isEmpty() && $geometry->isEmpty()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function isSimple()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not valid for this geometry type
|
||||
public function numGeometries()
|
||||
{
|
||||
return null; }
|
||||
public function geometryN($n)
|
||||
{
|
||||
return null; }
|
||||
public function startPoint()
|
||||
{
|
||||
return null; }
|
||||
public function endPoint()
|
||||
{
|
||||
return null; }
|
||||
public function isRing()
|
||||
{
|
||||
return null; }
|
||||
public function isClosed()
|
||||
{
|
||||
return null; }
|
||||
public function pointN($n)
|
||||
{
|
||||
return null; }
|
||||
public function exteriorRing()
|
||||
{
|
||||
return null; }
|
||||
public function numInteriorRings()
|
||||
{
|
||||
return null; }
|
||||
public function interiorRingN($n)
|
||||
{
|
||||
return null; }
|
||||
public function pointOnSurface()
|
||||
{
|
||||
return null; }
|
||||
public function explode()
|
||||
{
|
||||
return null; }
|
||||
}
|
||||
225
htdocs/includes/geoPHP/lib/geometry/Polygon.class.php
Normal file
225
htdocs/includes/geoPHP/lib/geometry/Polygon.class.php
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Polygon: A polygon is a plane figure that is bounded by a closed path,
|
||||
* composed of a finite sequence of straight line segments
|
||||
*/
|
||||
class Polygon extends Collection
|
||||
{
|
||||
protected $geom_type = 'Polygon';
|
||||
|
||||
// The boundary of a polygin is it's outer ring
|
||||
public function boundary()
|
||||
{
|
||||
return $this->exteriorRing();
|
||||
}
|
||||
|
||||
public function area($exterior_only = false, $signed = false)
|
||||
{
|
||||
if ($this->isEmpty()) return 0;
|
||||
|
||||
if ($this->geos() && $exterior_only == false) {
|
||||
return $this->geos()->area();
|
||||
}
|
||||
|
||||
$exterior_ring = $this->components[0];
|
||||
$pts = $exterior_ring->getComponents();
|
||||
|
||||
$c = count($pts);
|
||||
if ((int) $c == '0') return null;
|
||||
$a = '0';
|
||||
foreach ($pts as $k => $p) {
|
||||
$j = ($k + 1) % $c;
|
||||
$a = $a + ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX());
|
||||
}
|
||||
|
||||
if ($signed) $area = ($a / 2);
|
||||
else $area = abs(($a / 2));
|
||||
|
||||
if ($exterior_only == true) {
|
||||
return $area;
|
||||
}
|
||||
foreach ($this->components as $delta => $component) {
|
||||
if ($delta != 0) {
|
||||
$inner_poly = new Polygon(array($component));
|
||||
$area -= $inner_poly->area();
|
||||
}
|
||||
}
|
||||
return $area;
|
||||
}
|
||||
|
||||
public function centroid()
|
||||
{
|
||||
if ($this->isEmpty()) return null;
|
||||
|
||||
if ($this->geos()) {
|
||||
return geoPHP::geosToGeometry($this->geos()->centroid());
|
||||
}
|
||||
|
||||
$exterior_ring = $this->components[0];
|
||||
$pts = $exterior_ring->getComponents();
|
||||
|
||||
$c = count($pts);
|
||||
if ((int) $c == '0') return null;
|
||||
$cn = array('x' => '0', 'y' => '0');
|
||||
$a = $this->area(true, true);
|
||||
|
||||
// If this is a polygon with no area. Just return the first point.
|
||||
if ($a == 0) {
|
||||
return $this->exteriorRing()->pointN(1);
|
||||
}
|
||||
|
||||
foreach ($pts as $k => $p) {
|
||||
$j = ($k + 1) % $c;
|
||||
$P = ($p->getX() * $pts[$j]->getY()) - ($p->getY() * $pts[$j]->getX());
|
||||
$cn['x'] = $cn['x'] + ($p->getX() + $pts[$j]->getX()) * $P;
|
||||
$cn['y'] = $cn['y'] + ($p->getY() + $pts[$j]->getY()) * $P;
|
||||
}
|
||||
|
||||
$cn['x'] = $cn['x'] / ( 6 * $a);
|
||||
$cn['y'] = $cn['y'] / ( 6 * $a);
|
||||
|
||||
$centroid = new Point($cn['x'], $cn['y']);
|
||||
return $centroid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the outermost point from the centroid
|
||||
*
|
||||
* @returns Point The outermost point
|
||||
*/
|
||||
public function outermostPoint()
|
||||
{
|
||||
$centroid = $this->getCentroid();
|
||||
|
||||
$max = array('length' => 0, 'point' => null);
|
||||
|
||||
foreach ($this->getPoints() as $point) {
|
||||
$lineString = new LineString(array($centroid, $point));
|
||||
|
||||
if ($lineString->length() > $max['length']) {
|
||||
$max['length'] = $lineString->length();
|
||||
$max['point'] = $point;
|
||||
}
|
||||
}
|
||||
|
||||
return $max['point'];
|
||||
}
|
||||
|
||||
public function exteriorRing()
|
||||
{
|
||||
if ($this->isEmpty()) return new LineString();
|
||||
return $this->components[0];
|
||||
}
|
||||
|
||||
public function numInteriorRings()
|
||||
{
|
||||
if ($this->isEmpty()) return 0;
|
||||
return $this->numGeometries()-1;
|
||||
}
|
||||
|
||||
public function interiorRingN($n)
|
||||
{
|
||||
return $this->geometryN($n+1);
|
||||
}
|
||||
|
||||
public function dimension()
|
||||
{
|
||||
if ($this->isEmpty()) return 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
public function isSimple()
|
||||
{
|
||||
if ($this->geos()) {
|
||||
return $this->geos()->isSimple();
|
||||
}
|
||||
|
||||
$segments = $this->explode();
|
||||
|
||||
foreach ($segments as $i => $segment) {
|
||||
foreach ($segments as $j => $check_segment) {
|
||||
if ($i != $j) {
|
||||
if ($segment->lineSegmentIntersect($check_segment)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given point, determine whether it's bounded by the given polygon.
|
||||
* Adapted from http://www.assemblysys.com/dataServices/php_pointinpolygon.php
|
||||
* @see http://en.wikipedia.org/wiki/Point%5Fin%5Fpolygon
|
||||
*
|
||||
* @param Point $point
|
||||
* @param boolean $pointOnBoundary - whether a boundary should be considered "in" or not
|
||||
* @param boolean $pointOnVertex - whether a vertex should be considered "in" or not
|
||||
* @return boolean
|
||||
*/
|
||||
public function pointInPolygon($point, $pointOnBoundary = true, $pointOnVertex = true)
|
||||
{
|
||||
$vertices = $this->getPoints();
|
||||
|
||||
// Check if the point sits exactly on a vertex
|
||||
if ($this->pointOnVertex($point, $vertices)) {
|
||||
return $pointOnVertex ? true : false;
|
||||
}
|
||||
|
||||
// Check if the point is inside the polygon or on the boundary
|
||||
$intersections = 0;
|
||||
$vertices_count = count($vertices);
|
||||
|
||||
for ($i=1; $i < $vertices_count; $i++) {
|
||||
$vertex1 = $vertices[$i-1];
|
||||
$vertex2 = $vertices[$i];
|
||||
if ($vertex1->y() == $vertex2->y()
|
||||
&& $vertex1->y() == $point->y()
|
||||
&& $point->x() > min($vertex1->x(), $vertex2->x())
|
||||
&& $point->x() < max($vertex1->x(), $vertex2->x())) {
|
||||
// Check if point is on an horizontal polygon boundary
|
||||
return $pointOnBoundary ? true : false;
|
||||
}
|
||||
if ($point->y() > min($vertex1->y(), $vertex2->y())
|
||||
&& $point->y() <= max($vertex1->y(), $vertex2->y())
|
||||
&& $point->x() <= max($vertex1->x(), $vertex2->x())
|
||||
&& $vertex1->y() != $vertex2->y()) {
|
||||
$xinters =
|
||||
($point->y() - $vertex1->y()) * ($vertex2->x() - $vertex1->x())
|
||||
/ ($vertex2->y() - $vertex1->y())
|
||||
+ $vertex1->x();
|
||||
if ($xinters == $point->x()) {
|
||||
// Check if point is on the polygon boundary (other than horizontal)
|
||||
return $pointOnBoundary ? true : false;
|
||||
}
|
||||
if ($vertex1->x() == $vertex2->x() || $point->x() <= $xinters) {
|
||||
$intersections++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the number of edges we passed through is even, then it's in the polygon.
|
||||
if ($intersections % 2 != 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function pointOnVertex($point)
|
||||
{
|
||||
foreach ($this->getPoints() as $vertex) {
|
||||
if ($point->equals($vertex)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Not valid for this geometry type
|
||||
// --------------------------------
|
||||
public function length()
|
||||
{
|
||||
return null; }
|
||||
}
|
||||
BIN
htdocs/includes/leaflet/images/layers-2x.png
Normal file
BIN
htdocs/includes/leaflet/images/layers-2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
htdocs/includes/leaflet/images/layers.png
Normal file
BIN
htdocs/includes/leaflet/images/layers.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 696 B |
BIN
htdocs/includes/leaflet/images/marker-icon-2x.png
Normal file
BIN
htdocs/includes/leaflet/images/marker-icon-2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
htdocs/includes/leaflet/images/marker-icon.png
Normal file
BIN
htdocs/includes/leaflet/images/marker-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
htdocs/includes/leaflet/images/marker-shadow.png
Normal file
BIN
htdocs/includes/leaflet/images/marker-shadow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 618 B |
282
htdocs/includes/leaflet/leaflet-geoman.css
Normal file
282
htdocs/includes/leaflet/leaflet-geoman.css
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
.marker-icon,
|
||||
.marker-icon:focus {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #3388ff;
|
||||
border-radius: 50%;
|
||||
margin: -8px 0 0 -8px !important;
|
||||
width: 14px !important;
|
||||
height: 14px !important;
|
||||
outline: 0;
|
||||
transition: opacity ease 0.3s;
|
||||
}
|
||||
|
||||
.marker-icon-middle,
|
||||
.marker-icon-middle:focus {
|
||||
opacity: 0.7;
|
||||
margin: -6px 0 0 -6px !important;
|
||||
width: 10px !important;
|
||||
height: 10px !important;
|
||||
}
|
||||
|
||||
.leaflet-pm-draggable {
|
||||
cursor: move !important;
|
||||
}
|
||||
|
||||
.cursor-marker {
|
||||
cursor: crosshair;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cursor-marker.visible {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.geoman-draw-cursor {
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.rect-style-marker,
|
||||
.rect-start-marker {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.rect-style-marker.visible,
|
||||
.rect-start-marker.visible {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.vertexmarker-disabled {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.pm-text-marker {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.pm-textarea {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
resize: none;
|
||||
border: none;
|
||||
outline: 0;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
padding-left: 7px;
|
||||
padding-bottom: 0;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.leaflet-pm-draggable .pm-textarea {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.pm-textarea:focus,
|
||||
.pm-textarea:focus-within,
|
||||
.pm-textarea:focus-visible,
|
||||
.pm-textarea:active {
|
||||
border: 2px solid #000;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.pm-textarea.pm-disabled {
|
||||
border: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.pm-textarea.pm-hasfocus {
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.leaflet-pm-toolbar {
|
||||
}
|
||||
|
||||
.leaflet-pm-toolbar .leaflet-buttons-control-button {
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.leaflet-pm-toolbar
|
||||
.leaflet-pm-actions-container
|
||||
a.leaflet-pm-action:first-child:not(.pos-right),
|
||||
.leaflet-pm-toolbar
|
||||
.leaflet-pm-actions-container
|
||||
a.leaflet-pm-action:last-child.pos-right {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.leaflet-pm-toolbar .button-container a.leaflet-buttons-control-button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.leaflet-pm-toolbar
|
||||
.button-container:last-child
|
||||
a.leaflet-buttons-control-button {
|
||||
border-radius: 0 0 2px 2px;
|
||||
}
|
||||
|
||||
.leaflet-pm-toolbar
|
||||
.button-container:first-child
|
||||
a.leaflet-buttons-control-button {
|
||||
border-radius: 2px 2px 0 0;
|
||||
}
|
||||
|
||||
.leaflet-pm-toolbar
|
||||
.button-container:last-child
|
||||
a.leaflet-buttons-control-button {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.leaflet-pm-toolbar .control-fa-icon {
|
||||
font-size: 19px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.leaflet-pm-toolbar .control-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-marker {
|
||||
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjUgKDY3NDY5KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5BdG9tcy9JY29ucy9Ub29scy9NYXJrZXI8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNMTUuNSwyNC44NzgyOTU5IEMxNS4yOTA5MjAxLDI0Ljg3NzIyMTkgMTUuMTc0NDg1NywyNC44NDY3ODE3IDE0LjY1OTA4NjYsMjQuMjM1NDE2MyBDMTAuMjE5Njk1NSwxOS40MTE4MDU0IDgsMTUuNTAxNDM5MiA4LDEyLjUwNDMxNzcgQzgsOC4zNTk3OTc0NiAxMS4zNTc4NjQ0LDUgMTUuNSw1IEMxOS42NDIxMzU2LDUgMjMsOC4zNTk3OTc0NiAyMywxMi41MDQzMTc3IEMyMywxNyAxOC4yODc4MjE3LDIxLjkyNjgzNzggMTYuMzMzNjYwMSwyNC4yNDQwMTg2IEMxNS44MjI0NjIyLDI0Ljg1MDE4MDIgMTUuNzA5MDc5OSwyNC44NzkzNjk5IDE1LjUsMjQuODc4Mjk1OSBaIE0xNS41LDE1LjUzMjY5NDggQzE3LjI3NTIwMSwxNS41MzI2OTQ4IDE4LjcxNDI4NTcsMTQuMTE4MDAwNCAxOC43MTQyODU3LDEyLjM3Mjg4NjQgQzE4LjcxNDI4NTcsMTAuNjI3NzcyMyAxNy4yNzUyMDEsOS4yMTMwNzc5MiAxNS41LDkuMjEzMDc3OTIgQzEzLjcyNDc5OSw5LjIxMzA3NzkyIDEyLjI4NTcxNDMsMTAuNjI3NzcyMyAxMi4yODU3MTQzLDEyLjM3Mjg4NjQgQzEyLjI4NTcxNDMsMTQuMTE4MDAwNCAxMy43MjQ3OTksMTUuNTMyNjk0OCAxNS41LDE1LjUzMjY5NDggWiIgaWQ9InBhdGgtMSI+PC9wYXRoPgogICAgPC9kZWZzPgogICAgPGcgaWQ9IlN5bWJvbHMiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJBdG9tcy9JY29ucy9Ub29scy9NYXJrZXIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zLjAwMDAwMCwgLTMuMDAwMDAwKSI+CiAgICAgICAgICAgIDxtYXNrIGlkPSJtYXNrLTIiIGZpbGw9IndoaXRlIj4KICAgICAgICAgICAgICAgIDx1c2UgeGxpbms6aHJlZj0iI3BhdGgtMSI+PC91c2U+CiAgICAgICAgICAgIDwvbWFzaz4KICAgICAgICAgICAgPHVzZSBpZD0iTWFzayIgZmlsbD0iIzVCNUI1QiIgZmlsbC1ydWxlPSJub256ZXJvIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-polygon {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgPGRlZnM+CiAgICA8cGF0aCBpZD0icG9seWdvbi1hIiBkPSJNMTkuNDIwNjg5Miw5LjE2NTA5NzI1IEMxOS4xNTIzNjgxLDguNjY5OTI5MTQgMTksOC4xMDI3NTgzMSAxOSw3LjUgQzE5LDUuNTY3MDAzMzggMjAuNTY3MDAzNCw0IDIyLjUsNCBDMjQuNDMyOTk2Niw0IDI2LDUuNTY3MDAzMzggMjYsNy41IEMyNiw5LjI2MzIzNTk1IDI0LjY5NjE0NzEsMTAuNzIxOTQwNyAyMywxMC45NjQ1NTU2IEwyMywxOS4wMzU0NDQ0IEMyNC42OTYxNDcxLDE5LjI3ODA1OTMgMjYsMjAuNzM2NzY0IDI2LDIyLjUgQzI2LDI0LjQzMjk5NjYgMjQuNDMyOTk2NiwyNiAyMi41LDI2IEMyMC43MzY3NjQsMjYgMTkuMjc4MDU5MywyNC42OTYxNDcxIDE5LjAzNTQ0NDQsMjMgTDEwLjk2NDU1NTYsMjMgQzEwLjcyMTk0MDcsMjQuNjk2MTQ3MSA5LjI2MzIzNTk1LDI2IDcuNSwyNiBDNS41NjcwMDMzOCwyNiA0LDI0LjQzMjk5NjYgNCwyMi41IEM0LDIwLjU2NzAwMzQgNS41NjcwMDMzOCwxOSA3LjUsMTkgQzguMTAyNzU4MzEsMTkgOC42Njk5MjkxNCwxOS4xNTIzNjgxIDkuMTY1MDk3MjUsMTkuNDIwNjg5MiBMMTkuNDIwNjg5Miw5LjE2NTA5NzI1IFogTTIwLjgzNDkwNzMsMTAuNTc5MzA2MyBMMTAuNTc5MzEwOCwyMC44MzQ5MDI3IEMxMC42MDg2NzMxLDIwLjg4OTA4ODggMTAuNjM2NjQ2OSwyMC45NDQxMzcyIDEwLjY2MzE4NDQsMjEgTDE5LjMzNjgxNTYsMjEgQzE5LjY4MjU3NzUsMjAuMjcyMTU0IDIwLjI3MjE1NCwxOS42ODI1Nzc1IDIxLDE5LjMzNjgxNTYgTDIxLDEwLjY2MzE4NDQgQzIwLjk0NDEzNzIsMTAuNjM2NjQ2OSAyMC44ODkwODg4LDEwLjYwODY3MzEgMjAuODM0OTAyNywxMC41NzkzMTA4IFogTTIyLjUsOSBDMjMuMzI4NDI3MSw5IDI0LDguMzI4NDI3MTIgMjQsNy41IEMyNCw2LjY3MTU3Mjg4IDIzLjMyODQyNzEsNiAyMi41LDYgQzIxLjY3MTU3MjksNiAyMSw2LjY3MTU3Mjg4IDIxLDcuNSBDMjEsOC4zMjg0MjcxMiAyMS42NzE1NzI5LDkgMjIuNSw5IFogTTIyLjUsMjQgQzIzLjMyODQyNzEsMjQgMjQsMjMuMzI4NDI3MSAyNCwyMi41IEMyNCwyMS42NzE1NzI5IDIzLjMyODQyNzEsMjEgMjIuNSwyMSBDMjEuNjcxNTcyOSwyMSAyMSwyMS42NzE1NzI5IDIxLDIyLjUgQzIxLDIzLjMyODQyNzEgMjEuNjcxNTcyOSwyNCAyMi41LDI0IFogTTcuNSwyNCBDOC4zMjg0MjcxMiwyNCA5LDIzLjMyODQyNzEgOSwyMi41IEM5LDIxLjY3MTU3MjkgOC4zMjg0MjcxMiwyMSA3LjUsMjEgQzYuNjcxNTcyODgsMjEgNiwyMS42NzE1NzI5IDYsMjIuNSBDNiwyMy4zMjg0MjcxIDYuNjcxNTcyODgsMjQgNy41LDI0IFoiLz4KICA8L2RlZnM+CiAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMyAtMykiPgogICAgPG1hc2sgaWQ9InBvbHlnb24tYiIgZmlsbD0iI2ZmZiI+CiAgICAgIDx1c2UgeGxpbms6aHJlZj0iI3BvbHlnb24tYSIvPgogICAgPC9tYXNrPgogICAgPHVzZSBmaWxsPSIjNUI1QjVCIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHhsaW5rOmhyZWY9IiNwb2x5Z29uLWEiLz4KICAgIDxnIGZpbGw9IiM1QjVCNUIiIG1hc2s9InVybCgjcG9seWdvbi1iKSI+CiAgICAgIDxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIzMCIvPgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg==);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-polyline {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgPGRlZnM+CiAgICA8cGF0aCBpZD0ibGluZS1hIiBkPSJNOS4xNjUwOTcyNSwxOS40MjA2ODkyIEwxOC40MjA2ODkyLDEwLjE2NTA5NzMgQzE4LjE1MjM2ODEsOS42Njk5MjkxNCAxOCw5LjEwMjc1ODMxIDE4LDguNSBDMTgsNi41NjcwMDMzOCAxOS41NjcwMDM0LDUgMjEuNSw1IEMyMy40MzI5OTY2LDUgMjUsNi41NjcwMDMzOCAyNSw4LjUgQzI1LDEwLjQzMjk5NjYgMjMuNDMyOTk2NiwxMiAyMS41LDEyIEMyMC44OTcyNDE3LDEyIDIwLjMzMDA3MDksMTEuODQ3NjMxOSAxOS44MzQ5MDI3LDExLjU3OTMxMDggTDEwLjU3OTMxMDgsMjAuODM0OTAyNyBDMTAuODQ3NjMxOSwyMS4zMzAwNzA5IDExLDIxLjg5NzI0MTcgMTEsMjIuNSBDMTEsMjQuNDMyOTk2NiA5LjQzMjk5NjYyLDI2IDcuNSwyNiBDNS41NjcwMDMzOCwyNiA0LDI0LjQzMjk5NjYgNCwyMi41IEM0LDIwLjU2NzAwMzQgNS41NjcwMDMzOCwxOSA3LjUsMTkgQzguMTAyNzU4MzEsMTkgOC42Njk5MjkxNCwxOS4xNTIzNjgxIDkuMTY1MDk3MjUsMTkuNDIwNjg5MiBaIE0yMS41LDEwIEMyMi4zMjg0MjcxLDEwIDIzLDkuMzI4NDI3MTIgMjMsOC41IEMyMyw3LjY3MTU3Mjg4IDIyLjMyODQyNzEsNyAyMS41LDcgQzIwLjY3MTU3MjksNyAyMCw3LjY3MTU3Mjg4IDIwLDguNSBDMjAsOS4zMjg0MjcxMiAyMC42NzE1NzI5LDEwIDIxLjUsMTAgWiBNNy41LDI0IEM4LjMyODQyNzEyLDI0IDksMjMuMzI4NDI3MSA5LDIyLjUgQzksMjEuNjcxNTcyOSA4LjMyODQyNzEyLDIxIDcuNSwyMSBDNi42NzE1NzI4OCwyMSA2LDIxLjY3MTU3MjkgNiwyMi41IEM2LDIzLjMyODQyNzEgNi42NzE1NzI4OCwyNCA3LjUsMjQgWiIvPgogIDwvZGVmcz4KICA8ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zIC0zKSI+CiAgICA8bWFzayBpZD0ibGluZS1iIiBmaWxsPSIjZmZmIj4KICAgICAgPHVzZSB4bGluazpocmVmPSIjbGluZS1hIi8+CiAgICA8L21hc2s+CiAgICA8dXNlIGZpbGw9IiM1QjVCNUIiIGZpbGwtcnVsZT0ibm9uemVybyIgeGxpbms6aHJlZj0iI2xpbmUtYSIvPgogICAgPGcgZmlsbD0iIzVCNUI1QiIgbWFzaz0idXJsKCNsaW5lLWIpIj4KICAgICAgPHJlY3Qgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-circle {
|
||||
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjUgKDY3NDY5KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5BdG9tcy9JY29ucy9Ub29scy9DaXJjbGU8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNMTguMjg5Nzc1MSw2Ljc4NjAyMjc1IEMxOC44OTI0MTMxLDYuMjk0NjQ5ODEgMTkuNjYxNzk3LDYgMjAuNSw2IEMyMi40MzI5OTY2LDYgMjQsNy41NjcwMDMzOCAyNCw5LjUgQzI0LDEwLjMzODIwMyAyMy43MDUzNTAyLDExLjEwNzU4NjkgMjMuMjEzOTc3MiwxMS43MTAyMjQ5IEMyMy43MTk1OTksMTIuODcxMjA1MyAyNCwxNC4xNTI4NTcxIDI0LDE1LjUgQzI0LDIwLjc0NjcwNTEgMTkuNzQ2NzA1MSwyNSAxNC41LDI1IEM5LjI1MzI5NDg4LDI1IDUsMjAuNzQ2NzA1MSA1LDE1LjUgQzUsMTAuMjUzMjk0OSA5LjI1MzI5NDg4LDYgMTQuNSw2IEMxNS44NDcxNDI5LDYgMTcuMTI4Nzk0Nyw2LjI4MDQwMDk4IDE4LjI4OTc3NTEsNi43ODYwMjI3NSBaIE0xNy4xNTA0MjI4LDguNDgxNzU4NiBDMTYuMzI2MzU4MSw4LjE3MDM5MjM2IDE1LjQzMzA3NzcsOCAxNC41LDggQzEwLjM1Nzg2NDQsOCA3LDExLjM1Nzg2NDQgNywxNS41IEM3LDE5LjY0MjEzNTYgMTAuMzU3ODY0NCwyMyAxNC41LDIzIEMxOC42NDIxMzU2LDIzIDIyLDE5LjY0MjEzNTYgMjIsMTUuNSBDMjIsMTQuNTY2OTIyMyAyMS44Mjk2MDc2LDEzLjY3MzY0MTkgMjEuNTE4MjQxNCwxMi44NDk1NzcyIEMyMS4xOTYwMzgzLDEyLjk0NzM5NjggMjAuODU0MTYyMiwxMyAyMC41LDEzIEMxOC41NjcwMDM0LDEzIDE3LDExLjQzMjk5NjYgMTcsOS41IEMxNyw5LjE0NTgzNzc4IDE3LjA1MjYwMzIsOC44MDM5NjE2OSAxNy4xNTA0MjI4LDguNDgxNzU4NiBaIE0xNC41LDE3IEMxMy42NzE1NzI5LDE3IDEzLDE2LjMyODQyNzEgMTMsMTUuNSBDMTMsMTQuNjcxNTcyOSAxMy42NzE1NzI5LDE0IDE0LjUsMTQgQzE1LjMyODQyNzEsMTQgMTYsMTQuNjcxNTcyOSAxNiwxNS41IEMxNiwxNi4zMjg0MjcxIDE1LjMyODQyNzEsMTcgMTQuNSwxNyBaIE0yMC41LDExIEMyMS4zMjg0MjcxLDExIDIyLDEwLjMyODQyNzEgMjIsOS41IEMyMiw4LjY3MTU3Mjg4IDIxLjMyODQyNzEsOCAyMC41LDggQzE5LjY3MTU3MjksOCAxOSw4LjY3MTU3Mjg4IDE5LDkuNSBDMTksMTAuMzI4NDI3MSAxOS42NzE1NzI5LDExIDIwLjUsMTEgWiIgaWQ9InBhdGgtMSI+PC9wYXRoPgogICAgPC9kZWZzPgogICAgPGcgaWQ9IlN5bWJvbHMiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJBdG9tcy9JY29ucy9Ub29scy9DaXJjbGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zLjAwMDAwMCwgLTMuMDAwMDAwKSI+CiAgICAgICAgICAgIDxtYXNrIGlkPSJtYXNrLTIiIGZpbGw9IndoaXRlIj4KICAgICAgICAgICAgICAgIDx1c2UgeGxpbms6aHJlZj0iI3BhdGgtMSI+PC91c2U+CiAgICAgICAgICAgIDwvbWFzaz4KICAgICAgICAgICAgPHVzZSBpZD0iTWFzayIgZmlsbD0iIzVCNUI1QiIgZmlsbC1ydWxlPSJub256ZXJvIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgPGcgaWQ9IkF0b21zL0NvbG9yL0dyZXkiIG1hc2s9InVybCgjbWFzay0yKSIgZmlsbD0iIzVCNUI1QiI+CiAgICAgICAgICAgICAgICA8cmVjdCBpZD0iUmVjdGFuZ2xlIiB4PSIwIiB5PSIwIiB3aWR0aD0iMzAiIGhlaWdodD0iMzAiPjwvcmVjdD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-circle-marker {
|
||||
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KCjxzdmcgdmlld0JveD0iMCAwIDEwMCAxMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjNUI1QjVCIiBzdHJva2Utd2lkdGg9IjgiCiAgICAgZmlsbD0ibm9uZSI+CjxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjM1Ii8+CiAgPGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgcj0iMyIgZmlsbD0iIzVCNUI1QiIvPgo8L3N2Zz4=);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-rectangle {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgPGRlZnM+CiAgICA8cGF0aCBpZD0icmVjdGFuZ2xlLWEiIGQ9Ik0yMywxMC45NjQ1NTU2IEwyMywxOS4wMzU0NDQ0IEMyNC42OTYxNDcxLDE5LjI3ODA1OTMgMjYsMjAuNzM2NzY0IDI2LDIyLjUgQzI2LDI0LjQzMjk5NjYgMjQuNDMyOTk2NiwyNiAyMi41LDI2IEMyMC43MzY3NjQsMjYgMTkuMjc4MDU5MywyNC42OTYxNDcxIDE5LjAzNTQ0NDQsMjMgTDEwLjk2NDU1NTYsMjMgQzEwLjcyMTk0MDcsMjQuNjk2MTQ3MSA5LjI2MzIzNTk1LDI2IDcuNSwyNiBDNS41NjcwMDMzOCwyNiA0LDI0LjQzMjk5NjYgNCwyMi41IEM0LDIwLjczNjc2NCA1LjMwMzg1MjkzLDE5LjI3ODA1OTMgNywxOS4wMzU0NDQ0IEw3LDEwLjk2NDU1NTYgQzUuMzAzODUyOTMsMTAuNzIxOTQwNyA0LDkuMjYzMjM1OTUgNCw3LjUgQzQsNS41NjcwMDMzOCA1LjU2NzAwMzM4LDQgNy41LDQgQzkuMjYzMjM1OTUsNCAxMC43MjE5NDA3LDUuMzAzODUyOTMgMTAuOTY0NTU1Niw3IEwxOS4wMzU0NDQ0LDcgQzE5LjI3ODA1OTMsNS4zMDM4NTI5MyAyMC43MzY3NjQsNCAyMi41LDQgQzI0LjQzMjk5NjYsNCAyNiw1LjU2NzAwMzM4IDI2LDcuNSBDMjYsOS4yNjMyMzU5NSAyNC42OTYxNDcxLDEwLjcyMTk0MDcgMjMsMTAuOTY0NTU1NiBaIE0yMSwxMC42NjMxODQ0IEMyMC4yNzIxNTQsMTAuMzE3NDIyNSAxOS42ODI1Nzc1LDkuNzI3ODQ1OTggMTkuMzM2ODE1Niw5IEwxMC42NjMxODQ0LDkgQzEwLjMxNzQyMjUsOS43Mjc4NDU5OCA5LjcyNzg0NTk4LDEwLjMxNzQyMjUgOSwxMC42NjMxODQ0IEw5LDE5LjMzNjgxNTYgQzkuNzI3ODQ1OTgsMTkuNjgyNTc3NSAxMC4zMTc0MjI1LDIwLjI3MjE1NCAxMC42NjMxODQ0LDIxIEwxOS4zMzY4MTU2LDIxIEMxOS42ODI1Nzc1LDIwLjI3MjE1NCAyMC4yNzIxNTQsMTkuNjgyNTc3NSAyMSwxOS4zMzY4MTU2IEwyMSwxMC42NjMxODQ0IFogTTcuNSw5IEM4LjMyODQyNzEyLDkgOSw4LjMyODQyNzEyIDksNy41IEM5LDYuNjcxNTcyODggOC4zMjg0MjcxMiw2IDcuNSw2IEM2LjY3MTU3Mjg4LDYgNiw2LjY3MTU3Mjg4IDYsNy41IEM2LDguMzI4NDI3MTIgNi42NzE1NzI4OCw5IDcuNSw5IFogTTIyLjUsOSBDMjMuMzI4NDI3MSw5IDI0LDguMzI4NDI3MTIgMjQsNy41IEMyNCw2LjY3MTU3Mjg4IDIzLjMyODQyNzEsNiAyMi41LDYgQzIxLjY3MTU3MjksNiAyMSw2LjY3MTU3Mjg4IDIxLDcuNSBDMjEsOC4zMjg0MjcxMiAyMS42NzE1NzI5LDkgMjIuNSw5IFogTTIyLjUsMjQgQzIzLjMyODQyNzEsMjQgMjQsMjMuMzI4NDI3MSAyNCwyMi41IEMyNCwyMS42NzE1NzI5IDIzLjMyODQyNzEsMjEgMjIuNSwyMSBDMjEuNjcxNTcyOSwyMSAyMSwyMS42NzE1NzI5IDIxLDIyLjUgQzIxLDIzLjMyODQyNzEgMjEuNjcxNTcyOSwyNCAyMi41LDI0IFogTTcuNSwyNCBDOC4zMjg0MjcxMiwyNCA5LDIzLjMyODQyNzEgOSwyMi41IEM5LDIxLjY3MTU3MjkgOC4zMjg0MjcxMiwyMSA3LjUsMjEgQzYuNjcxNTcyODgsMjEgNiwyMS42NzE1NzI5IDYsMjIuNSBDNiwyMy4zMjg0MjcxIDYuNjcxNTcyODgsMjQgNy41LDI0IFoiLz4KICA8L2RlZnM+CiAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMyAtMykiPgogICAgPG1hc2sgaWQ9InJlY3RhbmdsZS1iIiBmaWxsPSIjZmZmIj4KICAgICAgPHVzZSB4bGluazpocmVmPSIjcmVjdGFuZ2xlLWEiLz4KICAgIDwvbWFzaz4KICAgIDx1c2UgZmlsbD0iIzVCNUI1QiIgZmlsbC1ydWxlPSJub256ZXJvIiB4bGluazpocmVmPSIjcmVjdGFuZ2xlLWEiLz4KICAgIDxnIGZpbGw9IiM1QjVCNUIiIG1hc2s9InVybCgjcmVjdGFuZ2xlLWIpIj4KICAgICAgPHJlY3Qgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-delete {
|
||||
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjUgKDY3NDY5KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5BdG9tcy9JY29ucy9Ub29scy9FcmFzZXI8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNMTcuNzg3NDIxOSwxOC40ODEyNTUyIEwxMS42NDgwMDc5LDEzLjM0OTgxODQgTDYuNDA0NjYwMDksMTkuMzgxNjAwMSBMMTAuNTUzOTE1NiwyMi45ODg0OTI5IEwxMy44NjkzNCwyMi45ODg0OTI5IEwxNy43ODc0MjE5LDE4LjQ4MTI1NTIgWiBNMTYuNTA3NDI1MiwyMi45ODg0OTI5IEwyNi4wMDAwMDAyLDIyLjk4ODQ5MjkgTDI2LjAwMDAwMDIsMjQuOTg4NDkyOSBMMTAuMDAwMDAwMiwyNC45ODg0OTI5IEw5LjgwNzA4MzEzLDI0Ljk4ODQ5MjkgTDUuMDkyNTQyMDQsMjAuODkxMDE5MiBDNC4yNTg5MTI4NSwyMC4xNjYzNTY0IDQuMTcwNTc4MTQsMTguOTAzMTExMiA0Ljg5NTI0MDkzLDE4LjA2OTQ4MiBMMTYuMDQ4MjQ0NCw1LjIzOTQxOTE2IEMxNi43NzI5MDcyLDQuNDA1Nzg5OTggMTguMDM2MTUyNSw0LjMxNzQ1NTI2IDE4Ljg2OTc4MTYsNS4wNDIxMTgwNiBMMjQuOTA3NDU4MywxMC4yOTA1OTAzIEMyNS43NDEwODc1LDExLjAxNTI1MzEgMjUuODI5NDIyMiwxMi4yNzg0OTgzIDI1LjEwNDc1OTQsMTMuMTEyMTI3NSBMMTYuNTA3NDI1MiwyMi45ODg0OTI5IFoiIGlkPSJwYXRoLTEiPjwvcGF0aD4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJTeW1ib2xzIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0iQXRvbXMvSWNvbnMvVG9vbHMvRXJhc2VyIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMy4wMDAwMDAsIC0zLjAwMDAwMCkiPgogICAgICAgICAgICA8bWFzayBpZD0ibWFzay0yIiBmaWxsPSJ3aGl0ZSI+CiAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICA8L21hc2s+CiAgICAgICAgICAgIDx1c2UgaWQ9IkNvbWJpbmVkLVNoYXBlIiBmaWxsPSIjNUI1QjVCIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-edit {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgPGRlZnM+CiAgICA8cGF0aCBpZD0iZWRpdF9hbmNob3ItYSIgZD0iTTEzLjUsMTEgQzExLjU2NzAwMzQsMTEgMTAsOS40MzI5OTY2MiAxMCw3LjUgQzEwLDUuNTY3MDAzMzggMTEuNTY3MDAzNCw0IDEzLjUsNCBDMTUuNDMyOTk2Niw0IDE3LDUuNTY3MDAzMzggMTcsNy41IEMxNyw5LjQzMjk5NjYyIDE1LjQzMjk5NjYsMTEgMTMuNSwxMSBaIE0xMy41LDkgQzE0LjMyODQyNzEsOSAxNSw4LjMyODQyNzEyIDE1LDcuNSBDMTUsNi42NzE1NzI4OCAxNC4zMjg0MjcxLDYgMTMuNSw2IEMxMi42NzE1NzI5LDYgMTIsNi42NzE1NzI4OCAxMiw3LjUgQzEyLDguMzI4NDI3MTIgMTIuNjcxNTcyOSw5IDEzLjUsOSBaIE0xMi4wMDAyODg5LDcuNTI5NzM4OTMgQzEyLjAxMjU5ODMsOC4xNjI3MzY3MiAxMi40MTcwMTk3LDguNjk5NjY0MyAxMi45ODA3MTExLDguOTA3Njc5NjYgTDMsMTUgTDMsMTMgTDEyLjAwMDI4ODksNy41Mjk3Mzg5MyBaIE0xNC4yMTcyNzIyLDYuMTgyMjg0NzIgTDE5LjQ1MzEyNSwzIEwyMi42NTg5MzU1LDMgTDE0Ljk4OTEwMiw3LjY4MTczODg1IEMxNC45OTYyOTcxLDcuNjIyMTY0NTkgMTUsNy41NjE1MTQ3MiAxNSw3LjUgQzE1LDYuOTMxMzgzODEgMTQuNjgzNjA5OCw2LjQzNjY2NDUgMTQuMjE3MjcyMiw2LjE4MjI4NDcyIFogTTIzLjQ0MzQwNDIsMTkuMjg1MTczNiBMMjAuMTI4Mjc5OSwxOS4yODUxNzM2IEwyMS44NzI5OTgzLDIzLjUzNDk1MjUgQzIxLjk5NDUyOTYsMjMuODI5NTc3MyAyMS44NTU2NTQ2LDI0LjE1OTkyMDkgMjEuNTc3ODczNCwyNC4yODQ5MjA4IEwyMC4wNDE0Njc1LDI0Ljk1NDUxNDIgQzE5Ljc1NTA2MTMsMjUuMDc5NTE0MSAxOS40MzM4NzM4LDI0LjkzNjY3MDQgMTkuMzEyMzQyNiwyNC42NTA5NTE4IEwxNy42NTQ0MzY3LDIwLjYxNTQ1NDEgTDE0Ljk0NjE4NzMsMjMuNDAxMDE1MSBDMTQuNTg1MjgxMSwyMy43NzIxNzExIDE0LDIzLjQ4NjA0NjMgMTQsMjIuOTk5MjY1MyBMMTQsOS41NzE4MzUzMyBDMTQsOS4wNTkzMzU2MSAxNC42MjI1MzExLDguODA5NDkyIDE0Ljk0NjE1Niw5LjE3MDA4NTU1IEwyMy44MzQwMjkyLDE4LjMxMjAxNzkgQzI0LjE5MjUyOTEsMTguNjYxMzYxNSAyMy45Mjc5OTc5LDE5LjI4NTE3MzYgMjMuNDQzNDA0MiwxOS4yODUxNzM2IFoiLz4KICA8L2RlZnM+CiAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMyAtMykiPgogICAgPG1hc2sgaWQ9ImVkaXRfYW5jaG9yLWIiIGZpbGw9IiNmZmYiPgogICAgICA8dXNlIHhsaW5rOmhyZWY9IiNlZGl0X2FuY2hvci1hIi8+CiAgICA8L21hc2s+CiAgICA8dXNlIGZpbGw9IiM1QjVCNUIiIGZpbGwtcnVsZT0ibm9uemVybyIgeGxpbms6aHJlZj0iI2VkaXRfYW5jaG9yLWEiLz4KICAgIDxnIGZpbGw9IiM1QjVCNUIiIG1hc2s9InVybCgjZWRpdF9hbmNob3ItYikiPgogICAgICA8cmVjdCB3aWR0aD0iMzAiIGhlaWdodD0iMzAiLz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-drag {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgPGRlZnM+CiAgICA8cGF0aCBpZD0ibW92ZS1hIiBkPSJNMjEsMTQgTDIxLDEwIEwyNywxNSBMMjEsMjAgTDIxLDE2IEwxNiwxNiBMMTYsMjEgTDIwLDIxIEwxNSwyNyBMMTAsMjEgTDE0LDIxIEwxNCwxNiBMOSwxNiBMOSwyMCBMMywxNSBMOSwxMCBMOSwxNCBMMTQsMTQgTDE0LDkgTDEwLDkgTDE1LDMgTDIwLDkgTDE2LDkgTDE2LDE0IEwyMSwxNCBaIi8+CiAgPC9kZWZzPgogIDxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTMgLTMpIj4KICAgIDxtYXNrIGlkPSJtb3ZlLWIiIGZpbGw9IiNmZmYiPgogICAgICA8dXNlIHhsaW5rOmhyZWY9IiNtb3ZlLWEiLz4KICAgIDwvbWFzaz4KICAgIDx1c2UgZmlsbD0iI0Q4RDhEOCIgeGxpbms6aHJlZj0iI21vdmUtYSIvPgogICAgPGcgZmlsbD0iIzVCNUI1QiIgbWFzaz0idXJsKCNtb3ZlLWIpIj4KICAgICAgPHJlY3Qgd2lkdGg9IjMwIiBoZWlnaHQ9IjMwIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-cut {
|
||||
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjUgKDY3NDY5KSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5BdG9tcy9JY29ucy9Ub29scy9TY2lzc29yczwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPgogICAgICAgIDxwYXRoIGQ9Ik0xMi45NjkxNTc0LDEzLjQ5Mzk0MzUgTDIxLjAzMTcwMzIsNS41NDE2NzAxMyBMMjMuNDY0OTQ5OSw1LjY3NzIyOTU3IEwxNy4wNDcwNzEzLDE0LjUxMDY4MTYgTDI3LjU2NjAzMzYsMTcuMTMzMzUzNSBMMjUuNzg5MTk0NCwxOC44MDEyNTg4IEwxNC41ODU0OTUxLDE3Ljg5ODc1MDYgTDEzLjY0ODc5NTUsMTkuMTg4MDA3IEMxMy43OTQ2MzksMTkuMjY1MDk1OCAxMy45MzY3OTg1LDE5LjM1MzQ0MTcgMTQuMDc0MTM3NywxOS40NTMyMjQ1IEMxNS42Mzc5NjQ4LDIwLjU4OTQxMTQgMTUuOTg0NjM1NywyMi43NzgyMDUyIDE0Ljg0ODQ0ODgsMjQuMzQyMDMyNCBDMTMuNzEyMjYxOSwyNS45MDU4NTk1IDExLjUyMzQ2ODEsMjYuMjUyNTMwNCA5Ljk1OTY0MDk2LDI1LjExNjM0MzUgQzguMzk1ODEzODQsMjMuOTgwMTU2NSA4LjA0OTE0Mjk2LDIxLjc5MTM2MjcgOS4xODUzMjk4NiwyMC4yMjc1MzU2IEM5Ljc0NTg3Mjc2LDE5LjQ1NjAxNDUgMTAuNTYyNjE4OCwxOC45ODA3NDc1IDExLjQzNDEyMTgsMTguODMzNjQwNyBMMTIuNjgwNTY1NiwxNy4xMTgwNTc5IEwxMi41MjM5NzI0LDE2LjM3NDcyMTYgTDExLjk1MDY5MzIsMTUuMzAxMjM5MSBMOS44OTMxMDY0NiwxNC43ODgyMjUxIEM5LjEzMDkzNzk2LDE1LjIzNTcyNjEgOC4xOTk3Nzg1NCwxNS4zOTY2NDQ3IDcuMjc0NDUzNTUsMTUuMTY1OTM1MiBDNS4zOTg4NzUxOSwxNC42OTgzMDEgNC4yNTc1MTA5NCwxMi43OTg3NTE5IDQuNzI1MTQ1MTUsMTAuOTIzMTczNiBDNS4xOTI3NzkzNSw5LjA0NzU5NTE5IDcuMDkyMzI4NDYsNy45MDYyMzA5NCA4Ljk2NzkwNjgyLDguMzczODY1MTUgQzEwLjg0MzQ4NTIsOC44NDE0OTkzNSAxMS45ODQ4NDk0LDEwLjc0MTA0ODUgMTEuNTE3MjE1MiwxMi42MTY2MjY4IEMxMS40NzYxNDY0LDEyLjc4MTM0NDkgMTEuNDI0MDMzNSwxMi45NDA0MDAxIDExLjM2MTg2MjcsMTMuMDkzMTk5OSBMMTIuOTY5MTU3NCwxMy40OTM5NDM1IFogTTcuNzU4Mjk3MzUsMTMuMjI1MzQzOCBDOC41NjIxMTY2NCwxMy40MjU3NTg0IDkuMzc2MjA5MTIsMTIuOTM2NjAyMyA5LjU3NjYyMzc4LDEyLjEzMjc4MyBDOS43NzcwMzg0NCwxMS4zMjg5NjM3IDkuMjg3ODgyMzMsMTAuNTE0ODcxMyA4LjQ4NDA2MzAzLDEwLjMxNDQ1NjYgQzcuNjgwMjQzNzMsMTAuMTE0MDQxOSA2Ljg2NjE1MTI2LDEwLjYwMzE5OCA2LjY2NTczNjYsMTEuNDA3MDE3MyBDNi40NjUzMjE5NCwxMi4yMTA4MzY2IDYuOTU0NDc4MDUsMTMuMDI0OTI5MSA3Ljc1ODI5NzM1LDEzLjIyNTM0MzggWiBNMTAuODAzMzYzOSwyMS40MDMxMDYxIEMxMC4zMTY0MjY2LDIyLjA3MzMxNzcgMTAuNDY0OTk5OCwyMy4wMTEzNzIyIDExLjEzNTIxMTUsMjMuNDk4MzA5NSBDMTEuODA1NDIzMSwyMy45ODUyNDY3IDEyLjc0MzQ3NzYsMjMuODM2NjczNSAxMy4yMzA0MTQ4LDIzLjE2NjQ2MTkgQzEzLjcxNzM1MjEsMjIuNDk2MjUwMiAxMy41Njg3Nzg4LDIxLjU1ODE5NTcgMTIuODk4NTY3MiwyMS4wNzEyNTg1IEMxMi4yMjgzNTU2LDIwLjU4NDMyMTIgMTEuMjkwMzAxMSwyMC43MzI4OTQ1IDEwLjgwMzM2MzksMjEuNDAzMTA2MSBaIiBpZD0icGF0aC0xIj48L3BhdGg+CiAgICA8L2RlZnM+CiAgICA8ZyBpZD0iU3ltYm9scyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IkF0b21zL0ljb25zL1Rvb2xzL1NjaXNzb3JzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMy4wMDAwMDAsIC0zLjAwMDAwMCkiPgogICAgICAgICAgICA8bWFzayBpZD0ibWFzay0yIiBmaWxsPSJ3aGl0ZSI+CiAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPgogICAgICAgICAgICA8L21hc2s+CiAgICAgICAgICAgIDx1c2UgaWQ9Ik1hc2siIGZpbGw9IiM1QjVCNUIiIGZpbGwtcnVsZT0ibm9uemVybyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTYuMDkzMTk0LCAxNS42NjMzNTEpIHJvdGF0ZSgtMzIuMDAwMDAwKSB0cmFuc2xhdGUoLTE2LjA5MzE5NCwgLTE1LjY2MzM1MSkgIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-snapping {
|
||||
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjRweCIgaGVpZ2h0PSIyNHB4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDU3LjEgKDgzMDg4KSAtIGh0dHBzOi8vc2tldGNoLmNvbSAtLT4KICAgIDx0aXRsZT5BdG9tcy9JY29ucy9Ub29scy9NYWduZXQ8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBkPSJNMjEuOTk5NDc1OSwxMC45NDI4MTgzIEwyMS45OTk5OTg1LDE2LjM3MTA0MTcgQzIyLDE2LjY4NzIwMDcgMjIsMTcuMDA1ODI3OCAyMiwxNy4zMjY5NDExIEMyMiwyMS41NjQ2NTQ1IDE4LjY0MjEzNTYsMjUgMTQuNSwyNSBDMTAuMzU3ODY0NCwyNSA3LDIxLjU2NDY1NDUgNywxNy4zMjY5NDExIEw3LjAwMDg3NTA4LDEwLjk5MDc1MDcgTDExLjAwMjI4MDgsMTAuOTk4NDEyNSBDMTEuMDAxNzAzMywxMS42OTgwMTE0IDExLjAwMTI0NywxMi40MTY4MjQ4IDExLjAwMDg5OTIsMTMuMTU1NDg4NyBMMTEsMTcuMzI2OTQxMSBDMTEsMTkuMzc1NjgwOSAxMi41ODc2ODQxLDIxIDE0LjUsMjEgQzE2LjQxMjMxNTksMjEgMTgsMTkuMzc1NjgwOSAxOCwxNy4zMjY5NDExIEMxOCwxNS4wNzAyMDMyIDE3Ljk5OTU2OTYsMTIuOTYxOTY2OCAxNy45OTg1MzksMTAuOTkxMDAzMiBMMjEuOTk5NDc1OSwxMC45NDI4MTgzIFogTTEwLDcgQzEwLjU1MjI4NDcsNyAxMSw3LjQ0NzcxNTI1IDExLDggTDExLDEwIEw3LDEwIEw3LDggQzcsNy40NDc3MTUyNSA3LjQ0NzcxNTI1LDcgOCw3IEwxMCw3IFogTTIxLDcgQzIxLjU1MjI4NDcsNyAyMiw3LjQ0NzcxNTI1IDIyLDggTDIyLDEwIEwxOCwxMCBMMTgsOCBDMTgsNy40NDc3MTUyNSAxOC40NDc3MTUzLDcgMTksNyBMMjEsNyBaIiBpZD0icGF0aC0xIj48L3BhdGg+CiAgICA8L2RlZnM+CiAgICA8ZyBpZD0iU3ltYm9scyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IkF0b21zL0ljb25zL1Rvb2xzL01hZ25ldCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTMuMDAwMDAwLCAtMy4wMDAwMDApIj4KICAgICAgICAgICAgPG1hc2sgaWQ9Im1hc2stMiIgZmlsbD0id2hpdGUiPgogICAgICAgICAgICAgICAgPHVzZSB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICAgICAgPC9tYXNrPgogICAgICAgICAgICA8dXNlIGlkPSJNYXNrIiBmaWxsPSIjNUI1QjVCIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE0LjUwMDAwMCwgMTYuMDAwMDAwKSByb3RhdGUoNDUuMDAwMDAwKSB0cmFuc2xhdGUoLTE0LjUwMDAwMCwgLTE2LjAwMDAwMCkgIiB4bGluazpocmVmPSIjcGF0aC0xIj48L3VzZT4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-rotate {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CiAgICA8ZGVmcz4KICAgICAgICA8cGF0aCBpZD0icm90YXRlIiBkPSJNMjEuMiw1LjhjLTAuMS0wLjItMC4yLTAuMy0wLjMtMC41bC0wLjEtMC4yYy0wLjEtMC4yLTAuMi0wLjMtMC4zLTAuNWwtMC4xLTAuMmMtMC4xLTAuMi0wLjItMC4zLTAuNC0wLjVsLTAuMi0wLjNsMi44LTMuMUwxOCwwLjZsLTQuNiwwLjFsMC41LDQuNWwwLjUsNC41bDMuMi0zLjZ2MC4xbDAuMSwwLjJjMC4xLDAuMSwwLjEsMC4yLDAuMiwwLjJsMC4xLDAuMkMxOCw3LDE4LDcuMSwxOC4xLDcuMmMwLjMsMC43LDAuNiwxLjQsMC43LDIuMWMwLjIsMS40LDAsMi45LTAuNiw0LjJMMTgsMTMuOUwxNy45LDE0bC0wLjMsMC41bC0wLjEsMC4yYy0wLjIsMC4yLTAuNCwwLjUtMC42LDAuN2MtMC41LDAuNS0xLjEsMS0xLjcsMS4zYy0wLjYsMC40LTEuMywwLjYtMi4xLDAuOGMtMC43LDAuMS0xLjUsMC4yLTIuMiwwLjFjLTAuOC0wLjEtMS41LTAuMy0yLjItMC41Yy0wLjctMC4zLTEuMy0wLjctMS45LTEuMmwtMC40LTAuNGwtMC4yLTAuM0w2LDE1Yy0wLjEtMC4xLTAuMi0wLjItMC4yLTAuM2wtMC4zLTAuNGwtMC4xLTAuMWwtMC4yLTAuNGMwLTAuMS0wLjEtMC4xLTAuMS0wLjJsLTAuMy0wLjVsLTAuMS0wLjJjLTAuMS0wLjMtMC4yLTAuNi0wLjMtMC45Yy0wLjItMC44LTAuMy0xLjYtMC4zLTIuNGMwLTAuMiwwLTAuMywwLTAuNVY4LjljMC0wLjIsMC0wLjMsMC4xLTAuNGwwLjEtMC42bDAuMi0wLjZjMC4zLTAuOCwwLjctMS41LDEuMi0yLjJjMC41LTAuNywxLjEtMS4zLDEuOC0xLjhjMC4yLTAuMSwwLjMtMC40LDAuMS0wLjZDNy41LDIuNiw3LjQsMi41LDcuMywyLjVINy4xTDcsMi42QzYuMSwzLDUuNCwzLjYsNC43LDQuMkM0LDQuOSwzLjUsNS43LDMsNi42Yy0wLjksMS44LTEuMiwzLjgtMC44LDUuOGMwLjEsMC41LDAuMiwwLjksMC4zLDEuNGwwLjMsMC44QzIuOSwxNC43LDMsMTQuOCwzLDE1bDAuMiwwLjRjMCwwLjEsMC4xLDAuMiwwLjEsMC4ybDAuMywwLjVjMC4xLDAuMiwwLjIsMC4zLDAuMywwLjVsMC4xLDAuMmMwLjEsMC4xLDAuMiwwLjMsMC4zLDAuNEw1LDE3LjhjMC43LDAuNywxLjYsMS4zLDIuNSwxLjhjMC45LDAuNSwxLjksMC44LDMsMC45YzAuNSwwLjEsMSwwLjEsMS41LDAuMWMwLjYsMCwxLjEsMCwxLjYtMC4xYzEtMC4yLDIuMS0wLjUsMy0xbDAuMi0wLjFjMC4yLTAuMSwwLjMtMC4yLDAuNS0wLjNsMC43LTAuNGMwLjItMC4xLDAuMy0wLjIsMC40LTAuM2wwLjItMC4yYzAuMi0wLjEsMC40LTAuMywwLjUtMC41bDAuMS0wLjFjMC4zLTAuMywwLjctMC43LDAuOS0xbDAuNi0wLjlsMC40LTAuNmMxLTEuOSwxLjQtNC4xLDEuMS02LjJDMjIsNy44LDIxLjcsNi43LDIxLjIsNS44eiIvPgogICAgPC9kZWZzPgogICAgPGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDIpIj4KICAgICAgICA8bWFzayBpZD0icm90YXRlLWIiIGZpbGw9IiNmZmYiPgogICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNyb3RhdGUiLz4KICAgICAgICA8L21hc2s+CiAgICAgICAgPHVzZSBmaWxsPSIjNUI1QjVCIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHhsaW5rOmhyZWY9IiNyb3RhdGUiLz4KICAgICAgICA8ZyBmaWxsPSIjNUI1QjVCIiBtYXNrPSJ1cmwoI3JvdGF0ZS1iKSI+CiAgICAgICAgICAgIDxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIzMCIvPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+Cg==);
|
||||
}
|
||||
.leaflet-pm-toolbar .leaflet-pm-icon-text {
|
||||
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOm5vbmU7c3Ryb2tlOiM1YjViNWI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS13aWR0aDoyLjVweDt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPlRleHQ8L3RpdGxlPjxnIGlkPSJFYmVuZV8yIiBkYXRhLW5hbWU9IkViZW5lIDIiPjxwb2x5bGluZSBjbGFzcz0iY2xzLTEiIHBvaW50cz0iMTkuNjQgNy4yNyAxOS42NCA0IDEyIDQgMTIgMjAgMTUuOTEgMjAgOC4wOSAyMCAxMiAyMCAxMiA0IDQuMzYgNCA0LjM2IDcuMjciLz48L2c+PC9zdmc+);
|
||||
}
|
||||
|
||||
.leaflet-buttons-control-button:hover,
|
||||
.leaflet-buttons-control-button:focus {
|
||||
cursor: pointer;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.active > .leaflet-buttons-control-button {
|
||||
box-shadow: inset 0 -1px 5px 2px rgba(81, 77, 77, 0.31);
|
||||
}
|
||||
|
||||
.leaflet-buttons-control-text-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.button-container .leaflet-pm-actions-container {
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 100%;
|
||||
display: none;
|
||||
white-space: nowrap;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.leaflet-right
|
||||
.leaflet-pm-toolbar
|
||||
.button-container
|
||||
.leaflet-pm-actions-container {
|
||||
right: 100%;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
.button-container.active .leaflet-pm-actions-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.button-container
|
||||
.leaflet-pm-actions-container:not(.pos-right)
|
||||
a.leaflet-pm-action:last-child {
|
||||
border-radius: 0 3px 3px 0;
|
||||
border-right: 0;
|
||||
}
|
||||
.button-container
|
||||
.leaflet-pm-actions-container.pos-right
|
||||
a.leaflet-pm-action:first-child {
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
.button-container
|
||||
.leaflet-pm-actions-container.pos-right
|
||||
a.leaflet-pm-action:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
.button-container .leaflet-pm-actions-container .leaflet-pm-action {
|
||||
padding: 0 10px;
|
||||
background-color: #666;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
border-right: 1px solid #eee;
|
||||
user-select: none;
|
||||
border-bottom: none;
|
||||
height: 29px;
|
||||
line-height: 29px;
|
||||
}
|
||||
.leaflet-pm-toolbar
|
||||
.button-container:first-child.pos-right.active
|
||||
a.leaflet-buttons-control-button {
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
.leaflet-pm-toolbar
|
||||
.button-container:first-child.active:not(.pos-right)
|
||||
a.leaflet-buttons-control-button {
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.button-container .leaflet-pm-actions-container .leaflet-pm-action:hover,
|
||||
.button-container .leaflet-pm-actions-container .leaflet-pm-action:focus {
|
||||
cursor: pointer;
|
||||
background-color: #777;
|
||||
}
|
||||
|
||||
/* That the active control is always over the other controls */
|
||||
.leaflet-pm-toolbar.activeChild {
|
||||
z-index: 801;
|
||||
}
|
||||
|
||||
.leaflet-buttons-control-button.pm-disabled {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
.leaflet-buttons-control-button.pm-disabled > .control-icon {
|
||||
filter: opacity(0.6);
|
||||
}
|
||||
1
htdocs/includes/leaflet/leaflet-geoman.min.js
vendored
Normal file
1
htdocs/includes/leaflet/leaflet-geoman.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
14419
htdocs/includes/leaflet/leaflet-src.esm.js
Normal file
14419
htdocs/includes/leaflet/leaflet-src.esm.js
Normal file
File diff suppressed because it is too large
Load Diff
1
htdocs/includes/leaflet/leaflet-src.esm.js.map
Normal file
1
htdocs/includes/leaflet/leaflet-src.esm.js.map
Normal file
File diff suppressed because one or more lines are too long
14512
htdocs/includes/leaflet/leaflet-src.js
Normal file
14512
htdocs/includes/leaflet/leaflet-src.js
Normal file
File diff suppressed because it is too large
Load Diff
1
htdocs/includes/leaflet/leaflet-src.js.map
Normal file
1
htdocs/includes/leaflet/leaflet-src.js.map
Normal file
File diff suppressed because one or more lines are too long
661
htdocs/includes/leaflet/leaflet.css
Normal file
661
htdocs/includes/leaflet/leaflet.css
Normal file
|
|
@ -0,0 +1,661 @@
|
|||
/* required styles */
|
||||
|
||||
.leaflet-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-pane > svg,
|
||||
.leaflet-pane > canvas,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
/* Prevents IE11 from highlighting tiles in blue */
|
||||
.leaflet-tile::selection {
|
||||
background: transparent;
|
||||
}
|
||||
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
|
||||
.leaflet-safari .leaflet-tile {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
}
|
||||
/* hack that prevents hw layers "stretching" when loading new tiles */
|
||||
.leaflet-safari .leaflet-tile-container {
|
||||
width: 1600px;
|
||||
height: 1600px;
|
||||
-webkit-transform-origin: 0 0;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
|
||||
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container .leaflet-overlay-pane svg {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
}
|
||||
.leaflet-container .leaflet-marker-pane img,
|
||||
.leaflet-container .leaflet-shadow-pane img,
|
||||
.leaflet-container .leaflet-tile-pane img,
|
||||
.leaflet-container img.leaflet-image-layer,
|
||||
.leaflet-container .leaflet-tile {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.leaflet-container img.leaflet-tile {
|
||||
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
|
||||
mix-blend-mode: plus-lighter;
|
||||
}
|
||||
|
||||
.leaflet-container.leaflet-touch-zoom {
|
||||
-ms-touch-action: pan-x pan-y;
|
||||
touch-action: pan-x pan-y;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag {
|
||||
-ms-touch-action: pinch-zoom;
|
||||
/* Fallback for FF which doesn't support pinch-zoom */
|
||||
touch-action: none;
|
||||
touch-action: pinch-zoom;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.leaflet-container {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.leaflet-container a {
|
||||
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
|
||||
}
|
||||
.leaflet-tile {
|
||||
filter: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility: inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width: 0;
|
||||
height: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
z-index: 800;
|
||||
}
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.leaflet-pane { z-index: 400; }
|
||||
|
||||
.leaflet-tile-pane { z-index: 200; }
|
||||
.leaflet-overlay-pane { z-index: 400; }
|
||||
.leaflet-shadow-pane { z-index: 500; }
|
||||
.leaflet-marker-pane { z-index: 600; }
|
||||
.leaflet-tooltip-pane { z-index: 650; }
|
||||
.leaflet-popup-pane { z-index: 700; }
|
||||
|
||||
.leaflet-map-pane canvas { z-index: 100; }
|
||||
.leaflet-map-pane svg { z-index: 200; }
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* control positioning */
|
||||
|
||||
.leaflet-control {
|
||||
position: relative;
|
||||
z-index: 800;
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-top {
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-right {
|
||||
right: 0;
|
||||
}
|
||||
.leaflet-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
.leaflet-left {
|
||||
left: 0;
|
||||
}
|
||||
.leaflet-control {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
float: right;
|
||||
}
|
||||
.leaflet-top .leaflet-control {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.leaflet-left .leaflet-control {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom and fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
.leaflet-zoom-animated {
|
||||
-webkit-transform-origin: 0 0;
|
||||
-ms-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
svg.leaflet-zoom-animated {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* cursors */
|
||||
|
||||
.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-grab {
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
.leaflet-crosshair,
|
||||
.leaflet-crosshair .leaflet-interactive {
|
||||
cursor: crosshair;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor: auto;
|
||||
}
|
||||
.leaflet-dragging .leaflet-grab,
|
||||
.leaflet-dragging .leaflet-grab .leaflet-interactive,
|
||||
.leaflet-dragging .leaflet-marker-draggable {
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
/* marker & overlays interactivity */
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-pane > svg path,
|
||||
.leaflet-tile-container {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.leaflet-interactive,
|
||||
.leaflet-image-layer.leaflet-interactive,
|
||||
.leaflet-pane > svg path.leaflet-interactive,
|
||||
svg.leaflet-image-layer.leaflet-interactive path {
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* visual tweaks */
|
||||
|
||||
.leaflet-container {
|
||||
background: #ddd;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.leaflet-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-control-layers-toggle {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.leaflet-bar a:hover,
|
||||
.leaflet-bar a:focus {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.leaflet-bar a.leaflet-disabled {
|
||||
cursor: default;
|
||||
background-color: #f4f4f4;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-bar a {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:first-child {
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
|
||||
/* zoom control */
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
||||
text-indent: 1px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.leaflet-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-retina .leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers-2x.png);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display: none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.leaflet-control-layers-expanded {
|
||||
padding: 6px 10px 6px 6px;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
}
|
||||
.leaflet-control-layers-scrollbar {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
/* Default icon URLs */
|
||||
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
|
||||
background-image: url(images/marker-icon.png);
|
||||
}
|
||||
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover,
|
||||
.leaflet-control-attribution a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-attribution-flag {
|
||||
display: inline !important;
|
||||
vertical-align: baseline !important;
|
||||
width: 1em;
|
||||
height: 0.6669em;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.leaflet-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
white-space: nowrap;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
text-shadow: 1px 1px #fff;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom: 2px solid #777;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-attribution,
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* popup */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 13px 24px 13px 20px;
|
||||
line-height: 1.3;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
min-height: 1px;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 17px 0;
|
||||
margin: 1.3em 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-top: -1px;
|
||||
margin-left: -20px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
pointer-events: auto;
|
||||
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.leaflet-popup-content-wrapper,
|
||||
.leaflet-popup-tip {
|
||||
background: white;
|
||||
color: #333;
|
||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
border: none;
|
||||
text-align: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font: 16px/24px Tahoma, Verdana, sans-serif;
|
||||
color: #757575;
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover,
|
||||
.leaflet-container a.leaflet-popup-close-button:focus {
|
||||
color: #585858;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
-ms-zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
margin: 0 auto;
|
||||
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
|
||||
/* div icon */
|
||||
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
|
||||
|
||||
/* Tooltip */
|
||||
/* Base styles for the element that has a tooltip */
|
||||
.leaflet-tooltip {
|
||||
position: absolute;
|
||||
padding: 6px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 3px;
|
||||
color: #222;
|
||||
white-space: nowrap;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-tooltip.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-tooltip-top:before,
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border: 6px solid transparent;
|
||||
background: transparent;
|
||||
content: "";
|
||||
}
|
||||
|
||||
/* Directions */
|
||||
|
||||
.leaflet-tooltip-bottom {
|
||||
margin-top: 6px;
|
||||
}
|
||||
.leaflet-tooltip-top {
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-top:before {
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-top:before {
|
||||
bottom: 0;
|
||||
margin-bottom: -12px;
|
||||
border-top-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before {
|
||||
top: 0;
|
||||
margin-top: -12px;
|
||||
margin-left: -6px;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-left {
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-right {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
top: 50%;
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before {
|
||||
right: 0;
|
||||
margin-right: -12px;
|
||||
border-left-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-right:before {
|
||||
left: 0;
|
||||
margin-left: -12px;
|
||||
border-right-color: #fff;
|
||||
}
|
||||
|
||||
/* Printing */
|
||||
|
||||
@media print {
|
||||
/* Prevent printers from removing background-images of controls. */
|
||||
.leaflet-control {
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
}
|
||||
6
htdocs/includes/leaflet/leaflet.js
Normal file
6
htdocs/includes/leaflet/leaflet.js
Normal file
File diff suppressed because one or more lines are too long
1
htdocs/includes/leaflet/leaflet.js.map
Normal file
1
htdocs/includes/leaflet/leaflet.js.map
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -458,6 +458,10 @@ ExtrafieldRadio=Radio buttons (one choice only)
|
|||
ExtrafieldCheckBox=Checkboxes
|
||||
ExtrafieldCheckBoxFromList=Checkboxes from table
|
||||
ExtrafieldLink=Link to an object
|
||||
ExtrafieldPointGeo=Geometric Point
|
||||
ExtrafieldMultiPointGeo=Geometric Multi Point
|
||||
ExtrafieldLinestringGeo=Geometric Linestring
|
||||
ExtrafieldPolygonGeo=Geometric Polygon
|
||||
ComputedFormula=Computed field
|
||||
ComputedFormulaDesc=You can enter here a formula using other properties of object or any PHP coding to get a dynamic computed value. You can use any PHP compatible formulas including the "?" condition operator, and following global object: <strong>$db, $conf, $langs, $mysoc, $user, $objectoffield</strong>.<br><strong>WARNING</strong>: If you need properties of an object not loaded, just fetch yourself the object into your formula like in the second example.<br>Using a computed field means you can't enter yourself any value from interface. Also, if there is a syntax error, the formula may return nothing.<br><br>Example of formula:<br>$objectoffield->id < 10 ? round($objectoffield->id / 2, 2): ($objectoffield->id + 2 * $user->id) * (int) substr($mysoc->zip, 1, 2)<br><br>Example to reload object<br>(($reloadedobj = new Societe($db)) && ($reloadedobj->fetchNoCompute($objectoffield->id) > 0 ? $reloadedobj->array_options['options_extrafieldkey'] * $reloadedobj->capital / 5: '-1')<br><br>Other example of formula to force load of object and its parent object:<br>(($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($objectoffield->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref: 'Parent project not found'
|
||||
Computedpersistent=Store computed field
|
||||
|
|
|
|||
|
|
@ -1935,6 +1935,10 @@ function top_htmlhead($head, $title = '', $disablejs = 0, $disablehead = 0, $arr
|
|||
print '<!-- Includes CSS that does not exists as a workaround of flash bug of chrome -->'."\n".'<link rel="stylesheet" type="text/css" href="filethatdoesnotexiststosolvechromeflashbug">'."\n";
|
||||
}
|
||||
|
||||
// LEAFLET AND GEOMAN
|
||||
print '<link rel="stylesheet" href="'.DOL_URL_ROOT.'/includes/leaflet/leaflet.css'.($ext ? '?'.$ext : '')."\">\n";
|
||||
print '<link rel="stylesheet" href="'.DOL_URL_ROOT.'/includes/leaflet/leaflet-geoman.css'.($ext ? '?'.$ext : '')."\">\n";
|
||||
|
||||
// CSS forced by modules (relative url starting with /)
|
||||
if (!empty($conf->modules_parts['css'])) {
|
||||
$arraycss = (array) $conf->modules_parts['css'];
|
||||
|
|
@ -2089,6 +2093,10 @@ function top_htmlhead($head, $title = '', $disablejs = 0, $disablehead = 0, $arr
|
|||
print '<!-- Includes JS of Dolibarr -->'."\n";
|
||||
print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/lib_head.js.php?lang='.$langs->defaultlang.($ext ? '&'.$ext : '').'"></script>'."\n";
|
||||
|
||||
// Leaflet TODO use dolibarr files
|
||||
print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/leaflet/leaflet.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
|
||||
print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/leaflet/leaflet-geoman.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
|
||||
|
||||
// JS forced by modules (relative url starting with /)
|
||||
if (!empty($conf->modules_parts['js'])) { // $conf->modules_parts['js'] is array('module'=>array('file1','file2'))
|
||||
$arrayjs = (array) $conf->modules_parts['js'];
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user