Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+173
@@ -0,0 +1,173 @@
|
||||
import {Point, toPoint} from './Point';
|
||||
|
||||
/*
|
||||
* @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 Leafet'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.
|
||||
*/
|
||||
|
||||
export 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.
|
||||
extend: function (point) { // (Point)
|
||||
point = toPoint(point);
|
||||
|
||||
// @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 = point.clone();
|
||||
this.max = point.clone();
|
||||
} else {
|
||||
this.min.x = Math.min(point.x, this.min.x);
|
||||
this.max.x = Math.max(point.x, this.max.x);
|
||||
this.min.y = Math.min(point.y, this.min.y);
|
||||
this.max.y = Math.max(point.y, this.max.y);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// @method getCenter(round?: Boolean): Point
|
||||
// Returns the center point of the bounds.
|
||||
getCenter: function (round) {
|
||||
return new Point(
|
||||
(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 new Point(this.min.x, this.max.y);
|
||||
},
|
||||
|
||||
// @method getTopRight(): Point
|
||||
// Returns the top-right point of the bounds.
|
||||
getTopRight: function () { // -> Point
|
||||
return new Point(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;
|
||||
},
|
||||
|
||||
isValid: function () {
|
||||
return !!(this.min && this.max);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// @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.
|
||||
export function toBounds(a, b) {
|
||||
if (!a || a instanceof Bounds) {
|
||||
return a;
|
||||
}
|
||||
return new Bounds(a, b);
|
||||
}
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
import {Point} from './Point';
|
||||
import * as Util from '../core/Util';
|
||||
|
||||
|
||||
/*
|
||||
* @namespace LineUtil
|
||||
*
|
||||
* Various utility functions for polyline points processing, used by Leaflet internally to make polylines lightning-fast.
|
||||
*/
|
||||
|
||||
// Simplify polyline with vertex reduction and Douglas-Peucker simplification.
|
||||
// Improves rendering performance dramatically by lessening the number of points to draw.
|
||||
|
||||
// @function simplify(points: Point[], tolerance: Number): Point[]
|
||||
// Dramatically reduces the number of points in a polyline while retaining
|
||||
// its shape and returns a new array of simplified points, using the
|
||||
// [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm).
|
||||
// Used for a huge performance boost when processing/displaying Leaflet polylines for
|
||||
// each zoom level and also reducing visual noise. tolerance affects the amount of
|
||||
// simplification (lesser value means higher quality but slower and with more points).
|
||||
// Also released as a separated micro-library [Simplify.js](http://mourner.github.com/simplify-js/).
|
||||
export function simplify(points, tolerance) {
|
||||
if (!tolerance || !points.length) {
|
||||
return points.slice();
|
||||
}
|
||||
|
||||
var sqTolerance = tolerance * tolerance;
|
||||
|
||||
// stage 1: vertex reduction
|
||||
points = _reducePoints(points, sqTolerance);
|
||||
|
||||
// stage 2: Douglas-Peucker simplification
|
||||
points = _simplifyDP(points, sqTolerance);
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
// @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number
|
||||
// Returns the distance between point `p` and segment `p1` to `p2`.
|
||||
export function pointToSegmentDistance(p, p1, p2) {
|
||||
return Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true));
|
||||
}
|
||||
|
||||
// @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number
|
||||
// Returns the closest point from a point `p` on a segment `p1` to `p2`.
|
||||
export function closestPointOnSegment(p, p1, p2) {
|
||||
return _sqClosestPointOnSegment(p, p1, p2);
|
||||
}
|
||||
|
||||
// Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm
|
||||
function _simplifyDP(points, sqTolerance) {
|
||||
|
||||
var len = points.length,
|
||||
ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,
|
||||
markers = new ArrayConstructor(len);
|
||||
|
||||
markers[0] = markers[len - 1] = 1;
|
||||
|
||||
_simplifyDPStep(points, markers, sqTolerance, 0, len - 1);
|
||||
|
||||
var i,
|
||||
newPoints = [];
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (markers[i]) {
|
||||
newPoints.push(points[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return newPoints;
|
||||
}
|
||||
|
||||
function _simplifyDPStep(points, markers, sqTolerance, first, last) {
|
||||
|
||||
var maxSqDist = 0,
|
||||
index, i, sqDist;
|
||||
|
||||
for (i = first + 1; i <= last - 1; i++) {
|
||||
sqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true);
|
||||
|
||||
if (sqDist > maxSqDist) {
|
||||
index = i;
|
||||
maxSqDist = sqDist;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxSqDist > sqTolerance) {
|
||||
markers[index] = 1;
|
||||
|
||||
_simplifyDPStep(points, markers, sqTolerance, first, index);
|
||||
_simplifyDPStep(points, markers, sqTolerance, index, last);
|
||||
}
|
||||
}
|
||||
|
||||
// reduce points that are too close to each other to a single point
|
||||
function _reducePoints(points, sqTolerance) {
|
||||
var reducedPoints = [points[0]];
|
||||
|
||||
for (var i = 1, prev = 0, len = points.length; i < len; i++) {
|
||||
if (_sqDist(points[i], points[prev]) > sqTolerance) {
|
||||
reducedPoints.push(points[i]);
|
||||
prev = i;
|
||||
}
|
||||
}
|
||||
if (prev < len - 1) {
|
||||
reducedPoints.push(points[len - 1]);
|
||||
}
|
||||
return reducedPoints;
|
||||
}
|
||||
|
||||
var _lastCode;
|
||||
|
||||
// @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean
|
||||
// Clips the segment a to b by rectangular bounds with the
|
||||
// [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm)
|
||||
// (modifying the segment points directly!). Used by Leaflet to only show polyline
|
||||
// points that are on the screen or near, increasing performance.
|
||||
export function clipSegment(a, b, bounds, useLastCode, round) {
|
||||
var codeA = useLastCode ? _lastCode : _getBitCode(a, bounds),
|
||||
codeB = _getBitCode(b, bounds),
|
||||
|
||||
codeOut, p, newCode;
|
||||
|
||||
// save 2nd code to avoid calculating it on the next segment
|
||||
_lastCode = codeB;
|
||||
|
||||
while (true) {
|
||||
// if a,b is inside the clip window (trivial accept)
|
||||
if (!(codeA | codeB)) {
|
||||
return [a, b];
|
||||
}
|
||||
|
||||
// if a,b is outside the clip window (trivial reject)
|
||||
if (codeA & codeB) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// other cases
|
||||
codeOut = codeA || codeB;
|
||||
p = _getEdgeIntersection(a, b, codeOut, bounds, round);
|
||||
newCode = _getBitCode(p, bounds);
|
||||
|
||||
if (codeOut === codeA) {
|
||||
a = p;
|
||||
codeA = newCode;
|
||||
} else {
|
||||
b = p;
|
||||
codeB = newCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function _getEdgeIntersection(a, b, code, bounds, round) {
|
||||
var dx = b.x - a.x,
|
||||
dy = b.y - a.y,
|
||||
min = bounds.min,
|
||||
max = bounds.max,
|
||||
x, y;
|
||||
|
||||
if (code & 8) { // top
|
||||
x = a.x + dx * (max.y - a.y) / dy;
|
||||
y = max.y;
|
||||
|
||||
} else if (code & 4) { // bottom
|
||||
x = a.x + dx * (min.y - a.y) / dy;
|
||||
y = min.y;
|
||||
|
||||
} else if (code & 2) { // right
|
||||
x = max.x;
|
||||
y = a.y + dy * (max.x - a.x) / dx;
|
||||
|
||||
} else if (code & 1) { // left
|
||||
x = min.x;
|
||||
y = a.y + dy * (min.x - a.x) / dx;
|
||||
}
|
||||
|
||||
return new Point(x, y, round);
|
||||
}
|
||||
|
||||
export function _getBitCode(p, bounds) {
|
||||
var code = 0;
|
||||
|
||||
if (p.x < bounds.min.x) { // left
|
||||
code |= 1;
|
||||
} else if (p.x > bounds.max.x) { // right
|
||||
code |= 2;
|
||||
}
|
||||
|
||||
if (p.y < bounds.min.y) { // bottom
|
||||
code |= 4;
|
||||
} else if (p.y > bounds.max.y) { // top
|
||||
code |= 8;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
// square distance (to avoid unnecessary Math.sqrt calls)
|
||||
function _sqDist(p1, p2) {
|
||||
var dx = p2.x - p1.x,
|
||||
dy = p2.y - p1.y;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
// return closest point on segment or distance to that point
|
||||
export function _sqClosestPointOnSegment(p, p1, p2, sqDist) {
|
||||
var x = p1.x,
|
||||
y = p1.y,
|
||||
dx = p2.x - x,
|
||||
dy = p2.y - y,
|
||||
dot = dx * dx + dy * dy,
|
||||
t;
|
||||
|
||||
if (dot > 0) {
|
||||
t = ((p.x - x) * dx + (p.y - y) * dy) / dot;
|
||||
|
||||
if (t > 1) {
|
||||
x = p2.x;
|
||||
y = p2.y;
|
||||
} else if (t > 0) {
|
||||
x += dx * t;
|
||||
y += dy * t;
|
||||
}
|
||||
}
|
||||
|
||||
dx = p.x - x;
|
||||
dy = p.y - y;
|
||||
|
||||
return sqDist ? dx * dx + dy * dy : new Point(x, y);
|
||||
}
|
||||
|
||||
|
||||
// @function isFlat(latlngs: LatLng[]): Boolean
|
||||
// Returns true if `latlngs` is a flat array, false is nested.
|
||||
export function isFlat(latlngs) {
|
||||
return !Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
|
||||
}
|
||||
|
||||
export function _flat(latlngs) {
|
||||
console.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.');
|
||||
return isFlat(latlngs);
|
||||
}
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
import {isArray, formatNum} from '../core/Util';
|
||||
|
||||
/*
|
||||
* @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 Leafet'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.
|
||||
*/
|
||||
|
||||
export 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.
|
||||
export 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);
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
import * as LineUtil from './LineUtil';
|
||||
|
||||
/*
|
||||
* @namespace PolyUtil
|
||||
* Various utility functions for polygon geometries.
|
||||
*/
|
||||
|
||||
/* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
|
||||
* Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
|
||||
* Used by Leaflet to only show polygon points that are on the screen or near, increasing
|
||||
* performance. Note that polygon points needs different algorithm for clipping
|
||||
* than polyline, so there's a separate method for it.
|
||||
*/
|
||||
export function clipPolygon(points, bounds, round) {
|
||||
var clippedPoints,
|
||||
edges = [1, 4, 2, 8],
|
||||
i, j, k,
|
||||
a, b,
|
||||
len, edge, p;
|
||||
|
||||
for (i = 0, len = points.length; i < len; i++) {
|
||||
points[i]._code = LineUtil._getBitCode(points[i], bounds);
|
||||
}
|
||||
|
||||
// for each edge (left, bottom, right, top)
|
||||
for (k = 0; k < 4; k++) {
|
||||
edge = edges[k];
|
||||
clippedPoints = [];
|
||||
|
||||
for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
|
||||
a = points[i];
|
||||
b = points[j];
|
||||
|
||||
// if a is inside the clip window
|
||||
if (!(a._code & edge)) {
|
||||
// if b is outside the clip window (a->b goes out of screen)
|
||||
if (b._code & edge) {
|
||||
p = LineUtil._getEdgeIntersection(b, a, edge, bounds, round);
|
||||
p._code = LineUtil._getBitCode(p, bounds);
|
||||
clippedPoints.push(p);
|
||||
}
|
||||
clippedPoints.push(a);
|
||||
|
||||
// else if b is inside the clip window (a->b enters the screen)
|
||||
} else if (!(b._code & edge)) {
|
||||
p = LineUtil._getEdgeIntersection(b, a, edge, bounds, round);
|
||||
p._code = LineUtil._getBitCode(p, bounds);
|
||||
clippedPoints.push(p);
|
||||
}
|
||||
}
|
||||
points = clippedPoints;
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
Generated
Vendored
Executable
+79
@@ -0,0 +1,79 @@
|
||||
import {Point} from './Point';
|
||||
import * as Util from '../core/Util';
|
||||
|
||||
/*
|
||||
* @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.
|
||||
export function Transformation(a, b, c, d) {
|
||||
if (Util.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]`.
|
||||
|
||||
export function toTransformation(a, b, c, d) {
|
||||
return new Transformation(a, b, c, d);
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
export {Point, toPoint as point} from './Point';
|
||||
export {Bounds, toBounds as bounds} from './Bounds';
|
||||
export {Transformation, toTransformation as transformation} from './Transformation';
|
||||
|
||||
import * as LineUtil from './LineUtil';
|
||||
export {LineUtil};
|
||||
import * as PolyUtil from './PolyUtil';
|
||||
export {PolyUtil};
|
||||
Reference in new issue
Block a user