diff --git a/dev/translation/dynamic_translation_keys.lst b/dev/translation/dynamic_translation_keys.lst index bdda966183a..6fcfefcc05e 100644 --- a/dev/translation/dynamic_translation_keys.lst +++ b/dev/translation/dynamic_translation_keys.lst @@ -3669,6 +3669,10 @@ EditWithEditor ElementId ElementType ErrorABatchShouldNotContainsSpaces +ExtrafieldLinestringGeo +ExtrafieldMultiPointGeo +ExtrafieldPointGeo +ExtrafieldPolygonGeo ImageGeneration ModelTemplate ModuleWebPortalDesc diff --git a/htdocs/core/actions_extrafields.inc.php b/htdocs/core/actions_extrafields.inc.php index 61b31bfb5fd..eef5f599dd8 100644 --- a/htdocs/core/actions_extrafields.inc.php +++ b/htdocs/core/actions_extrafields.inc.php @@ -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; } diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 921d483106c..d068104ad48 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -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'])) { diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 960f8253006..5fefd4f65ca 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -9,7 +9,7 @@ * Copyright (C) 2015-2023 Charlene BENKE * Copyright (C) 2016 Raphaël Doursenaud * Copyright (C) 2017 Nicolas ZABOURI - * Copyright (C) 2018-2022 Frédéric France + * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2022 Antonin MARCHAL * Copyright (C) 2024 MDW * @@ -47,7 +47,7 @@ class ExtraFields /** * @var array,type:array,size:array,default:array,computed:array,unique:array,required:array,param:array,perms:array,list:array,pos:array,totalizable:array,help:array,printable:array,enabled:array,langfile:array,css:array,csslist:array,hidden:array,mandatoryfieldsofotherentities:array,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 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 = ''; // 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 diff --git a/htdocs/core/class/geomapeditor.class.php b/htdocs/core/class/geomapeditor.class.php new file mode 100644 index 00000000000..adbf4d5fc66 --- /dev/null +++ b/htdocs/core/class/geomapeditor.class.php @@ -0,0 +1,231 @@ + + * + * 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 . + * 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 = ''; + $out .= '
'; + 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 .= ' + '; + + return $out; + } +} diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 21fc1144c7e..51770eb03a4 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -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' ); diff --git a/htdocs/core/tpl/admin_extrafields_add.tpl.php b/htdocs/core/tpl/admin_extrafields_add.tpl.php index d5176a852ba..9102972d4dc 100644 --- a/htdocs/core/tpl/admin_extrafields_add.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_add.tpl.php @@ -104,6 +104,9 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php
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
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); diff --git a/htdocs/core/tpl/admin_extrafields_edit.tpl.php b/htdocs/core/tpl/admin_extrafields_edit.tpl.php index db74b1677ee..94a7f990810 100644 --- a/htdocs/core/tpl/admin_extrafields_edit.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_edit.tpl.php @@ -59,7 +59,7 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php
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
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); diff --git a/htdocs/includes/geoPHP/.gitignore b/htdocs/includes/geoPHP/.gitignore new file mode 100644 index 00000000000..61ead86667c --- /dev/null +++ b/htdocs/includes/geoPHP/.gitignore @@ -0,0 +1 @@ +/vendor diff --git a/htdocs/includes/geoPHP/.travis.yml b/htdocs/includes/geoPHP/.travis.yml new file mode 100644 index 00000000000..069e48c2284 --- /dev/null +++ b/htdocs/includes/geoPHP/.travis.yml @@ -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 diff --git a/htdocs/includes/geoPHP/LICENSE b/htdocs/includes/geoPHP/LICENSE new file mode 100644 index 00000000000..d66b3eeed34 --- /dev/null +++ b/htdocs/includes/geoPHP/LICENSE @@ -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. + + + Copyright (C) + + 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. + + , 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. diff --git a/htdocs/includes/geoPHP/README.md b/htdocs/includes/geoPHP/README.md new file mode 100644 index 00000000000..9ff8e4cc4a3 --- /dev/null +++ b/htdocs/includes/geoPHP/README.md @@ -0,0 +1,155 @@ +[![Build Status](https://travis-ci.org/phayes/geoPHP.svg?branch=master)](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: + * Read the API Reference at: + * Examples + * Using geoPHP as a GIS format converter: + * Other Interesting Links: + * Learn about GEOS integration at: + +Example usage +------------------------------------------------- + +```php +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 "
"; +$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 +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 () + * HighWire Press () and GeoScienceWorld () + * Arnaud Renevier (gisconverter.php) + * Dave Tarc + * Elliott Hunston (documentation) + +This library is open-source and dual-licensed under both the Modified BSD License and GPLv2. Either license may be used at your option. diff --git a/htdocs/includes/geoPHP/composer.json b/htdocs/includes/geoPHP/composer.json new file mode 100644 index 00000000000..a02eba8a1a2 --- /dev/null +++ b/htdocs/includes/geoPHP/composer.json @@ -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.*" + } +} diff --git a/htdocs/includes/geoPHP/doc/api.html b/htdocs/includes/geoPHP/doc/api.html new file mode 100644 index 00000000000..afdaeb2da5b --- /dev/null +++ b/htdocs/includes/geoPHP/doc/api.html @@ -0,0 +1,734 @@ +
+ +
+
+
+
+ + + + +
+
Table of Contents
+ +
+

+ + geoPHP static class + +

+ +

geoPHP provides a static class that contains useful utility functions. All methods must + be called statically.

+

+ + Example + +

+ +
$geometry = geoPHP::load('MULTILINESTRING((10 10,20 20,10 40))','wkt');
+
$reduced_geometry = geoPHP::geometryReduce($geometry);
+ +

+ + Static Methods + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Method + + Description + + Returns +
version Provides the current geoPHP version. Useful if you need to check compatablity Numeric String
load 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 Geometry
getAdapterMap Get a list of adapters as an array keyed by the value that should be passed to + geoPHP::load Array
geometryList List all geometry types Array
geosToGeometry Given a GEOSGeometry, get a geoPHP geometry Geometry
geometryReduce 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. Geometry
geosInstalled Check if the GEOS php extension is installed and working Boolean
+

+ + Adapters + +

+ +

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 example-format-converter for an example of this). Adapters should be instantiated + and not called statically.

+

+ + Class Hierarchy + +

+ +
    +
  • GeoAdapter Abtract Class
      +
    • WKT Enables reading and writing WKT (Well Known Text)
    • +
    • WKB Enables reading and writing WKB (Well Known Binary). This is very fast.
    • +
    • GeoJSON Enables reading and writing GeoJSON
    • +
    • KML Enables reading and writing KML (Google Earth)
    • +
    • GoogleGeocode Enables geocoding and reverse-geocoding via google geocoding + API
    • +
    • GPX Enables reading and writing GPX (from handheld GPS devices)
    • +
    • GeoRSS Enables reading and writing of GeoRSS
    • +
    +
  • +
+

+ + Example + +

+ +
$wkb_reader = new WKB();
+
$geometry = $wkb_reader->read('0101000000000000000000f03f000000000000f03f',TRUE);
+
$wkt_writer = new wkt();
+
$wkt = $wkt_writer->write($geometry);
+ +

+ + Methods + +

+ + + + + + + + + + + + + + + + + +
+ Method + + Description + + Returns +
read Read in input (generally a string) and return a Geometry Geometry
write Write out the given geometry into the adapter formater String
+

+ + Geometries + +

+ +

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).

+

+ + Class Hierarchy + +

+ +
    +
  • Geometry
      +
    • Point
    • +
    • Collection
        +
      • LineString
      • +
      • Polygon
      • +
      • MultiLineString
      • +
      • MultiPoint
      • +
      • MultiPolygon
      • +
      • GeometryCollection
      • +
      +
    • +
    +
  • +
+

+ + Example + +

+ +
$poly1 = $geoPHP::load('POLYGON((30 10,10 20,20 40,40 40,30 10))','wkt');
+
$poly2 = $geoPHP::load('POLYGON((35 10,10 20,15 40,45 45,35 10),(20 30, 35 35, 30 20, 20 30))','wkt');
+
$combined_poly = $poly1->union($poly2);
+
$kml = $combined_poly->out('kml');
+ +

+ + Methods + +

+ +

+ Common Methods +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Method + + Description + + Returns +
out Outputs the geometry into the specified adapter format. Available formats are + wkt, wkb, json, kml, gpx, google_geocode + String
area The area of this Polygon (or GeometryCollection), as measured in the spatial + reference system of the geometry Float
boundary Returns the closure of the combinatorial boundary of this geometric object. LinearRing
envelope The minimum bounding box for this Geometry, returned as a Geometry. Polygon
getBBox The minimum bounding box for this Geometry, returned as an array. Also see + envelope() Array
centroid The mathematical centroid for this geometry as a Point. For polygons, the result + is not guaranteed to be interior. Point
length The length of this Curve in its associated spatial reference. Float
y The y-coordinate value for this Point. Float
x The x-coordinate value for this Point. Float
numGeometries The number of component geometries in this collection Integer
geometryN Returns the geometry N in this collection. Note that the index starts at 1. Geometry
startPoint The start Point of this LineString Point
endPoint The end Point of this LineString Point
isRing Returns 1 (TRUE) if this Curve is closed() and this Curve isSimple(). Boolean
isClosed Returns 1 (TRUE) if this Curve is closed. StartPoint() == EndPoint(). Boolean
getComponents Get all sub-geometry components of the geometry Array of geometries
numPoints The number of Points in this LineString Integer
pointN Returns the specified Point N in this LineString. Note that the index starts at + 1. Point
exteriorRing Returns the exterior ring of this Polygon. LineString
numInteriorRings Returns the number of interior rings in this Polygon. Integer
interiorRingN Returns the Nth interior ring for this Polygon as a LineString. Note that the + index starts at 1. LineString
dimension The inherent dimension of this geometric object. In non-homogeneous collections, + this will return the largest topological dimension of the contained objects. Integer
geometryType 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. String
SRID Returns the Spatial Reference System ID for this geometric object. integer
setSRID Set the Spatial Reference System ID for this geometric object. NULL
asArray Get the given geometry as an array of components (recursive) Array
getGeoInterface Get the geometryType and Coordinates as an array Array
+

+ Aliases +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Method + + Description + + Returns +
getCentroid Alias for centroid() Point
getArea Alias for area() Float
getX Alias for x() Float
getY Alias for y() Float
getGeos Alias for geos() GEOSGeometry
getGeomType Alias for geometryType() String
getSRID Alias for SRID() Integer
asText Alias for $this->out('wkt') + String
asBinary Alias for $this->out('wkb') + String
+

+ Advanced Methods +

+

The GEOS-php + extension needs to be installed for these functions to be available

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Method + + Description + + Returns +
geos Return a GEOSGeometry object representing this geometry GEOSGeometry
setGeos Set a GEOSGeometry object representing this geometry NULL
pointOnSurface A Point guaranteed to be within a polygon Point
equals Returns 1 (TRUE) if this geometry is “spatially equal” to another Geometry Boolean
equalsExact Returns 1 (TRUE) if this gemometric object is exactly the same as another object, + including the ordering of component parts Boolean
relate 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). Boolean
checkValidity Boolean
isSimple Returns 1 (TRUE) if this geometry does not pass through the same point in space + more than once Boolean
project Project the geometry from from one SRID to another Geometry
buffer 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. Geometry
intersection Returns a geometric object that represents the Point set intersection of this + geometric object with anotherGeometry. See http://en.wikipedia.org/wiki/Intersection_(set_theory) + Geometry
convexHull Returns a geometric object that represents the convex hull of this geometric + object. See http://en.wikipedia.org/wiki/Convex_hull + Geometry
difference Returns a geometric object that represents the Point set difference of this + geometric object with anotherGeometry. Geometry
symDifference Returns a geometric object that represents the Point set symmetric difference of + this geometric object with another Geometry. See http://en.wikipedia.org/wiki/Symmetric_difference + Geometry
union Returns a geometric object that represents the Point set union of this geometric + object with anotherGeometry. See http://en.wikipedia.org/wiki/Union_(set_theory) + Geometry
simplify Simplify the geometry Geometry
disjoint Returns 1 (TRUE) if this geometric object is “spatially disjoint” from another + Geometry. Boolean
touches Returns 1 (TRUE) if this geometric object “spatially touches” another Geometry. Boolean
intersects Returns 1 (TRUE) if this geometric object “spatially intersects” another + Geometry. Boolean
crosses Returns 1 (TRUE) if this geometric object “spatially crosses? another Geometry. Boolean
within Returns 1 (TRUE) if this geometric object is “spatially within” another Geometry. Boolean
contains Returns 1 (TRUE) if this geometric object “spatially contains” another Geometry. Boolean
overlaps Returns 1 (TRUE) if this geometric object “spatially overlaps” another Geometry. Boolean
covers Alias for contains() Boolean
coveredBy Alias for within() Boolean
distance 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. Float
hausdorffDistance See http://en.wikipedia.org/wiki/Hausdorff_distance + Float
+

+ Placeholders +

+

These methods are part of the specification, but are not really supported by geoPHP.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Method + + Description + + Returns +
hasZ returns FALSE. geoPHP does not support Z values at the moment. Boolean
is3D returns FALSE. geoPHP does not support 3D geometries at the moment. Boolean
isMeasured returns FALSE. geoPHP does not yet support M values Boolean
isEmpty returns FALSE. geoPHP does not yet support empty geometries Boolean
coordinateDimension returns 2. geoPHP only supports 2-dimentional space Integer
z returns NULL. geoPHP does not support Z values at the moment NULL
m returns NULL. geoPHP does not support M values NULL
+
+
+
+
+
diff --git a/htdocs/includes/geoPHP/geoPHP.inc.php b/htdocs/includes/geoPHP/geoPHP.inc.php new file mode 100644 index 00000000000..55b4f278a62 --- /dev/null +++ b/htdocs/includes/geoPHP/geoPHP.inc.php @@ -0,0 +1,303 @@ + '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, '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; + } + } +} diff --git a/htdocs/includes/geoPHP/lib/adapters/EWKT.class.php b/htdocs/includes/geoPHP/lib/adapters/EWKT.class.php new file mode 100644 index 00000000000..4108804d1bd --- /dev/null +++ b/htdocs/includes/geoPHP/lib/adapters/EWKT.class.php @@ -0,0 +1,27 @@ +SRID(); + $wkt = ''; + if ($srid) { + $wkt = 'SRID=' . $srid . ';'; + $wkt .= $geometry->out('wkt'); + return $wkt; + } else { + return $geometry->out('wkt'); + } + } +} diff --git a/htdocs/includes/geoPHP/lib/adapters/GPX.class.php b/htdocs/includes/geoPHP/lib/adapters/GPX.class.php new file mode 100644 index 00000000000..a1e35125ee1 --- /dev/null +++ b/htdocs/includes/geoPHP/lib/adapters/GPX.class.php @@ -0,0 +1,191 @@ +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).'nss.'gpx>'; + } + + public function geomFromText($text) + { + // Change to lower-case and strip all CDATA + $text = strtolower($text); + $text = preg_replace('//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 .= 'nss.'trkseg>nss.'trk>'; + + return $gpx; + } + + public function collectionToGPX($geom) + { + $gpx = ''; + $components = $geom->getComponents(); + foreach ($geom->getComponents() as $comp) { + $gpx .= $this->geometryToGPX($comp); + } + + return $gpx; + } +} diff --git a/htdocs/includes/geoPHP/lib/adapters/GeoAdapter.class.php b/htdocs/includes/geoPHP/lib/adapters/GeoAdapter.class.php new file mode 100644 index 00000000000..da365e6f900 --- /dev/null +++ b/htdocs/includes/geoPHP/lib/adapters/GeoAdapter.class.php @@ -0,0 +1,30 @@ + 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 + * @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 + * @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)]; + } +} diff --git a/htdocs/includes/geoPHP/lib/adapters/GeoJSON.class.php b/htdocs/includes/geoPHP/lib/adapters/GeoJSON.class.php new file mode 100644 index 00000000000..f402bcfc92c --- /dev/null +++ b/htdocs/includes/geoPHP/lib/adapters/GeoJSON.class.php @@ -0,0 +1,161 @@ +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(), + ); + } +} diff --git a/htdocs/includes/geoPHP/lib/adapters/GeoRSS.class.php b/htdocs/includes/geoPHP/lib/adapters/GeoRSS.class.php new file mode 100644 index 00000000000..b94b0969390 --- /dev/null +++ b/htdocs/includes/geoPHP/lib/adapters/GeoRSS.class.php @@ -0,0 +1,255 @@ +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('//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 .= '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 .= '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 .= '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 .= 'nss.'where>'; + + return $georss; + } +} diff --git a/htdocs/includes/geoPHP/lib/adapters/GoogleGeocode.class.php b/htdocs/includes/geoPHP/lib/adapters/GoogleGeocode.class.php new file mode 100644 index 00000000000..f590c274ee0 --- /dev/null +++ b/htdocs/includes/geoPHP/lib/adapters/GoogleGeocode.class.php @@ -0,0 +1,170 @@ + + * (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 + */ +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); + } +} diff --git a/htdocs/includes/geoPHP/lib/adapters/KML.class.php b/htdocs/includes/geoPHP/lib/adapters/KML.class.php new file mode 100644 index 00000000000..6e4a6eed3d4 --- /dev/null +++ b/htdocs/includes/geoPHP/lib/adapters/KML.class.php @@ -0,0 +1,284 @@ + + */ +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('//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().'nss.'coordinates>'; + } + $out .= '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 .= 'nss.'coordinates>'; + } + + $str .= 'nss . $type .'>'; + + return $str; + } + + public function polygonToKML($geom) + { + $components = $geom->getComponents(); + $str = ''; + if (!empty($components)) { + $str = '<'.$this->nss.'outerBoundaryIs>' . $this->linestringToKML($components[0], 'LinearRing') . 'nss.'outerBoundaryIs>'; + foreach (array_slice($components, 1) as $comp) { + $str .= '<'.$this->nss.'innerBoundaryIs>' . $this->linestringToKML($comp) . 'nss.'innerBoundaryIs>'; + } + } + + return '<'.$this->nss.'Polygon>'. $str .'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 .'nss.'MultiGeometry>'; + } +} diff --git a/htdocs/includes/geoPHP/lib/adapters/WKB.class.php b/htdocs/includes/geoPHP/lib/adapters/WKB.class.php new file mode 100644 index 00000000000..c96422120db --- /dev/null +++ b/htdocs/includes/geoPHP/lib/adapters/WKB.class.php @@ -0,0 +1,258 @@ +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; + } +} diff --git a/htdocs/includes/geoPHP/lib/adapters/WKT.class.php b/htdocs/includes/geoPHP/lib/adapters/WKT.class.php new file mode 100644 index 00000000000..c9bf51f8c4d --- /dev/null +++ b/htdocs/includes/geoPHP/lib/adapters/WKT.class.php @@ -0,0 +1,265 @@ +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); + } + } +} diff --git a/htdocs/includes/geoPHP/lib/geometry/Collection.class.php b/htdocs/includes/geoPHP/lib/geometry/Collection.class.php new file mode 100644 index 00000000000..1897d70225e --- /dev/null +++ b/htdocs/includes/geoPHP/lib/geometry/Collection.class.php @@ -0,0 +1,348 @@ +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;$icomponents);$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; } +} diff --git a/htdocs/includes/geoPHP/lib/geometry/Geometry.class.php b/htdocs/includes/geoPHP/lib/geometry/Geometry.class.php new file mode 100644 index 00000000000..3ebf57f85ba --- /dev/null +++ b/htdocs/includes/geoPHP/lib/geometry/Geometry.class.php @@ -0,0 +1,388 @@ +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; + } +} diff --git a/htdocs/includes/geoPHP/lib/geometry/GeometryCollection.class.php b/htdocs/includes/geoPHP/lib/geometry/GeometryCollection.class.php new file mode 100644 index 00000000000..ce70042fcf7 --- /dev/null +++ b/htdocs/includes/geoPHP/lib/geometry/GeometryCollection.class.php @@ -0,0 +1,33 @@ +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; } +} diff --git a/htdocs/includes/geoPHP/lib/geometry/LineString.class.php b/htdocs/includes/geoPHP/lib/geometry/LineString.class.php new file mode 100644 index 00000000000..d6368a2068d --- /dev/null +++ b/htdocs/includes/geoPHP/lib/geometry/LineString.class.php @@ -0,0 +1,204 @@ +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; + } +} diff --git a/htdocs/includes/geoPHP/lib/geometry/MultiLineString.class.php b/htdocs/includes/geoPHP/lib/geometry/MultiLineString.class.php new file mode 100644 index 00000000000..82f7d3fc3bb --- /dev/null +++ b/htdocs/includes/geoPHP/lib/geometry/MultiLineString.class.php @@ -0,0 +1,19 @@ +components as $line) { + if (!$line->isClosed()) { + return false; + } + } + return true; + } +} diff --git a/htdocs/includes/geoPHP/lib/geometry/MultiPoint.class.php b/htdocs/includes/geoPHP/lib/geometry/MultiPoint.class.php new file mode 100644 index 00000000000..34af5fb9e24 --- /dev/null +++ b/htdocs/includes/geoPHP/lib/geometry/MultiPoint.class.php @@ -0,0 +1,24 @@ +numGeometries(); + } + + public function isSimple() + { + return true; + } + + // Not valid for this geometry type + // -------------------------------- + public function explode() + { + return null; } +} diff --git a/htdocs/includes/geoPHP/lib/geometry/MultiPolygon.class.php b/htdocs/includes/geoPHP/lib/geometry/MultiPolygon.class.php new file mode 100644 index 00000000000..fe3440d0dd9 --- /dev/null +++ b/htdocs/includes/geoPHP/lib/geometry/MultiPolygon.class.php @@ -0,0 +1,8 @@ +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; } +} diff --git a/htdocs/includes/geoPHP/lib/geometry/Polygon.class.php b/htdocs/includes/geoPHP/lib/geometry/Polygon.class.php new file mode 100644 index 00000000000..1bbb2eecf01 --- /dev/null +++ b/htdocs/includes/geoPHP/lib/geometry/Polygon.class.php @@ -0,0 +1,225 @@ +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; } +} diff --git a/htdocs/includes/leaflet/images/layers-2x.png b/htdocs/includes/leaflet/images/layers-2x.png new file mode 100644 index 00000000000..200c333dca9 Binary files /dev/null and b/htdocs/includes/leaflet/images/layers-2x.png differ diff --git a/htdocs/includes/leaflet/images/layers.png b/htdocs/includes/leaflet/images/layers.png new file mode 100644 index 00000000000..1a72e5784b2 Binary files /dev/null and b/htdocs/includes/leaflet/images/layers.png differ diff --git a/htdocs/includes/leaflet/images/marker-icon-2x.png b/htdocs/includes/leaflet/images/marker-icon-2x.png new file mode 100644 index 00000000000..88f9e501888 Binary files /dev/null and b/htdocs/includes/leaflet/images/marker-icon-2x.png differ diff --git a/htdocs/includes/leaflet/images/marker-icon.png b/htdocs/includes/leaflet/images/marker-icon.png new file mode 100644 index 00000000000..950edf24677 Binary files /dev/null and b/htdocs/includes/leaflet/images/marker-icon.png differ diff --git a/htdocs/includes/leaflet/images/marker-shadow.png b/htdocs/includes/leaflet/images/marker-shadow.png new file mode 100644 index 00000000000..9fd2979532a Binary files /dev/null and b/htdocs/includes/leaflet/images/marker-shadow.png differ diff --git a/htdocs/includes/leaflet/leaflet-geoman.css b/htdocs/includes/leaflet/leaflet-geoman.css new file mode 100644 index 00000000000..3790dc8c00c --- /dev/null +++ b/htdocs/includes/leaflet/leaflet-geoman.css @@ -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); +} diff --git a/htdocs/includes/leaflet/leaflet-geoman.min.js b/htdocs/includes/leaflet/leaflet-geoman.min.js new file mode 100644 index 00000000000..77cc590292c --- /dev/null +++ b/htdocs/includes/leaflet/leaflet-geoman.min.js @@ -0,0 +1 @@ +(()=>{var t={9705:(t,e,i)=>{"use strict";var n=i(1540);function r(t){var e=[Infinity,Infinity,-Infinity,-Infinity];return n.coordEach(t,(function(t){e[0]>t[0]&&(e[0]=t[0]),e[1]>t[1]&&(e[1]=t[1]),e[2]{"use strict";function i(t,e,i){void 0===i&&(i={});var n={type:"Feature"};return(0===i.id||i.id)&&(n.id=i.id),i.bbox&&(n.bbox=i.bbox),n.properties=e||{},n.geometry=t,n}function n(t,e,n){if(void 0===n&&(n={}),!t)throw new Error("coordinates is required");if(!Array.isArray(t))throw new Error("coordinates must be an Array");if(t.length<2)throw new Error("coordinates must be at least 2 numbers long");if(!d(t[0])||!d(t[1]))throw new Error("coordinates must contain numbers");return i({type:"Point",coordinates:t},e,n)}function r(t,e,n){void 0===n&&(n={});for(var r=0,a=t;r=0))throw new Error("precision must be a positive number");var i=Math.pow(10,e||0);return Math.round(t*i)/i},e.radiansToLength=u,e.lengthToRadians=c,e.lengthToDegrees=function(t,e){return p(c(t,e))},e.bearingToAzimuth=function(t){var e=t%360;return e<0&&(e+=360),e},e.radiansToDegrees=p,e.degreesToRadians=function(t){return t%360*Math.PI/180},e.convertLength=function(t,e,i){if(void 0===e&&(e="kilometers"),void 0===i&&(i="kilometers"),!(t>=0))throw new Error("length must be a positive number");return u(c(t,e),i)},e.convertArea=function(t,i,n){if(void 0===i&&(i="meters"),void 0===n&&(n="kilometers"),!(t>=0))throw new Error("area must be a positive number");var r=e.areaFactors[i];if(!r)throw new Error("invalid original units");var a=e.areaFactors[n];if(!a)throw new Error("invalid final units");return t/r*a},e.isNumber=d,e.isObject=function(t){return!!t&&t.constructor===Object},e.validateBBox=function(t){if(!t)throw new Error("bbox is required");if(!Array.isArray(t))throw new Error("bbox must be an Array");if(4!==t.length&&6!==t.length)throw new Error("bbox must be an Array of 4 or 6 numbers");t.forEach((function(t){if(!d(t))throw new Error("bbox must only contain numbers")}))},e.validateId=function(t){if(!t)throw new Error("id is required");if(-1===["string","number"].indexOf(typeof t))throw new Error("id must be a number or a string")}},1540:(t,e,i)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});var n=i(4102);function r(t,e,i){if(null!==t)for(var n,a,o,s,l,h,u,c,p=0,d=0,f=t.type,g="FeatureCollection"===f,_="Feature"===f,m=g?t.features.length:1,y=0;yh||d>u||f>c)return l=r,h=i,u=d,c=f,void(o=0);var g=n.lineString([l,r],t.properties);if(!1===e(g,i,a,f,o))return!1;o++,l=r}))&&void 0}}}))}function u(t,e){if(!t)throw new Error("geojson is required");l(t,(function(t,i,r){if(null!==t.geometry){var a=t.geometry.type,o=t.geometry.coordinates;switch(a){case"LineString":if(!1===e(t,i,r,0,0))return!1;break;case"Polygon":for(var s=0;s{Array.prototype.findIndex=Array.prototype.findIndex||function(t){if(null===this)throw new TypeError("Array.prototype.findIndex called on null or undefined");if("function"!=typeof t)throw new TypeError("callback must be a function");for(var e=Object(this),i=e.length>>>0,n=arguments[1],r=0;r>>0,n=arguments[1],r=0;r>>0;if(0===n)return!1;var r,a,o=0|e,s=Math.max(o>=0?o:n-Math.abs(o),0);for(;s{var n=i(2582),r=i(4102),a=i(1540),o=i(9705).Z,s=a.featureEach,l=(a.coordEach,r.polygon,r.featureCollection);function h(t){var e=new n(t);return e.insert=function(t){if("Feature"!==t.type)throw new Error("invalid feature");return t.bbox=t.bbox?t.bbox:o(t),n.prototype.insert.call(this,t)},e.load=function(t){var e=[];return Array.isArray(t)?t.forEach((function(t){if("Feature"!==t.type)throw new Error("invalid features");t.bbox=t.bbox?t.bbox:o(t),e.push(t)})):s(t,(function(t){if("Feature"!==t.type)throw new Error("invalid features");t.bbox=t.bbox?t.bbox:o(t),e.push(t)})),n.prototype.load.call(this,e)},e.remove=function(t,e){if("Feature"!==t.type)throw new Error("invalid feature");return t.bbox=t.bbox?t.bbox:o(t),n.prototype.remove.call(this,t,e)},e.clear=function(){return n.prototype.clear.call(this)},e.search=function(t){var e=n.prototype.search.call(this,this.toBBox(t));return l(e)},e.collides=function(t){return n.prototype.collides.call(this,this.toBBox(t))},e.all=function(){var t=n.prototype.all.call(this);return l(t)},e.toJSON=function(){return n.prototype.toJSON.call(this)},e.fromJSON=function(t){return n.prototype.fromJSON.call(this,t)},e.toBBox=function(t){var e;if(t.bbox)e=t.bbox;else if(Array.isArray(t)&&4===t.length)e=t;else if(Array.isArray(t)&&6===t.length)e=[t[0],t[1],t[3],t[4]];else if("Feature"===t.type)e=o(t);else{if("FeatureCollection"!==t.type)throw new Error("invalid geojson");e=o(t)}return{minX:e[0],minY:e[1],maxX:e[2],maxY:e[3]}},e}t.exports=h,t.exports["default"]=h},1989:(t,e,i)=>{var n=i(1789),r=i(401),a=i(7667),o=i(1327),s=i(1866);function l(t){var e=-1,i=null==t?0:t.length;for(this.clear();++e{var n=i(7040),r=i(4125),a=i(2117),o=i(7518),s=i(4705);function l(t){var e=-1,i=null==t?0:t.length;for(this.clear();++e{var n=i(852)(i(5639),"Map");t.exports=n},3369:(t,e,i)=>{var n=i(4785),r=i(1285),a=i(6e3),o=i(9916),s=i(5265);function l(t){var e=-1,i=null==t?0:t.length;for(this.clear();++e{var n=i(8407),r=i(7465),a=i(3779),o=i(7599),s=i(4758),l=i(4309);function h(t){var e=this.__data__=new n(t);this.size=e.size}h.prototype.clear=r,h.prototype["delete"]=a,h.prototype.get=o,h.prototype.has=s,h.prototype.set=l,t.exports=h},2705:(t,e,i)=>{var n=i(5639).Symbol;t.exports=n},1149:(t,e,i)=>{var n=i(5639).Uint8Array;t.exports=n},6874:t=>{t.exports=function(t,e,i){switch(i.length){case 0:return t.call(e);case 1:return t.call(e,i[0]);case 2:return t.call(e,i[0],i[1]);case 3:return t.call(e,i[0],i[1],i[2])}return t.apply(e,i)}},4636:(t,e,i)=>{var n=i(2545),r=i(5694),a=i(1469),o=i(4144),s=i(5776),l=i(6719),h=Object.prototype.hasOwnProperty;t.exports=function(t,e){var i=a(t),u=!i&&r(t),c=!i&&!u&&o(t),p=!i&&!u&&!c&&l(t),d=i||u||c||p,f=d?n(t.length,String):[],g=f.length;for(var _ in t)!e&&!h.call(t,_)||d&&("length"==_||c&&("offset"==_||"parent"==_)||p&&("buffer"==_||"byteLength"==_||"byteOffset"==_)||s(_,g))||f.push(_);return f}},9932:t=>{t.exports=function(t,e){for(var i=-1,n=null==t?0:t.length,r=Array(n);++i{var n=i(9465),r=i(7813);t.exports=function(t,e,i){(i!==undefined&&!r(t[e],i)||i===undefined&&!(e in t))&&n(t,e,i)}},4865:(t,e,i)=>{var n=i(9465),r=i(7813),a=Object.prototype.hasOwnProperty;t.exports=function(t,e,i){var o=t[e];a.call(t,e)&&r(o,i)&&(i!==undefined||e in t)||n(t,e,i)}},8470:(t,e,i)=>{var n=i(7813);t.exports=function(t,e){for(var i=t.length;i--;)if(n(t[i][0],e))return i;return-1}},9465:(t,e,i)=>{var n=i(8777);t.exports=function(t,e,i){"__proto__"==e&&n?n(t,e,{configurable:!0,enumerable:!0,value:i,writable:!0}):t[e]=i}},3118:(t,e,i)=>{var n=i(3218),r=Object.create,a=function(){function t(){}return function(e){if(!n(e))return{};if(r)return r(e);t.prototype=e;var i=new t;return t.prototype=undefined,i}}();t.exports=a},8483:(t,e,i)=>{var n=i(5063)();t.exports=n},7786:(t,e,i)=>{var n=i(1811),r=i(327);t.exports=function(t,e){for(var i=0,a=(e=n(e,t)).length;null!=t&&i{var n=i(2705),r=i(9607),a=i(2333),o=n?n.toStringTag:undefined;t.exports=function(t){return null==t?t===undefined?"[object Undefined]":"[object Null]":o&&o in Object(t)?r(t):a(t)}},8565:t=>{var e=Object.prototype.hasOwnProperty;t.exports=function(t,i){return null!=t&&e.call(t,i)}},9454:(t,e,i)=>{var n=i(4239),r=i(7005);t.exports=function(t){return r(t)&&"[object Arguments]"==n(t)}},8458:(t,e,i)=>{var n=i(3560),r=i(5346),a=i(3218),o=i(346),s=/^\[object .+?Constructor\]$/,l=Function.prototype,h=Object.prototype,u=l.toString,c=h.hasOwnProperty,p=RegExp("^"+u.call(c).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");t.exports=function(t){return!(!a(t)||r(t))&&(n(t)?p:s).test(o(t))}},8749:(t,e,i)=>{var n=i(4239),r=i(1780),a=i(7005),o={};o["[object Float32Array]"]=o["[object Float64Array]"]=o["[object Int8Array]"]=o["[object Int16Array]"]=o["[object Int32Array]"]=o["[object Uint8Array]"]=o["[object Uint8ClampedArray]"]=o["[object Uint16Array]"]=o["[object Uint32Array]"]=!0,o["[object Arguments]"]=o["[object Array]"]=o["[object ArrayBuffer]"]=o["[object Boolean]"]=o["[object DataView]"]=o["[object Date]"]=o["[object Error]"]=o["[object Function]"]=o["[object Map]"]=o["[object Number]"]=o["[object Object]"]=o["[object RegExp]"]=o["[object Set]"]=o["[object String]"]=o["[object WeakMap]"]=!1,t.exports=function(t){return a(t)&&r(t.length)&&!!o[n(t)]}},313:(t,e,i)=>{var n=i(3218),r=i(5726),a=i(3498),o=Object.prototype.hasOwnProperty;t.exports=function(t){if(!n(t))return a(t);var e=r(t),i=[];for(var s in t)("constructor"!=s||!e&&o.call(t,s))&&i.push(s);return i}},2980:(t,e,i)=>{var n=i(6384),r=i(6556),a=i(8483),o=i(9783),s=i(3218),l=i(1704),h=i(6390);t.exports=function u(t,e,i,c,p){t!==e&&a(e,(function(a,l){if(p||(p=new n),s(a))o(t,e,l,i,u,c,p);else{var d=c?c(h(t,l),a,l+"",t,e,p):undefined;d===undefined&&(d=a),r(t,l,d)}}),l)}},9783:(t,e,i)=>{var n=i(6556),r=i(4626),a=i(7133),o=i(278),s=i(8517),l=i(5694),h=i(1469),u=i(9246),c=i(4144),p=i(3560),d=i(3218),f=i(8630),g=i(6719),_=i(6390),m=i(9881);t.exports=function(t,e,i,y,v,b,L){var k=_(t,i),M=_(e,i),x=L.get(M);if(x)n(t,i,x);else{var w=b?b(k,M,i+"",t,e,L):undefined,C=w===undefined;if(C){var P=h(M),E=!P&&c(M),S=!P&&!E&&g(M);w=M,P||E||S?h(k)?w=k:u(k)?w=o(k):E?(C=!1,w=r(M,!0)):S?(C=!1,w=a(M,!0)):w=[]:f(M)||l(M)?(w=k,l(k)?w=m(k):d(k)&&!p(k)||(w=s(M))):C=!1}C&&(L.set(M,w),v(w,M,y,b,L),L["delete"](M)),n(t,i,w)}}},5976:(t,e,i)=>{var n=i(6557),r=i(5357),a=i(61);t.exports=function(t,e){return a(r(t,e,n),t+"")}},6560:(t,e,i)=>{var n=i(5703),r=i(8777),a=i(6557),o=r?function(t,e){return r(t,"toString",{configurable:!0,enumerable:!1,value:n(e),writable:!0})}:a;t.exports=o},2545:t=>{t.exports=function(t,e){for(var i=-1,n=Array(t);++i{var n=i(2705),r=i(9932),a=i(1469),o=i(3448),s=n?n.prototype:undefined,l=s?s.toString:undefined;t.exports=function h(t){if("string"==typeof t)return t;if(a(t))return r(t,h)+"";if(o(t))return l?l.call(t):"";var e=t+"";return"0"==e&&1/t==-Infinity?"-0":e}},1717:t=>{t.exports=function(t){return function(e){return t(e)}}},1811:(t,e,i)=>{var n=i(1469),r=i(5403),a=i(5514),o=i(9833);t.exports=function(t,e){return n(t)?t:r(t,e)?[t]:a(o(t))}},4318:(t,e,i)=>{var n=i(1149);t.exports=function(t){var e=new t.constructor(t.byteLength);return new n(e).set(new n(t)),e}},4626:(t,e,i)=>{t=i.nmd(t);var n=i(5639),r=e&&!e.nodeType&&e,a=r&&t&&!t.nodeType&&t,o=a&&a.exports===r?n.Buffer:undefined,s=o?o.allocUnsafe:undefined;t.exports=function(t,e){if(e)return t.slice();var i=t.length,n=s?s(i):new t.constructor(i);return t.copy(n),n}},7133:(t,e,i)=>{var n=i(4318);t.exports=function(t,e){var i=e?n(t.buffer):t.buffer;return new t.constructor(i,t.byteOffset,t.length)}},278:t=>{t.exports=function(t,e){var i=-1,n=t.length;for(e||(e=Array(n));++i{var n=i(4865),r=i(9465);t.exports=function(t,e,i,a){var o=!i;i||(i={});for(var s=-1,l=e.length;++s{var n=i(5639)["__core-js_shared__"];t.exports=n},1463:(t,e,i)=>{var n=i(5976),r=i(6612);t.exports=function(t){return n((function(e,i){var n=-1,a=i.length,o=a>1?i[a-1]:undefined,s=a>2?i[2]:undefined;for(o=t.length>3&&"function"==typeof o?(a--,o):undefined,s&&r(i[0],i[1],s)&&(o=a<3?undefined:o,a=1),e=Object(e);++n{t.exports=function(t){return function(e,i,n){for(var r=-1,a=Object(e),o=n(e),s=o.length;s--;){var l=o[t?s:++r];if(!1===i(a[l],l,a))break}return e}}},8777:(t,e,i)=>{var n=i(852),r=function(){try{var t=n(Object,"defineProperty");return t({},"",{}),t}catch(e){}}();t.exports=r},1957:(t,e,i)=>{var n="object"==typeof i.g&&i.g&&i.g.Object===Object&&i.g;t.exports=n},5050:(t,e,i)=>{var n=i(7019);t.exports=function(t,e){var i=t.__data__;return n(e)?i["string"==typeof e?"string":"hash"]:i.map}},852:(t,e,i)=>{var n=i(8458),r=i(7801);t.exports=function(t,e){var i=r(t,e);return n(i)?i:undefined}},5924:(t,e,i)=>{var n=i(5569)(Object.getPrototypeOf,Object);t.exports=n},9607:(t,e,i)=>{var n=i(2705),r=Object.prototype,a=r.hasOwnProperty,o=r.toString,s=n?n.toStringTag:undefined;t.exports=function(t){var e=a.call(t,s),i=t[s];try{t[s]=undefined;var n=!0}catch(l){}var r=o.call(t);return n&&(e?t[s]=i:delete t[s]),r}},7801:t=>{t.exports=function(t,e){return null==t?undefined:t[e]}},222:(t,e,i)=>{var n=i(1811),r=i(5694),a=i(1469),o=i(5776),s=i(1780),l=i(327);t.exports=function(t,e,i){for(var h=-1,u=(e=n(e,t)).length,c=!1;++h{var n=i(4536);t.exports=function(){this.__data__=n?n(null):{},this.size=0}},401:t=>{t.exports=function(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e}},7667:(t,e,i)=>{var n=i(4536),r=Object.prototype.hasOwnProperty;t.exports=function(t){var e=this.__data__;if(n){var i=e[t];return"__lodash_hash_undefined__"===i?undefined:i}return r.call(e,t)?e[t]:undefined}},1327:(t,e,i)=>{var n=i(4536),r=Object.prototype.hasOwnProperty;t.exports=function(t){var e=this.__data__;return n?e[t]!==undefined:r.call(e,t)}},1866:(t,e,i)=>{var n=i(4536);t.exports=function(t,e){var i=this.__data__;return this.size+=this.has(t)?0:1,i[t]=n&&e===undefined?"__lodash_hash_undefined__":e,this}},8517:(t,e,i)=>{var n=i(3118),r=i(5924),a=i(5726);t.exports=function(t){return"function"!=typeof t.constructor||a(t)?{}:n(r(t))}},5776:t=>{var e=/^(?:0|[1-9]\d*)$/;t.exports=function(t,i){var n=typeof t;return!!(i=null==i?9007199254740991:i)&&("number"==n||"symbol"!=n&&e.test(t))&&t>-1&&t%1==0&&t{var n=i(7813),r=i(8612),a=i(5776),o=i(3218);t.exports=function(t,e,i){if(!o(i))return!1;var s=typeof e;return!!("number"==s?r(i)&&a(e,i.length):"string"==s&&e in i)&&n(i[e],t)}},5403:(t,e,i)=>{var n=i(1469),r=i(3448),a=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,o=/^\w*$/;t.exports=function(t,e){if(n(t))return!1;var i=typeof t;return!("number"!=i&&"symbol"!=i&&"boolean"!=i&&null!=t&&!r(t))||(o.test(t)||!a.test(t)||null!=e&&t in Object(e))}},7019:t=>{t.exports=function(t){var e=typeof t;return"string"==e||"number"==e||"symbol"==e||"boolean"==e?"__proto__"!==t:null===t}},5346:(t,e,i)=>{var n,r=i(4429),a=(n=/[^.]+$/.exec(r&&r.keys&&r.keys.IE_PROTO||""))?"Symbol(src)_1."+n:"";t.exports=function(t){return!!a&&a in t}},5726:t=>{var e=Object.prototype;t.exports=function(t){var i=t&&t.constructor;return t===("function"==typeof i&&i.prototype||e)}},7040:t=>{t.exports=function(){this.__data__=[],this.size=0}},4125:(t,e,i)=>{var n=i(8470),r=Array.prototype.splice;t.exports=function(t){var e=this.__data__,i=n(e,t);return!(i<0)&&(i==e.length-1?e.pop():r.call(e,i,1),--this.size,!0)}},2117:(t,e,i)=>{var n=i(8470);t.exports=function(t){var e=this.__data__,i=n(e,t);return i<0?undefined:e[i][1]}},7518:(t,e,i)=>{var n=i(8470);t.exports=function(t){return n(this.__data__,t)>-1}},4705:(t,e,i)=>{var n=i(8470);t.exports=function(t,e){var i=this.__data__,r=n(i,t);return r<0?(++this.size,i.push([t,e])):i[r][1]=e,this}},4785:(t,e,i)=>{var n=i(1989),r=i(8407),a=i(7071);t.exports=function(){this.size=0,this.__data__={hash:new n,map:new(a||r),string:new n}}},1285:(t,e,i)=>{var n=i(5050);t.exports=function(t){var e=n(this,t)["delete"](t);return this.size-=e?1:0,e}},6e3:(t,e,i)=>{var n=i(5050);t.exports=function(t){return n(this,t).get(t)}},9916:(t,e,i)=>{var n=i(5050);t.exports=function(t){return n(this,t).has(t)}},5265:(t,e,i)=>{var n=i(5050);t.exports=function(t,e){var i=n(this,t),r=i.size;return i.set(t,e),this.size+=i.size==r?0:1,this}},4523:(t,e,i)=>{var n=i(8306);t.exports=function(t){var e=n(t,(function(t){return 500===i.size&&i.clear(),t})),i=e.cache;return e}},4536:(t,e,i)=>{var n=i(852)(Object,"create");t.exports=n},3498:t=>{t.exports=function(t){var e=[];if(null!=t)for(var i in Object(t))e.push(i);return e}},1167:(t,e,i)=>{t=i.nmd(t);var n=i(1957),r=e&&!e.nodeType&&e,a=r&&t&&!t.nodeType&&t,o=a&&a.exports===r&&n.process,s=function(){try{var t=a&&a.require&&a.require("util").types;return t||o&&o.binding&&o.binding("util")}catch(e){}}();t.exports=s},2333:t=>{var e=Object.prototype.toString;t.exports=function(t){return e.call(t)}},5569:t=>{t.exports=function(t,e){return function(i){return t(e(i))}}},5357:(t,e,i)=>{var n=i(6874),r=Math.max;t.exports=function(t,e,i){return e=r(e===undefined?t.length-1:e,0),function(){for(var a=arguments,o=-1,s=r(a.length-e,0),l=Array(s);++o{var n=i(1957),r="object"==typeof self&&self&&self.Object===Object&&self,a=n||r||Function("return this")();t.exports=a},6390:t=>{t.exports=function(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]}},61:(t,e,i)=>{var n=i(6560),r=i(1275)(n);t.exports=r},1275:t=>{var e=Date.now;t.exports=function(t){var i=0,n=0;return function(){var r=e(),a=16-(r-n);if(n=r,a>0){if(++i>=800)return arguments[0]}else i=0;return t.apply(undefined,arguments)}}},7465:(t,e,i)=>{var n=i(8407);t.exports=function(){this.__data__=new n,this.size=0}},3779:t=>{t.exports=function(t){var e=this.__data__,i=e["delete"](t);return this.size=e.size,i}},7599:t=>{t.exports=function(t){return this.__data__.get(t)}},4758:t=>{t.exports=function(t){return this.__data__.has(t)}},4309:(t,e,i)=>{var n=i(8407),r=i(7071),a=i(3369);t.exports=function(t,e){var i=this.__data__;if(i instanceof n){var o=i.__data__;if(!r||o.length<199)return o.push([t,e]),this.size=++i.size,this;i=this.__data__=new a(o)}return i.set(t,e),this.size=i.size,this}},5514:(t,e,i)=>{var n=i(4523),r=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,a=/\\(\\)?/g,o=n((function(t){var e=[];return 46===t.charCodeAt(0)&&e.push(""),t.replace(r,(function(t,i,n,r){e.push(n?r.replace(a,"$1"):i||t)})),e}));t.exports=o},327:(t,e,i)=>{var n=i(3448);t.exports=function(t){if("string"==typeof t||n(t))return t;var e=t+"";return"0"==e&&1/t==-Infinity?"-0":e}},346:t=>{var e=Function.prototype.toString;t.exports=function(t){if(null!=t){try{return e.call(t)}catch(i){}try{return t+""}catch(i){}}return""}},5703:t=>{t.exports=function(t){return function(){return t}}},7813:t=>{t.exports=function(t,e){return t===e||t!=t&&e!=e}},7361:(t,e,i)=>{var n=i(7786);t.exports=function(t,e,i){var r=null==t?undefined:n(t,e);return r===undefined?i:r}},8721:(t,e,i)=>{var n=i(8565),r=i(222);t.exports=function(t,e){return null!=t&&r(t,e,n)}},6557:t=>{t.exports=function(t){return t}},5694:(t,e,i)=>{var n=i(9454),r=i(7005),a=Object.prototype,o=a.hasOwnProperty,s=a.propertyIsEnumerable,l=n(function(){return arguments}())?n:function(t){return r(t)&&o.call(t,"callee")&&!s.call(t,"callee")};t.exports=l},1469:t=>{var e=Array.isArray;t.exports=e},8612:(t,e,i)=>{var n=i(3560),r=i(1780);t.exports=function(t){return null!=t&&r(t.length)&&!n(t)}},9246:(t,e,i)=>{var n=i(8612),r=i(7005);t.exports=function(t){return r(t)&&n(t)}},4144:(t,e,i)=>{t=i.nmd(t);var n=i(5639),r=i(5062),a=e&&!e.nodeType&&e,o=a&&t&&!t.nodeType&&t,s=o&&o.exports===a?n.Buffer:undefined,l=(s?s.isBuffer:undefined)||r;t.exports=l},3560:(t,e,i)=>{var n=i(4239),r=i(3218);t.exports=function(t){if(!r(t))return!1;var e=n(t);return"[object Function]"==e||"[object GeneratorFunction]"==e||"[object AsyncFunction]"==e||"[object Proxy]"==e}},1780:t=>{t.exports=function(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=9007199254740991}},3218:t=>{t.exports=function(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}},7005:t=>{t.exports=function(t){return null!=t&&"object"==typeof t}},8630:(t,e,i)=>{var n=i(4239),r=i(5924),a=i(7005),o=Function.prototype,s=Object.prototype,l=o.toString,h=s.hasOwnProperty,u=l.call(Object);t.exports=function(t){if(!a(t)||"[object Object]"!=n(t))return!1;var e=r(t);if(null===e)return!0;var i=h.call(e,"constructor")&&e.constructor;return"function"==typeof i&&i instanceof i&&l.call(i)==u}},3448:(t,e,i)=>{var n=i(4239),r=i(7005);t.exports=function(t){return"symbol"==typeof t||r(t)&&"[object Symbol]"==n(t)}},6719:(t,e,i)=>{var n=i(8749),r=i(1717),a=i(1167),o=a&&a.isTypedArray,s=o?r(o):n;t.exports=s},1704:(t,e,i)=>{var n=i(4636),r=i(313),a=i(8612);t.exports=function(t){return a(t)?n(t,!0):r(t)}},8306:(t,e,i)=>{var n=i(3369);function r(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)throw new TypeError("Expected a function");var i=function(){var n=arguments,r=e?e.apply(this,n):n[0],a=i.cache;if(a.has(r))return a.get(r);var o=t.apply(this,n);return i.cache=a.set(r,o)||a,o};return i.cache=new(r.Cache||n),i}r.Cache=n,t.exports=r},2492:(t,e,i)=>{var n=i(2980),r=i(1463)((function(t,e,i){n(t,e,i)}));t.exports=r},5062:t=>{t.exports=function(){return!1}},9881:(t,e,i)=>{var n=i(8363),r=i(1704);t.exports=function(t){return n(t,r(t))}},9833:(t,e,i)=>{var n=i(531);t.exports=function(t){return null==t?"":n(t)}},2676:function(t){t.exports=function(){"use strict";function t(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function e(t,e){for(var i=0;ie?1:t0))break;if(null===e.right)break;if(i(t,e.right.key)>0&&(l=e.right,e.right=l.left,l.left=e,null===(e=l).right))break;a.right=e,a=e,e=e.right}}return a.right=e.left,o.left=e.right,e.left=r.right,e.right=r.left,e}function o(t,e,i,r){var o=new n(t,e);if(null===i)return o.left=o.right=null,o;var s=r(t,(i=a(t,i,r)).key);return s<0?(o.left=i.left,o.right=i,i.left=null):s>=0&&(o.right=i.right,o.left=i,i.right=null),o}function s(t,e,i){var n=null,r=null;if(e){var o=i((e=a(t,e,i)).key,t);0===o?(n=e.left,r=e.right):o<0?(r=e.right,e.right=null,n=e):(n=e.left,e.left=null,r=e)}return{left:n,right:r}}function l(t,e,i){return null===e?t:(null===t||((e=a(t.key,e,i)).left=t),e)}function h(t,e,i,n,r){if(t){n(e+(i?"└── ":"├── ")+r(t)+"\n");var a=e+(i?" ":"│ ");t.left&&h(t.left,a,!1,n,r),t.right&&h(t.right,a,!0,n,r)}}var u=function(){function t(t){void 0===t&&(t=r),this._root=null,this._size=0,this._comparator=t}return t.prototype.insert=function(t,e){return this._size++,this._root=o(t,e,this._root,this._comparator)},t.prototype.add=function(t,e){var i=new n(t,e);null===this._root&&(i.left=i.right=null,this._size++,this._root=i);var r=this._comparator,o=a(t,this._root,r),s=r(t,o.key);return 0===s?this._root=o:(s<0?(i.left=o.left,i.right=o,o.left=null):s>0&&(i.right=o.right,i.left=o,o.right=null),this._size++,this._root=i),this._root},t.prototype.remove=function(t){this._root=this._remove(t,this._root,this._comparator)},t.prototype._remove=function(t,e,i){var n;return null===e?null:0===i(t,(e=a(t,e,i)).key)?(null===e.left?n=e.right:(n=a(t,e.left,i)).right=e.right,this._size--,n):e},t.prototype.pop=function(){var t=this._root;if(t){for(;t.left;)t=t.left;return this._root=a(t.key,this._root,this._comparator),this._root=this._remove(t.key,this._root,this._comparator),{key:t.key,data:t.data}}return null},t.prototype.findStatic=function(t){for(var e=this._root,i=this._comparator;e;){var n=i(t,e.key);if(0===n)return e;e=n<0?e.left:e.right}return null},t.prototype.find=function(t){return this._root&&(this._root=a(t,this._root,this._comparator),0!==this._comparator(t,this._root.key))?null:this._root},t.prototype.contains=function(t){for(var e=this._root,i=this._comparator;e;){var n=i(t,e.key);if(0===n)return!0;e=n<0?e.left:e.right}return!1},t.prototype.forEach=function(t,e){for(var i=this._root,n=[],r=!1;!r;)null!==i?(n.push(i),i=i.left):0!==n.length?(i=n.pop(),t.call(e,i),i=i.right):r=!0;return this},t.prototype.range=function(t,e,i,n){for(var r=[],a=this._comparator,o=this._root;0!==r.length||o;)if(o)r.push(o),o=o.left;else{if(a((o=r.pop()).key,e)>0)break;if(a(o.key,t)>=0&&i.call(n,o))return this;o=o.right}return this},t.prototype.keys=function(){var t=[];return this.forEach((function(e){var i=e.key;return t.push(i)})),t},t.prototype.values=function(){var t=[];return this.forEach((function(e){var i=e.data;return t.push(i)})),t},t.prototype.min=function(){return this._root?this.minNode(this._root).key:null},t.prototype.max=function(){return this._root?this.maxNode(this._root).key:null},t.prototype.minNode=function(t){if(void 0===t&&(t=this._root),t)for(;t.left;)t=t.left;return t},t.prototype.maxNode=function(t){if(void 0===t&&(t=this._root),t)for(;t.right;)t=t.right;return t},t.prototype.at=function(t){for(var e=this._root,i=!1,n=0,r=[];!i;)if(e)r.push(e),e=e.left;else if(r.length>0){if(e=r.pop(),n===t)return e;n++,e=e.right}else i=!0;return null},t.prototype.next=function(t){var e=this._root,i=null;if(t.right){for(i=t.right;i.left;)i=i.left;return i}for(var n=this._comparator;e;){var r=n(t.key,e.key);if(0===r)break;r<0?(i=e,e=e.left):e=e.right}return i},t.prototype.prev=function(t){var e=this._root,i=null;if(null!==t.left){for(i=t.left;i.right;)i=i.right;return i}for(var n=this._comparator;e;){var r=n(t.key,e.key);if(0===r)break;r<0?e=e.left:(i=e,e=e.right)}return i},t.prototype.clear=function(){return this._root=null,this._size=0,this},t.prototype.toList=function(){return d(this._root)},t.prototype.load=function(t,e,i){void 0===e&&(e=[]),void 0===i&&(i=!1);var n=t.length,r=this._comparator;if(i&&_(t,e,0,n-1,r),null===this._root)this._root=c(t,e,0,n),this._size=n;else{var a=g(this.toList(),p(t,e),r);n=this._size+n,this._root=f({head:a},0,n)}return this},t.prototype.isEmpty=function(){return null===this._root},Object.defineProperty(t.prototype,"size",{get:function(){return this._size},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"root",{get:function(){return this._root},enumerable:!0,configurable:!0}),t.prototype.toString=function(t){void 0===t&&(t=function(t){return String(t.key)});var e=[];return h(this._root,"",!0,(function(t){return e.push(t)}),t),e.join("")},t.prototype.update=function(t,e,i){var n=this._comparator,r=s(t,this._root,n),a=r.left,h=r.right;n(t,e)<0?h=o(e,i,h,n):a=o(e,i,a,n),this._root=l(a,h,n)},t.prototype.split=function(t){return s(t,this._root,this._comparator)},t}();function c(t,e,i,r){var a=r-i;if(a>0){var o=i+Math.floor(a/2),s=t[o],l=e[o],h=new n(s,l);return h.left=c(t,e,i,o),h.right=c(t,e,o+1,r),h}return null}function p(t,e){for(var i=new n(null,null),r=i,a=0;a0?e=(e=o=o.next=i.pop()).right:r=!0;return o.next=null,a.next}function f(t,e,i){var n=i-e;if(n>0){var r=e+Math.floor(n/2),a=f(t,e,r),o=t.head;return o.left=a,t.head=t.head.next,o.right=f(t,r+1,i),o}return null}function g(t,e,i){for(var r=new n(null,null),a=r,o=t,s=e;null!==o&&null!==s;)i(o.key,s.key)<0?(a.next=o,o=o.next):(a.next=s,s=s.next),a=a.next;return null!==o?a.next=o:null!==s&&(a.next=s),r.next}function _(t,e,i,n,r){if(!(i>=n)){for(var a=t[i+n>>1],o=i-1,s=n+1;;){do{o++}while(r(t[o],a)<0);do{s--}while(r(t[s],a)>0);if(o>=s)break;var l=t[o];t[o]=t[s],t[s]=l,l=e[o],e[o]=e[s],e[s]=l}_(t,e,i,s,r),_(t,e,s+1,n,r)}}var m=function(t,e){return t.ll.x<=e.x&&e.x<=t.ur.x&&t.ll.y<=e.y&&e.y<=t.ur.y},y=function(t,e){if(e.ur.xe.x?1:t.ye.y?1:0}}]),i(e,[{key:"link",value:function(t){if(t.point===this.point)throw new Error("Tried to link already linked events");for(var e=t.point.events,i=0,n=e.length;i=0&&l>=0?oh?-1:0:a<0&&l<0?oh?1:0:la?1:0}}}]),e}(),I=0,A=function(){function e(i,n,r,a){t(this,e),this.id=++I,this.leftSE=i,i.segment=this,i.otherSE=n,this.rightSE=n,n.segment=this,n.otherSE=i,this.rings=r,this.windings=a}return i(e,null,[{key:"compare",value:function(t,e){var i=t.leftSE.point.x,n=e.leftSE.point.x,r=t.rightSE.point.x,a=e.rightSE.point.x;if(ao&&s>l)return-1;var u=t.comparePoint(e.leftSE.point);if(u<0)return 1;if(u>0)return-1;var c=e.comparePoint(t.rightSE.point);return 0!==c?c:-1}if(i>n){if(os&&o>h)return 1;var p=e.comparePoint(t.leftSE.point);if(0!==p)return p;var d=t.comparePoint(e.rightSE.point);return d<0?1:d>0?-1:1}if(os)return 1;if(ra){var g=t.comparePoint(e.rightSE.point);if(g<0)return 1;if(g>0)return-1}if(r!==a){var _=l-o,m=r-i,y=h-s,v=a-n;if(_>m&&yv)return-1}return r>a?1:rh?1:t.ide.id?1:0}}]),i(e,[{key:"replaceRightSE",value:function(t){this.rightSE=t,this.rightSE.segment=this,this.rightSE.otherSE=this.leftSE,this.leftSE.otherSE=this.rightSE}},{key:"bbox",value:function(){var t=this.leftSE.point.y,e=this.rightSE.point.y;return{ll:{x:this.leftSE.point.x,y:te?t:e}}}},{key:"vector",value:function(){return{x:this.rightSE.point.x-this.leftSE.point.x,y:this.rightSE.point.y-this.leftSE.point.y}}},{key:"isAnEndpoint",value:function(t){return t.x===this.leftSE.point.x&&t.y===this.leftSE.point.y||t.x===this.rightSE.point.x&&t.y===this.rightSE.point.y}},{key:"comparePoint",value:function(t){if(this.isAnEndpoint(t))return 0;var e=this.leftSE.point,i=this.rightSE.point,n=this.vector();if(e.x===i.x)return t.x===e.x?0:t.x0&&s.swapEvents(),T.comparePoints(this.leftSE.point,this.rightSE.point)>0&&this.swapEvents(),n&&(r.checkForConsuming(),a.checkForConsuming()),i}},{key:"swapEvents",value:function(){var t=this.rightSE;this.rightSE=this.leftSE,this.leftSE=t,this.leftSE.isLeft=!0,this.rightSE.isLeft=!1;for(var e=0,i=this.windings.length;e0){var a=i;i=n,n=a}if(i.prev===n){var o=i;i=n,n=o}for(var s=0,l=n.rings.length;s0))throw new Error("Tried to create degenerate segment at [".concat(t.x,", ").concat(t.y,"]"));r=i,a=t,o=-1}return new e(new T(r,!0),new T(a,!1),[n],[o])}}]),e}(),j=function(){function e(i,n,r){if(t(this,e),!Array.isArray(i)||0===i.length)throw new Error("Input geometry is not a valid Polygon or MultiPolygon");if(this.poly=n,this.isExterior=r,this.segments=[],"number"!=typeof i[0][0]||"number"!=typeof i[0][1])throw new Error("Input geometry is not a valid Polygon or MultiPolygon");var a=x.round(i[0][0],i[0][1]);this.bbox={ll:{x:a.x,y:a.y},ur:{x:a.x,y:a.y}};for(var o=a,s=1,l=i.length;sthis.bbox.ur.x&&(this.bbox.ur.x=h.x),h.y>this.bbox.ur.y&&(this.bbox.ur.y=h.y),o=h)}a.x===o.x&&a.y===o.y||this.segments.push(A.fromRing(o,a,this))}return i(e,[{key:"getSweepEvents",value:function(){for(var t=[],e=0,i=this.segments.length;ethis.bbox.ur.x&&(this.bbox.ur.x=o.bbox.ur.x),o.bbox.ur.y>this.bbox.ur.y&&(this.bbox.ur.y=o.bbox.ur.y),this.interiorRings.push(o)}this.multiPoly=n}return i(e,[{key:"getSweepEvents",value:function(){for(var t=this.exteriorRing.getSweepEvents(),e=0,i=this.interiorRings.length;ethis.bbox.ur.x&&(this.bbox.ur.x=o.bbox.ur.x),o.bbox.ur.y>this.bbox.ur.y&&(this.bbox.ur.y=o.bbox.ur.y),this.polys.push(o)}this.isSubject=n}return i(e,[{key:"getSweepEvents",value:function(){for(var t=[],e=0,i=this.polys.length;e0&&(t=n)}for(var r=t.segment.prevInResult(),a=r?r.prevInResult():null;;){if(!r)return null;if(!a)return r.ringOut;if(a.ringOut!==r.ringOut)return a.ringOut.enclosingRing()!==r.ringOut?r.ringOut:r.ringOut.enclosingRing();r=a.prevInResult(),a=r?r.prevInResult():null}}}]),e}(),F=function(){function e(i){t(this,e),this.exteriorRing=i,i.poly=this,this.interiorRings=[]}return i(e,[{key:"addInterior",value:function(t){this.interiorRings.push(t),t.poly=this}},{key:"getGeom",value:function(){var t=[this.exteriorRing.getGeom()];if(null===t[0])return null;for(var e=0,i=this.interiorRings.length;e1&&arguments[1]!==undefined?arguments[1]:A.compare;t(this,e),this.queue=i,this.tree=new u(n),this.segments=[]}return i(e,[{key:"process",value:function(t){var e=t.segment,i=[];if(t.consumedBy)return t.isLeft?this.queue.remove(t.otherSE):this.tree.remove(e),i;var n=t.isLeft?this.tree.insert(e):this.tree.find(e);if(!n)throw new Error("Unable to find segment #".concat(e.id," ")+"[".concat(e.leftSE.point.x,", ").concat(e.leftSE.point.y,"] -> ")+"[".concat(e.rightSE.point.x,", ").concat(e.rightSE.point.y,"] ")+"in SweepLine tree. Please submit a bug report.");for(var r=n,a=n,o=undefined,s=undefined;o===undefined;)null===(r=this.tree.prev(r))?o=null:r.key.consumedBy===undefined&&(o=r.key);for(;s===undefined;)null===(a=this.tree.next(a))?s=null:a.key.consumedBy===undefined&&(s=a.key);if(t.isLeft){var l=null;if(o){var h=o.getIntersection(e);if(null!==h&&(e.isAnEndpoint(h)||(l=h),!o.isAnEndpoint(h)))for(var u=this._splitSafely(o,h),c=0,p=u.length;c0?(this.tree.remove(e),i.push(t)):(this.segments.push(e),e.prev=o)}else{if(o&&s){var k=o.getIntersection(s);if(null!==k){if(!o.isAnEndpoint(k))for(var M=this._splitSafely(o,k),x=0,w=M.length;xK)throw new Error("Infinite loop when putting segment endpoints in a priority queue (queue size too big). Please file a bug report.");for(var L=new V(f),k=f.size,M=f.pop();M;){var w=M.key;if(f.size===k){var C=w.segment;throw new Error("Unable to pop() ".concat(w.isLeft?"left":"right"," SweepEvent ")+"[".concat(w.point.x,", ").concat(w.point.y,"] from segment #").concat(C.id," ")+"[".concat(C.leftSE.point.x,", ").concat(C.leftSE.point.y,"] -> ")+"[".concat(C.rightSE.point.x,", ").concat(C.rightSE.point.y,"] from queue. ")+"Please file a bug report.")}if(f.size>K)throw new Error("Infinite loop when passing sweep line over endpoints (queue size too big). Please file a bug report.");if(L.segments.length>q)throw new Error("Infinite loop when passing sweep line over endpoints (too many sweep line segments). Please file a bug report.");for(var P=L.process(w),E=0,S=P.length;E1?e-1:0),n=1;n1?e-1:0),n=1;n1?e-1:0),n=1;n1?e-1:0),n=1;nn;){if(r-n>600){var o=r-n+1,l=i-n+1,h=Math.log(o),u=.5*Math.exp(2*h/3),c=.5*Math.sqrt(h*u*(o-u)/o)*(l-o/2<0?-1:1);s(t,i,Math.max(n,Math.floor(i-l*u/o+c)),Math.min(r,Math.floor(i+(o-l)*u/o+c)),a)}var p=t[i],d=n,f=r;for(e(t,n,i),a(t[r],p)>0&&e(t,n,r);d0;)f--}0===a(t[n],p)?e(t,n,f):e(t,++f,r),f<=i&&(n=f+1),i<=f&&(r=f-1)}}(t,n,r||0,a||t.length-1,o||i)}function e(t,e,i){var n=t[e];t[e]=t[i],t[i]=n}function i(t,e){return te?1:0}var n=function(t){void 0===t&&(t=9),this._maxEntries=Math.max(4,t),this._minEntries=Math.max(2,Math.ceil(.4*this._maxEntries)),this.clear()};function r(t,e,i){if(!i)return e.indexOf(t);for(var n=0;n=t.minX&&e.maxY>=t.minY}function f(t){return{children:t,height:1,leaf:!0,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0}}function g(e,i,n,r,a){for(var o=[i,n];o.length;)if(!((n=o.pop())-(i=o.pop())<=r)){var s=i+Math.ceil((n-i)/r/2)*r;t(e,s,i,n,a),o.push(i,s,s,n)}}return n.prototype.all=function(){return this._all(this.data,[])},n.prototype.search=function(t){var e=this.data,i=[];if(!d(t,e))return i;for(var n=this.toBBox,r=[];e;){for(var a=0;a=0&&r[e].children.length>this._maxEntries;)this._split(r,e),e--;this._adjustParentBBoxes(n,r,e)},n.prototype._split=function(t,e){var i=t[e],n=i.children.length,r=this._minEntries;this._chooseSplitAxis(i,r,n);var o=this._chooseSplitIndex(i,r,n),s=f(i.children.splice(o,i.children.length-o));s.height=i.height,s.leaf=i.leaf,a(i,this.toBBox),a(s,this.toBBox),e?t[e-1].children.push(s):this._splitRoot(i,s)},n.prototype._splitRoot=function(t,e){this.data=f([t,e]),this.data.height=t.height+1,this.data.leaf=!1,a(this.data,this.toBBox)},n.prototype._chooseSplitIndex=function(t,e,i){for(var n,r,a,s,l,h,c,p=1/0,d=1/0,f=e;f<=i-e;f++){var g=o(t,0,f,this.toBBox),_=o(t,f,i,this.toBBox),m=(r=g,a=_,s=void 0,l=void 0,h=void 0,c=void 0,s=Math.max(r.minX,a.minX),l=Math.max(r.minY,a.minY),h=Math.min(r.maxX,a.maxX),c=Math.min(r.maxY,a.maxY),Math.max(0,h-s)*Math.max(0,c-l)),y=u(g)+u(_);m=e;d--){var f=t.children[d];s(l,t.leaf?r(f):f),h+=c(l)}return h},n.prototype._adjustParentBBoxes=function(t,e,i){for(var n=i;n>=0;n--)s(e[n],t)},n.prototype._condense=function(t){for(var e=t.length-1,i=void 0;e>=0;e--)0===t[e].children.length?e>0?(i=t[e-1].children).splice(i.indexOf(t[e]),1):this.clear():a(t[e],this.toBBox)},n}()}},e={};function i(n){var r=e[n];if(r!==undefined)return r.exports;var a=e[n]={id:n,loaded:!1,exports:{}};return t[n].call(a.exports,a,a.exports,i),a.loaded=!0,a.exports}i.n=t=>{var e=t&&t.__esModule?()=>t["default"]:()=>t;return i.d(e,{a:e}),e},i.d=(t,e)=>{for(var n in e)i.o(e,n)&&!i.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),i.nmd=t=>(t.paths=[],t.children||(t.children=[]),t),(()=>{"use strict";i(7107);var t=i(2492),e=i.n(t);const n=JSON.parse('{"tooltips":{"placeMarker":"Click to place marker","firstVertex":"Click to place first vertex","continueLine":"Click to continue drawing","finishLine":"Click any existing marker to finish","finishPoly":"Click first marker to finish","finishRect":"Click to finish","startCircle":"Click to place circle center","finishCircle":"Click to finish circle","placeCircleMarker":"Click to place circle marker","placeText":"Click to place text"},"actions":{"finish":"Finish","cancel":"Cancel","removeLastVertex":"Remove Last Vertex"},"buttonTitles":{"drawMarkerButton":"Draw Marker","drawPolyButton":"Draw Polygons","drawLineButton":"Draw Polyline","drawCircleButton":"Draw Circle","drawRectButton":"Draw Rectangle","editButton":"Edit Layers","dragButton":"Drag Layers","cutButton":"Cut Layers","deleteButton":"Remove Layers","drawCircleMarkerButton":"Draw Circle Marker","snappingButton":"Snap dragged marker to other layers and vertices","pinningButton":"Pin shared vertices together","rotateButton":"Rotate Layers","drawTextButton":"Draw Text","scaleButton":"Scale Layers","autoTracingButton":"Auto trace Line"},"measurements":{"totalLength":"Length","segmentLength":"Segment length","area":"Area","radius":"Radius","perimeter":"Perimeter","height":"Height","width":"Width","coordinates":"Position","coordinatesMarker":"Position Marker"}}'),r=JSON.parse('{"tooltips":{"placeMarker":"Platziere den Marker mit Klick","firstVertex":"Platziere den ersten Marker mit Klick","continueLine":"Klicke, um weiter zu zeichnen","finishLine":"Beende mit Klick auf existierenden Marker","finishPoly":"Beende mit Klick auf ersten Marker","finishRect":"Beende mit Klick","startCircle":"Platziere das Kreiszentrum mit Klick","finishCircle":"Beende den Kreis mit Klick","placeCircleMarker":"Platziere den Kreismarker mit Klick","placeText":"Platziere den Text mit Klick"},"actions":{"finish":"Beenden","cancel":"Abbrechen","removeLastVertex":"Letzten Vertex löschen"},"buttonTitles":{"drawMarkerButton":"Marker zeichnen","drawPolyButton":"Polygon zeichnen","drawLineButton":"Polyline zeichnen","drawCircleButton":"Kreis zeichnen","drawRectButton":"Rechteck zeichnen","editButton":"Layer editieren","dragButton":"Layer bewegen","cutButton":"Layer schneiden","deleteButton":"Layer löschen","drawCircleMarkerButton":"Kreismarker zeichnen","snappingButton":"Bewegter Layer an andere Layer oder Vertexe einhacken","pinningButton":"Vertexe an der gleichen Position verknüpfen","rotateButton":"Layer drehen","drawTextButton":"Text zeichnen","scaleButton":"Layer skalieren","autoTracingButton":"Linie automatisch nachzeichen"},"measurements":{"totalLength":"Länge","segmentLength":"Segment Länge","area":"Fläche","radius":"Radius","perimeter":"Umfang","height":"Höhe","width":"Breite","coordinates":"Position","coordinatesMarker":"Position Marker"}}'),a=JSON.parse('{"tooltips":{"placeMarker":"Clicca per posizionare un Marker","firstVertex":"Clicca per posizionare il primo vertice","continueLine":"Clicca per continuare a disegnare","finishLine":"Clicca qualsiasi marker esistente per terminare","finishPoly":"Clicca il primo marker per terminare","finishRect":"Clicca per terminare","startCircle":"Clicca per posizionare il punto centrale del cerchio","finishCircle":"Clicca per terminare il cerchio","placeCircleMarker":"Clicca per posizionare un Marker del cherchio"},"actions":{"finish":"Termina","cancel":"Annulla","removeLastVertex":"Rimuovi l\'ultimo vertice"},"buttonTitles":{"drawMarkerButton":"Disegna Marker","drawPolyButton":"Disegna Poligoni","drawLineButton":"Disegna Polilinea","drawCircleButton":"Disegna Cerchio","drawRectButton":"Disegna Rettangolo","editButton":"Modifica Livelli","dragButton":"Sposta Livelli","cutButton":"Ritaglia Livelli","deleteButton":"Elimina Livelli","drawCircleMarkerButton":"Disegna Marker del Cerchio","snappingButton":"Snap ha trascinato il pennarello su altri strati e vertici","pinningButton":"Pin condiviso vertici insieme"}}'),o=JSON.parse('{"tooltips":{"placeMarker":"Klik untuk menempatkan marker","firstVertex":"Klik untuk menempatkan vertex pertama","continueLine":"Klik untuk meneruskan digitasi","finishLine":"Klik pada sembarang marker yang ada untuk mengakhiri","finishPoly":"Klik marker pertama untuk mengakhiri","finishRect":"Klik untuk mengakhiri","startCircle":"Klik untuk menempatkan titik pusat lingkaran","finishCircle":"Klik untuk mengakhiri lingkaran","placeCircleMarker":"Klik untuk menempatkan penanda lingkarann"},"actions":{"finish":"Selesai","cancel":"Batal","removeLastVertex":"Hilangkan Vertex Terakhir"},"buttonTitles":{"drawMarkerButton":"Digitasi Marker","drawPolyButton":"Digitasi Polygon","drawLineButton":"Digitasi Polyline","drawCircleButton":"Digitasi Lingkaran","drawRectButton":"Digitasi Segi Empat","editButton":"Edit Layer","dragButton":"Geser Layer","cutButton":"Potong Layer","deleteButton":"Hilangkan Layer","drawCircleMarkerButton":"Digitasi Penanda Lingkaran","snappingButton":"Jepretkan penanda yang ditarik ke lapisan dan simpul lain","pinningButton":"Sematkan simpul bersama bersama"}}'),s=JSON.parse('{"tooltips":{"placeMarker":"Adaugă un punct","firstVertex":"Apasă aici pentru a adăuga primul Vertex","continueLine":"Apasă aici pentru a continua desenul","finishLine":"Apasă pe orice obiect pentru a finisa desenul","finishPoly":"Apasă pe primul obiect pentru a finisa","finishRect":"Apasă pentru a finisa","startCircle":"Apasă pentru a desena un cerc","finishCircle":"Apasă pentru a finisa un cerc","placeCircleMarker":"Adaugă un punct"},"actions":{"finish":"Termină","cancel":"Anulează","removeLastVertex":"Șterge ultimul Vertex"},"buttonTitles":{"drawMarkerButton":"Adaugă o bulină","drawPolyButton":"Desenează un poligon","drawLineButton":"Desenează o linie","drawCircleButton":"Desenează un cerc","drawRectButton":"Desenează un dreptunghi","editButton":"Editează straturile","dragButton":"Mută straturile","cutButton":"Taie straturile","deleteButton":"Șterge straturile","drawCircleMarkerButton":"Desenează marcatorul cercului","snappingButton":"Fixați marcatorul glisat pe alte straturi și vârfuri","pinningButton":"Fixați vârfurile partajate împreună"}}'),l=JSON.parse('{"tooltips":{"placeMarker":"Нажмите, чтобы нанести маркер","firstVertex":"Нажмите, чтобы нанести первый объект","continueLine":"Нажмите, чтобы продолжить рисование","finishLine":"Нажмите любой существующий маркер для завершения","finishPoly":"Выберите первую точку, чтобы закончить","finishRect":"Нажмите, чтобы закончить","startCircle":"Нажмите, чтобы добавить центр круга","finishCircle":"Нажмите, чтобы задать радиус","placeCircleMarker":"Нажмите, чтобы нанести круговой маркер"},"actions":{"finish":"Завершить","cancel":"Отменить","removeLastVertex":"Отменить последнее действие"},"buttonTitles":{"drawMarkerButton":"Добавить маркер","drawPolyButton":"Рисовать полигон","drawLineButton":"Рисовать кривую","drawCircleButton":"Рисовать круг","drawRectButton":"Рисовать прямоугольник","editButton":"Редактировать слой","dragButton":"Перенести слой","cutButton":"Вырезать слой","deleteButton":"Удалить слой","drawCircleMarkerButton":"Добавить круговой маркер","snappingButton":"Привязать перетаскиваемый маркер к другим слоям и вершинам","pinningButton":"Связать общие точки вместе"}}'),h=JSON.parse('{"tooltips":{"placeMarker":"Presiona para colocar un marcador","firstVertex":"Presiona para colocar el primer vértice","continueLine":"Presiona para continuar dibujando","finishLine":"Presiona cualquier marcador existente para finalizar","finishPoly":"Presiona el primer marcador para finalizar","finishRect":"Presiona para finalizar","startCircle":"Presiona para colocar el centro del círculo","finishCircle":"Presiona para finalizar el círculo","placeCircleMarker":"Presiona para colocar un marcador de círculo"},"actions":{"finish":"Finalizar","cancel":"Cancelar","removeLastVertex":"Eliminar último vértice"},"buttonTitles":{"drawMarkerButton":"Dibujar Marcador","drawPolyButton":"Dibujar Polígono","drawLineButton":"Dibujar Línea","drawCircleButton":"Dibujar Círculo","drawRectButton":"Dibujar Rectángulo","editButton":"Editar Capas","dragButton":"Arrastrar Capas","cutButton":"Cortar Capas","deleteButton":"Eliminar Capas","drawCircleMarkerButton":"Dibujar Marcador de Círculo","snappingButton":"El marcador de Snap arrastrado a otras capas y vértices","pinningButton":"Fijar juntos los vértices compartidos"}}'),u=JSON.parse('{"tooltips":{"placeMarker":"Klik om een marker te plaatsen","firstVertex":"Klik om het eerste punt te plaatsen","continueLine":"Klik om te blijven tekenen","finishLine":"Klik op een bestaand punt om te beëindigen","finishPoly":"Klik op het eerst punt om te beëindigen","finishRect":"Klik om te beëindigen","startCircle":"Klik om het middelpunt te plaatsen","finishCircle":"Klik om de cirkel te beëindigen","placeCircleMarker":"Klik om een marker te plaatsen"},"actions":{"finish":"Bewaar","cancel":"Annuleer","removeLastVertex":"Verwijder laatste punt"},"buttonTitles":{"drawMarkerButton":"Plaats Marker","drawPolyButton":"Teken een vlak","drawLineButton":"Teken een lijn","drawCircleButton":"Teken een cirkel","drawRectButton":"Teken een vierkant","editButton":"Bewerk","dragButton":"Verplaats","cutButton":"Knip","deleteButton":"Verwijder","drawCircleMarkerButton":"Plaats Marker","snappingButton":"Snap gesleepte marker naar andere lagen en hoekpunten","pinningButton":"Speld gedeelde hoekpunten samen"}}'),c=JSON.parse('{"tooltips":{"placeMarker":"Cliquez pour placer un marqueur","firstVertex":"Cliquez pour placer le premier sommet","continueLine":"Cliquez pour continuer à dessiner","finishLine":"Cliquez sur n\'importe quel marqueur pour terminer","finishPoly":"Cliquez sur le premier marqueur pour terminer","finishRect":"Cliquez pour terminer","startCircle":"Cliquez pour placer le centre du cercle","finishCircle":"Cliquez pour finir le cercle","placeCircleMarker":"Cliquez pour placer le marqueur circulaire"},"actions":{"finish":"Terminer","cancel":"Annuler","removeLastVertex":"Retirer le dernier sommet"},"buttonTitles":{"drawMarkerButton":"Placer des marqueurs","drawPolyButton":"Dessiner des polygones","drawLineButton":"Dessiner des polylignes","drawCircleButton":"Dessiner un cercle","drawRectButton":"Dessiner un rectangle","editButton":"Éditer des calques","dragButton":"Déplacer des calques","cutButton":"Couper des calques","deleteButton":"Supprimer des calques","drawCircleMarkerButton":"Dessiner un marqueur circulaire","snappingButton":"Glisser le marqueur vers d\'autres couches et sommets","pinningButton":"Épingler ensemble les sommets partagés","rotateButton":"Tourner des calques"}}'),p=JSON.parse('{"tooltips":{"placeMarker":"单击放置标记","firstVertex":"单击放置首个顶点","continueLine":"单击继续绘制","finishLine":"单击任何存在的标记以完成","finishPoly":"单击第一个标记以完成","finishRect":"单击完成","startCircle":"单击放置圆心","finishCircle":"单击完成圆形","placeCircleMarker":"点击放置圆形标记"},"actions":{"finish":"完成","cancel":"取消","removeLastVertex":"移除最后的顶点"},"buttonTitles":{"drawMarkerButton":"绘制标记","drawPolyButton":"绘制多边形","drawLineButton":"绘制线段","drawCircleButton":"绘制圆形","drawRectButton":"绘制长方形","editButton":"编辑图层","dragButton":"拖拽图层","cutButton":"剪切图层","deleteButton":"删除图层","drawCircleMarkerButton":"画圆圈标记","snappingButton":"将拖动的标记捕捉到其他图层和顶点","pinningButton":"将共享顶点固定在一起"}}'),d=JSON.parse('{"tooltips":{"placeMarker":"單擊放置標記","firstVertex":"單擊放置第一個頂點","continueLine":"單擊繼續繪製","finishLine":"單擊任何存在的標記以完成","finishPoly":"單擊第一個標記以完成","finishRect":"單擊完成","startCircle":"單擊放置圓心","finishCircle":"單擊完成圓形","placeCircleMarker":"點擊放置圓形標記"},"actions":{"finish":"完成","cancel":"取消","removeLastVertex":"移除最後一個頂點"},"buttonTitles":{"drawMarkerButton":"放置標記","drawPolyButton":"繪製多邊形","drawLineButton":"繪製線段","drawCircleButton":"繪製圓形","drawRectButton":"繪製方形","editButton":"編輯圖形","dragButton":"移動圖形","cutButton":"裁切圖形","deleteButton":"刪除圖形","drawCircleMarkerButton":"畫圓圈標記","snappingButton":"將拖動的標記對齊到其他圖層和頂點","pinningButton":"將共享頂點固定在一起"}}'),f={en:n,de:r,it:a,id:o,ro:s,ru:l,es:h,nl:u,fr:c,pt_br:JSON.parse('{"tooltips":{"placeMarker":"Clique para posicionar o marcador","firstVertex":"Clique para posicionar o primeiro vértice","continueLine":"Clique para continuar desenhando","finishLine":"Clique em qualquer marcador existente para finalizar","finishPoly":"Clique no primeiro ponto para fechar o polígono","finishRect":"Clique para finalizar","startCircle":"Clique para posicionar o centro do círculo","finishCircle":"Clique para fechar o círculo","placeCircleMarker":"Clique para posicionar o marcador circular"},"actions":{"finish":"Finalizar","cancel":"Cancelar","removeLastVertex":"Remover último vértice"},"buttonTitles":{"drawMarkerButton":"Desenhar um marcador","drawPolyButton":"Desenhar um polígono","drawLineButton":"Desenhar uma polilinha","drawCircleButton":"Desenhar um círculo","drawRectButton":"Desenhar um retângulo","editButton":"Editar camada(s)","dragButton":"Mover camada(s)","cutButton":"Recortar camada(s)","deleteButton":"Remover camada(s)","drawCircleMarkerButton":"Marcador de círculos de desenho","snappingButton":"Marcador arrastado para outras camadas e vértices","pinningButton":"Vértices compartilhados de pinos juntos"}}'),zh:p,zh_tw:d,pl:JSON.parse('{"tooltips":{"placeMarker":"Kliknij, aby umieścić znacznik","firstVertex":"Kliknij, aby umieścić pierwszy wierzchołek","continueLine":"Kliknij, aby kontynuować rysowanie","finishLine":"Kliknij dowolny istniejący znacznik, aby zakończyć","finishPoly":"Kliknij pierwszy znacznik, aby zakończyć","finishRect":"Kliknij, aby zakończyć","startCircle":"Kliknij, aby umieścić środek okręgu","finishCircle":"Kliknij, aby zakończyć okrąg","placeCircleMarker":"Kliknij, aby umieścić znacznik okręgu","placeText":"Kliknij, aby umieścić tekst"},"actions":{"finish":"Zakończ","cancel":"Anuluj","removeLastVertex":"Usuń ostatni wierzchołek"},"buttonTitles":{"drawMarkerButton":"Rysuj znacznik","drawPolyButton":"Rysuj wielokąt","drawLineButton":"Rysuj linię","drawCircleButton":"Rysuj okrąg","drawRectButton":"Rysuj prostokąt","editButton":"Edytuj warstwy","dragButton":"Przeciągnij warstwy","cutButton":"Wytnij warstwy","deleteButton":"Usuń warstwy","drawCircleMarkerButton":"Rysuj znacznik okrągły","snappingButton":"Przyciągnij przenoszony znacznik do innych warstw i wierzchołków","pinningButton":"Przypnij wspólne wierzchołki razem","rotateButton":"Obróć warstwy","drawTextButton":"Rysuj tekst","scaleButton":"Skaluj warstwy","autoTracingButton":"Automatyczne śledzenie linii"},"measurements":{"totalLength":"Długość","segmentLength":"Długość odcinka","area":"Obszar","radius":"Promień","perimeter":"Obwód","height":"Wysokość","width":"Szerokość","coordinates":"Pozycja","coordinatesMarker":"Znacznik pozycji"}}'),sv:JSON.parse('{"tooltips":{"placeMarker":"Klicka för att placera markör","firstVertex":"Klicka för att placera första hörnet","continueLine":"Klicka för att fortsätta rita","finishLine":"Klicka på en existerande punkt för att slutföra","finishPoly":"Klicka på den första punkten för att slutföra","finishRect":"Klicka för att slutföra","startCircle":"Klicka för att placera cirkelns centrum","finishCircle":"Klicka för att slutföra cirkeln","placeCircleMarker":"Klicka för att placera cirkelmarkör"},"actions":{"finish":"Slutför","cancel":"Avbryt","removeLastVertex":"Ta bort sista hörnet"},"buttonTitles":{"drawMarkerButton":"Rita Markör","drawPolyButton":"Rita Polygoner","drawLineButton":"Rita Linje","drawCircleButton":"Rita Cirkel","drawRectButton":"Rita Rektangel","editButton":"Redigera Lager","dragButton":"Dra Lager","cutButton":"Klipp i Lager","deleteButton":"Ta bort Lager","drawCircleMarkerButton":"Rita Cirkelmarkör","snappingButton":"Snäpp dra markören till andra lager och hörn","pinningButton":"Fäst delade hörn tillsammans"}}'),el:JSON.parse('{"tooltips":{"placeMarker":"Κάντε κλικ για να τοποθετήσετε Δείκτη","firstVertex":"Κάντε κλικ για να τοποθετήσετε το πρώτο σημείο","continueLine":"Κάντε κλικ για να συνεχίσετε να σχεδιάζετε","finishLine":"Κάντε κλικ σε οποιονδήποτε υπάρχον σημείο για να ολοκληρωθεί","finishPoly":"Κάντε κλικ στο πρώτο σημείο για να τελειώσετε","finishRect":"Κάντε κλικ για να τελειώσετε","startCircle":"Κάντε κλικ για να τοποθετήσετε κέντρο Κύκλου","finishCircle":"Κάντε κλικ για να ολοκληρώσετε τον Κύκλο","placeCircleMarker":"Κάντε κλικ για να τοποθετήσετε Κυκλικό Δείκτη"},"actions":{"finish":"Τέλος","cancel":"Ακύρωση","removeLastVertex":"Κατάργηση τελευταίου σημείου"},"buttonTitles":{"drawMarkerButton":"Σχεδίαση Δείκτη","drawPolyButton":"Σχεδίαση Πολυγώνου","drawLineButton":"Σχεδίαση Γραμμής","drawCircleButton":"Σχεδίαση Κύκλου","drawRectButton":"Σχεδίαση Ορθογωνίου","editButton":"Επεξεργασία Επιπέδων","dragButton":"Μεταφορά Επιπέδων","cutButton":"Αποκοπή Επιπέδων","deleteButton":"Κατάργηση Επιπέδων","drawCircleMarkerButton":"Σχεδίαση Κυκλικού Δείκτη","snappingButton":"Προσκόλληση του Δείκτη μεταφοράς σε άλλα Επίπεδα και Κορυφές","pinningButton":"Περικοπή κοινών κορυφών μαζί"}}'),hu:JSON.parse('{"tooltips":{"placeMarker":"Kattintson a jelölő elhelyezéséhez","firstVertex":"Kattintson az első pont elhelyezéséhez","continueLine":"Kattintson a következő pont elhelyezéséhez","finishLine":"A befejezéshez kattintson egy meglévő pontra","finishPoly":"A befejezéshez kattintson az első pontra","finishRect":"Kattintson a befejezéshez","startCircle":"Kattintson a kör középpontjának elhelyezéséhez","finishCircle":"Kattintson a kör befejezéséhez","placeCircleMarker":"Kattintson a körjelölő elhelyezéséhez"},"actions":{"finish":"Befejezés","cancel":"Mégse","removeLastVertex":"Utolsó pont eltávolítása"},"buttonTitles":{"drawMarkerButton":"Jelölő rajzolása","drawPolyButton":"Poligon rajzolása","drawLineButton":"Vonal rajzolása","drawCircleButton":"Kör rajzolása","drawRectButton":"Négyzet rajzolása","editButton":"Elemek szerkesztése","dragButton":"Elemek mozgatása","cutButton":"Elemek vágása","deleteButton":"Elemek törlése","drawCircleMarkerButton":"Kör jelölő rajzolása","snappingButton":"Kapcsolja a jelöltőt másik elemhez vagy ponthoz","pinningButton":"Közös pontok összekötése"}}'),da:JSON.parse('{"tooltips":{"placeMarker":"Tryk for at placere en markør","firstVertex":"Tryk for at placere det første punkt","continueLine":"Tryk for at fortsætte linjen","finishLine":"Tryk på et eksisterende punkt for at afslutte","finishPoly":"Tryk på det første punkt for at afslutte","finishRect":"Tryk for at afslutte","startCircle":"Tryk for at placere cirklens center","finishCircle":"Tryk for at afslutte cirklen","placeCircleMarker":"Tryk for at placere en cirkelmarkør"},"actions":{"finish":"Afslut","cancel":"Afbryd","removeLastVertex":"Fjern sidste punkt"},"buttonTitles":{"drawMarkerButton":"Placer markør","drawPolyButton":"Tegn polygon","drawLineButton":"Tegn linje","drawCircleButton":"Tegn cirkel","drawRectButton":"Tegn firkant","editButton":"Rediger","dragButton":"Træk","cutButton":"Klip","deleteButton":"Fjern","drawCircleMarkerButton":"Tegn cirkelmarkør","snappingButton":"Fastgør trukket markør til andre elementer","pinningButton":"Sammenlæg delte elementer"}}'),no:JSON.parse('{"tooltips":{"placeMarker":"Klikk for å plassere punkt","firstVertex":"Klikk for å plassere første punkt","continueLine":"Klikk for å tegne videre","finishLine":"Klikk på et eksisterende punkt for å fullføre","finishPoly":"Klikk første punkt for å fullføre","finishRect":"Klikk for å fullføre","startCircle":"Klikk for å sette sirkel midtpunkt","finishCircle":"Klikk for å fullføre sirkel","placeCircleMarker":"Klikk for å plassere sirkel","placeText":"Klikk for å plassere tekst"},"actions":{"finish":"Fullfør","cancel":"Kanseller","removeLastVertex":"Fjern forrige punkt"},"buttonTitles":{"drawMarkerButton":"Tegn punkt","drawPolyButton":"Tegn flate","drawLineButton":"Tegn linje","drawCircleButton":"Tegn sirkel","drawRectButton":"Tegn rektangel","editButton":"Rediger objekter","dragButton":"Dra objekter","cutButton":"Kutt objekter","deleteButton":"Fjern objekter","drawCircleMarkerButton":"Tegn sirkel-punkt","snappingButton":"Fest dratt punkt til andre objekter og punkt","pinningButton":"Pin delte punkter sammen","rotateButton":"Rotér objekter","drawTextButton":"Tegn tekst","scaleButton":"Skalér objekter","autoTracingButton":"Automatisk sporing av linje"},"measurements":{"totalLength":"Lengde","segmentLength":"Segmentlengde","area":"Område","radius":"Radius","perimeter":"Omriss","height":"Høyde","width":"Bredde","coordinates":"Posisjon","coordinatesMarker":"Posisjonsmarkør"}}'),fa:JSON.parse('{"tooltips":{"placeMarker":"کلیک برای جانمایی نشان","firstVertex":"کلیک برای رسم اولین رأس","continueLine":"کلیک برای ادامه رسم","finishLine":"کلیک روی هر نشان موجود برای پایان","finishPoly":"کلیک روی اولین نشان برای پایان","finishRect":"کلیک برای پایان","startCircle":"کلیک برای رسم مرکز دایره","finishCircle":"کلیک برای پایان رسم دایره","placeCircleMarker":"کلیک برای رسم نشان دایره","placeText":"کلیک برای نوشتن متن"},"actions":{"finish":"پایان","cancel":"لفو","removeLastVertex":"حذف آخرین رأس"},"buttonTitles":{"drawMarkerButton":"درج نشان","drawPolyButton":"رسم چندضلعی","drawLineButton":"رسم خط","drawCircleButton":"رسم دایره","drawRectButton":"رسم چهارضلعی","editButton":"ویرایش لایه‌ها","dragButton":"جابجایی لایه‌ها","cutButton":"برش لایه‌ها","deleteButton":"حذف لایه‌ها","drawCircleMarkerButton":"رسم نشان دایره","snappingButton":"نشانگر را به لایه‌ها و رئوس دیگر بکشید","pinningButton":"رئوس مشترک را با هم پین کنید","rotateButton":"چرخش لایه","drawTextButton":"رسم متن","scaleButton":"مقیاس‌گذاری","autoTracingButton":"ردیاب خودکار"},"measurements":{"totalLength":"طول","segmentLength":"طول بخش","area":"ناحیه","radius":"شعاع","perimeter":"محیط","height":"ارتفاع","width":"عرض","coordinates":"موقعیت","coordinatesMarker":"موقعیت نشان"}}'),ua:JSON.parse('{"tooltips":{"placeMarker":"Натисніть, щоб нанести маркер","firstVertex":"Натисніть, щоб нанести першу вершину","continueLine":"Натисніть, щоб продовжити малювати","finishLine":"Натисніть будь-який існуючий маркер для завершення","finishPoly":"Виберіть перший маркер, щоб завершити","finishRect":"Натисніть, щоб завершити","startCircle":"Натисніть, щоб додати центр кола","finishCircle":"Натисніть, щоб завершити коло","placeCircleMarker":"Натисніть, щоб нанести круговий маркер"},"actions":{"finish":"Завершити","cancel":"Відмінити","removeLastVertex":"Видалити попередню вершину"},"buttonTitles":{"drawMarkerButton":"Малювати маркер","drawPolyButton":"Малювати полігон","drawLineButton":"Малювати криву","drawCircleButton":"Малювати коло","drawRectButton":"Малювати прямокутник","editButton":"Редагувати шари","dragButton":"Перенести шари","cutButton":"Вирізати шари","deleteButton":"Видалити шари","drawCircleMarkerButton":"Малювати круговий маркер","snappingButton":"Прив’язати перетягнутий маркер до інших шарів та вершин","pinningButton":"Зв\'язати спільні вершини разом"}}'),tr:JSON.parse('{"tooltips":{"placeMarker":"İşaretçi yerleştirmek için tıklayın","firstVertex":"İlk tepe noktasını yerleştirmek için tıklayın","continueLine":"Çizime devam etmek için tıklayın","finishLine":"Bitirmek için mevcut herhangi bir işaretçiyi tıklayın","finishPoly":"Bitirmek için ilk işaretçiyi tıklayın","finishRect":"Bitirmek için tıklayın","startCircle":"Daire merkezine yerleştirmek için tıklayın","finishCircle":"Daireyi bitirmek için tıklayın","placeCircleMarker":"Daire işaretçisi yerleştirmek için tıklayın"},"actions":{"finish":"Bitir","cancel":"İptal","removeLastVertex":"Son köşeyi kaldır"},"buttonTitles":{"drawMarkerButton":"Çizim İşaretçisi","drawPolyButton":"Çokgenler çiz","drawLineButton":"Çoklu çizgi çiz","drawCircleButton":"Çember çiz","drawRectButton":"Dikdörtgen çiz","editButton":"Katmanları düzenle","dragButton":"Katmanları sürükle","cutButton":"Katmanları kes","deleteButton":"Katmanları kaldır","drawCircleMarkerButton":"Daire işaretçisi çiz","snappingButton":"Sürüklenen işaretçiyi diğer katmanlara ve köşelere yapıştır","pinningButton":"Paylaşılan köşeleri birbirine sabitle"}}'),cz:JSON.parse('{"tooltips":{"placeMarker":"Kliknutím vytvoříte značku","firstVertex":"Kliknutím vytvoříte první objekt","continueLine":"Kliknutím pokračujte v kreslení","finishLine":"Kliknutí na libovolnou existující značku pro dokončení","finishPoly":"Vyberte první bod pro dokončení","finishRect":"Klikněte pro dokončení","startCircle":"Kliknutím přidejte střed kruhu","finishCircle":"Нажмите, чтобы задать радиус","placeCircleMarker":"Kliknutím nastavte poloměr"},"actions":{"finish":"Dokončit","cancel":"Zrušit","removeLastVertex":"Zrušit poslední akci"},"buttonTitles":{"drawMarkerButton":"Přidat značku","drawPolyButton":"Nakreslit polygon","drawLineButton":"Nakreslit křivku","drawCircleButton":"Nakreslit kruh","drawRectButton":"Nakreslit obdélník","editButton":"Upravit vrstvu","dragButton":"Přeneste vrstvu","cutButton":"Vyjmout vrstvu","deleteButton":"Smazat vrstvu","drawCircleMarkerButton":"Přidat kruhovou značku","snappingButton":"Navázat tažnou značku k dalším vrstvám a vrcholům","pinningButton":"Spojit společné body dohromady"}}'),ja:JSON.parse('{"tooltips":{"placeMarker":"クリックしてマーカーを配置","firstVertex":"クリックして最初の頂点を配置","continueLine":"クリックして描画を続ける","finishLine":"任意のマーカーをクリックして終了","finishPoly":"最初のマーカーをクリックして終了","finishRect":"クリックして終了","startCircle":"クリックして円の中心を配置","finishCircle":"クリックして円の描画を終了","placeCircleMarker":"クリックして円マーカーを配置","placeText":"クリックしてテキストを配置"},"actions":{"finish":"終了","cancel":"キャンセル","removeLastVertex":"最後の頂点を削除"},"buttonTitles":{"drawMarkerButton":"マーカーを描画","drawPolyButton":"ポリゴンを描画","drawLineButton":"折れ線を描画","drawCircleButton":"円を描画","drawRectButton":"矩形を描画","editButton":"レイヤーを編集","dragButton":"レイヤーをドラッグ","cutButton":"レイヤーを切り取り","deleteButton":"レイヤーを削除","drawCircleMarkerButton":"円マーカーを描画","snappingButton":"ドラッグしたマーカーを他のレイヤーや頂点にスナップする","pinningButton":"共有する頂点を同時に動かす","rotateButton":"レイヤーを回転","drawTextButton":"テキストを描画"}}'),fi:JSON.parse('{"tooltips":{"placeMarker":"Klikkaa asettaaksesi merkin","firstVertex":"Klikkaa asettaakseni ensimmäisen osuuden","continueLine":"Klikkaa jatkaaksesi piirtämistä","finishLine":"Klikkaa olemassa olevaa merkkiä lopettaaksesi","finishPoly":"Klikkaa ensimmäistä merkkiä lopettaaksesi","finishRect":"Klikkaa lopettaaksesi","startCircle":"Klikkaa asettaaksesi ympyrän keskipisteen","finishCircle":"Klikkaa lopettaaksesi ympyrän","placeCircleMarker":"Klikkaa asettaaksesi ympyrämerkin","placeText":"Klikkaa asettaaksesi tekstin"},"actions":{"finish":"Valmis","cancel":"Peruuta","removeLastVertex":"Poista viimeinen osuus"},"buttonTitles":{"drawMarkerButton":"Piirrä merkkejä","drawPolyButton":"Piirrä monikulmioita","drawLineButton":"Piirrä viivoja","drawCircleButton":"Piirrä ympyrä","drawRectButton":"Piirrä neliskulmioita","editButton":"Muokkaa","dragButton":"Siirrä","cutButton":"Leikkaa","deleteButton":"Poista","drawCircleMarkerButton":"Piirrä ympyrämerkki","snappingButton":"Kiinnitä siirrettävä merkki toisiin muotoihin","pinningButton":"Kiinnitä jaetut muodot yhteen","rotateButton":"Käännä","drawTextButton":"Piirrä tekstiä"}}'),ko:JSON.parse('{"tooltips":{"placeMarker":"마커 위치를 클릭하세요","firstVertex":"첫번째 꼭지점 위치을 클릭하세요","continueLine":"계속 그리려면 클릭하세요","finishLine":"끝내려면 기존 마커를 클릭하세요","finishPoly":"끝내려면 처음 마커를 클릭하세요","finishRect":"끝내려면 클릭하세요","startCircle":"원의 중심이 될 위치를 클릭하세요","finishCircle":"원을 끝내려면 클릭하세요","placeCircleMarker":"원 마커 위치를 클릭하세요","placeText":"텍스트 위치를 클릭하세요"},"actions":{"finish":"끝내기","cancel":"취소","removeLastVertex":"마지막 꼭지점 제거"},"buttonTitles":{"drawMarkerButton":"마커 그리기","drawPolyButton":"다각형 그리기","drawLineButton":"다각선 그리기","drawCircleButton":"원 그리기","drawRectButton":"직사각형 그리기","editButton":"레이어 편집하기","dragButton":"레이어 끌기","cutButton":"레이어 자르기","deleteButton":"레이어 제거하기","drawCircleMarkerButton":"원 마커 그리기","snappingButton":"잡아끈 마커를 다른 레이어 및 꼭지점에 들러붙게 하기","pinningButton":"공유 꼭지점을 함께 찍기","rotateButton":"레이어 회전하기","drawTextButton":"텍스트 그리기"}}')};function g(t,e){var i=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),i.push.apply(i,n)}return i}function _(t){for(var e=1;e0&&arguments[0]!==undefined?arguments[0]:this.globalOptions;this.globalEditModeEnabled()?this.disableGlobalEditMode():this.enableGlobalEditMode(t)},handleLayerAdditionInGlobalEditMode:function(){var t=this._addedLayersEdit;if(this._addedLayersEdit={},this.globalEditModeEnabled())for(var e in t){var i=t[e];this._isRelevantForEdit(i)&&i.pm.enable(_({},this.globalOptions))}},_layerAddedEdit:function(t){var e=t.layer;this._addedLayersEdit[L.stamp(e)]=e},_isRelevantForEdit:function(t){return t.pm&&!(t instanceof L.LayerGroup)&&(!L.PM.optIn&&!t.options.pmIgnore||L.PM.optIn&&!1===t.options.pmIgnore)&&!t._pmTempLayer&&t.pm.options.allowEditing}};const v={_globalDragModeEnabled:!1,enableGlobalDragMode:function(){var t=this,e=L.PM.Utils.findLayers(this.map);this._globalDragModeEnabled=!0,this._addedLayersDrag={},e.forEach((function(e){t._isRelevantForDrag(e)&&e.pm.enableLayerDrag()})),this.throttledReInitDrag||(this.throttledReInitDrag=L.Util.throttle(this.reinitGlobalDragMode,100,this)),this.map.on("layeradd",this._layerAddedDrag,this),this.map.on("layeradd",this.throttledReInitDrag,this),this.Toolbar.toggleButton("dragMode",this.globalDragModeEnabled()),this._fireGlobalDragModeToggled(!0)},disableGlobalDragMode:function(){var t=L.PM.Utils.findLayers(this.map);this._globalDragModeEnabled=!1,t.forEach((function(t){t.pm.disableLayerDrag()})),this.map.off("layeradd",this._layerAddedDrag,this),this.map.off("layeradd",this.throttledReInitDrag,this),this.Toolbar.toggleButton("dragMode",this.globalDragModeEnabled()),this._fireGlobalDragModeToggled(!1)},globalDragModeEnabled:function(){return!!this._globalDragModeEnabled},toggleGlobalDragMode:function(){this.globalDragModeEnabled()?this.disableGlobalDragMode():this.enableGlobalDragMode()},reinitGlobalDragMode:function(){var t=this._addedLayersDrag;if(this._addedLayersDrag={},this.globalDragModeEnabled())for(var e in t){var i=t[e];this._isRelevantForDrag(i)&&i.pm.enableLayerDrag()}},_layerAddedDrag:function(t){var e=t.layer;this._addedLayersDrag[L.stamp(e)]=e},_isRelevantForDrag:function(t){return t.pm&&!(t instanceof L.LayerGroup)&&(!L.PM.optIn&&!t.options.pmIgnore||L.PM.optIn&&!1===t.options.pmIgnore)&&!t._pmTempLayer&&t.pm.options.draggable}};const b={_globalRemovalModeEnabled:!1,enableGlobalRemovalMode:function(){var t=this;this._globalRemovalModeEnabled=!0,this.map.eachLayer((function(e){t._isRelevantForRemoval(e)&&(e.pm.enabled()&&e.pm.disable(),e.on("click",t.removeLayer,t))})),this.throttledReInitRemoval||(this.throttledReInitRemoval=L.Util.throttle(this.handleLayerAdditionInGlobalRemovalMode,100,this)),this._addedLayersRemoval={},this.map.on("layeradd",this._layerAddedRemoval,this),this.map.on("layeradd",this.throttledReInitRemoval,this),this.Toolbar.toggleButton("removalMode",this.globalRemovalModeEnabled()),this._fireGlobalRemovalModeToggled(!0)},disableGlobalRemovalMode:function(){var t=this;this._globalRemovalModeEnabled=!1,this.map.eachLayer((function(e){e.off("click",t.removeLayer,t)})),this.map.off("layeradd",this._layerAddedRemoval,this),this.map.off("layeradd",this.throttledReInitRemoval,this),this.Toolbar.toggleButton("removalMode",this.globalRemovalModeEnabled()),this._fireGlobalRemovalModeToggled(!1)},globalRemovalEnabled:function(){return this.globalRemovalModeEnabled()},globalRemovalModeEnabled:function(){return!!this._globalRemovalModeEnabled},toggleGlobalRemovalMode:function(){this.globalRemovalModeEnabled()?this.disableGlobalRemovalMode():this.enableGlobalRemovalMode()},removeLayer:function(t){var e=t.target;this._isRelevantForRemoval(e)&&!e.pm.dragging()&&(e.removeFrom(this.map.pm._getContainingLayer()),e.remove(),e instanceof L.LayerGroup?(this._fireRemoveLayerGroup(e),this._fireRemoveLayerGroup(this.map,e)):(e.pm._fireRemove(e),e.pm._fireRemove(this.map,e)))},_isRelevantForRemoval:function(t){return t.pm&&!(t instanceof L.LayerGroup)&&(!L.PM.optIn&&!t.options.pmIgnore||L.PM.optIn&&!1===t.options.pmIgnore)&&!t._pmTempLayer&&t.pm.options.allowRemoval},handleLayerAdditionInGlobalRemovalMode:function(){var t=this._addedLayersRemoval;if(this._addedLayersRemoval={},this.globalRemovalModeEnabled())for(var e in t){var i=t[e];this._isRelevantForRemoval(i)&&(i.pm.enabled()&&i.pm.disable(),i.on("click",this.removeLayer,this))}},_layerAddedRemoval:function(t){var e=t.layer;this._addedLayersRemoval[L.stamp(e)]=e}};const k={_globalRotateModeEnabled:!1,enableGlobalRotateMode:function(){var t=this;this._globalRotateModeEnabled=!0,L.PM.Utils.findLayers(this.map).filter((function(t){return t instanceof L.Polyline})).forEach((function(e){t._isRelevantForRotate(e)&&e.pm.enableRotate()})),this.throttledReInitRotate||(this.throttledReInitRotate=L.Util.throttle(this.handleLayerAdditionInGlobalRotateMode,100,this)),this._addedLayersRotate={},this.map.on("layeradd",this._layerAddedRotate,this),this.map.on("layeradd",this.throttledReInitRotate,this),this.Toolbar.toggleButton("rotateMode",this.globalRotateModeEnabled()),this._fireGlobalRotateModeToggled()},disableGlobalRotateMode:function(){this._globalRotateModeEnabled=!1,L.PM.Utils.findLayers(this.map).filter((function(t){return t instanceof L.Polyline})).forEach((function(t){t.pm.disableRotate()})),this.map.off("layeradd",this._layerAddedRotate,this),this.map.off("layeradd",this.throttledReInitRotate,this),this.Toolbar.toggleButton("rotateMode",this.globalRotateModeEnabled()),this._fireGlobalRotateModeToggled()},globalRotateModeEnabled:function(){return!!this._globalRotateModeEnabled},toggleGlobalRotateMode:function(){this.globalRotateModeEnabled()?this.disableGlobalRotateMode():this.enableGlobalRotateMode()},_isRelevantForRotate:function(t){return t.pm&&t instanceof L.Polyline&&!(t instanceof L.LayerGroup)&&(!L.PM.optIn&&!t.options.pmIgnore||L.PM.optIn&&!1===t.options.pmIgnore)&&!t._pmTempLayer&&t.pm.options.allowRotation},handleLayerAdditionInGlobalRotateMode:function(){var t=this._addedLayersRotate;if(this._addedLayersRotate={},this.globalRotateModeEnabled())for(var e in t){var i=t[e];this._isRelevantForRemoval(i)&&i.pm.enableRotate()}},_layerAddedRotate:function(t){var e=t.layer;this._addedLayersRotate[L.stamp(e)]=e}};function M(t,e){var i=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),i.push.apply(i,n)}return i}function x(t){for(var e=1;e0&&arguments[0]!==undefined?arguments[0]:"Draw",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._map,"pm:drawstart",{shape:this._shape,workingLayer:this._layer},t,e)},_fireDrawEnd:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Draw",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._map,"pm:drawend",{shape:this._shape},t,e)},_fireCreate:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"Draw",i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{};this.__fire(this._map,"pm:create",{shape:this._shape,marker:t,layer:t},e,i)},_fireCenterPlaced:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Draw",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{},i="Draw"===t?this._layer:undefined,n="Draw"!==t?this._layer:undefined;this.__fire(this._layer,"pm:centerplaced",{shape:this._shape,workingLayer:i,layer:n,latlng:this._layer.getLatLng()},t,e)},_fireCut:function(t,e,i){var n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:"Draw",r=arguments.length>4&&arguments[4]!==undefined?arguments[4]:{};this.__fire(t,"pm:cut",{shape:this._shape,layer:e,originalLayer:i},n,r)},_fireEdit:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:this._layer,e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"Edit",i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{};this.__fire(t,"pm:edit",{layer:this._layer,shape:this.getShape()},e,i)},_fireEnable:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Edit",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._layer,"pm:enable",{layer:this._layer,shape:this.getShape()},t,e)},_fireDisable:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Edit",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._layer,"pm:disable",{layer:this._layer,shape:this.getShape()},t,e)},_fireUpdate:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Edit",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._layer,"pm:update",{layer:this._layer,shape:this.getShape()},t,e)},_fireMarkerDragStart:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:undefined,i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Edit",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(this._layer,"pm:markerdragstart",{layer:this._layer,markerEvent:t,shape:this.getShape(),indexPath:e},i,n)},_fireMarkerDrag:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:undefined,i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Edit",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(this._layer,"pm:markerdrag",{layer:this._layer,markerEvent:t,shape:this.getShape(),indexPath:e},i,n)},_fireMarkerDragEnd:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:undefined,i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:undefined,n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:"Edit",r=arguments.length>4&&arguments[4]!==undefined?arguments[4]:{};this.__fire(this._layer,"pm:markerdragend",{layer:this._layer,markerEvent:t,shape:this.getShape(),indexPath:e,intersectionReset:i},n,r)},_fireDragStart:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Edit",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._layer,"pm:dragstart",{layer:this._layer,shape:this.getShape()},t,e)},_fireDrag:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"Edit",i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{};this.__fire(this._layer,"pm:drag",x(x({},t),{},{shape:this.getShape()}),e,i)},_fireDragEnd:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Edit",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._layer,"pm:dragend",{layer:this._layer,shape:this.getShape()},t,e)},_fireDragEnable:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Edit",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._layer,"pm:dragenable",{layer:this._layer,shape:this.getShape()},t,e)},_fireDragDisable:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Edit",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._layer,"pm:dragdisable",{layer:this._layer,shape:this.getShape()},t,e)},_fireRemove:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:t,i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Edit",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(t,"pm:remove",{layer:e,shape:this.getShape()},i,n)},_fireVertexAdded:function(t,e,i){var n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:"Edit",r=arguments.length>4&&arguments[4]!==undefined?arguments[4]:{};this.__fire(this._layer,"pm:vertexadded",{layer:this._layer,workingLayer:this._layer,marker:t,indexPath:e,latlng:i,shape:this.getShape()},n,r)},_fireVertexRemoved:function(t,e){var i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Edit",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(this._layer,"pm:vertexremoved",{layer:this._layer,marker:t,indexPath:e,shape:this.getShape()},i,n)},_fireVertexClick:function(t,e){var i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Edit",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(this._layer,"pm:vertexclick",{layer:this._layer,markerEvent:t,indexPath:e,shape:this.getShape()},i,n)},_fireIntersect:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:this._layer,i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Edit",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(e,"pm:intersect",{layer:this._layer,intersection:t,shape:this.getShape()},i,n)},_fireLayerReset:function(t,e){var i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Edit",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(this._layer,"pm:layerreset",{layer:this._layer,markerEvent:t,indexPath:e,shape:this.getShape()},i,n)},_fireChange:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"Edit",i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{};this.__fire(this._layer,"pm:change",{layer:this._layer,latlngs:t,shape:this.getShape()},e,i)},_fireTextChange:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"Edit",i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{};this.__fire(this._layer,"pm:textchange",{layer:this._layer,text:t,shape:this.getShape()},e,i)},_fireTextFocus:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Edit",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._layer,"pm:textfocus",{layer:this._layer,shape:this.getShape()},t,e)},_fireTextBlur:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Edit",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._layer,"pm:textblur",{layer:this._layer,shape:this.getShape()},t,e)},_fireSnapDrag:function(t,e){var i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Snapping",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(t,"pm:snapdrag",e,i,n)},_fireSnap:function(t,e){var i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Snapping",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(t,"pm:snap",e,i,n)},_fireUnsnap:function(t,e){var i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Snapping",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(t,"pm:unsnap",e,i,n)},_fireRotationEnable:function(t,e){var i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Rotation",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(t,"pm:rotateenable",{layer:this._layer,helpLayer:this._rotatePoly,shape:this.getShape()},i,n)},_fireRotationDisable:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"Rotation",i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{};this.__fire(t,"pm:rotatedisable",{layer:this._layer,shape:this.getShape()},e,i)},_fireRotationStart:function(t,e){var i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Rotation",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(t,"pm:rotatestart",{layer:this._rotationLayer,helpLayer:this._layer,startAngle:this._startAngle,originLatLngs:e},i,n)},_fireRotation:function(t,e,i){var n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:this._rotationLayer,r=arguments.length>4&&arguments[4]!==undefined?arguments[4]:"Rotation",a=arguments.length>5&&arguments[5]!==undefined?arguments[5]:{};this.__fire(t,"pm:rotate",{layer:n,helpLayer:this._layer,startAngle:this._startAngle,angle:n.pm.getAngle(),angleDiff:e,oldLatLngs:i,newLatLngs:n.getLatLngs()},r,a)},_fireRotationEnd:function(t,e,i){var n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:"Rotation",r=arguments.length>4&&arguments[4]!==undefined?arguments[4]:{};this.__fire(t,"pm:rotateend",{layer:this._rotationLayer,helpLayer:this._layer,startAngle:e,angle:this._rotationLayer.pm.getAngle(),originLatLngs:i,newLatLngs:this._rotationLayer.getLatLngs()},n,r)},_fireActionClick:function(t,e,i){var n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:"Toolbar",r=arguments.length>4&&arguments[4]!==undefined?arguments[4]:{};this.__fire(this._map,"pm:actionclick",{text:t.text,action:t,btnName:e,button:i},n,r)},_fireButtonClick:function(t,e){var i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Toolbar",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(this._map,"pm:buttonclick",{btnName:t,button:e},i,n)},_fireLangChange:function(t,e,i,n){var r=arguments.length>4&&arguments[4]!==undefined?arguments[4]:"Global",a=arguments.length>5&&arguments[5]!==undefined?arguments[5]:{};this.__fire(this.map,"pm:langchange",{oldLang:t,activeLang:e,fallback:i,translations:n},r,a)},_fireGlobalDragModeToggled:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"Global",i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{};this.__fire(this.map,"pm:globaldragmodetoggled",{enabled:t,map:this.map},e,i)},_fireGlobalEditModeToggled:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"Global",i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{};this.__fire(this.map,"pm:globaleditmodetoggled",{enabled:t,map:this.map},e,i)},_fireGlobalRemovalModeToggled:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:"Global",i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{};this.__fire(this.map,"pm:globalremovalmodetoggled",{enabled:t,map:this.map},e,i)},_fireGlobalCutModeToggled:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Global",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._map,"pm:globalcutmodetoggled",{enabled:!!this._enabled,map:this._map},t,e)},_fireGlobalDrawModeToggled:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Global",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this._map,"pm:globaldrawmodetoggled",{enabled:this._enabled,shape:this._shape,map:this._map},t,e)},_fireGlobalRotateModeToggled:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Global",e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};this.__fire(this.map,"pm:globalrotatemodetoggled",{enabled:this.globalRotateModeEnabled(),map:this.map},t,e)},_fireRemoveLayerGroup:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:t,i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"Edit",n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:{};this.__fire(t,"pm:remove",{layer:e,shape:undefined},i,n)},_fireKeyeventEvent:function(t,e,i){var n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:"Global",r=arguments.length>4&&arguments[4]!==undefined?arguments[4]:{};this.__fire(this.map,"pm:keyevent",{event:t,eventType:e,focusOn:i},n,r)},__fire:function(t,i,n,r){var a=arguments.length>4&&arguments[4]!==undefined?arguments[4]:{};n=e()(n,a,{source:r}),L.PM.Utils._fireEvent(t,i,n)}};const P=C;const E={_lastEvents:{keydown:undefined,keyup:undefined,current:undefined},_initKeyListener:function(t){this.map=t,L.DomEvent.on(document,"keydown keyup",this._onKeyListener,this),L.DomEvent.on(window,"blur",this._onBlur,this)},_onKeyListener:function(t){var e="document";this.map.getContainer().contains(t.target)&&(e="map");var i={event:t,eventType:t.type,focusOn:e};this._lastEvents[t.type]=i,this._lastEvents.current=i,this.map.pm._fireKeyeventEvent(t,t.type,e)},_onBlur:function(t){t.altKey=!1;var e={event:t,eventType:t.type,focusOn:"document"};this._lastEvents[t.type]=e,this._lastEvents.current=e},getLastKeyEvent:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"current";return this._lastEvents[t]},isShiftKeyPressed:function(){var t;return null===(t=this._lastEvents.current)||void 0===t?void 0:t.event.shiftKey},isAltKeyPressed:function(){var t;return null===(t=this._lastEvents.current)||void 0===t?void 0:t.event.altKey},isCtrlKeyPressed:function(){var t;return null===(t=this._lastEvents.current)||void 0===t?void 0:t.event.ctrlKey},isMetaKeyPressed:function(){var t;return null===(t=this._lastEvents.current)||void 0===t?void 0:t.event.metaKey},getPressedKey:function(){var t;return null===(t=this._lastEvents.current)||void 0===t?void 0:t.event.key}};var S=i(7361),O=i.n(S),B=i(8721),D=i.n(B);function R(t){var e=L.PM.activeLang;return D()(f,e)||(e="en"),O()(f[e],t)}function T(t){for(var e=0;e1e-12;){n=Math.cos(2*b+P),E=P,P=p/(l*w)+C*(r=Math.sin(P))*(n+C/4*((a=Math.cos(P))*(2*n*n-1)-C/6*n*(4*r*r-3)*(4*n*n-3)))}var S=v*r-y*a*_,O=Math.atan2(v*a+y*r*_,(1-h)*Math.sqrt(k*k+S*S)),B=h/16*M*(4+h*(4-3*M)),D=u+180*(Math.atan2(r*g,y*a-v*r*_)-(1-B)*h*k*(P+B*r*(n+B*a*(2*n*n-1))))/d,R=180*O/d;return L.latLng(D,R)}function j(t,e,i,n){for(var r,a,o=!(arguments.length>4&&arguments[4]!==undefined)||arguments[4],s=[],l=0;l180?f-360:f<-180?f+360:f,L.latLng([d*r,f])}(e,G(t,e,i),n)}function N(t,e){var i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"asc";if(!e||0===Object.keys(e).length)return function(t,e){return t-e};for(var n,r=Object.keys(e),a=r.length-1,o={};a>=0;)n=r[a],o[n.toLowerCase()]=e[n],a-=1;function s(t){return t instanceof L.Marker?"Marker":t instanceof L.Circle?"Circle":t instanceof L.CircleMarker?"CircleMarker":t instanceof L.Rectangle?"Rectangle":t instanceof L.Polygon?"Polygon":t instanceof L.Polyline?"Line":undefined}return function(e,n){var r,a;if("instanceofShape"===t){if(r=s(e.layer).toLowerCase(),a=s(n.layer).toLowerCase(),!r||!a)return 0}else{if(!e.hasOwnProperty(t)||!n.hasOwnProperty(t))return 0;r=e[t].toLowerCase(),a=n[t].toLowerCase()}var l=r in o?o[r]:Number.MAX_SAFE_INTEGER,h=a in o?o[a]:Number.MAX_SAFE_INTEGER,u=0;return lh&&(u=1),"desc"===i?-1*u:u}}function F(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:t.getLatLngs();return t instanceof L.Polygon?L.polygon(e).getLatLngs():L.polyline(e).getLatLngs()}function U(t,e){var i,n;if(null!==(i=e.options.crs)&&void 0!==i&&null!==(n=i.projection)&&void 0!==n&&n.MAX_LATITUDE){var r,a,o=null===(r=e.options.crs)||void 0===r||null===(a=r.projection)||void 0===a?void 0:a.MAX_LATITUDE;t.lat=Math.max(Math.min(o,t.lat),-o)}return t}function V(t){return t.options.renderer||t._map&&(t._map._getPaneRenderer(t.options.pane)||t._map.options.renderer||t._map._renderer)||t._renderer}const K=L.Class.extend({includes:[y,v,b,k,P],initialize:function(t){this.map=t,this.Draw=new L.PM.Draw(t),this.Toolbar=new L.PM.Toolbar(t),this.Keyboard=E,this.globalOptions={snappable:!0,layerGroup:undefined,snappingOrder:["Marker","CircleMarker","Circle","Line","Polygon","Rectangle"],panes:{vertexPane:"markerPane",layerPane:"overlayPane",markerPane:"markerPane"},draggable:!0},this.Keyboard._initKeyListener(t)},setLang:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"en",i=arguments.length>1?arguments[1]:undefined,n=arguments.length>2&&arguments[2]!==undefined?arguments[2]:"en",r=L.PM.activeLang;i&&(f[t]=e()(f[n],i)),L.PM.activeLang=t,this.map.pm.Toolbar.reinit(),this._fireLangChange(r,t,n,f[t])},addControls:function(t){this.Toolbar.addControls(t)},removeControls:function(){this.Toolbar.removeControls()},toggleControls:function(){this.Toolbar.toggleControls()},controlsVisible:function(){return this.Toolbar.isVisible},enableDraw:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Polygon",e=arguments.length>1?arguments[1]:undefined;"Poly"===t&&(t="Polygon"),this.Draw.enable(t,e)},disableDraw:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:"Polygon";"Poly"===t&&(t="Polygon"),this.Draw.disable(t)},setPathOptions:function(t){var e=this,i=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{},n=i.ignoreShapes||[],r=i.merge||!1;this.map.pm.Draw.shapes.forEach((function(i){-1===n.indexOf(i)&&e.map.pm.Draw[i].setPathOptions(t,r)}))},getGlobalOptions:function(){return this.globalOptions},setGlobalOptions:function(t){var i=this,n=e()(this.globalOptions,t);n.editable&&(n.resizeableCircleMarker=n.editable,delete n.editable);var r=!1;this.map.pm.Draw.CircleMarker.enabled()&&!!this.map.pm.Draw.CircleMarker.options.resizeableCircleMarker!=!!n.resizeableCircleMarker&&(this.map.pm.Draw.CircleMarker.disable(),r=!0);var a=!1;this.map.pm.Draw.Circle.enabled()&&!!this.map.pm.Draw.Circle.options.resizableCircle!=!!n.resizableCircle&&(this.map.pm.Draw.Circle.disable(),a=!0),this.map.pm.Draw.shapes.forEach((function(t){i.map.pm.Draw[t].setOptions(n)})),r&&this.map.pm.Draw.CircleMarker.enable(),a&&this.map.pm.Draw.Circle.enable(),L.PM.Utils.findLayers(this.map).forEach((function(t){t.pm.setOptions(n)})),this.map.fire("pm:globaloptionschanged"),this.globalOptions=n,this.applyGlobalOptions()},applyGlobalOptions:function(){L.PM.Utils.findLayers(this.map).forEach((function(t){t.pm.enabled()&&t.pm.applyOptions()}))},globalDrawModeEnabled:function(){return!!this.Draw.getActiveShape()},globalCutModeEnabled:function(){return!!this.Draw.Cut.enabled()},enableGlobalCutMode:function(t){return this.Draw.Cut.enable(t)},toggleGlobalCutMode:function(t){return this.Draw.Cut.toggle(t)},disableGlobalCutMode:function(){return this.Draw.Cut.disable()},getGeomanLayers:function(){var t=arguments.length>0&&arguments[0]!==undefined&&arguments[0],e=L.PM.Utils.findLayers(this.map);if(!t)return e;var i=L.featureGroup();return i._pmTempLayer=!0,e.forEach((function(t){i.addLayer(t)})),i},getGeomanDrawLayers:function(){var t=arguments.length>0&&arguments[0]!==undefined&&arguments[0],e=L.PM.Utils.findLayers(this.map).filter((function(t){return!0===t._drawnByGeoman}));if(!t)return e;var i=L.featureGroup();return i._pmTempLayer=!0,e.forEach((function(t){i.addLayer(t)})),i},_getContainingLayer:function(){return this.globalOptions.layerGroup&&this.globalOptions.layerGroup instanceof L.LayerGroup?this.globalOptions.layerGroup:this.map},_isCRSSimple:function(){return this.map.options.crs===L.CRS.Simple},_touchEventCounter:0,_addTouchEvents:function(t){0===this._touchEventCounter&&(L.DomEvent.on(t,"touchmove",this._canvasTouchMove,this),L.DomEvent.on(t,"touchstart touchend touchcancel",this._canvasTouchClick,this)),this._touchEventCounter+=1},_removeTouchEvents:function(t){1===this._touchEventCounter&&(L.DomEvent.off(t,"touchmove",this._canvasTouchMove,this),L.DomEvent.off(t,"touchstart touchend touchcancel",this._canvasTouchClick,this)),this._touchEventCounter=this._touchEventCounter<=1?0:this._touchEventCounter-1},_canvasTouchMove:function(t){V(this.map)._onMouseMove(this._createMouseEvent("mousemove",t))},_canvasTouchClick:function(t){var e="";"touchstart"===t.type||"pointerdown"===t.type?e="mousedown":"touchend"===t.type||"pointerup"===t.type?e="mouseup":"touchcancel"!==t.type&&"pointercancel"!==t.type||(e="mouseup"),e&&V(this.map)._onClick(this._createMouseEvent(e,t))},_createMouseEvent:function(t,e){var i,n=e.touches[0]||e.changedTouches[0];try{i=new MouseEvent(t,{bubbles:e.bubbles,cancelable:e.cancelable,view:e.view,detail:n.detail,screenX:n.screenX,screenY:n.screenY,clientX:n.clientX,clientY:n.clientY,ctrlKey:e.ctrlKey,altKey:e.altKey,shiftKey:e.shiftKey,metaKey:e.metaKey,button:e.button,relatedTarget:e.relatedTarget})}catch(r){(i=document.createEvent("MouseEvents")).initMouseEvent(t,e.bubbles,e.cancelable,e.view,n.detail,n.screenX,n.screenY,n.clientX,n.clientY,e.ctrlKey,e.altKey,e.shiftKey,e.metaKey,e.button,e.relatedTarget)}return i}});const q=L.Control.extend({includes:[P],options:{position:"topleft",disableByOtherButtons:!0},initialize:function(t){this._button=L.Util.extend({},this.options,t)},onAdd:function(t){return this._map=t,this._map.pm.Toolbar.options.oneBlock?this._container=this._map.pm.Toolbar._createContainer(this.options.position):"edit"===this._button.tool?this._container=this._map.pm.Toolbar.editContainer:"options"===this._button.tool?this._container=this._map.pm.Toolbar.optionsContainer:"custom"===this._button.tool?this._container=this._map.pm.Toolbar.customContainer:this._container=this._map.pm.Toolbar.drawContainer,this.buttonsDomNode=this._makeButton(this._button),this._container.appendChild(this.buttonsDomNode),this._container},onRemove:function(){return this.buttonsDomNode.remove(),this._container},getText:function(){return this._button.text},getIconUrl:function(){return this._button.iconUrl},destroy:function(){this._button={},this._update()},toggle:function(t){return this._button.toggleStatus="boolean"==typeof t?t:!this._button.toggleStatus,this._applyStyleClasses(),this._button.toggleStatus},toggled:function(){return this._button.toggleStatus},onCreate:function(){this.toggle(!1)},disable:function(){this.toggle(!1),this._button.disabled=!0,this._updateDisabled()},enable:function(){this._button.disabled=!1,this._updateDisabled()},_triggerClick:function(t){t&&t.preventDefault(),this._button.disabled||(this._button.onClick(t,{button:this,event:t}),this._clicked(t),this._button.afterClick(t,{button:this,event:t}))},_makeButton:function(t){var e=this,i=this.options.position.indexOf("right")>-1?"pos-right":"",n=L.DomUtil.create("div","button-container ".concat(i),this._container);t.title&&n.setAttribute("title",t.title);var r=L.DomUtil.create("a","leaflet-buttons-control-button",n);r.setAttribute("role","button"),r.setAttribute("tabindex","0"),r.href="#";var a=L.DomUtil.create("div","leaflet-pm-actions-container ".concat(i),n),o=t.actions,s={cancel:{text:R("actions.cancel"),onClick:function(){this._triggerClick()}},finishMode:{text:R("actions.finish"),onClick:function(){this._triggerClick()}},removeLastVertex:{text:R("actions.removeLastVertex"),onClick:function(){this._map.pm.Draw[t.jsClass]._removeLastVertex()}},finish:{text:R("actions.finish"),onClick:function(e){this._map.pm.Draw[t.jsClass]._finishShape(e)}}};o.forEach((function(n){var r,o="string"==typeof n?n:n.name;if(s[o])r=s[o];else{if(!n.text)return;r=n}var l=L.DomUtil.create("a","leaflet-pm-action ".concat(i," action-").concat(o),a);if(l.setAttribute("role","button"),l.setAttribute("tabindex","0"),l.href="#",l.innerHTML=r.text,L.DomEvent.disableClickPropagation(l),L.DomEvent.on(l,"click",L.DomEvent.stop),!t.disabled&&r.onClick){L.DomEvent.addListener(l,"click",(function(i){i.preventDefault();var n="",a=e._map.pm.Toolbar.buttons;for(var o in a)if(a[o]._button===t){n=o;break}e._fireActionClick(r,n,t)}),e),L.DomEvent.addListener(l,"click",r.onClick,e)}})),t.toggleStatus&&L.DomUtil.addClass(n,"active");var l=L.DomUtil.create("div","control-icon",r);return t.iconUrl&&l.setAttribute("src",t.iconUrl),t.className&&L.DomUtil.addClass(l,t.className),L.DomEvent.disableClickPropagation(r),L.DomEvent.on(r,"click",L.DomEvent.stop),t.disabled||(L.DomEvent.addListener(r,"click",this._onBtnClick,this),L.DomEvent.addListener(r,"click",this._triggerClick,this)),t.disabled&&(L.DomUtil.addClass(r,"pm-disabled"),r.setAttribute("aria-disabled","true")),n},_applyStyleClasses:function(){this._container&&(this._button.toggleStatus&&!1!==this._button.cssToggle?(L.DomUtil.addClass(this.buttonsDomNode,"active"),L.DomUtil.addClass(this._container,"activeChild")):(L.DomUtil.removeClass(this.buttonsDomNode,"active"),L.DomUtil.removeClass(this._container,"activeChild")))},_onBtnClick:function(){this._button.disableOtherButtons&&this._map.pm.Toolbar.triggerClickOnToggledButtons(this);var t="",e=this._map.pm.Toolbar.buttons;for(var i in e)if(e[i]._button===this._button){t=i;break}this._fireButtonClick(t,this._button)},_clicked:function(){this._button.doToggle&&this.toggle()},_updateDisabled:function(){if(this._container){var t="pm-disabled",e=this.buttonsDomNode.children[0];this._button.disabled?(L.DomUtil.addClass(e,t),e.setAttribute("aria-disabled","true"),L.DomEvent.off(e,"click",this._triggerClick,this),L.DomEvent.off(e,"click",this._onBtnClick,this)):(L.DomUtil.removeClass(e,t),e.setAttribute("aria-disabled","false"),L.DomEvent.on(e,"click",this._triggerClick,this),L.DomEvent.on(e,"click",this._onBtnClick,this))}}});function H(t,e){var i=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),i.push.apply(i,n)}return i}function J(t){for(var e=1;e0&&arguments[0]!==undefined?arguments[0]:this.options;"undefined"!=typeof t.editPolygon&&(t.editMode=t.editPolygon),"undefined"!=typeof t.deleteLayer&&(t.removalMode=t.deleteLayer),L.Util.setOptions(this,t),this.applyIconStyle(),this.isVisible=!0,this._showHideButtons()},applyIconStyle:function(){var t=this.getButtons(),e={geomanIcons:{drawMarker:"control-icon leaflet-pm-icon-marker",drawPolyline:"control-icon leaflet-pm-icon-polyline",drawRectangle:"control-icon leaflet-pm-icon-rectangle",drawPolygon:"control-icon leaflet-pm-icon-polygon",drawCircle:"control-icon leaflet-pm-icon-circle",drawCircleMarker:"control-icon leaflet-pm-icon-circle-marker",editMode:"control-icon leaflet-pm-icon-edit",dragMode:"control-icon leaflet-pm-icon-drag",cutPolygon:"control-icon leaflet-pm-icon-cut",removalMode:"control-icon leaflet-pm-icon-delete",drawText:"control-icon leaflet-pm-icon-text"}};for(var i in t){var n=t[i];L.Util.setOptions(n,{className:e.geomanIcons[i]})}},removeControls:function(){var t=this.getButtons();for(var e in t)t[e].remove();this.isVisible=!1},toggleControls:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:this.options;this.isVisible?this.removeControls():this.addControls(t)},_addButton:function(t,e){return this.buttons[t]=e,this.options[t]=this.options[t]||!1,this.buttons[t]},triggerClickOnToggledButtons:function(t){for(var e in this.buttons){var i=this.buttons[e];i._button.disableByOtherButtons&&i!==t&&i.toggled()&&i._triggerClick()}},toggleButton:function(t,e){var i=!(arguments.length>2&&arguments[2]!==undefined)||arguments[2];return"editPolygon"===t&&(t="editMode"),"deleteLayer"===t&&(t="removalMode"),i&&this.triggerClickOnToggledButtons(this.buttons[t]),!!this.buttons[t]&&this.buttons[t].toggle(e)},_defineButtons:function(){var t=this,e={className:"control-icon leaflet-pm-icon-marker",title:R("buttonTitles.drawMarkerButton"),jsClass:"Marker",onClick:function(){},afterClick:function(e,i){t.map.pm.Draw[i.button._button.jsClass].toggle()},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,actions:["cancel"]},i={title:R("buttonTitles.drawPolyButton"),className:"control-icon leaflet-pm-icon-polygon",jsClass:"Polygon",onClick:function(){},afterClick:function(e,i){t.map.pm.Draw[i.button._button.jsClass].toggle()},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,actions:["finish","removeLastVertex","cancel"]},n={className:"control-icon leaflet-pm-icon-polyline",title:R("buttonTitles.drawLineButton"),jsClass:"Line",onClick:function(){},afterClick:function(e,i){t.map.pm.Draw[i.button._button.jsClass].toggle()},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,actions:["finish","removeLastVertex","cancel"]},r={title:R("buttonTitles.drawCircleButton"),className:"control-icon leaflet-pm-icon-circle",jsClass:"Circle",onClick:function(){},afterClick:function(e,i){t.map.pm.Draw[i.button._button.jsClass].toggle()},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,actions:["cancel"]},a={title:R("buttonTitles.drawCircleMarkerButton"),className:"control-icon leaflet-pm-icon-circle-marker",jsClass:"CircleMarker",onClick:function(){},afterClick:function(e,i){t.map.pm.Draw[i.button._button.jsClass].toggle()},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,actions:["cancel"]},o={title:R("buttonTitles.drawRectButton"),className:"control-icon leaflet-pm-icon-rectangle",jsClass:"Rectangle",onClick:function(){},afterClick:function(e,i){t.map.pm.Draw[i.button._button.jsClass].toggle()},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,actions:["cancel"]},s={title:R("buttonTitles.editButton"),className:"control-icon leaflet-pm-icon-edit",onClick:function(){},afterClick:function(){t.map.pm.toggleGlobalEditMode()},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,tool:"edit",actions:["finishMode"]},l={title:R("buttonTitles.dragButton"),className:"control-icon leaflet-pm-icon-drag",onClick:function(){},afterClick:function(){t.map.pm.toggleGlobalDragMode()},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,tool:"edit",actions:["finishMode"]},h={title:R("buttonTitles.cutButton"),className:"control-icon leaflet-pm-icon-cut",jsClass:"Cut",onClick:function(){},afterClick:function(e,i){t.map.pm.Draw[i.button._button.jsClass].toggle({snappable:!0,cursorMarker:!0,allowSelfIntersection:!1})},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,tool:"edit",actions:["finish","removeLastVertex","cancel"]},u={title:R("buttonTitles.deleteButton"),className:"control-icon leaflet-pm-icon-delete",onClick:function(){},afterClick:function(){t.map.pm.toggleGlobalRemovalMode()},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,tool:"edit",actions:["finishMode"]},c={title:R("buttonTitles.rotateButton"),className:"control-icon leaflet-pm-icon-rotate",onClick:function(){},afterClick:function(){t.map.pm.toggleGlobalRotateMode()},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,tool:"edit",actions:["finishMode"]},p={className:"control-icon leaflet-pm-icon-text",title:R("buttonTitles.drawTextButton"),jsClass:"Text",onClick:function(){},afterClick:function(e,i){t.map.pm.Draw[i.button._button.jsClass].toggle()},doToggle:!0,toggleStatus:!1,disableOtherButtons:!0,position:this.options.position,actions:["cancel"]};this._addButton("drawMarker",new L.Control.PMButton(e)),this._addButton("drawPolyline",new L.Control.PMButton(n)),this._addButton("drawRectangle",new L.Control.PMButton(o)),this._addButton("drawPolygon",new L.Control.PMButton(i)),this._addButton("drawCircle",new L.Control.PMButton(r)),this._addButton("drawCircleMarker",new L.Control.PMButton(a)),this._addButton("drawText",new L.Control.PMButton(p)),this._addButton("editMode",new L.Control.PMButton(s)),this._addButton("dragMode",new L.Control.PMButton(l)),this._addButton("cutPolygon",new L.Control.PMButton(h)),this._addButton("removalMode",new L.Control.PMButton(u)),this._addButton("rotateMode",new L.Control.PMButton(c))},_showHideButtons:function(){if(this.isVisible){this.removeControls(),this.isVisible=!0;var t=this.getButtons(),e=[];for(var i in!1===this.options.drawControls&&(e=e.concat(Object.keys(t).filter((function(e){return!t[e]._button.tool})))),!1===this.options.editControls&&(e=e.concat(Object.keys(t).filter((function(e){return"edit"===t[e]._button.tool})))),!1===this.options.optionsControls&&(e=e.concat(Object.keys(t).filter((function(e){return"options"===t[e]._button.tool})))),!1===this.options.customControls&&(e=e.concat(Object.keys(t).filter((function(e){return"custom"===t[e]._button.tool})))),t)if(this.options[i]&&-1===e.indexOf(i)){var n=t[i]._button.tool;n||(n="draw"),t[i].setPosition(this._getBtnPosition(n)),t[i].addTo(this.map)}}},_getBtnPosition:function(t){return this.options.positions&&this.options.positions[t]?this.options.positions[t]:this.options.position},setBlockPosition:function(t,e){this.options.positions[t]=e,this._showHideButtons(),this.changeControlOrder()},getBlockPositions:function(){return this.options.positions},copyDrawControl:function(t,e){if(!e)throw new TypeError("Button has no name");"object"!==X(e)&&(e={name:e});var i=this._btnNameMapping(t);if(!e.name)throw new TypeError("Button has no name");if(this.buttons[e.name])throw new TypeError("Button with this name already exists");var n=this.map.pm.Draw.createNewDrawInstance(e.name,i);return e=J(J({},this.buttons[i]._button),e),{drawInstance:n,control:this.createCustomControl(e)}},createCustomControl:function(t){var e,i;if(!t.name)throw new TypeError("Button has no name");if(this.buttons[t.name])throw new TypeError("Button with this name already exists");t.onClick||(t.onClick=function(){}),t.afterClick||(t.afterClick=function(){}),!1!==t.toggle&&(t.toggle=!0),t.block&&(t.block=t.block.toLowerCase()),t.block&&"draw"!==t.block||(t.block=""),t.className?-1===t.className.indexOf("control-icon")&&(t.className="control-icon ".concat(t.className)):t.className="control-icon";var n={tool:t.block,className:t.className,title:t.title||"",jsClass:t.name,onClick:t.onClick,afterClick:t.afterClick,doToggle:t.toggle,toggleStatus:!1,disableOtherButtons:null===(e=t.disableOtherButtons)||void 0===e||e,disableByOtherButtons:null===(i=t.disableByOtherButtons)||void 0===i||i,cssToggle:t.toggle,position:this.options.position,actions:t.actions||[],disabled:!!t.disabled};!1!==this.options[t.name]&&(this.options[t.name]=!0);var r=this._addButton(t.name,new L.Control.PMButton(n));return this.changeControlOrder(),r},changeControlOrder:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:[],e=this._shapeMapping(),i=[];t.forEach((function(t){e[t]?i.push(e[t]):i.push(t)}));var n=this.getButtons(),r={};i.forEach((function(t){n[t]&&(r[t]=n[t])}));var a=Object.keys(n).filter((function(t){return!n[t]._button.tool}));a.forEach((function(t){-1===i.indexOf(t)&&(r[t]=n[t])}));var o=Object.keys(n).filter((function(t){return"edit"===n[t]._button.tool}));o.forEach((function(t){-1===i.indexOf(t)&&(r[t]=n[t])}));var s=Object.keys(n).filter((function(t){return"options"===n[t]._button.tool}));s.forEach((function(t){-1===i.indexOf(t)&&(r[t]=n[t])}));var l=Object.keys(n).filter((function(t){return"custom"===n[t]._button.tool}));l.forEach((function(t){-1===i.indexOf(t)&&(r[t]=n[t])})),Object.keys(n).forEach((function(t){-1===i.indexOf(t)&&(r[t]=n[t])})),this.map.pm.Toolbar.buttons=r,this._showHideButtons()},getControlOrder:function(){var t=this.getButtons(),e=[];for(var i in t)e.push(i);return e},changeActionsOfControl:function(t,e){var i=this._btnNameMapping(t);if(!i)throw new TypeError("No name passed");if(!e)throw new TypeError("No actions passed");if(!this.buttons[i])throw new TypeError("Button with this name not exists");this.buttons[i]._button.actions=e,this.changeControlOrder()},setButtonDisabled:function(t,e){var i=this._btnNameMapping(t);e?this.buttons[i].disable():this.buttons[i].enable()},_shapeMapping:function(){return{Marker:"drawMarker",Circle:"drawCircle",Polygon:"drawPolygon",Rectangle:"drawRectangle",Polyline:"drawPolyline",Line:"drawPolyline",CircleMarker:"drawCircleMarker",Edit:"editMode",Drag:"dragMode",Cut:"cutPolygon",Removal:"removalMode",Rotate:"rotateMode",Text:"drawText"}},_btnNameMapping:function(t){var e=this._shapeMapping();return e[t]?e[t]:t}});function $(t,e){var i=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),i.push.apply(i,n)}return i}function W(t){for(var e=1;e-1&&this._snapList.splice(i,1)}},_calcClosestLayer:function(t,e){return this._calcClosestLayers(t,e,1)[0]},_calcClosestLayers:function(t,e){var i=this,n=arguments.length>2&&arguments[2]!==undefined?arguments[2]:1,r=[],a={};e.forEach((function(e,o){if(!e._parentCopy||e._parentCopy!==i._layer){var s=i._calcLayerDistances(t,e);if(s.distance=Math.floor(s.distance),i.debugIndicatorLines){if(!i.debugIndicatorLines[o]){var l=L.polyline([],{color:"red",pmIgnore:!0});l._pmTempLayer=!0,i.debugIndicatorLines[o]=l}i.debugIndicatorLines[o].setLatLngs([t,s.latlng])}1===n&&(a.distance===undefined||s.distance<=a.distance)?(s.distance3&&arguments[3]!==undefined&&arguments[3],l=function u(e){e.forEach((function(l,h){if(Array.isArray(l))u(l);else if(o.options.snapSegment){var c,p=l;c=s?h+1===e.length?0:h+1:h+1===e.length?undefined:h+1;var d=e[c];if(d){var f=o._getDistanceToSegment(i,t,p,d);(r===undefined||f1&&arguments[1]!==undefined?arguments[1]:1;t=t.sort((function(t,e){return t._leaflet_id-e._leaflet_id}));var i=["Marker","CircleMarker","Circle","Line","Polygon","Rectangle"],n=this._map.pm.globalOptions.snappingOrder||[],r=0,a={};return n.concat(i).forEach((function(t){a[t]||(r+=1,a[t]=r)})),t.sort(N("instanceofShape",a)),1===e?t[0]||{}:t.slice(0,e)},_checkPrioritiySnapping:function(t){var e=this._map,i=t.segment[0],n=t.segment[1],r=t.latlng,a=this._getDistance(e,i,r),o=this._getDistance(e,n,r),s=a1&&arguments[1]!==undefined&&arguments[1];this.options.pathOptions=i?e()(this.options.pathOptions,t):t},getShapes:function(){return this.shapes},getShape:function(){return this._shape},enable:function(t,e){if(!t)throw new Error("Error: Please pass a shape as a parameter. Possible shapes are: ".concat(this.getShapes().join(",")));this.disable(),this[t].enable(e)},disable:function(){var t=this;this.shapes.forEach((function(e){t[e].disable()}))},addControls:function(){var t=this;this.shapes.forEach((function(e){t[e].addButton()}))},getActiveShape:function(){var t,e=this;return this.shapes.forEach((function(i){e[i]._enabled&&(t=i)})),t},_setGlobalDrawMode:function(){"Cut"===this._shape?this._fireGlobalCutModeToggled():this._fireGlobalDrawModeToggled();var t=L.PM.Utils.findLayers(this._map);this._enabled?t.forEach((function(t){L.PM.Utils.disablePopup(t)})):t.forEach((function(t){L.PM.Utils.enablePopup(t)}))},createNewDrawInstance:function(t,e){var i=this._getShapeFromBtnName(e);if(this[t])throw new TypeError("Draw Type already exists");if(!L.PM.Draw[i])throw new TypeError("There is no class L.PM.Draw.".concat(i));return this[t]=new L.PM.Draw[i](this._map),this[t].toolbarButtonName=t,this[t]._shape=t,this.shapes.push(t),this[e]&&this[t].setOptions(this[e].options),this[t].setOptions(this[t].options),this[t]},_getShapeFromBtnName:function(t){var e={drawMarker:"Marker",drawCircle:"Circle",drawPolygon:"Polygon",drawPolyline:"Line",drawRectangle:"Rectangle",drawCircleMarker:"CircleMarker",editMode:"Edit",dragMode:"Drag",cutPolygon:"Cut",removalMode:"Removal",rotateMode:"Rotate",drawText:"Text"};return e[t]?e[t]:this[t]?this[t]._shape:t},_finishLayer:function(t){t.pm&&(t.pm.setOptions(this.options),t.pm._shape=this._shape,t.pm._map=this._map),this._addDrawnLayerProp(t)},_addDrawnLayerProp:function(t){t._drawnByGeoman=!0},_setPane:function(t,e){"layerPane"===e?t.options.pane=this._map.pm.globalOptions.panes&&this._map.pm.globalOptions.panes.layerPane||"overlayPane":"vertexPane"===e?t.options.pane=this._map.pm.globalOptions.panes&&this._map.pm.globalOptions.panes.vertexPane||"markerPane":"markerPane"===e&&(t.options.pane=this._map.pm.globalOptions.panes&&this._map.pm.globalOptions.panes.markerPane||"markerPane")},_isFirstLayer:function(){return 0===(this._map||this._layer._map).pm.getGeomanLayers().length}});it.Marker=it.extend({initialize:function(t){this._map=t,this._shape="Marker",this.toolbarButtonName="drawMarker"},enable:function(t){var e=this;L.Util.setOptions(this,t),this._enabled=!0,this._map.getContainer().classList.add("geoman-draw-cursor"),this._map.on("click",this._createMarker,this),this._map.pm.Toolbar.toggleButton(this.toolbarButtonName,!0),this._hintMarker=L.marker(this._map.getCenter(),this.options.markerStyle),this._setPane(this._hintMarker,"markerPane"),this._hintMarker._pmTempLayer=!0,this._hintMarker.addTo(this._map),this.options.tooltips&&this._hintMarker.bindTooltip(R("tooltips.placeMarker"),{permanent:!0,offset:L.point(0,10),direction:"bottom",opacity:.8}).openTooltip(),this._layer=this._hintMarker,this._map.on("mousemove",this._syncHintMarker,this),this.options.markerEditable&&this._map.eachLayer((function(t){e.isRelevantMarker(t)&&t.pm.enable()})),this._fireDrawStart(),this._setGlobalDrawMode()},disable:function(){var t=this;this._enabled&&(this._enabled=!1,this._map.getContainer().classList.remove("geoman-draw-cursor"),this._map.off("click",this._createMarker,this),this._hintMarker.remove(),this._map.off("mousemove",this._syncHintMarker,this),this._map.eachLayer((function(e){t.isRelevantMarker(e)&&e.pm.disable()})),this._map.pm.Toolbar.toggleButton(this.toolbarButtonName,!1),this.options.snappable&&this._cleanupSnapping(),this._fireDrawEnd(),this._setGlobalDrawMode())},enabled:function(){return this._enabled},toggle:function(t){this.enabled()?this.disable():this.enable(t)},isRelevantMarker:function(t){return t instanceof L.Marker&&t.pm&&!t._pmTempLayer&&!t.pm._initTextMarker},_syncHintMarker:function(t){if(this._hintMarker.setLatLng(t.latlng),this.options.snappable){var e=t;e.target=this._hintMarker,this._handleSnapping(e)}this._fireChange(this._hintMarker.getLatLng(),"Draw")},_createMarker:function(t){if(t.latlng&&(!this.options.requireSnapToFinish||this._hintMarker._snapped||this._isFirstLayer())){this._hintMarker._snapped||this._hintMarker.setLatLng(t.latlng);var e=this._hintMarker.getLatLng(),i=new L.Marker(e,this.options.markerStyle);this._setPane(i,"markerPane"),this._finishLayer(i),i.pm||(i.options.draggable=!1),i.addTo(this._map.pm._getContainingLayer()),i.pm&&this.options.markerEditable?i.pm.enable():i.dragging&&i.dragging.disable(),this._fireCreate(i),this._cleanupSnapping(),this.options.continueDrawing||this.disable()}},setStyle:function(){var t,e;null!==(t=this.options.markerStyle)&&void 0!==t&&t.icon&&(null===(e=this._hintMarker)||void 0===e||e.setIcon(this.options.markerStyle.icon))}});var nt=6371008.8,rt={centimeters:637100880,centimetres:637100880,degrees:57.22891354143274,feet:20902260.511392,inches:39.37*nt,kilometers:6371.0088,kilometres:6371.0088,meters:nt,metres:nt,miles:3958.761333810546,millimeters:6371008800,millimetres:6371008800,nauticalmiles:nt/1852,radians:1,yards:6967335.223679999};function at(t,e,i){void 0===i&&(i={});var n={type:"Feature"};return(0===i.id||i.id)&&(n.id=i.id),i.bbox&&(n.bbox=i.bbox),n.properties=e||{},n.geometry=t,n}function ot(t,e,i){if(void 0===i&&(i={}),!t)throw new Error("coordinates is required");if(!Array.isArray(t))throw new Error("coordinates must be an Array");if(t.length<2)throw new Error("coordinates must be at least 2 numbers long");if(!dt(t[0])||!dt(t[1]))throw new Error("coordinates must contain numbers");return at({type:"Point",coordinates:t},e,i)}function st(t,e,i){if(void 0===i&&(i={}),t.length<2)throw new Error("coordinates must be an array of two or more positions");return at({type:"LineString",coordinates:t},e,i)}function lt(t,e){void 0===e&&(e={});var i={type:"FeatureCollection"};return e.id&&(i.id=e.id),e.bbox&&(i.bbox=e.bbox),i.features=t,i}function ht(t,e){void 0===e&&(e="kilometers");var i=rt[e];if(!i)throw new Error(e+" units is invalid");return t*i}function ut(t,e){void 0===e&&(e="kilometers");var i=rt[e];if(!i)throw new Error(e+" units is invalid");return t/i}function ct(t){return 180*(t%(2*Math.PI))/Math.PI}function pt(t){return t%360*Math.PI/180}function dt(t){return!isNaN(t)&&null!==t&&!Array.isArray(t)}function ft(t){var e,i,n={type:"FeatureCollection",features:[]};if("LineString"===(i="Feature"===t.type?t.geometry:t).type)e=[i.coordinates];else if("MultiLineString"===i.type)e=i.coordinates;else if("MultiPolygon"===i.type)e=[].concat.apply([],i.coordinates);else{if("Polygon"!==i.type)throw new Error("Input must be a LineString, MultiLineString, Polygon, or MultiPolygon Feature or Geometry");e=i.coordinates}return e.forEach((function(t){e.forEach((function(e){for(var i=0;i=0&&h<=1&&(p.onLine1=!0),u>=0&&u<=1&&(p.onLine2=!0),!(!p.onLine1||!p.onLine2)&&[p.x,p.y])}function _t(t,e){var i=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),i.push.apply(i,n)}return i}function mt(t){for(var e=1;e=2&&!Array.isArray(t[0])&&!Array.isArray(t[1]))return t;throw new Error("coord must be GeoJSON Point or an Array of numbers")}function Mt(t){if(Array.isArray(t))return t;if("Feature"===t.type){if(null!==t.geometry)return t.geometry.coordinates}else if(t.coordinates)return t.coordinates;throw new Error("coords must be GeoJSON Feature, Geometry Object or an Array")}function xt(t){return"Feature"===t.type?t.geometry:t}function wt(t,e){return"FeatureCollection"===t.type?"FeatureCollection":"GeometryCollection"===t.type?"GeometryCollection":"Feature"===t.type&&null!==t.geometry?t.geometry.type:t.type}function Ct(t,e,i){if(null!==t)for(var n,r,a,o,s,l,h,u,c=0,p=0,d=t.type,f="FeatureCollection"===d,g="Feature"===d,_=f?t.features.length:1,m=0;m<_;m++){s=(u=!!(h=f?t.features[m].geometry:g?t.geometry:t)&&"GeometryCollection"===h.type)?h.geometries.length:1;for(var y=0;y0){var e=t[t.length-1];this._hintline.setLatLngs([e,this._hintMarker.getLatLng()])}},_syncHintMarker:function(t){if(this._hintMarker.setLatLng(t.latlng),this.options.snappable){var e=t;e.target=this._hintMarker,this._handleSnapping(e)}this.options.allowSelfIntersection||this._handleSelfIntersection(!0,this._hintMarker.getLatLng());var i=this._layer._defaultShape().slice();i.push(this._hintMarker.getLatLng()),this._change(i)},hasSelfIntersection:function(){return ft(this._layer.toGeoJSON(15)).features.length>0},_handleSelfIntersection:function(t,e){var i=L.polyline(this._layer.getLatLngs());t&&(e||(e=this._hintMarker.getLatLng()),i.addLatLng(e));var n=ft(i.toGeoJSON(15));this._doesSelfIntersect=n.features.length>0,this._doesSelfIntersect?this.isRed||(this.isRed=!0,this._hintline.setStyle({color:"#f00000ff"}),this._fireIntersect(n,this._map,"Draw")):this._hintline.isEmpty()||(this.isRed=!1,this._hintline.setStyle(this.options.hintlineStyle))},_createVertex:function(t){if(this.options.allowSelfIntersection||(this._handleSelfIntersection(!0,t.latlng),!this._doesSelfIntersect)){this._hintMarker._snapped||this._hintMarker.setLatLng(t.latlng);var e=this._hintMarker.getLatLng(),i=this._layer.getLatLngs(),n=i[i.length-1];if(e.equals(i[0])||i.length>0&&e.equals(n))this._finishShape();else{this._layer._latlngInfo=this._layer._latlngInfo||[],this._layer._latlngInfo.push({latlng:e,snapInfo:this._hintMarker._snapInfo}),this._layer.addLatLng(e);var r=this._createMarker(e);this._setTooltipText(),this._setHintLineAfterNewVertex(e),this._fireVertexAdded(r,undefined,e,"Draw"),this._change(this._layer.getLatLngs()),"snap"===this.options.finishOn&&this._hintMarker._snapped&&this._finishShape(t)}}},_setHintLineAfterNewVertex:function(t){this._hintline.setLatLngs([t,t])},_removeLastVertex:function(){var t=this._markers;if(t.length<=1)this.disable();else{var e=this._layer.getLatLngs(),i=t[t.length-1],n=L.PM.Utils.findDeepMarkerIndex(t,i).indexPath;t.pop(),this._layerGroup.removeLayer(i);var r=t[t.length-1],a=e.indexOf(r.getLatLng());e=e.slice(0,a+1),this._layer.setLatLngs(e),this._layer._latlngInfo.pop(),this._syncHintLine(),this._setTooltipText(),this._fireVertexRemoved(i,n,"Draw"),this._change(this._layer.getLatLngs())}},_finishShape:function(){if((this.options.allowSelfIntersection||(this._handleSelfIntersection(!1),!this._doesSelfIntersect))&&(!this.options.requireSnapToFinish||this._hintMarker._snapped||this._isFirstLayer())){var t=this._layer.getLatLngs();if(!(t.length<=1)){var e=L.polyline(t,this.options.pathOptions);this._setPane(e,"layerPane"),this._finishLayer(e),e.addTo(this._map.pm._getContainingLayer()),this._fireCreate(e),this.options.snappable&&this._cleanupSnapping(),this.disable(),this.options.continueDrawing&&this.enable()}}},_createMarker:function(t){var e=new L.Marker(t,{draggable:!1,icon:L.divIcon({className:"marker-icon"})});return this._setPane(e,"vertexPane"),e._pmTempLayer=!0,this._layerGroup.addLayer(e),this._markers.push(e),e.on("click",this._finishShape,this),e},_setTooltipText:function(){var t="";t=R(this._layer.getLatLngs().flat().length<=1?"tooltips.continueLine":"tooltips.finishLine"),this._hintMarker.setTooltipContent(t)},_change:function(t){this._fireChange(t,"Draw")},setStyle:function(){var t,e;null===(t=this._layer)||void 0===t||t.setStyle(this.options.templineStyle),null===(e=this._hintline)||void 0===e||e.setStyle(this.options.hintlineStyle)}}),it.Polygon=it.Line.extend({initialize:function(t){this._map=t,this._shape="Polygon",this.toolbarButtonName="drawPolygon"},enable:function(t){L.PM.Draw.Line.prototype.enable.call(this,t),this._layer.pm._shape="Polygon"},_createMarker:function(t){var e=new L.Marker(t,{draggable:!1,icon:L.divIcon({className:"marker-icon"})});return this._setPane(e,"vertexPane"),e._pmTempLayer=!0,this._layerGroup.addLayer(e),this._markers.push(e),1===this._layer.getLatLngs().flat().length?(e.on("click",this._finishShape,this),this._tempSnapLayerIndex=this._otherSnapLayers.push(e)-1,this.options.snappable&&this._cleanupSnapping()):e.on("click",(function(){return 1})),e},_setTooltipText:function(){var t="";t=R(this._layer.getLatLngs().flat().length<=2?"tooltips.continueLine":"tooltips.finishPoly"),this._hintMarker.setTooltipContent(t)},_finishShape:function(){if((this.options.allowSelfIntersection||(this._handleSelfIntersection(!0,this._layer.getLatLngs()[0]),!this._doesSelfIntersect))&&(!this.options.requireSnapToFinish||this._hintMarker._snapped||this._isFirstLayer())){var t=this._layer.getLatLngs();if(!(t.length<=2)){var e=L.polygon(t,this.options.pathOptions);this._setPane(e,"layerPane"),this._finishLayer(e),e.addTo(this._map.pm._getContainingLayer()),this._fireCreate(e),this._cleanupSnapping(),this._otherSnapLayers.splice(this._tempSnapLayerIndex,1),delete this._tempSnapLayerIndex,this.disable(),this.options.continueDrawing&&this.enable()}}}}),it.Rectangle=it.extend({initialize:function(t){this._map=t,this._shape="Rectangle",this.toolbarButtonName="drawRectangle"},enable:function(t){if(L.Util.setOptions(this,t),this._enabled=!0,this._layerGroup=new L.FeatureGroup,this._layerGroup._pmTempLayer=!0,this._layerGroup.addTo(this._map),this._layer=L.rectangle([[0,0],[0,0]],this.options.pathOptions),this._setPane(this._layer,"layerPane"),this._layer._pmTempLayer=!0,this._startMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"marker-icon rect-start-marker"}),draggable:!1,zIndexOffset:-100,opacity:this.options.cursorMarker?1:0}),this._setPane(this._startMarker,"vertexPane"),this._startMarker._pmTempLayer=!0,this._layerGroup.addLayer(this._startMarker),this._hintMarker=L.marker(this._map.getCenter(),{zIndexOffset:150,icon:L.divIcon({className:"marker-icon cursor-marker"})}),this._setPane(this._hintMarker,"vertexPane"),this._hintMarker._pmTempLayer=!0,this._layerGroup.addLayer(this._hintMarker),this.options.cursorMarker&&L.DomUtil.addClass(this._hintMarker._icon,"visible"),this.options.tooltips&&this._hintMarker.bindTooltip(R("tooltips.firstVertex"),{permanent:!0,offset:L.point(0,10),direction:"bottom",opacity:.8}).openTooltip(),this.options.cursorMarker){this._styleMarkers=[];for(var e=0;e<2;e+=1){var i=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"marker-icon rect-style-marker"}),draggable:!1,zIndexOffset:100});this._setPane(i,"vertexPane"),i._pmTempLayer=!0,this._layerGroup.addLayer(i),this._styleMarkers.push(i)}}this._map.getContainer().classList.add("geoman-draw-cursor"),this._map.on("click",this._placeStartingMarkers,this),this._map.on("mousemove",this._syncHintMarker,this),this._map.pm.Toolbar.toggleButton(this.toolbarButtonName,!0),this._otherSnapLayers=[],this._fireDrawStart(),this._setGlobalDrawMode()},disable:function(){this._enabled&&(this._enabled=!1,this._map.getContainer().classList.remove("geoman-draw-cursor"),this._map.off("click",this._finishShape,this),this._map.off("click",this._placeStartingMarkers,this),this._map.off("mousemove",this._syncHintMarker,this),this._map.removeLayer(this._layerGroup),this._map.pm.Toolbar.toggleButton(this.toolbarButtonName,!1),this.options.snappable&&this._cleanupSnapping(),this._fireDrawEnd(),this._setGlobalDrawMode())},enabled:function(){return this._enabled},toggle:function(t){this.enabled()?this.disable():this.enable(t)},_placeStartingMarkers:function(t){this._hintMarker._snapped||this._hintMarker.setLatLng(t.latlng);var e=this._hintMarker.getLatLng();L.DomUtil.addClass(this._startMarker._icon,"visible"),this._startMarker.setLatLng(e),this.options.cursorMarker&&this._styleMarkers&&this._styleMarkers.forEach((function(t){L.DomUtil.addClass(t._icon,"visible"),t.setLatLng(e)})),this._map.off("click",this._placeStartingMarkers,this),this._map.on("click",this._finishShape,this),this._hintMarker.setTooltipContent(R("tooltips.finishRect")),this._setRectangleOrigin()},_setRectangleOrigin:function(){var t=this._startMarker.getLatLng();t&&(this._layerGroup.addLayer(this._layer),this._layer.setLatLngs([t,t]),this._hintMarker.on("move",this._syncRectangleSize,this))},_syncHintMarker:function(t){if(this._hintMarker.setLatLng(t.latlng),this.options.snappable){var e=t;e.target=this._hintMarker,this._handleSnapping(e)}var i=this._layerGroup&&this._layerGroup.hasLayer(this._layer)?this._layer.getLatLngs():[this._hintMarker.getLatLng()];this._fireChange(i,"Draw")},_syncRectangleSize:function(){var t=this,e=U(this._startMarker.getLatLng(),this._map),i=U(this._hintMarker.getLatLng(),this._map),n=L.PM.Utils._getRotatedRectangle(e,i,this.options.rectangleAngle||0,this._map);if(this._layer.setLatLngs(n),this.options.cursorMarker&&this._styleMarkers){var r=[];n.forEach((function(t){t.equals(e,1e-8)||t.equals(i,1e-8)||r.push(t)})),r.forEach((function(e,i){try{t._styleMarkers[i].setLatLng(e)}catch(n){}}))}},_findCorners:function(){var t=this._layer.getLatLngs()[0];return L.PM.Utils._getRotatedRectangle(t[0],t[2],this.options.rectangleAngle||0,this._map)},_finishShape:function(t){this._hintMarker._snapped||this._hintMarker.setLatLng(t.latlng);var e=this._hintMarker.getLatLng(),i=this._startMarker.getLatLng();if(!this.options.requireSnapToFinish||this._hintMarker._snapped||this._isFirstLayer()){var n=L.rectangle([i,e],this.options.pathOptions);if(this.options.rectangleAngle){var r=L.PM.Utils._getRotatedRectangle(i,e,this.options.rectangleAngle||0,this._map);n.setLatLngs(r),n.pm&&n.pm._setAngle(this.options.rectangleAngle||0)}this._setPane(n,"layerPane"),this._finishLayer(n),n.addTo(this._map.pm._getContainingLayer()),this._fireCreate(n),this.disable(),this.options.continueDrawing&&this.enable()}},setStyle:function(){var t;null===(t=this._layer)||void 0===t||t.setStyle(this.options.pathOptions)}}),it.CircleMarker=it.extend({initialize:function(t){this._map=t,this._shape="CircleMarker",this.toolbarButtonName="drawCircleMarker",this._layerIsDragging=!1,this._BaseCircleClass=L.CircleMarker,this._minRadiusOption="minRadiusCircleMarker",this._maxRadiusOption="maxRadiusCircleMarker",this._editableOption="resizeableCircleMarker",this._defaultRadius=10},enable:function(t){if(L.Util.setOptions(this,t),this.options.editable&&(this.options.resizeableCircleMarker=this.options.editable,delete this.options.editable),this._enabled=!0,this._map.pm.Toolbar.toggleButton(this.toolbarButtonName,!0),this._map.getContainer().classList.add("geoman-draw-cursor"),this.options[this._editableOption]){var e={};L.extend(e,this.options.templineStyle),e.radius=0,this._layerGroup=new L.FeatureGroup,this._layerGroup._pmTempLayer=!0,this._layerGroup.addTo(this._map),this._layer=new this._BaseCircleClass(this._map.getCenter(),e),this._setPane(this._layer,"layerPane"),this._layer._pmTempLayer=!0,this._centerMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"marker-icon"}),draggable:!1,zIndexOffset:100}),this._setPane(this._centerMarker,"vertexPane"),this._centerMarker._pmTempLayer=!0,this._hintMarker=L.marker(this._map.getCenter(),{zIndexOffset:110,icon:L.divIcon({className:"marker-icon cursor-marker"})}),this._setPane(this._hintMarker,"vertexPane"),this._hintMarker._pmTempLayer=!0,this._layerGroup.addLayer(this._hintMarker),this.options.cursorMarker&&L.DomUtil.addClass(this._hintMarker._icon,"visible"),this.options.tooltips&&this._hintMarker.bindTooltip(R("tooltips.startCircle"),{permanent:!0,offset:L.point(0,10),direction:"bottom",opacity:.8}).openTooltip(),this._hintline=L.polyline([],this.options.hintlineStyle),this._setPane(this._hintline,"layerPane"),this._hintline._pmTempLayer=!0,this._layerGroup.addLayer(this._hintline),this._map.on("click",this._placeCenterMarker,this)}else this._map.on("click",this._createMarker,this),this._hintMarker=new this._BaseCircleClass(this._map.getCenter(),bt({radius:this._defaultRadius},this.options.templineStyle)),this._setPane(this._hintMarker,"layerPane"),this._hintMarker._pmTempLayer=!0,this._hintMarker.addTo(this._map),this._layer=this._hintMarker,this.options.tooltips&&this._hintMarker.bindTooltip(R("tooltips.placeCircleMarker"),{permanent:!0,offset:L.point(0,10),direction:"bottom",opacity:.8}).openTooltip();this._map.on("mousemove",this._syncHintMarker,this),this._extendingEnable(),this._otherSnapLayers=[],this._fireDrawStart(),this._setGlobalDrawMode()},_extendingEnable:function(){var t=this;!this.options[this._editableOption]&&this.options.markerEditable&&this._map.eachLayer((function(e){t.isRelevantMarker(e)&&e.pm.enable()})),this._layer.bringToBack()},disable:function(){this._enabled&&(this._enabled=!1,this._map.getContainer().classList.remove("geoman-draw-cursor"),this.options[this._editableOption]?(this._map.off("click",this._finishShape,this),this._map.off("click",this._placeCenterMarker,this),this._map.removeLayer(this._layerGroup)):(this._map.off("click",this._createMarker,this),this._extendingDisable(),this._hintMarker.remove()),this._map.off("mousemove",this._syncHintMarker,this),this._map.pm.Toolbar.toggleButton(this.toolbarButtonName,!1),this.options.snappable&&this._cleanupSnapping(),this._fireDrawEnd(),this._setGlobalDrawMode())},_extendingDisable:function(){var t=this;this._map.eachLayer((function(e){t.isRelevantMarker(e)&&e.pm.disable()}))},enabled:function(){return this._enabled},toggle:function(t){this.enabled()?this.disable():this.enable(t)},_placeCenterMarker:function(t){this._layerGroup.addLayer(this._layer),this._layerGroup.addLayer(this._centerMarker),this._hintMarker._snapped||this._hintMarker.setLatLng(t.latlng);var e=this._hintMarker.getLatLng();this._layerGroup.addLayer(this._layer),this._centerMarker.setLatLng(e),this._map.off("click",this._placeCenterMarker,this),this._map.on("click",this._finishShape,this),this._placeCircleCenter()},_placeCircleCenter:function(){var t=this._centerMarker.getLatLng();t&&(this._layer.setLatLng(t),this._hintMarker.on("move",this._syncHintLine,this),this._hintMarker.on("move",this._syncCircleRadius,this),this._hintMarker.setTooltipContent(R("tooltips.finishCircle")),this._fireCenterPlaced(),this._fireChange(this._layer.getLatLng(),"Draw"))},_syncHintLine:function(){var t=this._centerMarker.getLatLng(),e=this._getNewDestinationOfHintMarker();this._hintline.setLatLngs([t,e])},_syncCircleRadius:function(){var t=this._centerMarker.getLatLng(),e=this._hintMarker.getLatLng(),i=this._distanceCalculation(t,e);this.options[this._minRadiusOption]&&ithis.options[this._maxRadiusOption]?this._layer.setRadius(this.options[this._maxRadiusOption]):this._layer.setRadius(i)},_syncHintMarker:function(t){if(this._hintMarker.setLatLng(t.latlng),this._hintMarker.setLatLng(this._getNewDestinationOfHintMarker()),this.options.snappable){var e=t;e.target=this._hintMarker,this._handleSnapping(e)}this._handleHintMarkerSnapping();var i=this._layerGroup&&this._layerGroup.hasLayer(this._centerMarker)?this._centerMarker.getLatLng():this._hintMarker.getLatLng();this._fireChange(i,"Draw")},isRelevantMarker:function(t){return t instanceof L.CircleMarker&&!(t instanceof L.Circle)&&t.pm&&!t._pmTempLayer},_createMarker:function(t){if((!this.options.requireSnapToFinish||this._hintMarker._snapped||this._isFirstLayer())&&t.latlng&&!this._layerIsDragging){this._hintMarker._snapped||this._hintMarker.setLatLng(t.latlng);var e=this._hintMarker.getLatLng(),i=new this._BaseCircleClass(e,bt({radius:this._defaultRadius},this.options.pathOptions));this._setPane(i,"layerPane"),this._finishLayer(i),i.addTo(this._map.pm._getContainingLayer()),this._extendingCreateMarker(i),this._fireCreate(i),this._cleanupSnapping(),this.options.continueDrawing||this.disable()}},_extendingCreateMarker:function(t){t.pm&&this.options.markerEditable&&t.pm.enable()},_finishShape:function(t){if(!this.options.requireSnapToFinish||this._hintMarker._snapped||this._isFirstLayer()){this._hintMarker._snapped||this._hintMarker.setLatLng(t.latlng);var e=this._centerMarker.getLatLng(),i=this._defaultRadius;if(this.options[this._editableOption]){var n=this._hintMarker.getLatLng();i=this._distanceCalculation(e,n),this.options[this._minRadiusOption]&&ithis.options[this._maxRadiusOption]&&(i=this.options[this._maxRadiusOption])}var r=bt(bt({},this.options.pathOptions),{},{radius:i}),a=new this._BaseCircleClass(e,r);this._setPane(a,"layerPane"),this._finishLayer(a),a.addTo(this._map.pm._getContainingLayer()),a.pm&&a.pm._updateHiddenPolyCircle(),this._fireCreate(a),this.disable(),this.options.continueDrawing&&this.enable()}},_getNewDestinationOfHintMarker:function(){var t=this._hintMarker.getLatLng();if(this.options[this._editableOption]){if(!this._layerGroup.hasLayer(this._centerMarker))return t;var e=this._centerMarker.getLatLng(),i=this._distanceCalculation(e,t);this.options[this._minRadiusOption]&&ithis.options[this._maxRadiusOption]&&(t=z(this._map,e,t,this._getMaxDistanceInMeter()))}return t},_getMinDistanceInMeter:function(){return L.PM.Utils.pxRadiusToMeterRadius(this.options[this._minRadiusOption],this._map,this._centerMarker.getLatLng())},_getMaxDistanceInMeter:function(){return L.PM.Utils.pxRadiusToMeterRadius(this.options[this._maxRadiusOption],this._map,this._centerMarker.getLatLng())},_handleHintMarkerSnapping:function(){if(this.options[this._editableOption]){if(this._hintMarker._snapped){var t=this._centerMarker.getLatLng(),e=this._hintMarker.getLatLng(),i=this._distanceCalculation(t,e);this._layerGroup.hasLayer(this._centerMarker)&&(this.options[this._minRadiusOption]&&ithis.options[this._maxRadiusOption])&&this._hintMarker.setLatLng(this._hintMarker._orgLatLng)}this._hintMarker.setLatLng(this._getNewDestinationOfHintMarker())}},setStyle:function(){var t,e,i={};L.extend(i,this.options.templineStyle),this.options[this._editableOption]&&(i.radius=0),null===(t=this._layer)||void 0===t||t.setStyle(i),null===(e=this._hintline)||void 0===e||e.setStyle(this.options.hintlineStyle)},_distanceCalculation:function(t,e){return this._map.project(t).distanceTo(this._map.project(e))}}),it.Circle=it.CircleMarker.extend({initialize:function(t){this._map=t,this._shape="Circle",this.toolbarButtonName="drawCircle",this._BaseCircleClass=L.Circle,this._minRadiusOption="minRadiusCircle",this._maxRadiusOption="maxRadiusCircle",this._editableOption="resizableCircle",this._defaultRadius=100},_extendingEnable:function(){},_extendingDisable:function(){},_extendingCreateMarker:function(){},isRelevantMarker:function(){},_getMinDistanceInMeter:function(){return this.options[this._minRadiusOption]},_getMaxDistanceInMeter:function(){return this.options[this._maxRadiusOption]},_distanceCalculation:function(t,e){return this._map.distance(t,e)}});const Ot=function(t){if(!t)throw new Error("geojson is required");var e=[];return St(t,(function(t){!function(t,e){var i=[],n=t.geometry;if(null!==n){switch(n.type){case"Polygon":i=Mt(n);break;case"LineString":i=[Mt(n)]}i.forEach((function(i){var n=function(t,e){var i=[];return t.reduce((function(t,n){var r,a,o,s,l,h,u=st([t,n],e);return u.bbox=(a=n,o=(r=t)[0],s=r[1],l=a[0],h=a[1],[ol?o:l,s>h?s:h]),i.push(u),n})),i}(i,t.properties);n.forEach((function(t){t.id=e.length,e.push(t)}))}))}}(t,e)})),lt(e)};var Bt=i(1787);function Dt(t,e){var i=Mt(t),n=Mt(e);if(2!==i.length)throw new Error(" line1 must only contain 2 coordinates");if(2!==n.length)throw new Error(" line2 must only contain 2 coordinates");var r=i[0][0],a=i[0][1],o=i[1][0],s=i[1][1],l=n[0][0],h=n[0][1],u=n[1][0],c=n[1][1],p=(c-h)*(o-r)-(u-l)*(s-a),d=(u-l)*(a-h)-(c-h)*(r-l),f=(o-r)*(a-h)-(s-a)*(r-l);if(0===p)return null;var g=d/p,_=f/p;return g>=0&&g<=1&&_>=0&&_<=1?ot([r+g*(o-r),a+g*(s-a)]):null}const Rt=function(t,e){var i={},n=[];if("LineString"===t.type&&(t=at(t)),"LineString"===e.type&&(e=at(e)),"Feature"===t.type&&"Feature"===e.type&&null!==t.geometry&&null!==e.geometry&&"LineString"===t.geometry.type&&"LineString"===e.geometry.type&&2===t.geometry.coordinates.length&&2===e.geometry.coordinates.length){var r=Dt(t,e);return r&&n.push(r),lt(n)}var a=Bt();return a.load(Ot(e)),Pt(Ot(t),(function(t){Pt(a.search(t),(function(e){var r=Dt(t,e);if(r){var a=Mt(r).join(",");i[a]||(i[a]=!0,n.push(r))}}))})),lt(n)};const Tt=function(t,e,i){void 0===i&&(i={});var n=kt(t),r=kt(e),a=pt(r[1]-n[1]),o=pt(r[0]-n[0]),s=pt(n[1]),l=pt(r[1]),h=Math.pow(Math.sin(a/2),2)+Math.pow(Math.sin(o/2),2)*Math.cos(s)*Math.cos(l);return ht(2*Math.atan2(Math.sqrt(h),Math.sqrt(1-h)),i.units)};const It=function(t){var e=t[0],i=t[1],n=t[2],r=t[3];if(Tt(t.slice(0,2),[n,i])>=Tt(t.slice(0,2),[e,r])){var a=(i+r)/2;return[e,a-(n-e)/2,n,a+(n-e)/2]}var o=(e+n)/2;return[o-(r-i)/2,i,o+(r-i)/2,r]};function At(t){var e=[Infinity,Infinity,-Infinity,-Infinity];return Ct(t,(function(t){e[0]>t[0]&&(e[0]=t[0]),e[1]>t[1]&&(e[1]=t[1]),e[2] is required");if("number"!=typeof i)throw new Error(" must be a number");if("number"!=typeof n)throw new Error(" must be a number");!1!==r&&r!==undefined||(t=JSON.parse(JSON.stringify(t)));var a=Math.pow(10,i);return Ct(t,(function(t){!function(t,e,i){t.length>i&&t.splice(i,t.length);for(var n=0;n0&&((g=f.features[0]).properties.dist=Tt(e,g,i),g.properties.location=r+Tt(s,g,i)),s.properties.dist1&&i.push(st(h)),lt(i)}function Kt(t,e){if(!e.features.length)throw new Error("lines must contain features");if(1===e.features.length)return e.features[0];var i,n=Infinity;return Pt(e,(function(e){var r=Ft(e,t).properties.dist;r=t[0]&&e[3]>=t[1]}(n,o))return!1;"Polygon"===a&&(s=[s]);for(var l=!1,h=0;ht[1]!=h>t[1]&&t[0]<(l-o)*(t[1]-s)/(h-s)+o&&(n=!n)}return n}function Xt(t,e,i,n,r){var a=i[0],o=i[1],s=t[0],l=t[1],h=e[0],u=e[1],c=h-s,p=u-l,d=(i[0]-s)*p-(i[1]-l)*c;if(null!==r){if(Math.abs(d)>r)return!1}else if(0!==d)return!1;return n?"start"===n?Math.abs(c)>=Math.abs(p)?c>0?s0?l=Math.abs(p)?c>0?s<=a&&a0?l<=o&&o=Math.abs(p)?c>0?s0?l=Math.abs(p)?c>0?s<=a&&a<=h:h<=a&&a<=s:p>0?l<=o&&o<=u:u<=o&&o<=l}const Zt=function(t,e,i){void 0===i&&(i={});for(var n=kt(t),r=Mt(e),a=0;ae[0])&&(!(t[2]e[1])&&!(t[3]1?e.forEach((function(t){n.push(function(t){return ne({type:"LineString",coordinates:t})}(t))})):n.push(t),n}function ue(t){var e=[];return t.eachLayer((function(t){e.push(ae(t.toGeoJSON(15)))})),function(t){return ne({type:"MultiLineString",coordinates:t})}(e)}function ce(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var i=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null==i)return;var n,r,a=[],o=!0,s=!1;try{for(i=i.call(t);!(o=(n=i.next()).done)&&(a.push(n.value),!e||a.length!==e);o=!0);}catch(l){s=!0,r=l}finally{try{o||null==i["return"]||i["return"]()}finally{if(s)throw r}}return a}(t,e)||function(t,e){if(!t)return;if("string"==typeof t)return pe(t,e);var i=Object.prototype.toString.call(t).slice(8,-1);"Object"===i&&t.constructor&&(i=t.constructor.name);if("Map"===i||"Set"===i)return Array.from(t);if("Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i))return pe(t,e)}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function pe(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);it.length)&&(e=t.length);for(var i=0,n=new Array(e);i0)||e.options.layersToCut.indexOf(t)>-1})).filter((function(t){return!e._layerGroup.hasLayer(t)})).filter((function(e){try{var i=!!Rt(t.toGeoJSON(15),e.toGeoJSON(15)).features.length>0;return i||e instanceof L.Polyline&&!(e instanceof L.Polygon)?i:(n=t.toGeoJSON(15),r=e.toGeoJSON(15),a=re(n),o=re(r),!(0===(s=ie().intersection(a.coordinates,o.coordinates)).length||!(1===s.length?oe(s[0]):se(s))))}catch(l){return e instanceof L.Polygon&&console.error("You can't cut polygons with self-intersections"),!1}var n,r,a,o,s})).forEach((function(i){var r;if(i instanceof L.Polygon){var a=(r=L.polygon(i.getLatLngs())).getLatLngs();n.forEach((function(t){if(t&&t.snapInfo){var i=t.latlng,n=e._calcClosestLayer(i,[r]);if(n&&n.segment&&n.distance1?O()(a,h):a).splice(u,0,i)}}}}))}else r=i;var o=e._cutLayer(t,r),s=L.geoJSON(o,i.options);if(1===s.getLayers().length){var l=s.getLayers();s=ce(l,1)[0]}e._setPane(s,"layerPane");var h=s.addTo(e._map.pm._getContainingLayer());if(h.pm.enable(i.pm.options),h.pm.disable(),i._pmTempLayer=!0,t._pmTempLayer=!0,i.remove(),i.removeFrom(e._map.pm._getContainingLayer()),t.remove(),t.removeFrom(e._map.pm._getContainingLayer()),h.getLayers&&0===h.getLayers().length&&e._map.pm.removeLayer({target:h}),h instanceof L.LayerGroup?(h.eachLayer((function(t){e._addDrawnLayerProp(t)})),e._addDrawnLayerProp(h)):e._addDrawnLayerProp(h),e.options.layersToCut&&L.Util.isArray(e.options.layersToCut)&&e.options.layersToCut.length>0){var u=e.options.layersToCut.indexOf(i);u>-1&&e.options.layersToCut.splice(u,1)}e._editedLayers.push({layer:h,originalLayer:i})}))},_cutLayer:function(t,e){var i,n,r,a,o,s,l=L.geoJSON();if(e instanceof L.Polygon)n=e.toGeoJSON(15),r=t.toGeoJSON(15),a=re(n),o=re(r),i=0===(s=ie().difference(a.coordinates,o.coordinates)).length?null:1===s.length?oe(s[0]):se(s);else{var h=he(e);h.forEach((function(e){var i=Ht(e,t.toGeoJSON(15));(i&&i.features.length>0?L.geoJSON(i):L.geoJSON(e)).getLayers().forEach((function(e){$t(t.toGeoJSON(15),e.toGeoJSON(15))||e.addTo(l)}))})),i=h.length>1?ue(l):l.toGeoJSON(15)}return i},_change:L.Util.falseFn}),it.Text=it.extend({initialize:function(t){this._map=t,this._shape="Text",this.toolbarButtonName="drawText"},enable:function(t){L.Util.setOptions(this,t),this._enabled=!0,this._map.on("click",this._createMarker,this),this._map.pm.Toolbar.toggleButton(this.toolbarButtonName,!0),this._hintMarker=L.marker(this._map.getCenter(),{interactive:!1,zIndexOffset:100,icon:L.divIcon({className:"marker-icon cursor-marker"})}),this._setPane(this._hintMarker,"vertexPane"),this._hintMarker._pmTempLayer=!0,this._hintMarker.addTo(this._map),this.options.cursorMarker&&L.DomUtil.addClass(this._hintMarker._icon,"visible"),this.options.tooltips&&this._hintMarker.bindTooltip(R("tooltips.placeText"),{permanent:!0,offset:L.point(0,10),direction:"bottom",opacity:.8}).openTooltip(),this._layer=this._hintMarker,this._map.on("mousemove",this._syncHintMarker,this),this._map.getContainer().classList.add("geoman-draw-cursor"),this._fireDrawStart(),this._setGlobalDrawMode()},disable:function(){this._enabled&&(this._enabled=!1,this._map.off("click",this._createMarker,this),this._hintMarker.remove(),this._map.getContainer().classList.remove("geoman-draw-cursor"),this._map.off("mousemove",this._syncHintMarker,this),this._map.pm.Toolbar.toggleButton(this.toolbarButtonName,!1),this.options.snappable&&this._cleanupSnapping(),this._fireDrawEnd(),this._setGlobalDrawMode())},enabled:function(){return this._enabled},toggle:function(t){this.enabled()?this.disable():this.enable(t)},_syncHintMarker:function(t){if(this._hintMarker.setLatLng(t.latlng),this.options.snappable){var e=t;e.target=this._hintMarker,this._handleSnapping(e)}},_createMarker:function(t){var e;if(t.latlng&&(!this.options.requireSnapToFinish||this._hintMarker._snapped||this._isFirstLayer())){this._hintMarker._snapped||this._hintMarker.setLatLng(t.latlng);var i=this._hintMarker.getLatLng();if(this.textArea=this._createTextArea(),null!==(e=this.options.textOptions)&&void 0!==e&&e.className){var n,r=this.options.textOptions.className.split(" ");(n=this.textArea.classList).add.apply(n,de(r))}var a=this._createTextIcon(this.textArea),o=new L.Marker(i,{textMarker:!0,_textMarkerOverPM:!0,icon:a});if(this._setPane(o,"markerPane"),this._finishLayer(o),o.pm||(o.options.draggable=!1),o.addTo(this._map.pm._getContainingLayer()),o.pm){var s,l,h,u,c;o.pm.textArea=this.textArea,L.setOptions(o.pm,{removeIfEmpty:null===(s=null===(l=this.options.textOptions)||void 0===l?void 0:l.removeIfEmpty)||void 0===s||s});var p=null===(h=null===(u=this.options.textOptions)||void 0===u?void 0:u.focusAfterDraw)||void 0===h||h;o.pm._createTextMarker(p),null!==(c=this.options.textOptions)&&void 0!==c&&c.text&&o.pm.setText(this.options.textOptions.text)}this._fireCreate(o),this._cleanupSnapping(),this.disable(),this.options.continueDrawing&&this.enable()}},_createTextArea:function(){var t=document.createElement("textarea");return t.readOnly=!0,t.classList.add("pm-textarea","pm-disabled"),t},_createTextIcon:function(t){return L.divIcon({className:"pm-text-marker",html:t})}});const ge={enableLayerDrag:function(){if(this.options.draggable&&this._layer._map){this.disable(),this._layerDragEnabled=!0,this._map||(this._map=this._layer._map),(this._layer instanceof L.Marker||this._layer instanceof L.ImageOverlay)&&L.DomEvent.on(this._getDOMElem(),"dragstart",this._stopDOMImageDrag),this._layer.dragging&&this._layer.dragging.disable(),this._tempDragCoord=null,V(this._layer)instanceof L.Canvas?(this._layer.on("mouseout",this.removeDraggingClass,this),this._layer.on("mouseover",this.addDraggingClass,this)):this.addDraggingClass(),this._originalMapDragState=this._layer._map.dragging._enabled,this._safeToCacheDragState=!0;var t=this._getDOMElem();t&&(V(this._layer)instanceof L.Canvas?(this._layer.on("touchstart mousedown",this._dragMixinOnMouseDown,this),this._map.pm._addTouchEvents(t)):L.DomEvent.on(t,"touchstart mousedown",this._simulateMouseDownEvent,this)),this._fireDragEnable()}},disableLayerDrag:function(){this._layerDragEnabled=!1,V(this._layer)instanceof L.Canvas?(this._layer.off("mouseout",this.removeDraggingClass,this),this._layer.off("mouseover",this.addDraggingClass,this)):this.removeDraggingClass(),this._originalMapDragState&&this._dragging&&this._map.dragging.enable(),this._safeToCacheDragState=!1,this._layer.dragging&&this._layer.dragging.disable();var t=this._getDOMElem();t&&(V(this._layer)instanceof L.Canvas?(this._layer.off("touchstart mousedown",this._dragMixinOnMouseDown,this),this._map.pm._removeTouchEvents(t)):L.DomEvent.off(t,"touchstart mousedown",this._simulateMouseDownEvent,this)),this._layerDragged&&this._fireUpdate(),this._layerDragged=!1,this._fireDragDisable()},dragging:function(){return this._dragging},layerDragEnabled:function(){return!!this._layerDragEnabled},_simulateMouseDownEvent:function(t){var e=t.touches?t.touches[0]:t,i={originalEvent:e,target:this._layer};return i.containerPoint=this._map.mouseEventToContainerPoint(e),i.latlng=this._map.containerPointToLatLng(i.containerPoint),this._dragMixinOnMouseDown(i),!1},_simulateMouseMoveEvent:function(t){var e=t.touches?t.touches[0]:t,i={originalEvent:e,target:this._layer};return i.containerPoint=this._map.mouseEventToContainerPoint(e),i.latlng=this._map.containerPointToLatLng(i.containerPoint),this._dragMixinOnMouseMove(i),!1},_simulateMouseUpEvent:function(t){var e={originalEvent:t.touches?t.touches[0]:t,target:this._layer};return-1===t.type.indexOf("touch")&&(e.containerPoint=this._map.mouseEventToContainerPoint(t),e.latlng=this._map.containerPointToLatLng(e.containerPoint)),this._dragMixinOnMouseUp(e),!1},_dragMixinOnMouseDown:function(t){if(!(t.originalEvent.button>0)){this._overwriteEventIfItComesFromMarker(t);var e=t._fromLayerSync,i=this._syncLayers("_dragMixinOnMouseDown",t);if(this._layer instanceof L.Marker&&(!this.options.snappable||e||i?this._disableSnapping():this._initSnappableMarkers()),this._layer instanceof L.CircleMarker){var n="resizeableCircleMarker";this._layer instanceof L.Circle&&(n="resizableCircle"),!this.options.snappable||e||i?this._layer.pm.options[n]?this._layer.pm._disableSnapping():this._layer.pm._disableSnappingDrag():this._layer.pm.options[n]||this._initSnappableMarkersDrag()}this._safeToCacheDragState&&(this._originalMapDragState=this._layer._map.dragging._enabled,this._safeToCacheDragState=!1),this._tempDragCoord=t.latlng,L.DomEvent.on(this._map.getContainer(),"touchend mouseup",this._simulateMouseUpEvent,this),L.DomEvent.on(this._map.getContainer(),"touchmove mousemove",this._simulateMouseMoveEvent,this)}},_dragMixinOnMouseMove:function(t){this._overwriteEventIfItComesFromMarker(t);var e=this._getDOMElem();this._syncLayers("_dragMixinOnMouseMove",t),this._dragging||(this._dragging=!0,L.DomUtil.addClass(e,"leaflet-pm-dragging"),this._layer instanceof L.Marker||this._layer.bringToFront(),this._originalMapDragState&&this._map.dragging.disable(),this._fireDragStart()),this._tempDragCoord||(this._tempDragCoord=t.latlng),this._onLayerDrag(t),this._layer instanceof L.CircleMarker&&this._layer.pm._updateHiddenPolyCircle()},_dragMixinOnMouseUp:function(t){var e=this,i=this._getDOMElem();return this._syncLayers("_dragMixinOnMouseUp",t),this._originalMapDragState&&this._map.dragging.enable(),this._safeToCacheDragState=!0,L.DomEvent.off(this._map.getContainer(),"touchmove mousemove",this._simulateMouseMoveEvent,this),L.DomEvent.off(this._map.getContainer(),"touchend mouseup",this._simulateMouseUpEvent,this),!!this._dragging&&(this._layer instanceof L.CircleMarker&&this._layer.pm._updateHiddenPolyCircle(),this._layerDragged=!0,window.setTimeout((function(){e._dragging=!1,i&&L.DomUtil.removeClass(i,"leaflet-pm-dragging"),e._fireDragEnd(),e._fireEdit(),e._layerEdited=!0}),10),!0)},_onLayerDrag:function(t){var e=t.latlng,i=e.lat-this._tempDragCoord.lat,n=e.lng-this._tempDragCoord.lng,r=function u(t){return t.map((function(t){if(Array.isArray(t))return u(t);var e={lat:t.lat+i,lng:t.lng+n};return(t.alt||0===t.alt)&&(e.alt=t.alt),e}))};if(this._layer instanceof L.Circle&&this._layer.options.resizableCircle||this._layer instanceof L.CircleMarker&&this._layer.options.resizeableCircleMarker){var a=r([this._layer.getLatLng()]);this._layer.setLatLng(a[0]),this._fireChange(this._layer.getLatLng(),"Edit")}else if(this._layer instanceof L.CircleMarker||this._layer instanceof L.Marker){var o=this._layer.getLatLng();this._layer._snapped&&(o=this._layer._orgLatLng);var s=r([o]);this._layer.setLatLng(s[0]),this._fireChange(this._layer.getLatLng(),"Edit")}else if(this._layer instanceof L.ImageOverlay){var l=r([this._layer.getBounds().getNorthWest(),this._layer.getBounds().getSouthEast()]);this._layer.setBounds(l),this._fireChange(this._layer.getBounds(),"Edit")}else{var h=r(this._layer.getLatLngs());this._layer.setLatLngs(h),this._fireChange(this._layer.getLatLngs(),"Edit")}this._tempDragCoord=e,t.layer=this._layer,this._fireDrag(t)},addDraggingClass:function(){var t=this._getDOMElem();t&&L.DomUtil.addClass(t,"leaflet-pm-draggable")},removeDraggingClass:function(){var t=this._getDOMElem();t&&L.DomUtil.removeClass(t,"leaflet-pm-draggable")},_getDOMElem:function(){var t=null;return this._layer._path?t=this._layer._path:this._layer._renderer&&this._layer._renderer._container?t=this._layer._renderer._container:this._layer._image?t=this._layer._image:this._layer._icon&&(t=this._layer._icon),t},_overwriteEventIfItComesFromMarker:function(t){t.target.getLatLng&&(!t.target._radius||t.target._radius<=10)&&(t.containerPoint=this._map.mouseEventToContainerPoint(t.originalEvent),t.latlng=this._map.containerPointToLatLng(t.containerPoint))},_syncLayers:function(t,e){var i=this;if(this.enabled())return!1;if(!e._fromLayerSync&&this._layer===e.target&&this.options.syncLayersOnDrag){e._fromLayerSync=!0;var n=[];if(L.Util.isArray(this.options.syncLayersOnDrag))n=this.options.syncLayersOnDrag,this.options.syncLayersOnDrag.forEach((function(t){t instanceof L.LayerGroup&&(n=n.concat(t.pm.getLayers(!0)))}));else if(!0===this.options.syncLayersOnDrag&&this._parentLayerGroup)for(var r in this._parentLayerGroup){var a=this._parentLayerGroup[r];a.pm&&(n=a.pm.getLayers(!0))}return L.Util.isArray(n)&&n.length>0&&(n=n.filter((function(t){return!!t.pm})).filter((function(t){return!!t.pm.options.draggable}))).forEach((function(n){n!==i._layer&&n.pm[t]&&(n._snapped=!1,n.pm[t](e))})),n.length>0}return!1},_stopDOMImageDrag:function(t){return t.preventDefault(),!1}};function _e(t,e,i){var n=i.getMaxZoom();if(n===Infinity&&(n=i.getZoom()),L.Util.isArray(t)){var r=[];return t.forEach((function(t){r.push(_e(t,e,i))})),r}return t instanceof L.LatLng?function(t,e,i,n){return i.unproject(e.transform(i.project(t,n)),n)}(t,e,i,n):null}function me(t,e){e instanceof L.Layer&&(e=e.getLatLng());var i=t.getMaxZoom();return i===Infinity&&(i=t.getZoom()),t.project(e,i)}function ye(t,e){var i=t.getMaxZoom();return i===Infinity&&(i=t.getZoom()),t.unproject(e,i)}var ve={_onRotateStart:function(t){this._preventRenderingMarkers(!0),this._rotationOriginLatLng=this._getRotationCenter().clone(),this._rotationOriginPoint=me(this._map,this._rotationOriginLatLng),this._rotationStartPoint=me(this._map,t.target.getLatLng()),this._initialRotateLatLng=F(this._layer),this._startAngle=this.getAngle();var e=F(this._rotationLayer,this._rotationLayer.pm._rotateOrgLatLng);this._fireRotationStart(this._rotationLayer,e),this._fireRotationStart(this._map,e)},_onRotate:function(t){var e=me(this._map,t.target.getLatLng()),i=this._rotationStartPoint,n=this._rotationOriginPoint,r=Math.atan2(e.y-n.y,e.x-n.x)-Math.atan2(i.y-n.y,i.x-n.x);this._layer.setLatLngs(this._rotateLayer(r,this._initialRotateLatLng,this._rotationOriginLatLng,L.PM.Matrix.init(),this._map));var a=this;!function h(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:[],i=arguments.length>2&&arguments[2]!==undefined?arguments[2]:-1;if(i>-1&&e.push(i),L.Util.isArray(t[0]))t.forEach((function(t,i){return h(t,e.slice(),i)}));else{var n=O()(a._markers,e);t.forEach((function(t,e){n[e].setLatLng(t)}))}}(this._layer.getLatLngs());var o=F(this._rotationLayer);this._rotationLayer.setLatLngs(this._rotateLayer(r,this._rotationLayer.pm._rotateOrgLatLng,this._rotationOriginLatLng,L.PM.Matrix.init(),this._map));var s=180*r/Math.PI,l=(s=s<0?s+360:s)+this._startAngle;this._setAngle(l),this._rotationLayer.pm._setAngle(l),this._fireRotation(this._rotationLayer,s,o),this._fireRotation(this._map,s,o),this._rotationLayer.pm._fireChange(this._rotationLayer.getLatLngs(),"Rotation")},_onRotateEnd:function(){var t=this._startAngle;delete this._rotationOriginLatLng,delete this._rotationOriginPoint,delete this._rotationStartPoint,delete this._initialRotateLatLng,delete this._startAngle;var e=F(this._rotationLayer,this._rotationLayer.pm._rotateOrgLatLng);this._rotationLayer.pm._rotateOrgLatLng=F(this._rotationLayer),this._fireRotationEnd(this._rotationLayer,t,e),this._fireRotationEnd(this._map,t,e),this._rotationLayer.pm._fireEdit(this._rotationLayer,"Rotation"),this._preventRenderingMarkers(!1),this._layerRotated=!0},_rotateLayer:function(t,e,i,n,r){var a=me(r,i);return this._matrix=n.clone().rotate(t,a).flip(),_e(e,this._matrix,r)},_setAngle:function(t){t=t<0?t+360:t,this._angle=t%360},_getRotationCenter:function(){if(this._rotationCenter)return this._rotationCenter;var t=L.polygon(this._layer.getLatLngs(),{stroke:!1,fill:!1,pmIgnore:!0}).addTo(this._layer._map),e=t.getCenter();return t.removeFrom(this._layer._map),e},enableRotate:function(){if(this.options.allowRotation){this.rotateEnabled()&&this.disableRotate(),this._layer instanceof L.Rectangle&&this._angle===undefined&&this.setInitAngle(G(this._layer._map,this._layer.getLatLngs()[0][0],this._layer.getLatLngs()[0][1])||0);this._rotatePoly=L.polygon(this._layer.getLatLngs(),{fill:!1,stroke:!1,pmIgnore:!1,snapIgnore:!0}),this._rotatePoly._pmTempLayer=!0,this._rotatePoly.addTo(this._layer._map),this._rotatePoly.pm._setAngle(this.getAngle()),this._rotatePoly.pm.setRotationCenter(this.getRotationCenter()),this._rotatePoly.pm.setOptions(this._layer._map.pm.getGlobalOptions()),this._rotatePoly.pm.setOptions({rotate:!0,snappable:!1,hideMiddleMarkers:!0}),this._rotatePoly.pm._rotationLayer=this._layer,this._rotatePoly.pm.enable(),this._rotateOrgLatLng=F(this._layer),this._rotateEnabled=!0,this._layer.on("remove",this.disableRotate,this),this._fireRotationEnable(this._layer),this._fireRotationEnable(this._layer._map)}else this.disableRotate()},disableRotate:function(){this.rotateEnabled()&&(this._rotatePoly.pm._layerRotated&&this._fireUpdate(),this._rotatePoly.pm._layerRotated=!1,this._rotatePoly.pm.disable(),this._rotatePoly.remove(),this._rotatePoly.pm.setOptions({rotate:!1}),this._rotatePoly=undefined,this._rotateOrgLatLng=undefined,this._layer.off("remove",this.disableRotate,this),this._rotateEnabled=!1,this._fireRotationDisable(this._layer),this._fireRotationDisable(this._layer._map))},rotateEnabled:function(){return this._rotateEnabled},rotateLayer:function(t){var e=this.getAngle(),i=this._layer.getLatLngs(),n=t*(Math.PI/180);this._layer.setLatLngs(this._rotateLayer(n,this._layer.getLatLngs(),this._getRotationCenter(),L.PM.Matrix.init(),this._layer._map)),this._rotateOrgLatLng=L.polygon(this._layer.getLatLngs()).getLatLngs(),this._setAngle(this.getAngle()+t),this.rotateEnabled()&&this._rotatePoly&&this._rotatePoly.pm.enabled()&&(this._rotatePoly.setLatLngs(this._rotateLayer(n,this._rotatePoly.getLatLngs(),this._getRotationCenter(),L.PM.Matrix.init(),this._rotatePoly._map)),this._rotatePoly.pm._initMarkers());var r=this.getAngle()-e;r=r<0?r+360:r,this._startAngle=e,this._fireRotation(this._layer,r,i,this._layer),this._fireRotation(this._map||this._layer._map,r,i,this._layer),delete this._startAngle,this._fireChange(this._layer.getLatLngs(),"Rotation")},rotateLayerToAngle:function(t){var e=t-this.getAngle();this.rotateLayer(e)},getAngle:function(){return this._angle||0},setInitAngle:function(t){this._setAngle(t)},getRotationCenter:function(){return this._getRotationCenter()},setRotationCenter:function(t){this._rotationCenter=t,this._rotatePoly&&this._rotatePoly.pm.setRotationCenter(t)}};const be=ve;const Le=L.Class.extend({includes:[ge,et,be,P],options:{snappable:!0,snapDistance:20,allowSelfIntersection:!0,allowSelfIntersectionEdit:!1,preventMarkerRemoval:!1,removeLayerBelowMinVertexCount:!0,limitMarkersToCount:-1,hideMiddleMarkers:!1,snapSegment:!0,syncLayersOnDrag:!1,draggable:!0,allowEditing:!0,allowRemoval:!0,allowCutting:!0,allowRotation:!0,addVertexOn:"click",removeVertexOn:"contextmenu",removeVertexValidation:undefined,addVertexValidation:undefined,moveVertexValidation:undefined,resizeableCircleMarker:!1,resizableCircle:!0},setOptions:function(t){L.Util.setOptions(this,t)},getOptions:function(){return this.options},applyOptions:function(){},isPolygon:function(){return this._layer instanceof L.Polygon},getShape:function(){return this._shape},_setPane:function(t,e){"layerPane"===e?t.options.pane=this._map.pm.globalOptions.panes&&this._map.pm.globalOptions.panes.layerPane||"overlayPane":"vertexPane"===e?t.options.pane=this._map.pm.globalOptions.panes&&this._map.pm.globalOptions.panes.vertexPane||"markerPane":"markerPane"===e&&(t.options.pane=this._map.pm.globalOptions.panes&&this._map.pm.globalOptions.panes.markerPane||"markerPane")},remove:function(){(this._map||this._layer._map).pm.removeLayer({target:this._layer})},_vertexValidation:function(t,e){var i=e.target,n={layer:this._layer,marker:i,event:e},r="";return"move"===t?r="moveVertexValidation":"add"===t?r="addVertexValidation":"remove"===t&&(r="removeVertexValidation"),this.options[r]&&"function"==typeof this.options[r]&&!this.options[r](n)?("move"===t&&(i._cancelDragEventChain=i.getLatLng()),!1):(i._cancelDragEventChain=null,!0)},_vertexValidationDrag:function(t){return!t._cancelDragEventChain||(t._latlng=t._cancelDragEventChain,t.update(),!1)},_vertexValidationDragEnd:function(t){return!t._cancelDragEventChain||(t._cancelDragEventChain=null,!1)}});function ke(t){return function(t){if(Array.isArray(t))return Me(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(!t)return;if("string"==typeof t)return Me(t,e);var i=Object.prototype.toString.call(t).slice(8,-1);"Object"===i&&t.constructor&&(i=t.constructor.name);if("Map"===i||"Set"===i)return Array.from(t);if("Arguments"===i||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(i))return Me(t,e)}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Me(t,e){(null==e||e>t.length)&&(e=t.length);for(var i=0,n=new Array(e);i0&&e._getMap()&&e._getMap().pm.globalEditModeEnabled()&&e.enabled()&&e.enable(e.getOptions())}}),100,this),this),this._layerGroup.on("layerremove",(function(t){e._removeLayerFromGroup(t.target)}),this);this._layerGroup.on("layerremove",L.Util.throttle((function(t){t.target._pmTempLayer||(e._layers=e.getLayers())}),100,this),this)},enable:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:[];0===e.length&&(this._layers=this.getLayers()),this._options=t,this._layers.forEach((function(i){i instanceof L.LayerGroup?-1===e.indexOf(i._leaflet_id)&&(e.push(i._leaflet_id),i.pm.enable(t,e)):i.pm.enable(t)}))},disable:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:[];0===t.length&&(this._layers=this.getLayers()),this._layers.forEach((function(e){e instanceof L.LayerGroup?-1===t.indexOf(e._leaflet_id)&&(t.push(e._leaflet_id),e.pm.disable(t)):e.pm.disable()}))},enabled:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:[];0===t.length&&(this._layers=this.getLayers());var e=this._layers.find((function(e){return e instanceof L.LayerGroup?-1===t.indexOf(e._leaflet_id)&&(t.push(e._leaflet_id),e.pm.enabled(t)):e.pm.enabled()}));return!!e},toggleEdit:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:[];0===e.length&&(this._layers=this.getLayers()),this._options=t,this._layers.forEach((function(i){i instanceof L.LayerGroup?-1===e.indexOf(i._leaflet_id)&&(e.push(i._leaflet_id),i.pm.toggleEdit(t,e)):i.pm.toggleEdit(t)}))},_initLayer:function(t){var e=L.Util.stamp(this._layerGroup);t.pm._parentLayerGroup||(t.pm._parentLayerGroup={}),t.pm._parentLayerGroup[e]=this._layerGroup},_removeLayerFromGroup:function(t){if(t.pm&&t.pm._layerGroup){var e=L.Util.stamp(this._layerGroup);delete t.pm._layerGroup[e]}},dragging:function(){if(this._layers=this.getLayers(),this._layers){var t=this._layers.find((function(t){return t.pm.dragging()}));return!!t}return!1},getOptions:function(){return this.options},_getMap:function(){var t;return this._map||(null===(t=this._layers.find((function(t){return!!t._map})))||void 0===t?void 0:t._map)||null},getLayers:function(){var t=arguments.length>0&&arguments[0]!==undefined&&arguments[0],e=!(arguments.length>1&&arguments[1]!==undefined)||arguments[1],i=!(arguments.length>2&&arguments[2]!==undefined)||arguments[2],n=arguments.length>3&&arguments[3]!==undefined?arguments[3]:[],r=[];return t?this._layerGroup.getLayers().forEach((function(t){r.push(t),t instanceof L.LayerGroup&&-1===n.indexOf(t._leaflet_id)&&(n.push(t._leaflet_id),r=r.concat(t.pm.getLayers(!0,!0,!0,n)))})):r=this._layerGroup.getLayers(),i&&(r=r.filter((function(t){return!(t instanceof L.LayerGroup)}))),e&&(r=(r=(r=r.filter((function(t){return!!t.pm}))).filter((function(t){return!t._pmTempLayer}))).filter((function(t){return!L.PM.optIn&&!t.options.pmIgnore||L.PM.optIn&&!1===t.options.pmIgnore}))),r},setOptions:function(t){var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:[];0===e.length&&(this._layers=this.getLayers()),this.options=t,this._layers.forEach((function(i){i.pm&&(i instanceof L.LayerGroup?-1===e.indexOf(i._leaflet_id)&&(e.push(i._leaflet_id),i.pm.setOptions(t,e)):i.pm.setOptions(t))}))}}),Le.Marker=Le.extend({_shape:"Marker",initialize:function(t){this._layer=t,this._enabled=!1,this._layer.on("dragend",this._onDragEnd,this)},enable:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{draggable:!0};L.Util.setOptions(this,t),this.options.allowEditing&&this._layer._map?(this._map=this._layer._map,this.enabled()&&this.disable(),this.applyOptions(),this._layer.on("remove",this.disable,this),this._enabled=!0,this._fireEnable()):this.disable()},disable:function(){this.enabled()&&(this.disableLayerDrag(),this._layer.off("remove",this.disable,this),this._layer.off("contextmenu",this._removeMarker,this),this._layerEdited&&this._fireUpdate(),this._layerEdited=!1,this._fireDisable(),this._enabled=!1)},enabled:function(){return this._enabled},toggleEdit:function(t){this.enabled()?this.disable():this.enable(t)},applyOptions:function(){this.options.snappable?this._initSnappableMarkers():this._disableSnapping(),this.options.draggable?this.enableLayerDrag():this.disableLayerDrag(),this.options.preventMarkerRemoval||this._layer.on("contextmenu",this._removeMarker,this)},_removeMarker:function(t){var e=t.target;e.remove(),this._fireRemove(e),this._fireRemove(this._map,e)},_onDragEnd:function(){this._fireEdit(),this._layerEdited=!0},_initSnappableMarkers:function(){var t=this._layer;this.options.snapDistance=this.options.snapDistance||30,this.options.snapSegment=this.options.snapSegment===undefined||this.options.snapSegment,t.off("pm:drag",this._handleSnapping,this),t.on("pm:drag",this._handleSnapping,this),t.off("pm:dragend",this._cleanupSnapping,this),t.on("pm:dragend",this._cleanupSnapping,this),t.off("pm:dragstart",this._unsnap,this),t.on("pm:dragstart",this._unsnap,this)},_disableSnapping:function(){var t=this._layer;t.off("pm:drag",this._handleSnapping,this),t.off("pm:dragend",this._cleanupSnapping,this),t.off("pm:dragstart",this._unsnap,this)}});const xe={filterMarkerGroup:function(){this.markerCache=[],this.createCache(),this._layer.on("pm:edit",this.createCache,this),this.applyLimitFilters({}),this.throttledApplyLimitFilters||(this.throttledApplyLimitFilters=L.Util.throttle(this.applyLimitFilters,100,this)),this._layer.on("pm:disable",this._removeMarkerLimitEvents,this),this.options.limitMarkersToCount>-1&&(this._layer.on("pm:vertexremoved",this._initMarkers,this),this._map.on("mousemove",this.throttledApplyLimitFilters,this))},_removeMarkerLimitEvents:function(){this._map.off("mousemove",this.throttledApplyLimitFilters,this),this._layer.off("pm:edit",this.createCache,this),this._layer.off("pm:disable",this._removeMarkerLimitEvents,this),this._layer.off("pm:vertexremoved",this._initMarkers,this)},createCache:function(){var t=[].concat(ke(this._markerGroup.getLayers()),ke(this.markerCache));this.markerCache=t.filter((function(t,e,i){return i.indexOf(t)===e}))},renderLimits:function(t){var e=this;this.markerCache.forEach((function(i){t.includes(i)?e._markerGroup.addLayer(i):e._markerGroup.removeLayer(i)}))},applyLimitFilters:function(t){var e=t.latlng,i=void 0===e?{lat:0,lng:0}:e;if(!this._preventRenderMarkers){var n=ke(this._filterClosestMarkers(i));this.renderLimits(n)}},_filterClosestMarkers:function(t){var e=ke(this.markerCache),i=this.options.limitMarkersToCount;return-1===i?e:(e.sort((function(e,i){return e._latlng.distanceTo(t)-i._latlng.distanceTo(t)})),e.filter((function(t,e){return!(i>-1)||et.length)&&(e=t.length);for(var i=0,n=new Array(e);it.length)&&(e=t.length);for(var i=0,n=new Array(e);i1?O()(r,l):r,u=o.length>1?O()(this._markers,l):this._markers;h.splice(s+1,0,n),u.splice(s+1,0,t),this._layer.setLatLngs(r),!0!==this.options.hideMiddleMarkers&&(this._createMiddleMarker(e,t),this._createMiddleMarker(t,i)),this._fireEdit(),this._layerEdited=!0,this._fireChange(this._layer.getLatLngs(),"Edit"),this._fireVertexAdded(t,L.PM.Utils.findDeepMarkerIndex(this._markers,t).indexPath,n),this.options.snappable&&this._initSnappableMarkers()},hasSelfIntersection:function(){return ft(this._layer.toGeoJSON(15)).features.length>0},_handleSelfIntersectionOnVertexRemoval:function(){this._handleLayerStyle(!0)&&(this._layer.setLatLngs(this._coordsBeforeEdit),this._coordsBeforeEdit=null,this._initMarkers())},_handleLayerStyle:function(t){var e,i,n=this._layer;if(e=!this.options.allowSelfIntersection&&(i=ft(this._layer.toGeoJSON(15))).features.length>0){if(!this.options.allowSelfIntersection&&this.options.allowSelfIntersectionEdit&&this._updateDisabledMarkerStyle(this._markers,!0),this.isRed)return e;t?this._flashLayer():(n.setStyle({color:"#f00000ff"}),this.isRed=!0),this._fireIntersect(i)}else n.setStyle({color:this.cachedColor}),this.isRed=!1,!this.options.allowSelfIntersection&&this.options.allowSelfIntersectionEdit&&this._updateDisabledMarkerStyle(this._markers,!1);return e},_flashLayer:function(){var t=this;this.cachedColor||(this.cachedColor=this._layer.options.color),this._layer.setStyle({color:"#f00000ff"}),this.isRed=!0,window.setTimeout((function(){t._layer.setStyle({color:t.cachedColor}),t.isRed=!1}),200)},_updateDisabledMarkerStyle:function(t,e){var i=this;t.forEach((function(t){Array.isArray(t)?i._updateDisabledMarkerStyle(t,e):t._icon&&(e&&!i._checkMarkerAllowedToDrag(t)?L.DomUtil.addClass(t._icon,"vertexmarker-disabled"):L.DomUtil.removeClass(t._icon,"vertexmarker-disabled"))}))},_removeMarker:function(t){var e=t.target;if(this._vertexValidation("remove",t)){this.options.allowSelfIntersection||(this._coordsBeforeEdit=F(this._layer,this._layer.getLatLngs()));var i=this._layer.getLatLngs(),n=L.PM.Utils.findDeepMarkerIndex(this._markers,e),r=n.indexPath,a=n.index,o=n.parentPath;if(r){var s=r.length>1?O()(i,o):i,l=r.length>1?O()(this._markers,o):this._markers;if(this.options.removeLayerBelowMinVertexCount||!(s.length<=2||this.isPolygon()&&s.length<=3)){s.splice(a,1),this._layer.setLatLngs(i),this.isPolygon()&&s.length<=2&&s.splice(0,s.length);var h=!1;if(s.length<=1&&(s.splice(0,s.length),o.length>1&&r.length>1&&(i=I(i)),this._layer.setLatLngs(i),this._initMarkers(),h=!0),T(i)||this._layer.remove(),i=I(i),this._layer.setLatLngs(i),this._markers=I(this._markers),!h&&(l=r.length>1?O()(this._markers,o):this._markers,e._middleMarkerPrev&&this._markerGroup.removeLayer(e._middleMarkerPrev),e._middleMarkerNext&&this._markerGroup.removeLayer(e._middleMarkerNext),this._markerGroup.removeLayer(e),l)){var u,c;if(this.isPolygon()?(u=(a+1)%l.length,c=(a+(l.length-1))%l.length):(c=a-1<0?undefined:a-1,u=a+1>=l.length?undefined:a+1),u!==c){var p=l[c],d=l[u];!0!==this.options.hideMiddleMarkers&&this._createMiddleMarker(p,d)}l.splice(a,1)}this._fireEdit(),this._layerEdited=!0,this._fireVertexRemoved(e,r),this._fireChange(this._layer.getLatLngs(),"Edit")}else this._flashLayer()}}},updatePolygonCoordsFromMarkerDrag:function(t){var e=this._layer.getLatLngs(),i=t.getLatLng(),n=L.PM.Utils.findDeepMarkerIndex(this._markers,t),r=n.indexPath,a=n.index,o=n.parentPath;(r.length>1?O()(e,o):e).splice(a,1,i),this._layer.setLatLngs(e)},_getNeighborMarkers:function(t){var e=L.PM.Utils.findDeepMarkerIndex(this._markers,t),i=e.indexPath,n=e.index,r=e.parentPath,a=i.length>1?O()(this._markers,r):this._markers,o=(n+1)%a.length;return{prevMarker:a[(n+(a.length-1))%a.length],nextMarker:a[o]}},_checkMarkerAllowedToDrag:function(t){var e=this._getNeighborMarkers(t),i=e.prevMarker,n=e.nextMarker,r=L.polyline([i.getLatLng(),t.getLatLng()]),a=L.polyline([t.getLatLng(),n.getLatLng()]),o=Rt(this._layer.toGeoJSON(15),r.toGeoJSON(15)).features.length,s=Rt(this._layer.toGeoJSON(15),a.toGeoJSON(15)).features.length;return t.getLatLng()===this._markers[0][0].getLatLng()?s+=1:t.getLatLng()===this._markers[0][this._markers[0].length-1].getLatLng()&&(o+=1),!(o<=2&&s<=2)},_onMarkerDragStart:function(t){var e=t.target;if(this.cachedColor||(this.cachedColor=this._layer.options.color),this._vertexValidation("move",t)){var i=L.PM.Utils.findDeepMarkerIndex(this._markers,e).indexPath;this._fireMarkerDragStart(t,i),this.options.allowSelfIntersection||(this._coordsBeforeEdit=F(this._layer,this._layer.getLatLngs())),!this.options.allowSelfIntersection&&this.options.allowSelfIntersectionEdit&&this.hasSelfIntersection()?this._markerAllowedToDrag=this._checkMarkerAllowedToDrag(e):this._markerAllowedToDrag=null}},_onMarkerDrag:function(t){var e=t.target;if(this._vertexValidationDrag(e)){var i=L.PM.Utils.findDeepMarkerIndex(this._markers,e),n=i.indexPath,r=i.index,a=i.parentPath;if(n){if(!this.options.allowSelfIntersection&&this.options.allowSelfIntersectionEdit&&this.hasSelfIntersection()&&!1===this._markerAllowedToDrag)return this._layer.setLatLngs(this._coordsBeforeEdit),this._initMarkers(),void this._handleLayerStyle();this.updatePolygonCoordsFromMarkerDrag(e);var o=n.length>1?O()(this._markers,a):this._markers,s=(r+1)%o.length,l=(r+(o.length-1))%o.length,h=e.getLatLng(),u=o[l].getLatLng(),c=o[s].getLatLng();if(e._middleMarkerNext){var p=L.PM.Utils.calcMiddleLatLng(this._map,h,c);e._middleMarkerNext.setLatLng(p)}if(e._middleMarkerPrev){var d=L.PM.Utils.calcMiddleLatLng(this._map,h,u);e._middleMarkerPrev.setLatLng(d)}this.options.allowSelfIntersection||this._handleLayerStyle(),this._fireMarkerDrag(t,n),this._fireChange(this._layer.getLatLngs(),"Edit")}}},_onMarkerDragEnd:function(t){var e=t.target;if(this._vertexValidationDragEnd(e)){var i=L.PM.Utils.findDeepMarkerIndex(this._markers,e).indexPath,n=this.hasSelfIntersection();n&&this.options.allowSelfIntersectionEdit&&this._markerAllowedToDrag&&(n=!1);var r=!this.options.allowSelfIntersection&&n;if(this._fireMarkerDragEnd(t,i,r),r)return this._layer.setLatLngs(this._coordsBeforeEdit),this._coordsBeforeEdit=null,this._initMarkers(),this.options.snappable&&this._initSnappableMarkers(),this._handleLayerStyle(),void this._fireLayerReset(t,i);!this.options.allowSelfIntersection&&this.options.allowSelfIntersectionEdit&&this._handleLayerStyle(),this._fireEdit(),this._layerEdited=!0,this._fireChange(this._layer.getLatLngs(),"Edit")}},_onVertexClick:function(t){var e=t.target;if(!e._dragging){var i=L.PM.Utils.findDeepMarkerIndex(this._markers,e).indexPath;this._fireVertexClick(t,i)}}}),Le.Polygon=Le.Line.extend({_shape:"Polygon",_checkMarkerAllowedToDrag:function(t){var e=this._getNeighborMarkers(t),i=e.prevMarker,n=e.nextMarker,r=L.polyline([i.getLatLng(),t.getLatLng()]),a=L.polyline([t.getLatLng(),n.getLatLng()]),o=Rt(this._layer.toGeoJSON(15),r.toGeoJSON(15)).features.length,s=Rt(this._layer.toGeoJSON(15),a.toGeoJSON(15)).features.length;return!(o<=2&&s<=2)}}),Le.Rectangle=Le.Polygon.extend({_shape:"Rectangle",_initMarkers:function(){var t=this,e=this._map,i=this._findCorners();this._markerGroup&&this._markerGroup.clearLayers(),this._markerGroup=new L.FeatureGroup,this._markerGroup._pmTempLayer=!0,e.addLayer(this._markerGroup),this._markers=[],this._markers[0]=i.map(this._createMarker,this);var n=we(this._markers,1);this._cornerMarkers=n[0],this._layer.getLatLngs()[0].forEach((function(e,i){var n=t._cornerMarkers.find((function(t){return t._index===i}));n&&n.setLatLng(e)}))},applyOptions:function(){this.options.snappable?this._initSnappableMarkers():this._disableSnapping(),this._addMarkerEvents()},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:L.divIcon({className:"marker-icon"})});return this._setPane(i,"vertexPane"),i._origLatLng=t,i._index=e,i._pmTempLayer=!0,i.on("click",this._onVertexClick,this),this._markerGroup.addLayer(i),i},_addMarkerEvents:function(){var t=this;this._markers[0].forEach((function(e){e.on("dragstart",t._onMarkerDragStart,t),e.on("drag",t._onMarkerDrag,t),e.on("dragend",t._onMarkerDragEnd,t),t.options.preventMarkerRemoval||e.on("contextmenu",t._removeMarker,t)}))},_removeMarker:function(){return null},_onMarkerDragStart:function(t){if(this._vertexValidation("move",t)){var e=t.target,i=this._cornerMarkers;e._oppositeCornerLatLng=i.find((function(t){return t._index===(e._index+2)%4})).getLatLng(),e._snapped=!1,this._fireMarkerDragStart(t)}},_onMarkerDrag:function(t){var e=t.target;this._vertexValidationDrag(e)&&e._index!==undefined&&(this._adjustRectangleForMarkerMove(e),this._fireMarkerDrag(t),this._fireChange(this._layer.getLatLngs(),"Edit"))},_onMarkerDragEnd:function(t){var e=t.target;this._vertexValidationDragEnd(e)&&(this._cornerMarkers.forEach((function(t){delete t._oppositeCornerLatLng})),this._fireMarkerDragEnd(t),this._fireEdit(),this._layerEdited=!0,this._fireChange(this._layer.getLatLngs(),"Edit"))},_adjustRectangleForMarkerMove:function(t){L.extend(t._origLatLng,t._latlng);var e=L.PM.Utils._getRotatedRectangle(t.getLatLng(),t._oppositeCornerLatLng,this.getAngle(),this._map);this._layer.setLatLngs(e),this._adjustAllMarkers(),this._layer.redraw()},_adjustAllMarkers:function(){var t=this,e=this._layer.getLatLngs()[0];e&&4!==e.length&&e.length>0?(e.forEach((function(e,i){t._cornerMarkers[i].setLatLng(e)})),this._cornerMarkers.slice(e.length).forEach((function(t){t.setLatLng(e[0])}))):e&&e.length?this._cornerMarkers.forEach((function(t){t.setLatLng(e[t._index])})):console.error("The layer has no LatLngs")},_findCorners:function(){this._angle===undefined&&this.setInitAngle(G(this._map,this._layer.getLatLngs()[0][0],this._layer.getLatLngs()[0][1])||0);var t=this._layer.getLatLngs()[0];return L.PM.Utils._getRotatedRectangle(t[0],t[2],this.getAngle(),this._map||this)}}),Le.CircleMarker=Le.extend({_shape:"CircleMarker",initialize:function(t){this._layer=t,this._enabled=!1,this._minRadiusOption="minRadiusCircleMarker",this._maxRadiusOption="maxRadiusCircleMarker",this._editableOption="resizeableCircleMarker",this._updateHiddenPolyCircle()},enable:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{draggable:!0,snappable:!0};L.Util.setOptions(this,t),this.options.editable&&(this.options.resizeableCircleMarker=this.options.editable,delete this.options.editable),this.options.allowEditing&&this._layer._map?(this._map=this._layer._map,this.enabled()&&this.disable(),this.applyOptions(),this._layer.on("remove",this.disable,this),this._enabled=!0,this._extendingEnable(),this._updateHiddenPolyCircle(),this._fireEnable()):this.disable()},_extendingEnable:function(){this._layer.on("pm:dragstart",this._onDragStart,this),this._layer.on("pm:drag",this._onMarkerDrag,this),this._layer.on("pm:dragend",this._onMarkerDragEnd,this)},disable:function(){this.dragging()||(this._map||(this._map=this._layer._map),this._map&&this.enabled()&&(this.layerDragEnabled()&&this.disableLayerDrag(),this.options[this._editableOption]?(this._helperLayers&&this._helperLayers.clearLayers(),this._map.off("move",this._syncMarkers,this),this._outerMarker.off("drag",this._handleOuterMarkerSnapping,this)):this._map.off("move",this._updateHiddenPolyCircle,this),this._extendingDisable(),this._layer.off("remove",this.disable,this),this._layerEdited&&this._fireUpdate(),this._layerEdited=!1,this._fireDisable(),this._enabled=!1))},_extendingDisable:function(){this._layer.off("contextmenu",this._removeMarker,this)},enabled:function(){return this._enabled},toggleEdit:function(t){this.enabled()?this.disable():this.enable(t)},applyOptions:function(){this.options[this._editableOption]?(this._initMarkers(),this._map.on("move",this._syncMarkers,this),this.options.snappable?(this._initSnappableMarkers(),this._outerMarker.on("drag",this._handleOuterMarkerSnapping,this),this._outerMarker.on("move",this._syncHintLine,this),this._outerMarker.on("move",this._syncCircleRadius,this),this._centerMarker.on("move",this._moveCircle,this)):this._disableSnapping()):(this.options.draggable&&this.enableLayerDrag(),this._map.on("move",this._updateHiddenPolyCircle,this),this.options.snappable?this._initSnappableMarkersDrag():this._disableSnappingDrag()),this._extendingApplyOptions()},_extendingApplyOptions:function(){this.options.preventMarkerRemoval||this._layer.on("contextmenu",this._removeMarker,this)},_initMarkers:function(){var t=this._map;this._helperLayers&&this._helperLayers.clearLayers(),this._helperLayers=new L.FeatureGroup,this._helperLayers._pmTempLayer=!0,this._helperLayers.addTo(t);var e=this._layer.getLatLng(),i=this._layer._radius,n=this._getLatLngOnCircle(e,i);this._centerMarker=this._createCenterMarker(e),this._outerMarker=this._createOuterMarker(n),this._markers=[this._centerMarker,this._outerMarker],this._createHintLine(this._centerMarker,this._outerMarker)},_getLatLngOnCircle:function(t,e){var i=this._map.project(t),n=L.point(i.x+e,i.y);return this._map.unproject(n)},_createHintLine:function(t,e){var i=t.getLatLng(),n=e.getLatLng();this._hintline=L.polyline([i,n],this.options.hintlineStyle),this._setPane(this._hintline,"layerPane"),this._hintline._pmTempLayer=!0,this._helperLayers.addLayer(this._hintline)},_createCenterMarker:function(t){var e=this._createMarker(t);return this.options.draggable?L.DomUtil.addClass(e._icon,"leaflet-pm-draggable"):e.dragging.disable(),e},_createOuterMarker:function(t){var e=this._createMarker(t);return e.on("drag",this._resizeCircle,this),e},_createMarker:function(t){var e=new L.Marker(t,{draggable:!0,icon:L.divIcon({className:"marker-icon"})});return this._setPane(e,"vertexPane"),e._origLatLng=t,e._pmTempLayer=!0,e.on("dragstart",this._onMarkerDragStart,this),e.on("drag",this._onMarkerDrag,this),e.on("dragend",this._onMarkerDragEnd,this),e.on("click",this._onVertexClick,this),this._helperLayers.addLayer(e),e},_moveCircle:function(t){if(!t.target._cancelDragEventChain){var e=this._centerMarker.getLatLng();this._layer.setLatLng(e);var i=this._layer._radius,n=this._getLatLngOnCircle(e,i);this._outerMarker._latlng=n,this._outerMarker.update(),this._syncHintLine(),this._updateHiddenPolyCircle(),this._fireCenterPlaced("Edit"),this._fireChange(this._layer.getLatLng(),"Edit")}},_syncMarkers:function(){var t=this._layer.getLatLng(),e=this._layer._radius,i=this._getLatLngOnCircle(t,e);this._outerMarker.setLatLng(i),this._centerMarker.setLatLng(t),this._syncHintLine(),this._updateHiddenPolyCircle()},_resizeCircle:function(){this._outerMarker.setLatLng(this._getNewDestinationOfOuterMarker()),this._syncHintLine(),this._syncCircleRadius()},_syncCircleRadius:function(){var t=this._centerMarker.getLatLng(),e=this._outerMarker.getLatLng(),i=this._distanceCalculation(t,e);this.options[this._minRadiusOption]&&ithis.options[this._maxRadiusOption]?this._layer.setRadius(this.options[this._maxRadiusOption]):this._layer.setRadius(i),this._updateHiddenPolyCircle(),this._fireChange(this._layer.getLatLng(),"Edit")},_syncHintLine:function(){var t=this._centerMarker.getLatLng(),e=this._outerMarker.getLatLng();this._hintline.setLatLngs([t,e])},_removeMarker:function(){this.options[this._editableOption]&&this.disable(),this._layer.remove(),this._fireRemove(this._layer),this._fireRemove(this._map,this._layer)},_onDragStart:function(){this._map.pm.Draw.CircleMarker._layerIsDragging=!0},_onMarkerDragStart:function(t){this._vertexValidation("move",t)&&this._fireMarkerDragStart(t)},_onMarkerDrag:function(t){var e=t.target;e instanceof L.Marker&&!this._vertexValidationDrag(e)||this._fireMarkerDrag(t)},_onMarkerDragEnd:function(t){this._extedingMarkerDragEnd();var e=t.target;this._vertexValidationDragEnd(e)&&(this.options[this._editableOption]&&(this._fireEdit(),this._layerEdited=!0),this._fireMarkerDragEnd(t))},_extedingMarkerDragEnd:function(){this._map.pm.Draw.CircleMarker._layerIsDragging=!1},_initSnappableMarkersDrag:function(){var t=this._layer;this.options.snapDistance=this.options.snapDistance||30,this.options.snapSegment=this.options.snapSegment===undefined||this.options.snapSegment,t.off("pm:drag",this._handleSnapping,this),t.on("pm:drag",this._handleSnapping,this),t.off("pm:dragend",this._cleanupSnapping,this),t.on("pm:dragend",this._cleanupSnapping,this),t.off("pm:dragstart",this._unsnap,this),t.on("pm:dragstart",this._unsnap,this)},_disableSnappingDrag:function(){var t=this._layer;t.off("pm:drag",this._handleSnapping,this),t.off("pm:dragend",this._cleanupSnapping,this),t.off("pm:dragstart",this._unsnap,this)},_updateHiddenPolyCircle:function(){var t=this._layer._map||this._map;if(t){var e=L.PM.Utils.pxRadiusToMeterRadius(this._layer.getRadius(),t,this._layer.getLatLng()),i=L.circle(this._layer.getLatLng(),this._layer.options);i.setRadius(e);var n=t&&t.pm._isCRSSimple();this._hiddenPolyCircle?this._hiddenPolyCircle.setLatLngs(L.PM.Utils.circleToPolygon(i,200,!n).getLatLngs()):this._hiddenPolyCircle=L.PM.Utils.circleToPolygon(i,200,!n),this._hiddenPolyCircle._parentCopy||(this._hiddenPolyCircle._parentCopy=this._layer)}},_getNewDestinationOfOuterMarker:function(){var t=this._centerMarker.getLatLng(),e=this._outerMarker.getLatLng(),i=this._distanceCalculation(t,e);return this.options[this._minRadiusOption]&&ithis.options[this._maxRadiusOption]&&(e=z(this._map,t,e,this._getMaxDistanceInMeter(t))),e},_handleOuterMarkerSnapping:function(){if(this._outerMarker._snapped){var t=this._centerMarker.getLatLng(),e=this._outerMarker.getLatLng(),i=this._distanceCalculation(t,e);(this.options[this._minRadiusOption]&&ithis.options[this._maxRadiusOption])&&this._outerMarker.setLatLng(this._outerMarker._orgLatLng)}this._outerMarker.setLatLng(this._getNewDestinationOfOuterMarker())},_distanceCalculation:function(t,e){return this._map.project(t).distanceTo(this._map.project(e))},_getMinDistanceInMeter:function(t){return L.PM.Utils.pxRadiusToMeterRadius(this.options[this._minRadiusOption],this._map,t)},_getMaxDistanceInMeter:function(t){return L.PM.Utils.pxRadiusToMeterRadius(this.options[this._maxRadiusOption],this._map,t)},_onVertexClick:function(t){t.target._dragging||this._fireVertexClick(t,undefined)}}),Le.Circle=Le.CircleMarker.extend({_shape:"Circle",initialize:function(t){this._layer=t,this._enabled=!1,this._minRadiusOption="minRadiusCircle",this._maxRadiusOption="maxRadiusCircle",this._editableOption="resizableCircle",this._updateHiddenPolyCircle()},enable:function(t){L.PM.Edit.CircleMarker.prototype.enable.call(this,t||{})},_extendingEnable:function(){},_extendingDisable:function(){this._layer.off("remove",this.disable,this);var t=this._layer._path?this._layer._path:this._layer._renderer._container;L.DomUtil.removeClass(t,"leaflet-pm-draggable")},_extendingApplyOptions:function(){},_syncMarkers:function(){},_removeMarker:function(){},_onDragStart:function(){},_extedingMarkerDragEnd:function(){},_updateHiddenPolyCircle:function(){var t=this._map&&this._map.pm._isCRSSimple();this._hiddenPolyCircle?this._hiddenPolyCircle.setLatLngs(L.PM.Utils.circleToPolygon(this._layer,200,!t).getLatLngs()):this._hiddenPolyCircle=L.PM.Utils.circleToPolygon(this._layer,200,!t),this._hiddenPolyCircle._parentCopy||(this._hiddenPolyCircle._parentCopy=this._layer)},_distanceCalculation:function(t,e){return this._map.distance(t,e)},_getMinDistanceInMeter:function(){return this.options[this._minRadiusOption]},_getMaxDistanceInMeter:function(){return this.options[this._maxRadiusOption]},_onVertexClick:function(t){t.target._dragging||this._fireVertexClick(t,undefined)}}),Le.ImageOverlay=Le.extend({_shape:"ImageOverlay",initialize:function(t){this._layer=t,this._enabled=!1},toggleEdit:function(t){this.enabled()?this.disable():this.enable(t)},enabled:function(){return this._enabled},enable:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{draggable:!0,snappable:!0};L.Util.setOptions(this,t),this._map=this._layer._map,this._map&&(this.options.allowEditing?(this.enabled()||this.disable(),this.enableLayerDrag(),this._layer.on("remove",this.disable,this),this._enabled=!0,this._otherSnapLayers=this._findCorners(),this._fireEnable()):this.disable())},disable:function(){this._dragging||(this._map||(this._map=this._layer._map),this.disableLayerDrag(),this._layer.off("remove",this.disable,this),this.enabled()||(this._layerEdited&&this._fireUpdate(),this._layerEdited=!1,this._fireDisable()),this._enabled=!1)},_findCorners:function(){var t=this._layer.getBounds();return[t.getNorthWest(),t.getNorthEast(),t.getSouthEast(),t.getSouthWest()]}}),Le.Text=Le.extend({_shape:"Text",initialize:function(t){this._layer=t,this._enabled=!1},enable:function(t){L.Util.setOptions(this,t),this.textArea&&(this.options.allowEditing&&this._layer._map?(this._map=this._layer._map,this.enabled()&&this.disable(),this.applyOptions(),this._safeToCacheDragState=!0,this._focusChange(),this.textArea.readOnly=!1,this.textArea.classList.remove("pm-disabled"),this._layer.on("remove",this.disable,this),L.DomEvent.on(this.textArea,"input",this._autoResize,this),L.DomEvent.on(this.textArea,"focus",this._focusChange,this),L.DomEvent.on(this.textArea,"blur",this._focusChange,this),this._layer.on("dblclick",L.DomEvent.stop),L.DomEvent.off(this.textArea,"mousedown",this._preventTextSelection),this._enabled=!0,this._fireEnable()):this.disable())},disable:function(){if(this.enabled()){this._layer.off("remove",this.disable,this),L.DomEvent.off(this.textArea,"input",this._autoResize,this),L.DomEvent.off(this.textArea,"focus",this._focusChange,this),L.DomEvent.off(this.textArea,"blur",this._focusChange,this),L.DomEvent.off(document,"click",this._documentClick,this),this._focusChange(),this.textArea.readOnly=!0,this.textArea.classList.add("pm-disabled");var t=document.activeElement;this.textArea.focus(),this.textArea.selectionStart=0,this.textArea.selectionEnd=0,L.DomEvent.on(this.textArea,"mousedown",this._preventTextSelection),t.focus(),this._disableOnBlurActive=!1,this._layerEdited&&this._fireUpdate(),this._layerEdited=!1,this._fireDisable(),this._enabled=!1}},enabled:function(){return this._enabled},toggleEdit:function(t){this.enabled()?this.disable():this.enable(t)},applyOptions:function(){this.options.snappable?this._initSnappableMarkers():this._disableSnapping()},_initSnappableMarkers:function(){var t=this._layer;this.options.snapDistance=this.options.snapDistance||30,this.options.snapSegment=this.options.snapSegment===undefined||this.options.snapSegment,t.off("pm:drag",this._handleSnapping,this),t.on("pm:drag",this._handleSnapping,this),t.off("pm:dragend",this._cleanupSnapping,this),t.on("pm:dragend",this._cleanupSnapping,this),t.off("pm:dragstart",this._unsnap,this),t.on("pm:dragstart",this._unsnap,this)},_disableSnapping:function(){var t=this._layer;t.off("pm:drag",this._handleSnapping,this),t.off("pm:dragend",this._cleanupSnapping,this),t.off("pm:dragstart",this._unsnap,this)},_autoResize:function(){this.textArea.style.height="1px",this.textArea.style.width="1px";var t=this.textArea.scrollHeight>21?this.textArea.scrollHeight:21,e=this.textArea.scrollWidth>16?this.textArea.scrollWidth:16;this.textArea.style.height="".concat(t,"px"),this.textArea.style.width="".concat(e,"px"),this._layer.options.text=this.getText(),this._fireTextChange(this.getText())},_disableOnBlur:function(){var t=this;this._disableOnBlurActive=!0,setTimeout((function(){t.enabled()&&L.DomEvent.on(document,"click",t._documentClick,t)}),100)},_documentClick:function(t){t.target!==this.textArea&&(this.disable(),!this.getText()&&this.options.removeIfEmpty&&this.remove())},_focusChange:function(){var t=arguments.length>0&&arguments[0]!==undefined?arguments[0]:{},e=this._hasFocus;this._hasFocus="focus"===t.type,!e!=!this._hasFocus&&(this._hasFocus?(this._applyFocus(),this._focusText=this.getText(),this._fireTextFocus()):(this._removeFocus(),this._fireTextBlur(),this._focusText!==this.getText()&&(this._fireEdit(),this._layerEdited=!0)))},_applyFocus:function(){this.textArea.classList.add("pm-hasfocus"),this._map.dragging&&(this._safeToCacheDragState&&(this._originalMapDragState=this._map.dragging._enabled,this._safeToCacheDragState=!1),this._map.dragging.disable())},_removeFocus:function(){this._map.dragging&&(this._originalMapDragState&&this._map.dragging.enable(),this._safeToCacheDragState=!0),this.textArea.classList.remove("pm-hasfocus")},focus:function(){if(!this.enabled())throw new TypeError("Layer is not enabled");this.textArea.focus()},blur:function(){if(!this.enabled())throw new TypeError("Layer is not enabled");this.textArea.blur(),this._disableOnBlurActive&&this.disable()},hasFocus:function(){return this._hasFocus},getElement:function(){return this.textArea},setText:function(t){this.textArea.value=t,this._autoResize()},getText:function(){return this.textArea.value},_initTextMarker:function(){if(this.textArea=L.PM.Draw.Text.prototype._createTextArea.call(this),this.options.className){var t,e=this.options.className.split(" ");(t=this.textArea.classList).add.apply(t,Pe(e))}var i=L.PM.Draw.Text.prototype._createTextIcon.call(this,this.textArea);this._layer.setIcon(i),this._layer.once("add",this._createTextMarker,this)},_createTextMarker:function(){var t=arguments.length>0&&arguments[0]!==undefined&&arguments[0];this._layer.off("add",this._createTextMarker,this),this._layer.getElement().tabIndex=-1,this.textArea.wrap="off",this.textArea.style.overflow="hidden",this.textArea.style.height=L.DomUtil.getStyle(this.textArea,"font-size"),this.textArea.style.width="1px",this._layer.options.text&&this.setText(this._layer.options.text),this._autoResize(),!0===t&&(this.enable(),this.focus(),this._disableOnBlur())},_preventTextSelection:function(t){t.preventDefault()}});var Se=function(t,e,i,n,r,a){this._matrix=[t,e,i,n,r,a]};Se.init=function(){return new L.PM.Matrix(1,0,0,1,0,0)},Se.prototype={transform:function(t){return this._transform(t.clone())},_transform:function(t){var e=this._matrix,i=t.x,n=t.y;return t.x=e[0]*i+e[1]*n+e[4],t.y=e[2]*i+e[3]*n+e[5],t},untransform:function(t){var e=this._matrix;return new L.Point((t.x/e[0]-e[4])/e[0],(t.y/e[2]-e[5])/e[2])},clone:function(){var t=this._matrix;return new L.PM.Matrix(t[0],t[1],t[2],t[3],t[4],t[5])},translate:function(t){return t===undefined?new L.Point(this._matrix[4],this._matrix[5]):("number"==typeof t?(e=t,i=t):(e=t.x,i=t.y),this._add(1,0,0,1,e,i));var e,i},scale:function(t,e){return t===undefined?new L.Point(this._matrix[0],this._matrix[3]):(e=e||L.point(0,0),"number"==typeof t?(i=t,n=t):(i=t.x,n=t.y),this._add(i,0,0,n,e.x,e.y)._add(1,0,0,1,-e.x,-e.y));var i,n},rotate:function(t,e){var i=Math.cos(t),n=Math.sin(t);return e=e||new L.Point(0,0),this._add(i,n,-n,i,e.x,e.y)._add(1,0,0,1,-e.x,-e.y)},flip:function(){return this._matrix[1]*=-1,this._matrix[2]*=-1,this},_add:function(t,e,i,n,r,a){var o,s=[[],[],[]],l=this._matrix,h=[[l[0],l[2],l[4]],[l[1],l[3],l[5]],[0,0,1]],u=[[t,i,r],[e,n,a],[0,0,1]];t&&t instanceof L.PM.Matrix&&(u=[[(l=t._matrix)[0],l[2],l[4]],[l[1],l[3],l[5]],[0,0,1]]);for(var c=0;c<3;c+=1)for(var p=0;p<3;p+=1){o=0;for(var d=0;d<3;d+=1)o+=h[c][d]*u[d][p];s[c][p]=o}return this._matrix=[s[0][0],s[1][0],s[0][1],s[1][1],s[0][2],s[1][2]],this}};const Oe=Se;var Be={calcMiddleLatLng:function(t,e,i){var n=t.project(e),r=t.project(i);return t.unproject(n._add(r)._divideBy(2))},findLayers:function(t){var e=[];return t.eachLayer((function(t){(t instanceof L.Polyline||t instanceof L.Marker||t instanceof L.Circle||t instanceof L.CircleMarker||t instanceof L.ImageOverlay)&&e.push(t)})),e=(e=(e=e.filter((function(t){return!!t.pm}))).filter((function(t){return!t._pmTempLayer}))).filter((function(t){return!L.PM.optIn&&!t.options.pmIgnore||L.PM.optIn&&!1===t.options.pmIgnore}))},circleToPolygon:function(t){for(var e=arguments.length>1&&arguments[1]!==undefined?arguments[1]:60,i=!(arguments.length>2&&arguments[2]!==undefined)||arguments[2],n=t.getLatLng(),r=t.getRadius(),a=j(n,r,e,0,i),o=[],s=0;s3&&arguments[3]!==undefined&&arguments[3];t.fire(e,i,n);var r=this.getAllParentGroups(t),a=r.groups;a.forEach((function(t){t.fire(e,i,n)}))},getAllParentGroups:function(t){var e=[],i=[];return!t._pmLastGroupFetch||!t._pmLastGroupFetch.time||(new Date).getTime()-t._pmLastGroupFetch.time>1e3?(function n(t){for(var r in t._eventParents)if(-1===e.indexOf(r)){e.push(r);var a=t._eventParents[r];i.push(a),n(a)}}(t),t._pmLastGroupFetch={time:(new Date).getTime(),groups:i,groupIds:e},{groupIds:e,groups:i}):{groups:t._pmLastGroupFetch.groups,groupIds:t._pmLastGroupFetch.groupIds}},createGeodesicPolygon:j,getTranslation:R,findDeepCoordIndex:function(t,e){var i,n=!(arguments.length>2&&arguments[2]!==undefined)||arguments[2],r=function o(t){return function(r,a){var s=t.concat(a);if(n){if(r.lat&&r.lat===e.lat&&r.lng===e.lng)return i=s,!0}else if(r.lat&&L.latLng(r).equals(e))return i=s,!0;return Array.isArray(r)&&r.some(o(s))}};t.some(r([]));var a={};return i&&(a={indexPath:i,index:i[i.length-1],parentPath:i.slice(0,i.length-1)}),a},findDeepMarkerIndex:function(t,e){var i;t.some(function r(t){return function(n,a){var o=t.concat(a);return n._leaflet_id===e._leaflet_id?(i=o,!0):Array.isArray(n)&&n.some(r(o))}}([]));var n={};return i&&(n={indexPath:i,index:i[i.length-1],parentPath:i.slice(0,i.length-1)}),n},_getIndexFromSegment:function(t,e){if(e&&2===e.length){var i=this.findDeepCoordIndex(t,e[0]),n=this.findDeepCoordIndex(t,e[1]),r=Math.max(i.index,n.index);return 0!==i.index&&0!==n.index||1===r||(r+=1),{indexA:i,indexB:n,newIndex:r,indexPath:i.indexPath,parentPath:i.parentPath}}return null},_getRotatedRectangle:function(t,e,i,n){var r=me(n,t),a=me(n,e),o=i*Math.PI/180,s=Math.cos(o),l=Math.sin(o),h=(a.x-r.x)*s+(a.y-r.y)*l,u=(a.y-r.y)*s-(a.x-r.x)*l,c=h*s+r.x,p=h*l+r.y,d=-u*l+r.x,f=u*s+r.y;return[ye(n,r),ye(n,{x:c,y:p}),ye(n,a),ye(n,{x:d,y:f})]},pxRadiusToMeterRadius:function(t,e,i){var n=e.project(i),r=L.point(n.x+t,n.y);return e.distance(e.unproject(r),i)}};const De=Be;L.PM=L.PM||{version:"2.15.0",Map:K,Toolbar:Z,Draw:it,Edit:Le,Utils:De,Matrix:Oe,activeLang:"en",optIn:!1,initialize:function(t){this.addInitHooks(t)},setOptIn:function(t){this.optIn=!!t},addInitHooks:function(){L.Map.addInitHook((function(){this.pm=undefined,L.PM.optIn?!1===this.options.pmIgnore&&(this.pm=new L.PM.Map(this)):this.options.pmIgnore||(this.pm=new L.PM.Map(this)),this.pm&&this.pm.setGlobalOptions({})})),L.LayerGroup.addInitHook((function(){this.pm=undefined,L.PM.optIn?!1===this.options.pmIgnore&&(this.pm=new L.PM.Edit.LayerGroup(this)):this.options.pmIgnore||(this.pm=new L.PM.Edit.LayerGroup(this))})),L.Marker.addInitHook((function(){this.pm=undefined,L.PM.optIn?!1===this.options.pmIgnore&&(this.options.textMarker?(this.pm=new L.PM.Edit.Text(this),this.options._textMarkerOverPM||this.pm._initTextMarker(),delete this.options._textMarkerOverPM):this.pm=new L.PM.Edit.Marker(this)):this.options.pmIgnore||(this.options.textMarker?(this.pm=new L.PM.Edit.Text(this),this.options._textMarkerOverPM||this.pm._initTextMarker(),delete this.options._textMarkerOverPM):this.pm=new L.PM.Edit.Marker(this))})),L.CircleMarker.addInitHook((function(){this.pm=undefined,L.PM.optIn?!1===this.options.pmIgnore&&(this.pm=new L.PM.Edit.CircleMarker(this)):this.options.pmIgnore||(this.pm=new L.PM.Edit.CircleMarker(this))})),L.Polyline.addInitHook((function(){this.pm=undefined,L.PM.optIn?!1===this.options.pmIgnore&&(this.pm=new L.PM.Edit.Line(this)):this.options.pmIgnore||(this.pm=new L.PM.Edit.Line(this))})),L.Polygon.addInitHook((function(){this.pm=undefined,L.PM.optIn?!1===this.options.pmIgnore&&(this.pm=new L.PM.Edit.Polygon(this)):this.options.pmIgnore||(this.pm=new L.PM.Edit.Polygon(this))})),L.Rectangle.addInitHook((function(){this.pm=undefined,L.PM.optIn?!1===this.options.pmIgnore&&(this.pm=new L.PM.Edit.Rectangle(this)):this.options.pmIgnore||(this.pm=new L.PM.Edit.Rectangle(this))})),L.Circle.addInitHook((function(){this.pm=undefined,L.PM.optIn?!1===this.options.pmIgnore&&(this.pm=new L.PM.Edit.Circle(this)):this.options.pmIgnore||(this.pm=new L.PM.Edit.Circle(this))})),L.ImageOverlay.addInitHook((function(){this.pm=undefined,L.PM.optIn?!1===this.options.pmIgnore&&(this.pm=new L.PM.Edit.ImageOverlay(this)):this.options.pmIgnore||(this.pm=new L.PM.Edit.ImageOverlay(this))}))},reInitLayer:function(t){var e=this;t instanceof L.LayerGroup&&t.eachLayer((function(t){e.reInitLayer(t)})),t.pm||L.PM.optIn&&!1!==t.options.pmIgnore||t.options.pmIgnore||(t instanceof L.Map?t.pm=new L.PM.Map(t):t instanceof L.Marker?t.options.textMarker?(t.pm=new L.PM.Edit.Text(t),t.pm._initTextMarker(),t.pm._createTextMarker(!1)):t.pm=new L.PM.Edit.Marker(t):t instanceof L.Circle?t.pm=new L.PM.Edit.Circle(t):t instanceof L.CircleMarker?t.pm=new L.PM.Edit.CircleMarker(t):t instanceof L.Rectangle?t.pm=new L.PM.Edit.Rectangle(t):t instanceof L.Polygon?t.pm=new L.PM.Edit.Polygon(t):t instanceof L.Polyline?t.pm=new L.PM.Edit.Line(t):t instanceof L.LayerGroup?t.pm=new L.PM.Edit.LayerGroup(t):t instanceof L.ImageOverlay&&(t.pm=new L.PM.Edit.ImageOverlay(t)))}},"1.7.1"===L.version&&L.Canvas.include({_onClick:function(t){for(var e,i,n=this._map.mouseEventToLayerPoint(t),r=this._drawFirst;r;r=r.next)(e=r.layer).options.interactive&&e._containsPoint(n)&&("click"!==t.type&&"preclick"!==t.type||!this._map._draggableMoved(e))&&(i=e);i&&(L.DomEvent.fakeStop(t),this._fireEvent([i],t))}}),L.PM.initialize()})()})(); diff --git a/htdocs/includes/leaflet/leaflet-src.esm.js b/htdocs/includes/leaflet/leaflet-src.esm.js new file mode 100644 index 00000000000..1bb1d6aeb8f --- /dev/null +++ b/htdocs/includes/leaflet/leaflet-src.esm.js @@ -0,0 +1,14419 @@ +/* @preserve + * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com + * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade + */ + +var version = "1.9.4"; + +/* + * @namespace Util + * + * Various utility functions, used by Leaflet internally. + */ + +// @function extend(dest: Object, src?: Object): Object +// Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut. +function extend(dest) { + var i, j, len, src; + + for (j = 1, len = arguments.length; j < len; j++) { + src = arguments[j]; + for (i in src) { + dest[i] = src[i]; + } + } + return dest; +} + +// @function create(proto: Object, properties?: Object): Object +// Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create) +var create$2 = Object.create || (function () { + function F() {} + return function (proto) { + F.prototype = proto; + return new F(); + }; +})(); + +// @function bind(fn: Function, …): Function +// Returns a new function bound to the arguments passed, like [Function.prototype.bind](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). +// Has a `L.bind()` shortcut. +function bind(fn, obj) { + var slice = Array.prototype.slice; + + if (fn.bind) { + return fn.bind.apply(fn, slice.call(arguments, 1)); + } + + var args = slice.call(arguments, 2); + + return function () { + return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments); + }; +} + +// @property lastId: Number +// Last unique ID used by [`stamp()`](#util-stamp) +var lastId = 0; + +// @function stamp(obj: Object): Number +// Returns the unique ID of an object, assigning it one if it doesn't have it. +function stamp(obj) { + if (!('_leaflet_id' in obj)) { + obj['_leaflet_id'] = ++lastId; + } + return obj._leaflet_id; +} + +// @function throttle(fn: Function, time: Number, context: Object): Function +// Returns a function which executes function `fn` with the given scope `context` +// (so that the `this` keyword refers to `context` inside `fn`'s code). The function +// `fn` will be called no more than one time per given amount of `time`. The arguments +// received by the bound function will be any arguments passed when binding the +// function, followed by any arguments passed when invoking the bound function. +// Has an `L.throttle` shortcut. +function throttle(fn, time, context) { + var lock, args, wrapperFn, later; + + later = function () { + // reset lock and call if queued + lock = false; + if (args) { + wrapperFn.apply(context, args); + args = false; + } + }; + + wrapperFn = function () { + if (lock) { + // called too soon, queue to call later + args = arguments; + + } else { + // call and lock until later + fn.apply(context, arguments); + setTimeout(later, time); + lock = true; + } + }; + + return wrapperFn; +} + +// @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number +// Returns the number `num` modulo `range` in such a way so it lies within +// `range[0]` and `range[1]`. The returned value will be always smaller than +// `range[1]` unless `includeMax` is set to `true`. +function wrapNum(x, range, includeMax) { + var max = range[1], + min = range[0], + d = max - min; + return x === max && includeMax ? x : ((x - min) % d + d) % d + min; +} + +// @function falseFn(): Function +// Returns a function which always returns `false`. +function falseFn() { return false; } + +// @function formatNum(num: Number, precision?: Number|false): Number +// Returns the number `num` rounded with specified `precision`. +// The default `precision` value is 6 decimal places. +// `false` can be passed to skip any processing (can be useful to avoid round-off errors). +function formatNum(num, precision) { + if (precision === false) { return num; } + var pow = Math.pow(10, precision === undefined ? 6 : precision); + return Math.round(num * pow) / pow; +} + +// @function trim(str: String): String +// Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim) +function trim(str) { + return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); +} + +// @function splitWords(str: String): String[] +// Trims and splits the string on whitespace and returns the array of parts. +function splitWords(str) { + return trim(str).split(/\s+/); +} + +// @function setOptions(obj: Object, options: Object): Object +// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut. +function setOptions(obj, options) { + if (!Object.prototype.hasOwnProperty.call(obj, 'options')) { + obj.options = obj.options ? create$2(obj.options) : {}; + } + for (var i in options) { + obj.options[i] = options[i]; + } + return obj.options; +} + +// @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String +// Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}` +// translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will +// be appended at the end. If `uppercase` is `true`, the parameter names will +// be uppercased (e.g. `'?A=foo&B=bar'`) +function getParamString(obj, existingUrl, uppercase) { + var params = []; + for (var i in obj) { + params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); + } + return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&'); +} + +var templateRe = /\{ *([\w_ -]+) *\}/g; + +// @function template(str: String, data: Object): String +// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'` +// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string +// `('Hello foo, bar')`. You can also specify functions instead of strings for +// data values — they will be evaluated passing `data` as an argument. +function template(str, data) { + return str.replace(templateRe, function (str, key) { + var value = data[key]; + + if (value === undefined) { + throw new Error('No value provided for variable ' + str); + + } else if (typeof value === 'function') { + value = value(data); + } + return value; + }); +} + +// @function isArray(obj): Boolean +// Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray) +var isArray = Array.isArray || function (obj) { + return (Object.prototype.toString.call(obj) === '[object Array]'); +}; + +// @function indexOf(array: Array, el: Object): Number +// Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) +function indexOf(array, el) { + for (var i = 0; i < array.length; i++) { + if (array[i] === el) { return i; } + } + return -1; +} + +// @property emptyImageUrl: String +// Data URI string containing a base64-encoded empty GIF image. +// Used as a hack to free memory from unused images on WebKit-powered +// mobile devices (by setting image `src` to this string). +var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; + +// inspired by https://paulirish.com/2011/requestanimationframe-for-smart-animating/ + +function getPrefixed(name) { + return window['webkit' + name] || window['moz' + name] || window['ms' + name]; +} + +var lastTime = 0; + +// fallback for IE 7-8 +function timeoutDefer(fn) { + var time = +new Date(), + timeToCall = Math.max(0, 16 - (time - lastTime)); + + lastTime = time + timeToCall; + return window.setTimeout(fn, timeToCall); +} + +var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer; +var cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') || + getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); }; + +// @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number +// Schedules `fn` to be executed when the browser repaints. `fn` is bound to +// `context` if given. When `immediate` is set, `fn` is called immediately if +// the browser doesn't have native support for +// [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame), +// otherwise it's delayed. Returns a request ID that can be used to cancel the request. +function requestAnimFrame(fn, context, immediate) { + if (immediate && requestFn === timeoutDefer) { + fn.call(context); + } else { + return requestFn.call(window, bind(fn, context)); + } +} + +// @function cancelAnimFrame(id: Number): undefined +// Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame). +function cancelAnimFrame(id) { + if (id) { + cancelFn.call(window, id); + } +} + +var Util = { + __proto__: null, + extend: extend, + create: create$2, + bind: bind, + get lastId () { return lastId; }, + stamp: stamp, + throttle: throttle, + wrapNum: wrapNum, + falseFn: falseFn, + formatNum: formatNum, + trim: trim, + splitWords: splitWords, + setOptions: setOptions, + getParamString: getParamString, + template: template, + isArray: isArray, + indexOf: indexOf, + emptyImageUrl: emptyImageUrl, + requestFn: requestFn, + cancelFn: cancelFn, + requestAnimFrame: requestAnimFrame, + cancelAnimFrame: cancelAnimFrame +}; + +// @class Class +// @aka L.Class + +// @section +// @uninheritable + +// Thanks to John Resig and Dean Edwards for inspiration! + +function Class() {} + +Class.extend = function (props) { + + // @function extend(props: Object): Function + // [Extends the current class](#class-inheritance) given the properties to be included. + // Returns a Javascript function that is a class constructor (to be called with `new`). + var NewClass = function () { + + setOptions(this); + + // call the constructor + if (this.initialize) { + this.initialize.apply(this, arguments); + } + + // call all constructor hooks + this.callInitHooks(); + }; + + var parentProto = NewClass.__super__ = this.prototype; + + var proto = create$2(parentProto); + proto.constructor = NewClass; + + NewClass.prototype = proto; + + // inherit parent's statics + for (var i in this) { + if (Object.prototype.hasOwnProperty.call(this, i) && i !== 'prototype' && i !== '__super__') { + NewClass[i] = this[i]; + } + } + + // mix static properties into the class + if (props.statics) { + extend(NewClass, props.statics); + } + + // mix includes into the prototype + if (props.includes) { + checkDeprecatedMixinEvents(props.includes); + extend.apply(null, [proto].concat(props.includes)); + } + + // mix given properties into the prototype + extend(proto, props); + delete proto.statics; + delete proto.includes; + + // merge options + if (proto.options) { + proto.options = parentProto.options ? create$2(parentProto.options) : {}; + extend(proto.options, props.options); + } + + proto._initHooks = []; + + // add method for calling all hooks + proto.callInitHooks = function () { + + if (this._initHooksCalled) { return; } + + if (parentProto.callInitHooks) { + parentProto.callInitHooks.call(this); + } + + this._initHooksCalled = true; + + for (var i = 0, len = proto._initHooks.length; i < len; i++) { + proto._initHooks[i].call(this); + } + }; + + return NewClass; +}; + + +// @function include(properties: Object): this +// [Includes a mixin](#class-includes) into the current class. +Class.include = function (props) { + var parentOptions = this.prototype.options; + extend(this.prototype, props); + if (props.options) { + this.prototype.options = parentOptions; + this.mergeOptions(props.options); + } + return this; +}; + +// @function mergeOptions(options: Object): this +// [Merges `options`](#class-options) into the defaults of the class. +Class.mergeOptions = function (options) { + extend(this.prototype.options, options); + return this; +}; + +// @function addInitHook(fn: Function): this +// Adds a [constructor hook](#class-constructor-hooks) to the class. +Class.addInitHook = function (fn) { // (Function) || (String, args...) + var args = Array.prototype.slice.call(arguments, 1); + + var init = typeof fn === 'function' ? fn : function () { + this[fn].apply(this, args); + }; + + this.prototype._initHooks = this.prototype._initHooks || []; + this.prototype._initHooks.push(init); + return this; +}; + +function checkDeprecatedMixinEvents(includes) { + /* global L: true */ + if (typeof L === 'undefined' || !L || !L.Mixin) { return; } + + includes = isArray(includes) ? includes : [includes]; + + for (var i = 0; i < includes.length; i++) { + if (includes[i] === L.Mixin.Events) { + console.warn('Deprecated include of L.Mixin.Events: ' + + 'this property will be removed in future releases, ' + + 'please inherit from L.Evented instead.', new Error().stack); + } + } +} + +/* + * @class Evented + * @aka L.Evented + * @inherits Class + * + * A set of methods shared between event-powered classes (like `Map` and `Marker`). Generally, events allow you to execute some function when something happens with an object (e.g. the user clicks on the map, causing the map to fire `'click'` event). + * + * @example + * + * ```js + * map.on('click', function(e) { + * alert(e.latlng); + * } ); + * ``` + * + * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function: + * + * ```js + * function onClick(e) { ... } + * + * map.on('click', onClick); + * map.off('click', onClick); + * ``` + */ + +var Events = { + /* @method on(type: String, fn: Function, context?: Object): this + * Adds a listener function (`fn`) to a particular event type of the object. You can optionally specify the context of the listener (object the this keyword will point to). You can also pass several space-separated types (e.g. `'click dblclick'`). + * + * @alternative + * @method on(eventMap: Object): this + * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` + */ + on: function (types, fn, context) { + + // types can be a map of types/handlers + if (typeof types === 'object') { + for (var type in types) { + // we don't process space-separated events here for performance; + // it's a hot path since Layer uses the on(obj) syntax + this._on(type, types[type], fn); + } + + } else { + // types can be a string of space-separated words + types = splitWords(types); + + for (var i = 0, len = types.length; i < len; i++) { + this._on(types[i], fn, context); + } + } + + return this; + }, + + /* @method off(type: String, fn?: Function, context?: Object): this + * Removes a previously added listener function. If no function is specified, it will remove all the listeners of that particular event from the object. Note that if you passed a custom context to `on`, you must pass the same context to `off` in order to remove the listener. + * + * @alternative + * @method off(eventMap: Object): this + * Removes a set of type/listener pairs. + * + * @alternative + * @method off: this + * Removes all listeners to all events on the object. This includes implicitly attached events. + */ + off: function (types, fn, context) { + + if (!arguments.length) { + // clear all listeners if called without arguments + delete this._events; + + } else if (typeof types === 'object') { + for (var type in types) { + this._off(type, types[type], fn); + } + + } else { + types = splitWords(types); + + var removeAll = arguments.length === 1; + for (var i = 0, len = types.length; i < len; i++) { + if (removeAll) { + this._off(types[i]); + } else { + this._off(types[i], fn, context); + } + } + } + + return this; + }, + + // attach listener (without syntactic sugar now) + _on: function (type, fn, context, _once) { + if (typeof fn !== 'function') { + console.warn('wrong listener type: ' + typeof fn); + return; + } + + // check if fn already there + if (this._listens(type, fn, context) !== false) { + return; + } + + if (context === this) { + // Less memory footprint. + context = undefined; + } + + var newListener = {fn: fn, ctx: context}; + if (_once) { + newListener.once = true; + } + + this._events = this._events || {}; + this._events[type] = this._events[type] || []; + this._events[type].push(newListener); + }, + + _off: function (type, fn, context) { + var listeners, + i, + len; + + if (!this._events) { + return; + } + + listeners = this._events[type]; + if (!listeners) { + return; + } + + if (arguments.length === 1) { // remove all + if (this._firingCount) { + // Set all removed listeners to noop + // so they are not called if remove happens in fire + for (i = 0, len = listeners.length; i < len; i++) { + listeners[i].fn = falseFn; + } + } + // clear all listeners for a type if function isn't specified + delete this._events[type]; + return; + } + + if (typeof fn !== 'function') { + console.warn('wrong listener type: ' + typeof fn); + return; + } + + // find fn and remove it + var index = this._listens(type, fn, context); + if (index !== false) { + var listener = listeners[index]; + if (this._firingCount) { + // set the removed listener to noop so that's not called if remove happens in fire + listener.fn = falseFn; + + /* copy array in case events are being fired */ + this._events[type] = listeners = listeners.slice(); + } + listeners.splice(index, 1); + } + }, + + // @method fire(type: String, data?: Object, propagate?: Boolean): this + // Fires an event of the specified type. You can optionally provide a data + // object — the first argument of the listener function will contain its + // properties. The event can optionally be propagated to event parents. + fire: function (type, data, propagate) { + if (!this.listens(type, propagate)) { return this; } + + var event = extend({}, data, { + type: type, + target: this, + sourceTarget: data && data.sourceTarget || this + }); + + if (this._events) { + var listeners = this._events[type]; + if (listeners) { + this._firingCount = (this._firingCount + 1) || 1; + for (var i = 0, len = listeners.length; i < len; i++) { + var l = listeners[i]; + // off overwrites l.fn, so we need to copy fn to a var + var fn = l.fn; + if (l.once) { + this.off(type, fn, l.ctx); + } + fn.call(l.ctx || this, event); + } + + this._firingCount--; + } + } + + if (propagate) { + // propagate the event to parents (set with addEventParent) + this._propagateEvent(event); + } + + return this; + }, + + // @method listens(type: String, propagate?: Boolean): Boolean + // @method listens(type: String, fn: Function, context?: Object, propagate?: Boolean): Boolean + // Returns `true` if a particular event type has any listeners attached to it. + // The verification can optionally be propagated, it will return `true` if parents have the listener attached to it. + listens: function (type, fn, context, propagate) { + if (typeof type !== 'string') { + console.warn('"string" type argument expected'); + } + + // we don't overwrite the input `fn` value, because we need to use it for propagation + var _fn = fn; + if (typeof fn !== 'function') { + propagate = !!fn; + _fn = undefined; + context = undefined; + } + + var listeners = this._events && this._events[type]; + if (listeners && listeners.length) { + if (this._listens(type, _fn, context) !== false) { + return true; + } + } + + if (propagate) { + // also check parents for listeners if event propagates + for (var id in this._eventParents) { + if (this._eventParents[id].listens(type, fn, context, propagate)) { return true; } + } + } + return false; + }, + + // returns the index (number) or false + _listens: function (type, fn, context) { + if (!this._events) { + return false; + } + + var listeners = this._events[type] || []; + if (!fn) { + return !!listeners.length; + } + + if (context === this) { + // Less memory footprint. + context = undefined; + } + + for (var i = 0, len = listeners.length; i < len; i++) { + if (listeners[i].fn === fn && listeners[i].ctx === context) { + return i; + } + } + return false; + + }, + + // @method once(…): this + // Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed. + once: function (types, fn, context) { + + // types can be a map of types/handlers + if (typeof types === 'object') { + for (var type in types) { + // we don't process space-separated events here for performance; + // it's a hot path since Layer uses the on(obj) syntax + this._on(type, types[type], fn, true); + } + + } else { + // types can be a string of space-separated words + types = splitWords(types); + + for (var i = 0, len = types.length; i < len; i++) { + this._on(types[i], fn, context, true); + } + } + + return this; + }, + + // @method addEventParent(obj: Evented): this + // Adds an event parent - an `Evented` that will receive propagated events + addEventParent: function (obj) { + this._eventParents = this._eventParents || {}; + this._eventParents[stamp(obj)] = obj; + return this; + }, + + // @method removeEventParent(obj: Evented): this + // Removes an event parent, so it will stop receiving propagated events + removeEventParent: function (obj) { + if (this._eventParents) { + delete this._eventParents[stamp(obj)]; + } + return this; + }, + + _propagateEvent: function (e) { + for (var id in this._eventParents) { + this._eventParents[id].fire(e.type, extend({ + layer: e.target, + propagatedFrom: e.target + }, e), true); + } + } +}; + +// aliases; we should ditch those eventually + +// @method addEventListener(…): this +// Alias to [`on(…)`](#evented-on) +Events.addEventListener = Events.on; + +// @method removeEventListener(…): this +// Alias to [`off(…)`](#evented-off) + +// @method clearAllEventListeners(…): this +// Alias to [`off()`](#evented-off) +Events.removeEventListener = Events.clearAllEventListeners = Events.off; + +// @method addOneTimeEventListener(…): this +// Alias to [`once(…)`](#evented-once) +Events.addOneTimeEventListener = Events.once; + +// @method fireEvent(…): this +// Alias to [`fire(…)`](#evented-fire) +Events.fireEvent = Events.fire; + +// @method hasEventListeners(…): Boolean +// Alias to [`listens(…)`](#evented-listens) +Events.hasEventListeners = Events.listens; + +var Evented = Class.extend(Events); + +/* + * @class Point + * @aka L.Point + * + * Represents a point with `x` and `y` coordinates in pixels. + * + * @example + * + * ```js + * var point = L.point(200, 300); + * ``` + * + * All Leaflet methods and options that accept `Point` objects also accept them in a simple Array form (unless noted otherwise), so these lines are equivalent: + * + * ```js + * map.panBy([200, 300]); + * map.panBy(L.point(200, 300)); + * ``` + * + * Note that `Point` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function Point(x, y, round) { + // @property x: Number; The `x` coordinate of the point + this.x = (round ? Math.round(x) : x); + // @property y: Number; The `y` coordinate of the point + this.y = (round ? Math.round(y) : y); +} + +var trunc = Math.trunc || function (v) { + return v > 0 ? Math.floor(v) : Math.ceil(v); +}; + +Point.prototype = { + + // @method clone(): Point + // Returns a copy of the current point. + clone: function () { + return new Point(this.x, this.y); + }, + + // @method add(otherPoint: Point): Point + // Returns the result of addition of the current and the given points. + add: function (point) { + // non-destructive, returns a new point + return this.clone()._add(toPoint(point)); + }, + + _add: function (point) { + // destructive, used directly for performance in situations where it's safe to modify existing point + this.x += point.x; + this.y += point.y; + return this; + }, + + // @method subtract(otherPoint: Point): Point + // Returns the result of subtraction of the given point from the current. + subtract: function (point) { + return this.clone()._subtract(toPoint(point)); + }, + + _subtract: function (point) { + this.x -= point.x; + this.y -= point.y; + return this; + }, + + // @method divideBy(num: Number): Point + // Returns the result of division of the current point by the given number. + divideBy: function (num) { + return this.clone()._divideBy(num); + }, + + _divideBy: function (num) { + this.x /= num; + this.y /= num; + return this; + }, + + // @method multiplyBy(num: Number): Point + // Returns the result of multiplication of the current point by the given number. + multiplyBy: function (num) { + return this.clone()._multiplyBy(num); + }, + + _multiplyBy: function (num) { + this.x *= num; + this.y *= num; + return this; + }, + + // @method scaleBy(scale: Point): Point + // Multiply each coordinate of the current point by each coordinate of + // `scale`. In linear algebra terms, multiply the point by the + // [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation) + // defined by `scale`. + scaleBy: function (point) { + return new Point(this.x * point.x, this.y * point.y); + }, + + // @method unscaleBy(scale: Point): Point + // Inverse of `scaleBy`. Divide each coordinate of the current point by + // each coordinate of `scale`. + unscaleBy: function (point) { + return new Point(this.x / point.x, this.y / point.y); + }, + + // @method round(): Point + // Returns a copy of the current point with rounded coordinates. + round: function () { + return this.clone()._round(); + }, + + _round: function () { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + return this; + }, + + // @method floor(): Point + // Returns a copy of the current point with floored coordinates (rounded down). + floor: function () { + return this.clone()._floor(); + }, + + _floor: function () { + this.x = Math.floor(this.x); + this.y = Math.floor(this.y); + return this; + }, + + // @method ceil(): Point + // Returns a copy of the current point with ceiled coordinates (rounded up). + ceil: function () { + return this.clone()._ceil(); + }, + + _ceil: function () { + this.x = Math.ceil(this.x); + this.y = Math.ceil(this.y); + return this; + }, + + // @method trunc(): Point + // Returns a copy of the current point with truncated coordinates (rounded towards zero). + trunc: function () { + return this.clone()._trunc(); + }, + + _trunc: function () { + this.x = trunc(this.x); + this.y = trunc(this.y); + return this; + }, + + // @method distanceTo(otherPoint: Point): Number + // Returns the cartesian distance between the current and the given points. + distanceTo: function (point) { + point = toPoint(point); + + var x = point.x - this.x, + y = point.y - this.y; + + return Math.sqrt(x * x + y * y); + }, + + // @method equals(otherPoint: Point): Boolean + // Returns `true` if the given point has the same coordinates. + equals: function (point) { + point = toPoint(point); + + return point.x === this.x && + point.y === this.y; + }, + + // @method contains(otherPoint: Point): Boolean + // Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values). + contains: function (point) { + point = toPoint(point); + + return Math.abs(point.x) <= Math.abs(this.x) && + Math.abs(point.y) <= Math.abs(this.y); + }, + + // @method toString(): String + // Returns a string representation of the point for debugging purposes. + toString: function () { + return 'Point(' + + formatNum(this.x) + ', ' + + formatNum(this.y) + ')'; + } +}; + +// @factory L.point(x: Number, y: Number, round?: Boolean) +// Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values. + +// @alternative +// @factory L.point(coords: Number[]) +// Expects an array of the form `[x, y]` instead. + +// @alternative +// @factory L.point(coords: Object) +// Expects a plain object of the form `{x: Number, y: Number}` instead. +function toPoint(x, y, round) { + if (x instanceof Point) { + return x; + } + if (isArray(x)) { + return new Point(x[0], x[1]); + } + if (x === undefined || x === null) { + return x; + } + if (typeof x === 'object' && 'x' in x && 'y' in x) { + return new Point(x.x, x.y); + } + return new Point(x, y, round); +} + +/* + * @class Bounds + * @aka L.Bounds + * + * Represents a rectangular area in pixel coordinates. + * + * @example + * + * ```js + * var p1 = L.point(10, 10), + * p2 = L.point(40, 60), + * bounds = L.bounds(p1, p2); + * ``` + * + * All Leaflet methods that accept `Bounds` objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this: + * + * ```js + * otherBounds.intersects([[10, 10], [40, 60]]); + * ``` + * + * Note that `Bounds` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function Bounds(a, b) { + if (!a) { return; } + + var points = b ? [a, b] : a; + + for (var i = 0, len = points.length; i < len; i++) { + this.extend(points[i]); + } +} + +Bounds.prototype = { + // @method extend(point: Point): this + // Extends the bounds to contain the given point. + + // @alternative + // @method extend(otherBounds: Bounds): this + // Extend the bounds to contain the given bounds + extend: function (obj) { + var min2, max2; + if (!obj) { return this; } + + if (obj instanceof Point || typeof obj[0] === 'number' || 'x' in obj) { + min2 = max2 = toPoint(obj); + } else { + obj = toBounds(obj); + min2 = obj.min; + max2 = obj.max; + + if (!min2 || !max2) { return this; } + } + + // @property min: Point + // The top left corner of the rectangle. + // @property max: Point + // The bottom right corner of the rectangle. + if (!this.min && !this.max) { + this.min = min2.clone(); + this.max = max2.clone(); + } else { + this.min.x = Math.min(min2.x, this.min.x); + this.max.x = Math.max(max2.x, this.max.x); + this.min.y = Math.min(min2.y, this.min.y); + this.max.y = Math.max(max2.y, this.max.y); + } + return this; + }, + + // @method getCenter(round?: Boolean): Point + // Returns the center point of the bounds. + getCenter: function (round) { + return toPoint( + (this.min.x + this.max.x) / 2, + (this.min.y + this.max.y) / 2, round); + }, + + // @method getBottomLeft(): Point + // Returns the bottom-left point of the bounds. + getBottomLeft: function () { + return toPoint(this.min.x, this.max.y); + }, + + // @method getTopRight(): Point + // Returns the top-right point of the bounds. + getTopRight: function () { // -> Point + return toPoint(this.max.x, this.min.y); + }, + + // @method getTopLeft(): Point + // Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)). + getTopLeft: function () { + return this.min; // left, top + }, + + // @method getBottomRight(): Point + // Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)). + getBottomRight: function () { + return this.max; // right, bottom + }, + + // @method getSize(): Point + // Returns the size of the given bounds + getSize: function () { + return this.max.subtract(this.min); + }, + + // @method contains(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle contains the given one. + // @alternative + // @method contains(point: Point): Boolean + // Returns `true` if the rectangle contains the given point. + contains: function (obj) { + var min, max; + + if (typeof obj[0] === 'number' || obj instanceof Point) { + obj = toPoint(obj); + } else { + obj = toBounds(obj); + } + + if (obj instanceof Bounds) { + min = obj.min; + max = obj.max; + } else { + min = max = obj; + } + + return (min.x >= this.min.x) && + (max.x <= this.max.x) && + (min.y >= this.min.y) && + (max.y <= this.max.y); + }, + + // @method intersects(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle intersects the given bounds. Two bounds + // intersect if they have at least one point in common. + intersects: function (bounds) { // (Bounds) -> Boolean + bounds = toBounds(bounds); + + var min = this.min, + max = this.max, + min2 = bounds.min, + max2 = bounds.max, + xIntersects = (max2.x >= min.x) && (min2.x <= max.x), + yIntersects = (max2.y >= min.y) && (min2.y <= max.y); + + return xIntersects && yIntersects; + }, + + // @method overlaps(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle overlaps the given bounds. Two bounds + // overlap if their intersection is an area. + overlaps: function (bounds) { // (Bounds) -> Boolean + bounds = toBounds(bounds); + + var min = this.min, + max = this.max, + min2 = bounds.min, + max2 = bounds.max, + xOverlaps = (max2.x > min.x) && (min2.x < max.x), + yOverlaps = (max2.y > min.y) && (min2.y < max.y); + + return xOverlaps && yOverlaps; + }, + + // @method isValid(): Boolean + // Returns `true` if the bounds are properly initialized. + isValid: function () { + return !!(this.min && this.max); + }, + + + // @method pad(bufferRatio: Number): Bounds + // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction. + // For example, a ratio of 0.5 extends the bounds by 50% in each direction. + // Negative values will retract the bounds. + pad: function (bufferRatio) { + var min = this.min, + max = this.max, + heightBuffer = Math.abs(min.x - max.x) * bufferRatio, + widthBuffer = Math.abs(min.y - max.y) * bufferRatio; + + + return toBounds( + toPoint(min.x - heightBuffer, min.y - widthBuffer), + toPoint(max.x + heightBuffer, max.y + widthBuffer)); + }, + + + // @method equals(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle is equivalent to the given bounds. + equals: function (bounds) { + if (!bounds) { return false; } + + bounds = toBounds(bounds); + + return this.min.equals(bounds.getTopLeft()) && + this.max.equals(bounds.getBottomRight()); + }, +}; + + +// @factory L.bounds(corner1: Point, corner2: Point) +// Creates a Bounds object from two corners coordinate pairs. +// @alternative +// @factory L.bounds(points: Point[]) +// Creates a Bounds object from the given array of points. +function toBounds(a, b) { + if (!a || a instanceof Bounds) { + return a; + } + return new Bounds(a, b); +} + +/* + * @class LatLngBounds + * @aka L.LatLngBounds + * + * Represents a rectangular geographical area on a map. + * + * @example + * + * ```js + * var corner1 = L.latLng(40.712, -74.227), + * corner2 = L.latLng(40.774, -74.125), + * bounds = L.latLngBounds(corner1, corner2); + * ``` + * + * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this: + * + * ```js + * map.fitBounds([ + * [40.712, -74.227], + * [40.774, -74.125] + * ]); + * ``` + * + * Caution: if the area crosses the antimeridian (often confused with the International Date Line), you must specify corners _outside_ the [-180, 180] degrees longitude range. + * + * Note that `LatLngBounds` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[]) + if (!corner1) { return; } + + var latlngs = corner2 ? [corner1, corner2] : corner1; + + for (var i = 0, len = latlngs.length; i < len; i++) { + this.extend(latlngs[i]); + } +} + +LatLngBounds.prototype = { + + // @method extend(latlng: LatLng): this + // Extend the bounds to contain the given point + + // @alternative + // @method extend(otherBounds: LatLngBounds): this + // Extend the bounds to contain the given bounds + extend: function (obj) { + var sw = this._southWest, + ne = this._northEast, + sw2, ne2; + + if (obj instanceof LatLng) { + sw2 = obj; + ne2 = obj; + + } else if (obj instanceof LatLngBounds) { + sw2 = obj._southWest; + ne2 = obj._northEast; + + if (!sw2 || !ne2) { return this; } + + } else { + return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this; + } + + if (!sw && !ne) { + this._southWest = new LatLng(sw2.lat, sw2.lng); + this._northEast = new LatLng(ne2.lat, ne2.lng); + } else { + sw.lat = Math.min(sw2.lat, sw.lat); + sw.lng = Math.min(sw2.lng, sw.lng); + ne.lat = Math.max(ne2.lat, ne.lat); + ne.lng = Math.max(ne2.lng, ne.lng); + } + + return this; + }, + + // @method pad(bufferRatio: Number): LatLngBounds + // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction. + // For example, a ratio of 0.5 extends the bounds by 50% in each direction. + // Negative values will retract the bounds. + pad: function (bufferRatio) { + var sw = this._southWest, + ne = this._northEast, + heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio, + widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio; + + return new LatLngBounds( + new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer), + new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer)); + }, + + // @method getCenter(): LatLng + // Returns the center point of the bounds. + getCenter: function () { + return new LatLng( + (this._southWest.lat + this._northEast.lat) / 2, + (this._southWest.lng + this._northEast.lng) / 2); + }, + + // @method getSouthWest(): LatLng + // Returns the south-west point of the bounds. + getSouthWest: function () { + return this._southWest; + }, + + // @method getNorthEast(): LatLng + // Returns the north-east point of the bounds. + getNorthEast: function () { + return this._northEast; + }, + + // @method getNorthWest(): LatLng + // Returns the north-west point of the bounds. + getNorthWest: function () { + return new LatLng(this.getNorth(), this.getWest()); + }, + + // @method getSouthEast(): LatLng + // Returns the south-east point of the bounds. + getSouthEast: function () { + return new LatLng(this.getSouth(), this.getEast()); + }, + + // @method getWest(): Number + // Returns the west longitude of the bounds + getWest: function () { + return this._southWest.lng; + }, + + // @method getSouth(): Number + // Returns the south latitude of the bounds + getSouth: function () { + return this._southWest.lat; + }, + + // @method getEast(): Number + // Returns the east longitude of the bounds + getEast: function () { + return this._northEast.lng; + }, + + // @method getNorth(): Number + // Returns the north latitude of the bounds + getNorth: function () { + return this._northEast.lat; + }, + + // @method contains(otherBounds: LatLngBounds): Boolean + // Returns `true` if the rectangle contains the given one. + + // @alternative + // @method contains (latlng: LatLng): Boolean + // Returns `true` if the rectangle contains the given point. + contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean + if (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) { + obj = toLatLng(obj); + } else { + obj = toLatLngBounds(obj); + } + + var sw = this._southWest, + ne = this._northEast, + sw2, ne2; + + if (obj instanceof LatLngBounds) { + sw2 = obj.getSouthWest(); + ne2 = obj.getNorthEast(); + } else { + sw2 = ne2 = obj; + } + + return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) && + (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng); + }, + + // @method intersects(otherBounds: LatLngBounds): Boolean + // Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common. + intersects: function (bounds) { + bounds = toLatLngBounds(bounds); + + var sw = this._southWest, + ne = this._northEast, + sw2 = bounds.getSouthWest(), + ne2 = bounds.getNorthEast(), + + latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat), + lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng); + + return latIntersects && lngIntersects; + }, + + // @method overlaps(otherBounds: LatLngBounds): Boolean + // Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area. + overlaps: function (bounds) { + bounds = toLatLngBounds(bounds); + + var sw = this._southWest, + ne = this._northEast, + sw2 = bounds.getSouthWest(), + ne2 = bounds.getNorthEast(), + + latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat), + lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng); + + return latOverlaps && lngOverlaps; + }, + + // @method toBBoxString(): String + // Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data. + toBBoxString: function () { + return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(','); + }, + + // @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean + // Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overridden by setting `maxMargin` to a small number. + equals: function (bounds, maxMargin) { + if (!bounds) { return false; } + + bounds = toLatLngBounds(bounds); + + return this._southWest.equals(bounds.getSouthWest(), maxMargin) && + this._northEast.equals(bounds.getNorthEast(), maxMargin); + }, + + // @method isValid(): Boolean + // Returns `true` if the bounds are properly initialized. + isValid: function () { + return !!(this._southWest && this._northEast); + } +}; + +// TODO International date line? + +// @factory L.latLngBounds(corner1: LatLng, corner2: LatLng) +// Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle. + +// @alternative +// @factory L.latLngBounds(latlngs: LatLng[]) +// Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds). +function toLatLngBounds(a, b) { + if (a instanceof LatLngBounds) { + return a; + } + return new LatLngBounds(a, b); +} + +/* @class LatLng + * @aka L.LatLng + * + * Represents a geographical point with a certain latitude and longitude. + * + * @example + * + * ``` + * var latlng = L.latLng(50.5, 30.5); + * ``` + * + * All Leaflet methods that accept LatLng objects also accept them in a simple Array form and simple object form (unless noted otherwise), so these lines are equivalent: + * + * ``` + * map.panTo([50, 30]); + * map.panTo({lon: 30, lat: 50}); + * map.panTo({lat: 50, lng: 30}); + * map.panTo(L.latLng(50, 30)); + * ``` + * + * Note that `LatLng` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function LatLng(lat, lng, alt) { + if (isNaN(lat) || isNaN(lng)) { + throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')'); + } + + // @property lat: Number + // Latitude in degrees + this.lat = +lat; + + // @property lng: Number + // Longitude in degrees + this.lng = +lng; + + // @property alt: Number + // Altitude in meters (optional) + if (alt !== undefined) { + this.alt = +alt; + } +} + +LatLng.prototype = { + // @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean + // Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overridden by setting `maxMargin` to a small number. + equals: function (obj, maxMargin) { + if (!obj) { return false; } + + obj = toLatLng(obj); + + var margin = Math.max( + Math.abs(this.lat - obj.lat), + Math.abs(this.lng - obj.lng)); + + return margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin); + }, + + // @method toString(): String + // Returns a string representation of the point (for debugging purposes). + toString: function (precision) { + return 'LatLng(' + + formatNum(this.lat, precision) + ', ' + + formatNum(this.lng, precision) + ')'; + }, + + // @method distanceTo(otherLatLng: LatLng): Number + // Returns the distance (in meters) to the given `LatLng` calculated using the [Spherical Law of Cosines](https://en.wikipedia.org/wiki/Spherical_law_of_cosines). + distanceTo: function (other) { + return Earth.distance(this, toLatLng(other)); + }, + + // @method wrap(): LatLng + // Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees. + wrap: function () { + return Earth.wrapLatLng(this); + }, + + // @method toBounds(sizeInMeters: Number): LatLngBounds + // Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`. + toBounds: function (sizeInMeters) { + var latAccuracy = 180 * sizeInMeters / 40075017, + lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat); + + return toLatLngBounds( + [this.lat - latAccuracy, this.lng - lngAccuracy], + [this.lat + latAccuracy, this.lng + lngAccuracy]); + }, + + clone: function () { + return new LatLng(this.lat, this.lng, this.alt); + } +}; + + + +// @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng +// Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude). + +// @alternative +// @factory L.latLng(coords: Array): LatLng +// Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead. + +// @alternative +// @factory L.latLng(coords: Object): LatLng +// Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead. + +function toLatLng(a, b, c) { + if (a instanceof LatLng) { + return a; + } + if (isArray(a) && typeof a[0] !== 'object') { + if (a.length === 3) { + return new LatLng(a[0], a[1], a[2]); + } + if (a.length === 2) { + return new LatLng(a[0], a[1]); + } + return null; + } + if (a === undefined || a === null) { + return a; + } + if (typeof a === 'object' && 'lat' in a) { + return new LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt); + } + if (b === undefined) { + return null; + } + return new LatLng(a, b, c); +} + +/* + * @namespace CRS + * @crs L.CRS.Base + * Object that defines coordinate reference systems for projecting + * geographical points into pixel (screen) coordinates and back (and to + * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See + * [spatial reference system](https://en.wikipedia.org/wiki/Spatial_reference_system). + * + * Leaflet defines the most usual CRSs by default. If you want to use a + * CRS not defined by default, take a look at the + * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin. + * + * Note that the CRS instances do not inherit from Leaflet's `Class` object, + * and can't be instantiated. Also, new classes can't inherit from them, + * and methods can't be added to them with the `include` function. + */ + +var CRS = { + // @method latLngToPoint(latlng: LatLng, zoom: Number): Point + // Projects geographical coordinates into pixel coordinates for a given zoom. + latLngToPoint: function (latlng, zoom) { + var projectedPoint = this.projection.project(latlng), + scale = this.scale(zoom); + + return this.transformation._transform(projectedPoint, scale); + }, + + // @method pointToLatLng(point: Point, zoom: Number): LatLng + // The inverse of `latLngToPoint`. Projects pixel coordinates on a given + // zoom into geographical coordinates. + pointToLatLng: function (point, zoom) { + var scale = this.scale(zoom), + untransformedPoint = this.transformation.untransform(point, scale); + + return this.projection.unproject(untransformedPoint); + }, + + // @method project(latlng: LatLng): Point + // Projects geographical coordinates into coordinates in units accepted for + // this CRS (e.g. meters for EPSG:3857, for passing it to WMS services). + project: function (latlng) { + return this.projection.project(latlng); + }, + + // @method unproject(point: Point): LatLng + // Given a projected coordinate returns the corresponding LatLng. + // The inverse of `project`. + unproject: function (point) { + return this.projection.unproject(point); + }, + + // @method scale(zoom: Number): Number + // Returns the scale used when transforming projected coordinates into + // pixel coordinates for a particular zoom. For example, it returns + // `256 * 2^zoom` for Mercator-based CRS. + scale: function (zoom) { + return 256 * Math.pow(2, zoom); + }, + + // @method zoom(scale: Number): Number + // Inverse of `scale()`, returns the zoom level corresponding to a scale + // factor of `scale`. + zoom: function (scale) { + return Math.log(scale / 256) / Math.LN2; + }, + + // @method getProjectedBounds(zoom: Number): Bounds + // Returns the projection's bounds scaled and transformed for the provided `zoom`. + getProjectedBounds: function (zoom) { + if (this.infinite) { return null; } + + var b = this.projection.bounds, + s = this.scale(zoom), + min = this.transformation.transform(b.min, s), + max = this.transformation.transform(b.max, s); + + return new Bounds(min, max); + }, + + // @method distance(latlng1: LatLng, latlng2: LatLng): Number + // Returns the distance between two geographical coordinates. + + // @property code: String + // Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`) + // + // @property wrapLng: Number[] + // An array of two numbers defining whether the longitude (horizontal) coordinate + // axis wraps around a given range and how. Defaults to `[-180, 180]` in most + // geographical CRSs. If `undefined`, the longitude axis does not wrap around. + // + // @property wrapLat: Number[] + // Like `wrapLng`, but for the latitude (vertical) axis. + + // wrapLng: [min, max], + // wrapLat: [min, max], + + // @property infinite: Boolean + // If true, the coordinate space will be unbounded (infinite in both axes) + infinite: false, + + // @method wrapLatLng(latlng: LatLng): LatLng + // Returns a `LatLng` where lat and lng has been wrapped according to the + // CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds. + wrapLatLng: function (latlng) { + var lng = this.wrapLng ? wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng, + lat = this.wrapLat ? wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat, + alt = latlng.alt; + + return new LatLng(lat, lng, alt); + }, + + // @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds + // Returns a `LatLngBounds` with the same size as the given one, ensuring + // that its center is within the CRS's bounds. + // Only accepts actual `L.LatLngBounds` instances, not arrays. + wrapLatLngBounds: function (bounds) { + var center = bounds.getCenter(), + newCenter = this.wrapLatLng(center), + latShift = center.lat - newCenter.lat, + lngShift = center.lng - newCenter.lng; + + if (latShift === 0 && lngShift === 0) { + return bounds; + } + + var sw = bounds.getSouthWest(), + ne = bounds.getNorthEast(), + newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift), + newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift); + + return new LatLngBounds(newSw, newNe); + } +}; + +/* + * @namespace CRS + * @crs L.CRS.Earth + * + * Serves as the base for CRS that are global such that they cover the earth. + * Can only be used as the base for other CRS and cannot be used directly, + * since it does not have a `code`, `projection` or `transformation`. `distance()` returns + * meters. + */ + +var Earth = extend({}, CRS, { + wrapLng: [-180, 180], + + // Mean Earth Radius, as recommended for use by + // the International Union of Geodesy and Geophysics, + // see https://rosettacode.org/wiki/Haversine_formula + R: 6371000, + + // distance between two geographical points using spherical law of cosines approximation + distance: function (latlng1, latlng2) { + var rad = Math.PI / 180, + lat1 = latlng1.lat * rad, + lat2 = latlng2.lat * rad, + sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2), + sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2), + a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon, + c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + return this.R * c; + } +}); + +/* + * @namespace Projection + * @projection L.Projection.SphericalMercator + * + * Spherical Mercator projection — the most common projection for online maps, + * used by almost all free and commercial tile providers. Assumes that Earth is + * a sphere. Used by the `EPSG:3857` CRS. + */ + +var earthRadius = 6378137; + +var SphericalMercator = { + + R: earthRadius, + MAX_LATITUDE: 85.0511287798, + + project: function (latlng) { + var d = Math.PI / 180, + max = this.MAX_LATITUDE, + lat = Math.max(Math.min(max, latlng.lat), -max), + sin = Math.sin(lat * d); + + return new Point( + this.R * latlng.lng * d, + this.R * Math.log((1 + sin) / (1 - sin)) / 2); + }, + + unproject: function (point) { + var d = 180 / Math.PI; + + return new LatLng( + (2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d, + point.x * d / this.R); + }, + + bounds: (function () { + var d = earthRadius * Math.PI; + return new Bounds([-d, -d], [d, d]); + })() +}; + +/* + * @class Transformation + * @aka L.Transformation + * + * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d` + * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing + * the reverse. Used by Leaflet in its projections code. + * + * @example + * + * ```js + * var transformation = L.transformation(2, 5, -1, 10), + * p = L.point(1, 2), + * p2 = transformation.transform(p), // L.point(7, 8) + * p3 = transformation.untransform(p2); // L.point(1, 2) + * ``` + */ + + +// factory new L.Transformation(a: Number, b: Number, c: Number, d: Number) +// Creates a `Transformation` object with the given coefficients. +function Transformation(a, b, c, d) { + if (isArray(a)) { + // use array properties + this._a = a[0]; + this._b = a[1]; + this._c = a[2]; + this._d = a[3]; + return; + } + this._a = a; + this._b = b; + this._c = c; + this._d = d; +} + +Transformation.prototype = { + // @method transform(point: Point, scale?: Number): Point + // Returns a transformed point, optionally multiplied by the given scale. + // Only accepts actual `L.Point` instances, not arrays. + transform: function (point, scale) { // (Point, Number) -> Point + return this._transform(point.clone(), scale); + }, + + // destructive transform (faster) + _transform: function (point, scale) { + scale = scale || 1; + point.x = scale * (this._a * point.x + this._b); + point.y = scale * (this._c * point.y + this._d); + return point; + }, + + // @method untransform(point: Point, scale?: Number): Point + // Returns the reverse transformation of the given point, optionally divided + // by the given scale. Only accepts actual `L.Point` instances, not arrays. + untransform: function (point, scale) { + scale = scale || 1; + return new Point( + (point.x / scale - this._b) / this._a, + (point.y / scale - this._d) / this._c); + } +}; + +// factory L.transformation(a: Number, b: Number, c: Number, d: Number) + +// @factory L.transformation(a: Number, b: Number, c: Number, d: Number) +// Instantiates a Transformation object with the given coefficients. + +// @alternative +// @factory L.transformation(coefficients: Array): Transformation +// Expects an coefficients array of the form +// `[a: Number, b: Number, c: Number, d: Number]`. + +function toTransformation(a, b, c, d) { + return new Transformation(a, b, c, d); +} + +/* + * @namespace CRS + * @crs L.CRS.EPSG3857 + * + * The most common CRS for online maps, used by almost all free and commercial + * tile providers. Uses Spherical Mercator projection. Set in by default in + * Map's `crs` option. + */ + +var EPSG3857 = extend({}, Earth, { + code: 'EPSG:3857', + projection: SphericalMercator, + + transformation: (function () { + var scale = 0.5 / (Math.PI * SphericalMercator.R); + return toTransformation(scale, 0.5, -scale, 0.5); + }()) +}); + +var EPSG900913 = extend({}, EPSG3857, { + code: 'EPSG:900913' +}); + +// @namespace SVG; @section +// There are several static functions which can be called without instantiating L.SVG: + +// @function create(name: String): SVGElement +// Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement), +// corresponding to the class name passed. For example, using 'line' will return +// an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement). +function svgCreate(name) { + return document.createElementNS('http://www.w3.org/2000/svg', name); +} + +// @function pointsToPath(rings: Point[], closed: Boolean): String +// Generates a SVG path string for multiple rings, with each ring turning +// into "M..L..L.." instructions +function pointsToPath(rings, closed) { + var str = '', + i, j, len, len2, points, p; + + for (i = 0, len = rings.length; i < len; i++) { + points = rings[i]; + + for (j = 0, len2 = points.length; j < len2; j++) { + p = points[j]; + str += (j ? 'L' : 'M') + p.x + ' ' + p.y; + } + + // closes the ring for polygons; "x" is VML syntax + str += closed ? (Browser.svg ? 'z' : 'x') : ''; + } + + // SVG complains about empty path strings + return str || 'M0 0'; +} + +/* + * @namespace Browser + * @aka L.Browser + * + * A namespace with static properties for browser/feature detection used by Leaflet internally. + * + * @example + * + * ```js + * if (L.Browser.ielt9) { + * alert('Upgrade your browser, dude!'); + * } + * ``` + */ + +var style = document.documentElement.style; + +// @property ie: Boolean; `true` for all Internet Explorer versions (not Edge). +var ie = 'ActiveXObject' in window; + +// @property ielt9: Boolean; `true` for Internet Explorer versions less than 9. +var ielt9 = ie && !document.addEventListener; + +// @property edge: Boolean; `true` for the Edge web browser. +var edge = 'msLaunchUri' in navigator && !('documentMode' in document); + +// @property webkit: Boolean; +// `true` for webkit-based browsers like Chrome and Safari (including mobile versions). +var webkit = userAgentContains('webkit'); + +// @property android: Boolean +// **Deprecated.** `true` for any browser running on an Android platform. +var android = userAgentContains('android'); + +// @property android23: Boolean; **Deprecated.** `true` for browsers running on Android 2 or Android 3. +var android23 = userAgentContains('android 2') || userAgentContains('android 3'); + +/* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */ +var webkitVer = parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit +// @property androidStock: Boolean; **Deprecated.** `true` for the Android stock browser (i.e. not Chrome) +var androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window); + +// @property opera: Boolean; `true` for the Opera browser +var opera = !!window.opera; + +// @property chrome: Boolean; `true` for the Chrome browser. +var chrome = !edge && userAgentContains('chrome'); + +// @property gecko: Boolean; `true` for gecko-based browsers like Firefox. +var gecko = userAgentContains('gecko') && !webkit && !opera && !ie; + +// @property safari: Boolean; `true` for the Safari browser. +var safari = !chrome && userAgentContains('safari'); + +var phantom = userAgentContains('phantom'); + +// @property opera12: Boolean +// `true` for the Opera browser supporting CSS transforms (version 12 or later). +var opera12 = 'OTransition' in style; + +// @property win: Boolean; `true` when the browser is running in a Windows platform +var win = navigator.platform.indexOf('Win') === 0; + +// @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms. +var ie3d = ie && ('transition' in style); + +// @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms. +var webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23; + +// @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms. +var gecko3d = 'MozPerspective' in style; + +// @property any3d: Boolean +// `true` for all browsers supporting CSS transforms. +var any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom; + +// @property mobile: Boolean; `true` for all browsers running in a mobile device. +var mobile = typeof orientation !== 'undefined' || userAgentContains('mobile'); + +// @property mobileWebkit: Boolean; `true` for all webkit-based browsers in a mobile device. +var mobileWebkit = mobile && webkit; + +// @property mobileWebkit3d: Boolean +// `true` for all webkit-based browsers in a mobile device supporting CSS transforms. +var mobileWebkit3d = mobile && webkit3d; + +// @property msPointer: Boolean +// `true` for browsers implementing the Microsoft touch events model (notably IE10). +var msPointer = !window.PointerEvent && window.MSPointerEvent; + +// @property pointer: Boolean +// `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx). +var pointer = !!(window.PointerEvent || msPointer); + +// @property touchNative: Boolean +// `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events). +// **This does not necessarily mean** that the browser is running in a computer with +// a touchscreen, it only means that the browser is capable of understanding +// touch events. +var touchNative = 'ontouchstart' in window || !!window.TouchEvent; + +// @property touch: Boolean +// `true` for all browsers supporting either [touch](#browser-touch) or [pointer](#browser-pointer) events. +// Note: pointer events will be preferred (if available), and processed for all `touch*` listeners. +var touch = !window.L_NO_TOUCH && (touchNative || pointer); + +// @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device. +var mobileOpera = mobile && opera; + +// @property mobileGecko: Boolean +// `true` for gecko-based browsers running in a mobile device. +var mobileGecko = mobile && gecko; + +// @property retina: Boolean +// `true` for browsers on a high-resolution "retina" screen or on any screen when browser's display zoom is more than 100%. +var retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1; + +// @property passiveEvents: Boolean +// `true` for browsers that support passive events. +var passiveEvents = (function () { + var supportsPassiveOption = false; + try { + var opts = Object.defineProperty({}, 'passive', { + get: function () { // eslint-disable-line getter-return + supportsPassiveOption = true; + } + }); + window.addEventListener('testPassiveEventSupport', falseFn, opts); + window.removeEventListener('testPassiveEventSupport', falseFn, opts); + } catch (e) { + // Errors can safely be ignored since this is only a browser support test. + } + return supportsPassiveOption; +}()); + +// @property canvas: Boolean +// `true` when the browser supports [``](https://developer.mozilla.org/docs/Web/API/Canvas_API). +var canvas$1 = (function () { + return !!document.createElement('canvas').getContext; +}()); + +// @property svg: Boolean +// `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG). +var svg$1 = !!(document.createElementNS && svgCreate('svg').createSVGRect); + +var inlineSvg = !!svg$1 && (function () { + var div = document.createElement('div'); + div.innerHTML = ''; + return (div.firstChild && div.firstChild.namespaceURI) === 'http://www.w3.org/2000/svg'; +})(); + +// @property vml: Boolean +// `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language). +var vml = !svg$1 && (function () { + try { + var div = document.createElement('div'); + div.innerHTML = ''; + + var shape = div.firstChild; + shape.style.behavior = 'url(#default#VML)'; + + return shape && (typeof shape.adj === 'object'); + + } catch (e) { + return false; + } +}()); + + +// @property mac: Boolean; `true` when the browser is running in a Mac platform +var mac = navigator.platform.indexOf('Mac') === 0; + +// @property mac: Boolean; `true` when the browser is running in a Linux platform +var linux = navigator.platform.indexOf('Linux') === 0; + +function userAgentContains(str) { + return navigator.userAgent.toLowerCase().indexOf(str) >= 0; +} + + +var Browser = { + ie: ie, + ielt9: ielt9, + edge: edge, + webkit: webkit, + android: android, + android23: android23, + androidStock: androidStock, + opera: opera, + chrome: chrome, + gecko: gecko, + safari: safari, + phantom: phantom, + opera12: opera12, + win: win, + ie3d: ie3d, + webkit3d: webkit3d, + gecko3d: gecko3d, + any3d: any3d, + mobile: mobile, + mobileWebkit: mobileWebkit, + mobileWebkit3d: mobileWebkit3d, + msPointer: msPointer, + pointer: pointer, + touch: touch, + touchNative: touchNative, + mobileOpera: mobileOpera, + mobileGecko: mobileGecko, + retina: retina, + passiveEvents: passiveEvents, + canvas: canvas$1, + svg: svg$1, + vml: vml, + inlineSvg: inlineSvg, + mac: mac, + linux: linux +}; + +/* + * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices. + */ + +var POINTER_DOWN = Browser.msPointer ? 'MSPointerDown' : 'pointerdown'; +var POINTER_MOVE = Browser.msPointer ? 'MSPointerMove' : 'pointermove'; +var POINTER_UP = Browser.msPointer ? 'MSPointerUp' : 'pointerup'; +var POINTER_CANCEL = Browser.msPointer ? 'MSPointerCancel' : 'pointercancel'; +var pEvent = { + touchstart : POINTER_DOWN, + touchmove : POINTER_MOVE, + touchend : POINTER_UP, + touchcancel : POINTER_CANCEL +}; +var handle = { + touchstart : _onPointerStart, + touchmove : _handlePointer, + touchend : _handlePointer, + touchcancel : _handlePointer +}; +var _pointers = {}; +var _pointerDocListener = false; + +// Provides a touch events wrapper for (ms)pointer events. +// ref https://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890 + +function addPointerListener(obj, type, handler) { + if (type === 'touchstart') { + _addPointerDocListener(); + } + if (!handle[type]) { + console.warn('wrong event specified:', type); + return falseFn; + } + handler = handle[type].bind(this, handler); + obj.addEventListener(pEvent[type], handler, false); + return handler; +} + +function removePointerListener(obj, type, handler) { + if (!pEvent[type]) { + console.warn('wrong event specified:', type); + return; + } + obj.removeEventListener(pEvent[type], handler, false); +} + +function _globalPointerDown(e) { + _pointers[e.pointerId] = e; +} + +function _globalPointerMove(e) { + if (_pointers[e.pointerId]) { + _pointers[e.pointerId] = e; + } +} + +function _globalPointerUp(e) { + delete _pointers[e.pointerId]; +} + +function _addPointerDocListener() { + // need to keep track of what pointers and how many are active to provide e.touches emulation + if (!_pointerDocListener) { + // we listen document as any drags that end by moving the touch off the screen get fired there + document.addEventListener(POINTER_DOWN, _globalPointerDown, true); + document.addEventListener(POINTER_MOVE, _globalPointerMove, true); + document.addEventListener(POINTER_UP, _globalPointerUp, true); + document.addEventListener(POINTER_CANCEL, _globalPointerUp, true); + + _pointerDocListener = true; + } +} + +function _handlePointer(handler, e) { + if (e.pointerType === (e.MSPOINTER_TYPE_MOUSE || 'mouse')) { return; } + + e.touches = []; + for (var i in _pointers) { + e.touches.push(_pointers[i]); + } + e.changedTouches = [e]; + + handler(e); +} + +function _onPointerStart(handler, e) { + // IE10 specific: MsTouch needs preventDefault. See #2000 + if (e.MSPOINTER_TYPE_TOUCH && e.pointerType === e.MSPOINTER_TYPE_TOUCH) { + preventDefault(e); + } + _handlePointer(handler, e); +} + +/* + * Extends the event handling code with double tap support for mobile browsers. + * + * Note: currently most browsers fire native dblclick, with only a few exceptions + * (see https://github.com/Leaflet/Leaflet/issues/7012#issuecomment-595087386) + */ + +function makeDblclick(event) { + // in modern browsers `type` cannot be just overridden: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only + var newEvent = {}, + prop, i; + for (i in event) { + prop = event[i]; + newEvent[i] = prop && prop.bind ? prop.bind(event) : prop; + } + event = newEvent; + newEvent.type = 'dblclick'; + newEvent.detail = 2; + newEvent.isTrusted = false; + newEvent._simulated = true; // for debug purposes + return newEvent; +} + +var delay = 200; +function addDoubleTapListener(obj, handler) { + // Most browsers handle double tap natively + obj.addEventListener('dblclick', handler); + + // On some platforms the browser doesn't fire native dblclicks for touch events. + // It seems that in all such cases `detail` property of `click` event is always `1`. + // So here we rely on that fact to avoid excessive 'dblclick' simulation when not needed. + var last = 0, + detail; + function simDblclick(e) { + if (e.detail !== 1) { + detail = e.detail; // keep in sync to avoid false dblclick in some cases + return; + } + + if (e.pointerType === 'mouse' || + (e.sourceCapabilities && !e.sourceCapabilities.firesTouchEvents)) { + + return; + } + + // When clicking on an , the browser generates a click on its + //