moved files into subdirs

This commit is contained in:
asohh 2025-10-13 16:28:20 +02:00
commit 10fcf55b10
230 changed files with 23 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

View file

@ -0,0 +1,23 @@
Copyright (c) 2010-2021, Vladimir Agafonkin
Copyright (c) 2010-2011, CloudMade
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. 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.
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 OR CONTRIBUTORS 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.

View file

@ -0,0 +1,32 @@
<img width="600" src="https://rawgit.com/Leaflet/Leaflet/master/src/images/logo.svg" alt="Leaflet" />
Leaflet is the leading open-source JavaScript library for **mobile-friendly interactive maps**.
Weighing just about 39 KB of gzipped JS plus 4 KB of gzipped CSS code, it has all the mapping [features][] most developers ever need.
Leaflet is designed with *simplicity*, *performance* and *usability* in mind.
It works efficiently across all major desktop and mobile platforms out of the box,
taking advantage of HTML5 and CSS3 on modern browsers while being accessible on older ones too.
It can be extended with a huge amount of [plugins][],
has a beautiful, easy to use and [well-documented][] API
and a simple, readable [source code][] that is a joy to [contribute][] to.
For more info, docs and tutorials, check out the [official website][].<br>
For **Leaflet downloads** (including the built master version), check out the [download page][].
We're happy to meet new contributors.
If you want to **get involved** with Leaflet development, check out the [contribution guide][contribute].
Let's make the best mapping library that will ever exist,
and push the limits of what's possible with online maps!
[![Build Status](https://travis-ci.org/Leaflet/Leaflet.svg?branch=master)](https://travis-ci.org/Leaflet/Leaflet)
[contributors]: https://github.com/Leaflet/Leaflet/graphs/contributors
[features]: http://leafletjs.com/#features
[plugins]: http://leafletjs.com/plugins.html
[well-documented]: http://leafletjs.com/reference.html "Leaflet API reference"
[source code]: https://github.com/Leaflet/Leaflet "Leaflet GitHub repository"
[hosted on GitHub]: http://github.com/Leaflet/Leaflet
[contribute]: https://github.com/Leaflet/Leaflet/blob/master/CONTRIBUTING.md "A guide to contributing to Leaflet"
[official website]: http://leafletjs.com
[download page]: http://leafletjs.com/download.html

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,661 @@
/* required styles */
.leaflet-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-container,
.leaflet-pane > svg,
.leaflet-pane > canvas,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
position: absolute;
left: 0;
top: 0;
}
.leaflet-container {
overflow: hidden;
}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
/* Prevents IE11 from highlighting tiles in blue */
.leaflet-tile::selection {
background: transparent;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast;
}
/* hack that prevents hw layers "stretching" when loading new tiles */
.leaflet-safari .leaflet-tile-container {
width: 1600px;
height: 1600px;
-webkit-transform-origin: 0 0;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg {
max-width: none !important;
max-height: none !important;
}
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer,
.leaflet-container .leaflet-tile {
max-width: none !important;
max-height: none !important;
width: auto;
padding: 0;
}
.leaflet-container img.leaflet-tile {
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
mix-blend-mode: plus-lighter;
}
.leaflet-container.leaflet-touch-zoom {
-ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y;
}
.leaflet-container.leaflet-touch-drag {
-ms-touch-action: pinch-zoom;
/* Fallback for FF which doesn't support pinch-zoom */
touch-action: none;
touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
-ms-touch-action: none;
touch-action: none;
}
.leaflet-container {
-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
width: 0;
height: 0;
-moz-box-sizing: border-box;
box-sizing: border-box;
z-index: 800;
}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
-moz-user-select: none;
}
.leaflet-pane { z-index: 400; }
.leaflet-tile-pane { z-index: 200; }
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane { z-index: 500; }
.leaflet-marker-pane { z-index: 600; }
.leaflet-tooltip-pane { z-index: 650; }
.leaflet-popup-pane { z-index: 700; }
.leaflet-map-pane canvas { z-index: 100; }
.leaflet-map-pane svg { z-index: 200; }
.leaflet-vml-shape {
width: 1px;
height: 1px;
}
.lvml {
behavior: url(#default#VML);
display: inline-block;
position: absolute;
}
/* control positioning */
.leaflet-control {
position: relative;
z-index: 800;
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
.leaflet-top,
.leaflet-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
float: left;
clear: both;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
/* zoom and fade animations */
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-animated {
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
}
svg.leaflet-zoom-animated {
will-change: transform;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
-webkit-transition: none;
-moz-transition: none;
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
/* cursors */
.leaflet-interactive {
cursor: pointer;
}
.leaflet-grab {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
cursor: crosshair;
}
.leaflet-popup-pane,
.leaflet-control {
cursor: auto;
}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
/* marker & overlays interactivity */
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-image-layer,
.leaflet-pane > svg path,
.leaflet-tile-container {
pointer-events: none;
}
.leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
/* visual tweaks */
.leaflet-container {
background: #ddd;
outline-offset: 1px;
}
.leaflet-container a {
color: #0078A8;
}
.leaflet-zoom-box {
border: 2px dotted #38f;
background: rgba(255,255,255,0.5);
}
/* general typography */
.leaflet-container {
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
font-size: 12px;
font-size: 0.75rem;
line-height: 1.5;
}
/* general toolbar styles */
.leaflet-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.leaflet-bar a {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.leaflet-bar a,
.leaflet-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.leaflet-bar a:hover,
.leaflet-bar a:focus {
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.leaflet-bar a.leaflet-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
.leaflet-touch .leaflet-bar a {
width: 30px;
height: 30px;
line-height: 30px;
}
.leaflet-touch .leaflet-bar a:first-child {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
.leaflet-touch .leaflet-bar a:last-child {
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
/* zoom control */
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
font: bold 18px 'Lucida Console', Monaco, monospace;
text-indent: 1px;
}
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
font-size: 22px;
}
/* layers control */
.leaflet-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.leaflet-control-layers-toggle {
background-image: url(images/layers.png);
width: 36px;
height: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(images/layers-2x.png);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
width: 44px;
height: 44px;
}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
display: none;
}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
display: block;
position: relative;
}
.leaflet-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.leaflet-control-layers-scrollbar {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 5px;
}
.leaflet-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.leaflet-control-layers label {
display: block;
font-size: 13px;
font-size: 1.08333em;
}
.leaflet-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}
/* Default icon URLs */
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
background-image: url(images/marker-icon.png);
}
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.8);
margin: 0;
}
.leaflet-control-attribution,
.leaflet-control-scale-line {
padding: 0 5px;
color: #333;
line-height: 1.4;
}
.leaflet-control-attribution a {
text-decoration: none;
}
.leaflet-control-attribution a:hover,
.leaflet-control-attribution a:focus {
text-decoration: underline;
}
.leaflet-attribution-flag {
display: inline !important;
vertical-align: baseline !important;
width: 1em;
height: 0.6669em;
}
.leaflet-left .leaflet-control-scale {
margin-left: 5px;
}
.leaflet-bottom .leaflet-control-scale {
margin-bottom: 5px;
}
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
line-height: 1.1;
padding: 2px 5px 1px;
white-space: nowrap;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.8);
text-shadow: 1px 1px #fff;
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
box-shadow: none;
}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* popup */
.leaflet-popup {
position: absolute;
text-align: center;
margin-bottom: 20px;
}
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
border-radius: 12px;
}
.leaflet-popup-content {
margin: 13px 24px 13px 20px;
line-height: 1.3;
font-size: 13px;
font-size: 1.08333em;
min-height: 1px;
}
.leaflet-popup-content p {
margin: 17px 0;
margin: 1.3em 0;
}
.leaflet-popup-tip-container {
width: 40px;
height: 20px;
position: absolute;
left: 50%;
margin-top: -1px;
margin-left: -20px;
overflow: hidden;
pointer-events: none;
}
.leaflet-popup-tip {
width: 17px;
height: 17px;
padding: 1px;
margin: -10px auto 0;
pointer-events: auto;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: white;
color: #333;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: 0;
right: 0;
border: none;
text-align: center;
width: 24px;
height: 24px;
font: 16px/24px Tahoma, Verdana, sans-serif;
color: #757575;
text-decoration: none;
background: transparent;
}
.leaflet-container a.leaflet-popup-close-button:hover,
.leaflet-container a.leaflet-popup-close-button:focus {
color: #585858;
}
.leaflet-popup-scrolled {
overflow: auto;
}
.leaflet-oldie .leaflet-popup-content-wrapper {
-ms-zoom: 1;
}
.leaflet-oldie .leaflet-popup-tip {
width: 24px;
margin: 0 auto;
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
}
.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
border: 1px solid #999;
}
/* div icon */
.leaflet-div-icon {
background: #fff;
border: 1px solid #666;
}
/* Tooltip */
/* Base styles for the element that has a tooltip */
.leaflet-tooltip {
position: absolute;
padding: 6px;
background-color: #fff;
border: 1px solid #fff;
border-radius: 3px;
color: #222;
white-space: nowrap;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.leaflet-tooltip.leaflet-interactive {
cursor: pointer;
pointer-events: auto;
}
.leaflet-tooltip-top:before,
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
position: absolute;
pointer-events: none;
border: 6px solid transparent;
background: transparent;
content: "";
}
/* Directions */
.leaflet-tooltip-bottom {
margin-top: 6px;
}
.leaflet-tooltip-top {
margin-top: -6px;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-top:before {
left: 50%;
margin-left: -6px;
}
.leaflet-tooltip-top:before {
bottom: 0;
margin-bottom: -12px;
border-top-color: #fff;
}
.leaflet-tooltip-bottom:before {
top: 0;
margin-top: -12px;
margin-left: -6px;
border-bottom-color: #fff;
}
.leaflet-tooltip-left {
margin-left: -6px;
}
.leaflet-tooltip-right {
margin-left: 6px;
}
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
top: 50%;
margin-top: -6px;
}
.leaflet-tooltip-left:before {
right: 0;
margin-right: -12px;
border-left-color: #fff;
}
.leaflet-tooltip-right:before {
left: 0;
margin-left: -12px;
border-right-color: #fff;
}
/* Printing */
@media print {
/* Prevent printers from removing background-images of controls. */
.leaflet-control {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,20 @@
Copyright 2013 - 2017, Jieter
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,83 @@
Leaflet-Semicircle.
-------------------
Allows drawing semicircles on leaflet maps.
It's an extension of Leaflet's [`L.Circle`](http://leafletjs.com/reference-1.1.0.html#circle),
and behaves like `L.Circle` if the a semicircle of almost 360 degrees is displayed.
Updated for use with leaflet 1.1.0.
## Provided classes: ##
<table>
<tr>
<td>
<code>L.SemiCircle</code>/
<code>L.SemiCircleMarker</code><br />
factories: <code>L.semiCircle</code>/<code>L.SemiCircleMarker</code>
</td>
<td>
Options:<br />
<code>startAngle</code>: start angle of the semicircle <br />
<code>stopAngle</code>: stop angle of the semicircle<br />
Angles are defined like compass courses: 0 = north, 90 = east, etc.
</td>
</tr>
## Provided methods: ##
<table>
<tr>
<td><code>L.SemiCircle.setStartAngle(angle)</code></td>
<td>Set the start angle of the circle to <code>angle</code> and redraw.</td>
</tr>
<tr>
<td><code>L.Circle.setStopAngle(angle)</code></td>
<td>Set the stop angle of the circle to <code>angle</code> and redraw.</td>
</tr>
<tr>
<td><code>L.Circle.setDirection(direction, size)</code></td>
<td>Set the <code>startAngle</code> to <code>direction - (0.5 * size)</code> and the <code>stopAngle</code> to <code>direction + (0.5 * size)</code> and redraw.</td>
</tr>
</table>
## Usage:
The plugin provides two ways to only display a part of the circle:
1. Use the `options` map and set `startAngle` and `stopAngle`.
2. Use `setDirection(direction, size)` to display a semicircle of `size` degrees at `direction`.
## Example:
[Live demo](http://jieter.github.com/Leaflet-semicircle/examples/semicircle.html)
Using `options.startAngle` and `options.stopAngle`:
```
L.semiCircle([51.5, -0.09], {
radius: 500,
startAngle: 45,
stopAngle: 135
}).addTo(map);
```
Draw the same semicircle using `setDirection(direction, size)`:
```
L.semiCircle([51.5, -0.09], {radius: 500})
.setDirection(90, 90)
.addTo(map);
```
## Screenshot:
[Live demo](http://jieter.github.com/Leaflet-semicircle/examples/semicircle.html)
![Semicircles screenshot](screenshot.png)
## Changelog
### 2.0.2 (2017-09-01)
- Fixed #24: instance check for canvas renderer
### 2.0.1 (2017-07-22)
- Fixed #14: Poleward displacement of circle center when radius is large.
### 2.0.0 (2017-07-09)
- Changed the API to stand-alone classes rather than overwriting `L.Circle` with an extension of itself.
- Added support for Leaflet 1.1.0

View file

@ -0,0 +1,196 @@
/**
* Semicircle extension for L.Circle.
* Jan Pieter Waagmeester <jieter@jieter.nl>
*
* This version is tested with leaflet 1.0.2
*/
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['leaflet'], factory);
} else if (typeof module !== 'undefined' && typeof require !== 'undefined') {
// Node/CommonJS
module.exports = factory(require('leaflet'));
} else {
// Browser globals
if (typeof window.L === 'undefined') {
throw 'Leaflet must be loaded first';
}
factory(window.L);
}
})(function (L) {
var DEG_TO_RAD = Math.PI / 180;
// make sure 0 degrees is up (North) and convert to radians.
function fixAngle (angle) {
return (angle - 90) * DEG_TO_RAD;
}
// rotate point [x + r, y+r] around [x, y] by `angle` radians.
function rotated (p, angle, r) {
return p.add(
L.point(Math.cos(angle), Math.sin(angle)).multiplyBy(r)
);
}
L.Point.prototype.rotated = function (angle, r) {
return rotated(this, angle, r);
};
var semicircle = {
options: {
startAngle: 0,
stopAngle: 359.9999
},
startAngle: function () {
if (this.options.startAngle < this.options.stopAngle) {
return fixAngle(this.options.startAngle);
} else {
return fixAngle(this.options.stopAngle);
}
},
stopAngle: function () {
if (this.options.startAngle < this.options.stopAngle) {
return fixAngle(this.options.stopAngle);
} else {
return fixAngle(this.options.startAngle);
}
},
setStartAngle: function (angle) {
this.options.startAngle = angle;
return this.redraw();
},
setStopAngle: function (angle) {
this.options.stopAngle = angle;
return this.redraw();
},
setDirection: function (direction, degrees) {
if (degrees === undefined) {
degrees = 10;
}
this.options.startAngle = direction - (degrees / 2);
this.options.stopAngle = direction + (degrees / 2);
return this.redraw();
},
getDirection: function () {
return this.stopAngle() - (this.stopAngle() - this.startAngle()) / 2;
},
isSemicircle: function () {
var startAngle = this.options.startAngle,
stopAngle = this.options.stopAngle;
return (
!(startAngle === 0 && stopAngle > 359) &&
!(startAngle === stopAngle)
);
},
_containsPoint: function (p) {
function normalize (angle) {
while (angle <= -Math.PI) {
angle += 2.0 * Math.PI;
}
while (angle > Math.PI) {
angle -= 2.0 * Math.PI;
}
return angle;
}
var angle = Math.atan2(p.y - this._point.y, p.x - this._point.x);
var nStart = normalize(this.startAngle());
var nStop = normalize(this.stopAngle());
if (nStop <= nStart) {
nStop += 2.0 * Math.PI;
}
if (angle <= nStart) {
angle += 2.0 * Math.PI;
}
return (
nStart < angle && angle <= nStop &&
p.distanceTo(this._point) <= this._radius + this._clickTolerance()
);
}
};
L.SemiCircle = L.Circle.extend(semicircle);
L.SemiCircleMarker = L.CircleMarker.extend(semicircle);
L.semiCircle = function (latlng, options) {
return new L.SemiCircle(latlng, options);
};
L.semiCircleMarker = function (latlng, options) {
return new L.SemiCircleMarker(latlng, options);
};
var _updateCircleSVG = L.SVG.prototype._updateCircle;
var _updateCircleCanvas = L.Canvas.prototype._updateCircle;
L.SVG.include({
_updateCircle: function (layer) {
// If we want a circle, we use the original function
if (!(layer instanceof L.SemiCircle || layer instanceof L.SemiCircleMarker) ||
!layer.isSemicircle()) {
return _updateCircleSVG.call(this, layer);
}
if (layer._empty()) {
return this._setPath(layer, 'M0 0');
}
var p = layer._map.latLngToLayerPoint(layer._latlng),
r = layer._radius,
r2 = Math.round(layer._radiusY || r),
start = p.rotated(layer.startAngle(), r),
end = p.rotated(layer.stopAngle(), r);
var largeArc = (layer.options.stopAngle - layer.options.startAngle >= 180) ? '1' : '0';
var d = 'M' + p.x + ',' + p.y +
// line to first start point
'L' + start.x + ',' + start.y +
'A ' + r + ',' + r2 + ',0,' + largeArc + ',1,' + end.x + ',' + end.y +
' z';
this._setPath(layer, d);
}
});
L.Canvas.include({
_updateCircle: function (layer) {
// If we want a circle, we use the original function
if (!(layer instanceof L.SemiCircle || layer instanceof L.SemiCircleMarker) ||
!layer.isSemicircle()) {
return _updateCircleCanvas.call(this, layer);
}
if (!this._drawing || layer._empty()) { return; }
var p = layer._point,
ctx = this._ctx,
r = layer._radius,
s = (layer._radiusY || r) / r,
start = p.rotated(layer.startAngle(), r);
if (s !== 1) {
ctx.save();
ctx.scale(1, s);
}
ctx.beginPath();
ctx.moveTo(p.x, p.y);
ctx.lineTo(start.x, start.y);
ctx.arc(p.x, p.y, r, layer.startAngle(), layer.stopAngle());
ctx.lineTo(p.x, p.y);
if (s !== 1) {
ctx.restore();
}
this._fillStroke(ctx, layer);
}
});
});

View file

@ -0,0 +1,300 @@
<?php
error_reporting(0);
// Convert the content of the symbology JSON file to HTML.
function addListSymbology($jsonPath, $i18n, $i18nDefault) {
global $pathToWebFolder;
$decodedJSON = getDecodedJSON($jsonPath);
echo '<div class="slider-item slider-list">';
// Loop over the lists to display.
foreach($decodedJSON as $listObject) {
echo '<div class="slider-list-title">'.translate($i18n, $i18nDefault, $listObject->{'listTitle'}, [], [], []).'</div>';
// Loop over the entries of the current list.
foreach($listObject->{'listEntries'} as $listEntryObject) {
echo '<div class="slider-list-entry">
<div class="w-45">';
// Loop over the icons of the current list entry.
foreach($listEntryObject->{'icons'} as $icon) {
echo '<img src="'.$pathToWebFolder.'images/'.$icon->{'src'}.'" alt="'.translate($i18n, $i18nDefault, $icon->{'alt'}, [], [], []).'">';
}
echo '</div>
<div class="pl-20 w-315">'.translate($i18n, $i18nDefault, $listEntryObject->{'description'}, [], [], []).'</div>
</div>';
}
}
echo '</div>';
}
// Convert the content of the manual JSON file to HTML.
function addListManual($jsonPath, $i18n, $i18nDefault) {
global $pathToWebFolder;
$decodedJSON = getDecodedJSON($jsonPath);
echo '<div class="slider-item slider-list text-small">';
// Loop over the lists to display.
foreach($decodedJSON as $listObject) {
echo '<div class="slider-list-title">'.translate($i18n, $i18nDefault, $listObject->{'listTitle'}, [], [], []).'</div>';
// Loop over the entries of the current list.
foreach($listObject->{'listEntries'} as $listEntryObject) {
$keysAsHTMLArray = array();
$valuesAsHTMLArray = array();
// Loop over the keys of the current list entry.
foreach($listEntryObject->{'keys'} as $key) {
if (is_null($key->{'href'})) {
array_push($keysAsHTMLArray, translate($i18n, $i18nDefault, $key->{'key'}, [], [], []));
} else {
array_push($keysAsHTMLArray, translate($i18n, $i18nDefault, $key->{'key'}, [$key->{'href'}], [], []));
}
}
// Loop over the values of the current list entry.
foreach($listEntryObject->{'values'} as $value) {
if (is_null($value->{'href'})) {
array_push($valuesAsHTMLArray, translate($i18n, $i18nDefault, $value->{'value'}, [], [], []));
} else {
array_push($valuesAsHTMLArray, translate($i18n, $i18nDefault, $value->{'value'}, [$value->{'href'}], [], []));
}
}
echo '<div class="slider-list-entry">
<div class="w-120">';
echo implode('<br>', $keysAsHTMLArray);
echo '</div>';
// Some lists have an icon column.
if ($listObject->{'isListWithIcons'}) {
echo '<div class="pl-20 w-240">'
.implode('<br>', $valuesAsHTMLArray).'
</div>
<div class="w-20">';
$iconObject = $listEntryObject->{'icon'};
if (!is_null($iconObject)){
echo '<img src="'.$pathToWebFolder.'images/'.$iconObject->{'src'}.'" alt="'.translate($i18n, $i18nDefault, $iconObject->{'alt'}, [], [], []).'">';
}
} else {
echo '<div class="pl-20 w-260">'
.implode('<br>', $valuesAsHTMLArray).'';
}
echo '</div>
</div>';
}
// Some lists end with examples, i.e. 3 images with descriptions.
if (!is_null($listObject->{'examples'})) {
$examplesObject = $listObject->{'examples'};
$examplesObjectImages = $examplesObject->{'images'};
$examplesObjectDescriptions = $examplesObject->{'descriptions'};
echo '<div class="slider-list-entry">
<div>
<br>'.translate($i18n, $i18nDefault, 'examples', [], [], []).':
</div>
</div>
<div class="slider-list-entry">
<div class="example-boxes">';
for($i = 0; $i < count($examplesObjectImages); ++$i) {
$linesAsHTMLArray = array();
foreach($examplesObjectDescriptions[$i]->{'lines'} as $line) {
array_push($linesAsHTMLArray, translate($i18n, $i18nDefault, $line, [], [], []));
}
echo '<div class="example-box">
<div class="example-box-image">
<img src="'.$pathToWebFolder.'images/'.$examplesObjectImages[$i]->{'src'}.'" alt="'.translate($i18n, $i18nDefault, $examplesObjectImages[$i]->{'alt'}, [], [], []).'">
</div>
<div class="example-box-description">'
.implode('<br>', $linesAsHTMLArray).'
</div>
</div>';
}
echo ' </div>
</div>';
}
}
echo '</div>';
}
// Convert the content of the links JSON file to HTML.
/* function addListLinks($jsonPath, $i18n, $i18nDefault) {
global $pathToWebFolder;
$expandSectionCounter = 0;
$decodedJSON = getDecodedJSON($jsonPath);
echo '<div class="slider-item slider-list">';
// Loop over the lists to display.
foreach($decodedJSON as $listObject) {
echo '<div class="slider-list-title">'.translate($i18n, $i18nDefault, $listObject->{'listTitle'}, [], [], []).'</div>';
// Loop over the sections of the current list.
foreach($listObject->{'sections'} as $sectionObject) {
if ($sectionObject->{'isExpandable'}) {
$sectionToggleChecked = '';
if ($sectionObject->{'isExpandedByDefault'}) {
$sectionToggleChecked = 'checked="checked"';
}
echo '<input class="slider-list-section-toggle" id="section'.$expandSectionCounter.'-id" type="checkbox" '.$sectionToggleChecked.$
<label class="slider-list-section" for="section'.$expandSectionCounter++.'-id"> '.translate($i18n, $i18nDefault, $sectionOb$
}
echo '<div>';
// Loop over the entries of the current section.
foreach($sectionObject->{'listEntries'} as $listEntryObject) {
echo '<div class="slider-list-entry">
<div class="w-20">';
// Choose lock icon according to https or http connection.
if (substr($listEntryObject->{'href'}, 0, 5) == 'https') {
echo '<img src="'.$pathToWebFolder.'images/lock-secure.png" alt="'.translate($i18n, $i18nDefault, 'secure-alt', [], [], [])$
} else {
echo '<img src="'.$pathToWebFolder.'images/lock-insecure.png" alt="'.translate($i18n, $i18nDefault, 'insecure-alt', [], [],$
}
echo '</div>
<div class="pl-20 w-340">
[ '.htmlentities($listEntryObject->{'sourceText'}).' ]<br><a href="'.$listEntryObject->{'href'}.'">'.htmlentities($li$
</div>
</div>';
}
echo '</div>';
}
}
echo '</div>';
}
*/
// Convert the content of the links JSON file to HTML.
function addListLinks($jsonPath, $i18n, $i18nDefault) {
global $pathToWebFolder;
$expandSectionCounter = 0;
$decodedJSON = getDecodedJSON($jsonPath);
echo '<div class="slider-item slider-list">';
// Loop over the lists to display.
foreach($decodedJSON as $listObject) {
echo '<div class="slider-list-title">'.translate($i18n, $i18nDefault, $listObject->{'listTitle'}, [], [], []).'</div>';
// Loop over the sections of the current list.
foreach($listObject->{'sections'} as $sectionObject) {
if ($sectionObject->{'isExpandable'}) {
$sectionToggleChecked = '';
if ($sectionObject->{'isExpandedByDefault'}) {
$sectionToggleChecked = 'checked="checked"';
}
echo '<input class="slider-list-section-toggle" id="section'.$expandSectionCounter.'-id" type="checkbox" '.$sectionToggleChecked.'>
<label class="slider-list-section" for="section'.$expandSectionCounter++.'-id"> '.translate($i18n, $i18nDefault, $sectionObject->{'sectionTitle'}, [], [], []).'</label>';
}
echo '<div>';
// Loop over the entries of the current section.
foreach($sectionObject->{'listEntries'} as $listEntryObject) {
echo '<div class="slider-list-entry">
<div class="pl-20">
[ '.htmlentities($listEntryObject->{'sourceText'}).' ]<br><a href="'.$listEntryObject->{'href'}.'">'.htmlentities($listEntryObject->{'linkText'}).'</a>
</div>
</div>';
}
echo '</div>';
}
}
echo '</div>';
}
// Convert the content of the credits and licenses JSON file to HTML.
function addListCredits($jsonPath, $i18n, $i18nDefault) {
global $pathToWebFolder;
$decodedJSON = getDecodedJSON($jsonPath);
// Loop over the lists to display.
foreach($decodedJSON as $listObject) {
echo '<div class="slider-footer-title">'
.translate($i18n, $i18nDefault, $listObject->{'listTitle'}, [], [], []).'
</div>';
// Loop over the entries of the current list.
foreach($listObject->{'listEntries'} as $listEntryObject) {
echo '<div class="slider-credit-type">'
.translate($i18n, $i18nDefault, $listEntryObject->{'type'}, [], [], []).'
</div>';
// Loop over the credits of the current list entry.
foreach($listEntryObject->{'credits'} as $credit) {
$hrefCredit = $credit->{'href-credit'};
$hrefLicense = $credit->{'href-license'};
if (substr($hrefCredit, 0, 4) != 'http') {
$hrefCredit = $pathToWebFolder.$hrefCredit;
}
if (substr($hrefLicense, 0, 4) != 'http') {
$hrefLicense = $pathToWebFolder.$hrefLicense;
}
echo '<div>
<a href="'.$hrefCredit.'">'.htmlentities($credit->{'credit'}).'</a> [<a href="'.$hrefLicense.'">'.htmlentities($credit->{'license'}).'</a>]
</div>';
}
}
}
}
// Create a HTML list that contains the supported languages (i18n).
function addListLanguages($initialLanguage, $i18n, $i18nDefault) {
global $pathToWebFolder, $embedPerma;
$supportedLanguages = [
'de' => 'deutsch',
'en' => 'english',
'es' => 'espa&#x00F1;ol',
'fr' => 'fran&#x00E7;ais',
'it' => 'italiano',
'ru' => '&#x0440;&#x0443;&#x0441;&#x0441;&#x043A;&#x0438;&#x0439;'
];
echo '<input class="language-toggle-input" type="checkbox" id="language-id">
<label class="language-toggle-button" for="language-id">
<ul class="bar-button" id="language">
<li>
<div title="'.translate($i18n, $i18nDefault, 'language-button-alt', [], [], []).'">&nbsp;</div>
<ul>';
foreach ($supportedLanguages as $languageID => $languageDisplay) {
$classLanguangeCurrent = '';
if ($languageID == $initialLanguage) {
$classLanguangeCurrent = ' class="language-current"';
}
echo ' <a href="#" onClick="permalink(\''.$languageID.'\', '.$embedPerma.');return false;"><li'.$classLanguangeCurrent.'>'.$languageDisplay.'</li></a>';
}
echo ' </ul>
</li>
</ul>
</label>';
}
?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

445
web/www/sunders/camera.php Normal file
View file

@ -0,0 +1,445 @@
<?php
error_reporting(0);
include $pathToWebFolder.'config.php';
define('MAX_POINTS_FOR_QUICKHULL', 3000);
class OsmPoint {
var $id;
var $lat;
var $lon;
function __construct($valId, $valLat, $valLon) {
$this->id = $valId;
$this->lat = $valLat;
$this->lon = $valLon;
}
}
function mergeNeighbor(&$clusterGrid, $posCell, $pos) {
global $divDiag2;
if (!array_key_exists($pos, $clusterGrid)) {
/* the neighbor is empty */
return;
}
$neighbor = $clusterGrid[$pos];
if ($neighbor['count'] == 0) {
/* The neighbor is merged to an other cell, yet */
return;
}
$cell = $clusterGrid[$posCell];
/* Calculate the (square of) distance from the cell to its neighbor */
$lonDist = ($cell['longitude']/$cell['count']) - ($neighbor['longitude']/$neighbor['count']);
$latDist = ($cell['latitude'] /$cell['count']) - ($neighbor['latitude'] /$neighbor['count']);
$dist = ($lonDist * $lonDist) + ($latDist * $latDist);
if ($dist < $divDiag2 / 10) {
$count = $cell['count'] + $neighbor['count'];
$clusterGrid[$posCell]['latitude'] = $cell['latitude'] + $neighbor['latitude'];
$clusterGrid[$posCell]['longitude'] = $cell['longitude'] + $neighbor['longitude'];
$clusterGrid[$posCell]['count'] = $count;
$clusterGrid[$posCell]['points'] = array_merge($cell['points'], $neighbor['points']);
/* Invalidate the merged neighbor */
$clusterGrid[$pos]['count'] = 0;
}
}
function mergeNeighborhood(&$clusterGrid, $pos) {
global $divWCount, $divHCount;
if ($clusterGrid[$pos]['count'] == 0) {
/* cell merged yet */
return;
}
$latLon = explode(',', $clusterGrid[$pos]['grid'] );
if ($latLon[0] > 0 && $latLon[1] < $divHCount - 1) {
if ($latLon[0] > 0) {
$posNeigh = ($latLon[0] - 1) . ',' . ($latLon[1] + 1);
mergeNeighbor($clusterGrid, $pos, $posNeigh);
}
$posNeigh = $latLon[0] . ',' . ($latLon[1] + 1);
mergeNeighbor($clusterGrid, $pos, $posNeigh);
if ($latLon[0] < $divWCount - 1) {
$posNeigh = ($latLon[0] + 1) . ',' . ($latLon[1] + 1);
mergeNeighbor($clusterGrid, $pos, $posNeigh);
}
}
if ($latLon[0] < $divWCount - 1) {
$posNeigh = ($latLon[0] + 1) . ',' . $latLon[1];
mergeNeighbor($clusterGrid, $pos, $posNeigh);
}
}
/* Recursive calculation of the quick hull algo
$isBottom : 1 if bottom point is searched, -1 if top point is searched */
function quickHullCalc(&$pointList, $count, $minPoint, $maxPoint, $isBottom) {
$msg = 'Quick count='.$count.', min=('.$minPoint->id.','.$minPoint->lat.','.$minPoint->lon.'), max=('.$minPoint->id.','.$minPoint->lat.','.$minPoint->lon.'), isBottom='.$isBottom;
$farthestPoint = null;
$farthestDist = 0;
$outsideList = array();
$outsideListCount = 0;
if ($maxPoint->lon != $minPoint->lon) {
/* Get the line equation as y = mx + p */
$m = ($maxPoint->lat - $minPoint->lat) / ($maxPoint->lon - $minPoint->lon);
$p = ($maxPoint->lat * $minPoint->lon - $minPoint->lat * $maxPoint->lon) / ($minPoint->lon - $maxPoint->lon);
} else {
/* The line equation is y = p */
$m = null;
$p = $minPoint->lat;
$coef = (($minPoint->lon > $maxPoint->lon) ? 1 : -1);
}
/* For each point, check whether :
- it is on the right side of the line
- it is the farthest from the line
*/
foreach ($pointList as $point) {
if (isset($m)) {
$dist = $isBottom * ($m * $point->lon - $point->lat + $p);
} else {
$dist = $coef * ($point->lon - $p);
}
if ($dist > 0
&& $point->id != $minPoint->id
&& $point->id != $maxPoint->id) {
array_push($outsideList, $point);
$outsideListCount++;
if ($dist > $farthestDist) {
$farthestPoint = $point;
$farthestDist = $dist;
}
}
}
if ($outsideListCount == 0) {
return array($minPoint);
} else if ($outsideListCount == 1) {
return array($minPoint, $outsideList[0]);
} else {
return array_merge(
quickHullCalc($outsideList, $outsideListCount, $minPoint, $farthestPoint, $isBottom),
quickHullCalc($outsideList, $outsideListCount, $farthestPoint, $maxPoint, $isBottom));
}
}
/* This function receives a list of points [lat, lon] and returns a list of points [lat, lon]
representing the minimal convex polygon containing the points */
function quickHull(&$pointList, $count) {
$msg= 'Quick count='.$count;
if ($count == 0) {
return array();
} else if ($count == 1) {
return array($pointList[0]);
} else if ($count == 2) {
return array($pointList[0], $pointList[1]);
}
/* retrieves the min and max points on the x axe */
$minPoint = $pointList[0];
$maxPoint = $pointList[0];
foreach ($pointList as $point) {
if ($point->lon < $minPoint->lon || ($point->lon == $minPoint->lon && $point->lat < $minPoint->lat)) {
$minPoint = $point;
}
if ($point->lon > $maxPoint->lon || ($point->lon == $maxPoint->lon && $point->lat > $maxPoint->lat)) {
$maxPoint = $point;
}
}
$bottomPoints = quickHullCalc($pointList, $count, $minPoint, $maxPoint, 1);
$topPoints = quickHullCalc($pointList, $count, $maxPoint, $minPoint, -1);
return array_merge($bottomPoints, $topPoints);
}
$GRID_MAX_ZOOM = 16;
$GRID_CELL_PIXEL = 90;
/* Check if parameters are not empty */
if ( !array_key_exists('bbox', $_GET)
|| !array_key_exists('zoom', $_GET)
|| !array_key_exists('width', $_GET)
|| !array_key_exists('height', $_GET)) {
header('Content-type: application/json');
$result = '{"error":"bbox, zoom, width and height parameters are required. '
.(array_key_exists('bbox', $_GET) ? '' : 'bbox is empty. ')
.(array_key_exists('zoom', $_GET) ? '' : 'zoom is empty. ')
.(array_key_exists('width', $_GET) ? '' : 'width is empty. ')
.(array_key_exists('height', $_GET) ? '' : 'height is empty. ')
.'"}';
echo $result;
exit;
}
/* Check zoom */
$zoom = $_GET['zoom'];
if ( !is_numeric($zoom)
|| intval($zoom) < 1
|| intval($zoom) > 19) {
header('Content-type: application/json');
$result = '{"error":"unexpected zoom value : '
.htmlentities($zoom)
.'"}';
echo $result;
exit;
}
/* Check bounds box --> bbox=boundsSW.lng,boundsSW.lat,boundsNE.lng,boundsNE.lat */
$bbox = explode(',', $_GET['bbox']);
if ( !is_numeric($bbox[0]) || $bbox[0] > 180 // 0 = SW.lng
|| !is_numeric($bbox[2]) || $bbox[2] < -180 // 2 = NE.lng
|| !is_numeric($bbox[1]) || $bbox[1] < -90 || $bbox[1] > 90 // 1 = SW.lat
|| !is_numeric($bbox[3]) || $bbox[3] < -90 || $bbox[3] > 90) { // 3 = NE.lat
header('Content-type: application/json');
$result = '{"error":"unexpected bbox longitude and latitude values : '
.'lon ['.htmlentities($bbox[0]).', '.htmlentities($bbox[2]).'], '
.'lat ['.htmlentities($bbox[1]).', '.htmlentities($bbox[3]).']'
.'"}';
echo $result;
exit;
}
if ($bbox[0] >= $bbox[2]) { // 0 = SW.lng | 2 = NE.lng
header('Content-type: application/json');
$result = '{"error":"min longitude greater than max longitude : '
.'lon ['.htmlentities($bbox[0]).', '.htmlentities($bbox[2]).']'
.'"}';
echo $result;
exit;
}
if ($bbox[1] >= $bbox[3]) { // 1 = SW.lat | 3 = NE.lat
header('Content-type: application/json');
$result = '{"error":"min latitude greater than max latitude : '
.'lat ['.htmlentities($bbox[1]).', '.htmlentities($bbox[3]).']'
.'"}';
echo $result;
exit;
}
$lonMin = $bbox[0]; // 0 = SW.lng
$lonMax = $bbox[2]; // 2 = NE.lng
$latMin = $bbox[1]; // 1 = SW.lat
$latMax = $bbox[3]; // 3 = NE.lat
$pixelWidth = (int) $_GET['width'];
$pixelHeight = (int) $_GET['height'];
if ($pixelWidth == 0 || $pixelHeight == 0) {
header('Content-type: application/json');
$result = '{"error":"width or height is null : '
.htmlentities($pixelWidth).'x'.htmlentities($pixelHeight)
.'"}';
echo $result;
exit;
}
$lonWidth = $lonMax - $lonMin; // NE.lng - SW.lng
$latHeight = $latMax - $latMin; // NE.lat - SW.lat
$divWCount = ((int) ($pixelWidth / $GRID_CELL_PIXEL)) + 1;
$divHCount = ((int) ($pixelHeight / $GRID_CELL_PIXEL)) + 1;
$divWidth = $lonWidth / $divWCount;
$divHeight = $latHeight / $divHCount;
$divDiag2 = ($divWidth * $divWidth) + ($divHeight * $divHeight);
/* Connect to database */
$mysqli = new mysqli(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB);
if($mysqli->connect_errno) {
header('Content-type: application/json');
$result = '{"error":"error while connecting to db : ' . $mysqli->error . '"}';
echo $result;
exit;
}
$rqtLonMin = $lonMin; // SW.lng
$rqtLonMax = $lonMax; // NE.lng
/* Indicates whether the map displays the -180/180° longitude */
if ($rqtLonMax - $rqtLonMin > 360) {
$rqtLonMin = -180;
$rqtLonMax = 180;
}
/* Select the nodes to be returned, and cluster them on a grid if necessary */
if ($rqtLonMin >= -180 && $lonMax <= 180) {
$sql='SELECT id, latitude, longitude
FROM position
WHERE latitude between ? and ?
AND longitude between ? and ?';
} else {
$sql='SELECT id, latitude, longitude
FROM position
WHERE latitude between ? and ?
AND (longitude between ? and 1800000000 OR longitude between -1800000000 and ?)';
while ($rqtLonMin < -180) {
$rqtLonMin += 360;
}
while ($rqtLonMax > 180) {
$rqtLonMax -= 360;
}
}
$rqtLonMin = bcmul($rqtLonMin, 10000000, 0); // SW.lng
$rqtLonMax = bcmul($rqtLonMax, 10000000, 0); // NE.lng
$rqtLatMin = bcmul($latMin, 10000000, 0); // SW.lat
$rqtLatMax = bcmul($latMax, 10000000, 0); // NE.lat
$resArray = array();
$nbFetch = 0;
if ($stmt = $mysqli->prepare($sql)) {
$stmt->bind_param('iiii', $rqtLatMin, $rqtLatMax, $rqtLonMin, $rqtLonMax); // SW.lat, NE.lat, SW.lng, NE.lng
$stmt->execute();
$stmt->bind_result($id, $latitude, $longitude);
while ($stmt->fetch()) {
$nbFetch++;
$latitude = bcdiv($latitude, 10000000, 7);
$longitude = bcdiv($longitude, 10000000, 7);
while ($longitude < $lonMin) { // $lonMin = SW.lng
$longitude += 360;
}
while ($longitude > $lonMax) { // $lonMax = NE.lng
$longitude -= 360;
}
/* Initialize the current point */
if ($zoom >= $GRID_MAX_ZOOM) {
array_push($resArray, array(
'points' => array(new OsmPoint($id, $latitude, $longitude)),
'latitude' => $latitude,
'longitude' => $longitude,
'count' => 1 ));
} else {
$posLat = (int) (($latitude - $latMin) / $divHeight); // $latMin = SW.lat
$posLon = (int) (($longitude - $lonMin) / $divWidth); // $lonMin = SW.lng
$pos = $posLon.','.$posLat;
if (!array_key_exists($pos, $resArray)) {
$resArray[$pos] = array(
'points' => array(),
'latitude' => 0,
'longitude' => 0,
'count' => 0,
'grid' => $pos);
}
$elt = new OsmPoint($id, $latitude, $longitude);
array_push($resArray[$pos]['points'], $elt);
/* Increment the number of points */
$resArray[$pos]['count']++;
$resArray[$pos]['latitude'] += $latitude;
$resArray[$pos]['longitude'] += $longitude;
}
}
$stmt->close();
} else {
$mysqli->close();
header('Content-type: application/json');
$result = '{"error":"Error while request : ' . $mysqli->error . '"}';
echo $result;
exit;
}
/* Unify some clusters if nodes center are near */
$pointsCount = 0;
if ($zoom < $GRID_MAX_ZOOM) {
foreach($resArray as $val) {
mergeNeighborhood($resArray, $val['grid']);
$pointsCount += $val['count'];
}
}
$result='[';
$separator='';
/* Writing selected points */
$sql='SELECT k, v
FROM tag
WHERE id = ?
AND k NOT IN ("lat", "lon")';
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('d', $id);
$stmt->bind_result($k, $v);
/* Writing grouped items or not */
foreach($resArray as $val) {
if ($val['count'] > 0) {
$result = $result.$separator
.'{"lat":"'.($val['latitude'] / $val['count']).'"'
.',"lon":"'.($val['longitude'] / $val['count']).'"';
if ($val['count'] == 1) {
$id = $val['points'][0]->id;
$result = $result.',"id":"'.$id.'"';
$stmt->execute();
while($stmt->fetch()) {
$result = $result.',"'.htmlentities($k).'":"'.htmlentities($v, ENT_COMPAT, 'UTF-8').'"';
}
} else {
$result = $result
.',"count":"'.$val['count'].'"'
.',"multi":"yes"'
.',"poly":[';
if ($pointsCount < MAX_POINTS_FOR_QUICKHULL) {
$convexPoly = quickHull($val['points'], $val['count']);
$sepPoly = '';
foreach($convexPoly as $point) {
$result = $result.$sepPoly.'{'
.'"lat":"'.$point->lat.'"'
.',"id":"'.$point->id.'"'
.',"lon":"'.$point->lon.'"}';
$sepPoly=',';
}
}
$result=$result.']';
}
$result = $result.'}';
$separator=',';
}
}
$stmt->close();
$result = $result . ']';
$mysqli->close();
header('Content-type: application/json; Charset : utf-8');
echo $result;
?>

Some files were not shown because too many files have changed in this diff Show more