744 lines
22 KiB
JavaScript
744 lines
22 KiB
JavaScript
/*! geolib.isPointInsideRobust 2.0.21
|
|
* !!EXPERIMENTAL!!
|
|
*
|
|
* Robust version of isPointInside for Geolib.js
|
|
*
|
|
* Based on https://github.com/mikolalysenko/robust-point-in-polygon
|
|
* by Mikola Lysenko, licensed under MIT
|
|
*
|
|
* @author Manuel Bieh
|
|
* @url http://www.manuelbieh.com/
|
|
* @version 2.0.21
|
|
* @license MIT
|
|
*
|
|
*/
|
|
;(function(global, geolib, undefined) {
|
|
|
|
var addOn = function(geolib) {
|
|
|
|
var SPLITTER = +(Math.pow(2, 27) + 1.0);
|
|
|
|
var NUM_EXPAND = 5;
|
|
var EPSILON = 1.1102230246251565e-16;
|
|
var ERRBOUND3 = (3.0 + 16.0 * EPSILON) * EPSILON;
|
|
var ERRBOUND4 = (7.0 + 56.0 * EPSILON) * EPSILON;
|
|
|
|
var twoProduct = function(a, b, result) {
|
|
var x = a * b;
|
|
var c = SPLITTER * a;
|
|
var abig = c - a;
|
|
var ahi = c - abig;
|
|
var alo = a - ahi;
|
|
var d = SPLITTER * b;
|
|
var bbig = d - b;
|
|
var bhi = d - bbig;
|
|
var blo = b - bhi;
|
|
var err1 = x - (ahi * bhi);
|
|
var err2 = err1 - (alo * bhi);
|
|
var err3 = err2 - (ahi * blo);
|
|
var y = alo * blo - err3;
|
|
if(result) {
|
|
result[0] = y;
|
|
result[1] = x;
|
|
return result;
|
|
}
|
|
return [ y, x ];
|
|
};
|
|
|
|
var fastTwoSum = function(a, b, result) {
|
|
var x = a + b;
|
|
var bv = x - a;
|
|
var av = x - bv;
|
|
var br = b - bv;
|
|
var ar = a - av;
|
|
if(result) {
|
|
result[0] = ar + br;
|
|
result[1] = x;
|
|
return result;
|
|
}
|
|
return [ar+br, x];
|
|
};
|
|
|
|
var twoSum = fastTwoSum;
|
|
|
|
var linearExpansionSum = function(e, f) {
|
|
var ne = e.length|0;
|
|
var nf = f.length|0;
|
|
if(ne === 1 && nf === 1) {
|
|
return scalarScalar(e[0], f[0]);
|
|
}
|
|
var n = ne + nf;
|
|
var g = new Array(n);
|
|
var count = 0;
|
|
var eptr = 0;
|
|
var fptr = 0;
|
|
var abs = Math.abs;
|
|
var ei = e[eptr];
|
|
var ea = abs(ei);
|
|
var fi = f[fptr];
|
|
var fa = abs(fi);
|
|
var a, b;
|
|
if(ea < fa) {
|
|
b = ei;
|
|
eptr += 1;
|
|
if(eptr < ne) {
|
|
ei = e[eptr];
|
|
ea = abs(ei);
|
|
}
|
|
} else {
|
|
b = fi;
|
|
fptr += 1;
|
|
if(fptr < nf) {
|
|
fi = f[fptr];
|
|
fa = abs(fi);
|
|
}
|
|
}
|
|
if((eptr < ne && ea < fa) || (fptr >= nf)) {
|
|
a = ei;
|
|
eptr += 1;
|
|
if(eptr < ne) {
|
|
ei = e[eptr];
|
|
ea = abs(ei);
|
|
}
|
|
} else {
|
|
a = fi;
|
|
fptr += 1;
|
|
if(fptr < nf) {
|
|
fi = f[fptr];
|
|
fa = abs(fi);
|
|
}
|
|
}
|
|
var x = a + b;
|
|
var bv = x - a;
|
|
var y = b - bv;
|
|
var q0 = y;
|
|
var q1 = x;
|
|
var _x, _bv, _av, _br, _ar;
|
|
while(eptr < ne && fptr < nf) {
|
|
if(ea < fa) {
|
|
a = ei;
|
|
eptr += 1;
|
|
if(eptr < ne) {
|
|
ei = e[eptr];
|
|
ea = abs(ei);
|
|
}
|
|
} else {
|
|
a = fi;
|
|
fptr += 1;
|
|
if(fptr < nf) {
|
|
fi = f[fptr];
|
|
fa = abs(fi);
|
|
}
|
|
}
|
|
b = q0;
|
|
x = a + b;
|
|
bv = x - a;
|
|
y = b - bv;
|
|
if(y) {
|
|
g[count++] = y;
|
|
}
|
|
_x = q1 + x;
|
|
_bv = _x - q1;
|
|
_av = _x - _bv;
|
|
_br = x - _bv;
|
|
_ar = q1 - _av;
|
|
q0 = _ar + _br;
|
|
q1 = _x;
|
|
}
|
|
while(eptr < ne) {
|
|
a = ei;
|
|
b = q0;
|
|
x = a + b;
|
|
bv = x - a;
|
|
y = b - bv;
|
|
if(y) {
|
|
g[count++] = y;
|
|
}
|
|
_x = q1 + x;
|
|
_bv = _x - q1;
|
|
_av = _x - _bv;
|
|
_br = x - _bv;
|
|
_ar = q1 - _av;
|
|
q0 = _ar + _br;
|
|
q1 = _x;
|
|
eptr += 1;
|
|
if(eptr < ne) {
|
|
ei = e[eptr];
|
|
}
|
|
}
|
|
while(fptr < nf) {
|
|
a = fi;
|
|
b = q0;
|
|
x = a + b;
|
|
bv = x - a;
|
|
y = b - bv;
|
|
if(y) {
|
|
g[count++] = y;
|
|
}
|
|
_x = q1 + x;
|
|
_bv = _x - q1;
|
|
_av = _x - _bv;
|
|
_br = x - _bv;
|
|
_ar = q1 - _av;
|
|
q0 = _ar + _br;
|
|
q1 = _x;
|
|
fptr += 1;
|
|
if(fptr < nf) {
|
|
fi = f[fptr];
|
|
}
|
|
}
|
|
if(q0) {
|
|
g[count++] = q0;
|
|
}
|
|
if(q1) {
|
|
g[count++] = q1;
|
|
}
|
|
if(!count) {
|
|
g[count++] = 0.0;
|
|
}
|
|
g.length = count;
|
|
return g;
|
|
};
|
|
|
|
var robustSum = linearExpansionSum;
|
|
|
|
var scaleLinearExpansion = function(e, scale) {
|
|
var n = e.length;
|
|
if(n === 1) {
|
|
var ts = twoProduct(e[0], scale);
|
|
if(ts[0]) {
|
|
return ts;
|
|
}
|
|
return [ ts[1] ];
|
|
}
|
|
var g = new Array(2 * n);
|
|
var q = [0.1, 0.1];
|
|
var t = [0.1, 0.1];
|
|
var count = 0;
|
|
twoProduct(e[0], scale, q);
|
|
if(q[0]) {
|
|
g[count++] = q[0];
|
|
}
|
|
for(var i=1; i<n; ++i) {
|
|
twoProduct(e[i], scale, t);
|
|
var pq = q[1];
|
|
twoSum(pq, t[0], q);
|
|
if(q[0]) {
|
|
g[count++] = q[0];
|
|
}
|
|
var a = t[1];
|
|
var b = q[1];
|
|
var x = a + b;
|
|
var bv = x - a;
|
|
var y = b - bv;
|
|
q[1] = x;
|
|
if(y) {
|
|
g[count++] = y;
|
|
}
|
|
}
|
|
if(q[1]) {
|
|
g[count++] = q[1];
|
|
}
|
|
if(count === 0) {
|
|
g[count++] = 0.0;
|
|
}
|
|
g.length = count;
|
|
return g;
|
|
};
|
|
|
|
var robustScale = scaleLinearExpansion;
|
|
|
|
var scalarScalar = function(a, b) {
|
|
var x = a + b;
|
|
var bv = x - a;
|
|
var av = x - bv;
|
|
var br = b - bv;
|
|
var ar = a - av;
|
|
var y = ar + br;
|
|
if(y) {
|
|
return [y, x];
|
|
}
|
|
return [x];
|
|
};
|
|
|
|
var robustSubtract = function(e, f) {
|
|
var ne = e.length|0;
|
|
var nf = f.length|0;
|
|
if(ne === 1 && nf === 1) {
|
|
return scalarScalar(e[0], -f[0]);
|
|
}
|
|
var n = ne + nf;
|
|
var g = new Array(n);
|
|
var count = 0;
|
|
var eptr = 0;
|
|
var fptr = 0;
|
|
var abs = Math.abs;
|
|
var ei = e[eptr];
|
|
var ea = abs(ei);
|
|
var fi = -f[fptr];
|
|
var fa = abs(fi);
|
|
var a, b;
|
|
if(ea < fa) {
|
|
b = ei;
|
|
eptr += 1;
|
|
if(eptr < ne) {
|
|
ei = e[eptr];
|
|
ea = abs(ei);
|
|
}
|
|
} else {
|
|
b = fi;
|
|
fptr += 1;
|
|
if(fptr < nf) {
|
|
fi = -f[fptr];
|
|
fa = abs(fi);
|
|
}
|
|
}
|
|
if((eptr < ne && ea < fa) || (fptr >= nf)) {
|
|
a = ei;
|
|
eptr += 1;
|
|
if(eptr < ne) {
|
|
ei = e[eptr];
|
|
ea = abs(ei);
|
|
}
|
|
} else {
|
|
a = fi;
|
|
fptr += 1;
|
|
if(fptr < nf) {
|
|
fi = -f[fptr];
|
|
fa = abs(fi);
|
|
}
|
|
}
|
|
var x = a + b;
|
|
var bv = x - a;
|
|
var y = b - bv;
|
|
var q0 = y;
|
|
var q1 = x;
|
|
var _x, _bv, _av, _br, _ar;
|
|
while(eptr < ne && fptr < nf) {
|
|
if(ea < fa) {
|
|
a = ei;
|
|
eptr += 1;
|
|
if(eptr < ne) {
|
|
ei = e[eptr];
|
|
ea = abs(ei);
|
|
}
|
|
} else {
|
|
a = fi;
|
|
fptr += 1;
|
|
if(fptr < nf) {
|
|
fi = -f[fptr];
|
|
fa = abs(fi);
|
|
}
|
|
}
|
|
b = q0;
|
|
x = a + b;
|
|
bv = x - a;
|
|
y = b - bv;
|
|
if(y) {
|
|
g[count++] = y;
|
|
}
|
|
_x = q1 + x;
|
|
_bv = _x - q1;
|
|
_av = _x - _bv;
|
|
_br = x - _bv;
|
|
_ar = q1 - _av;
|
|
q0 = _ar + _br;
|
|
q1 = _x;
|
|
}
|
|
while(eptr < ne) {
|
|
a = ei;
|
|
b = q0;
|
|
x = a + b;
|
|
bv = x - a;
|
|
y = b - bv;
|
|
if(y) {
|
|
g[count++] = y;
|
|
}
|
|
_x = q1 + x;
|
|
_bv = _x - q1;
|
|
_av = _x - _bv;
|
|
_br = x - _bv;
|
|
_ar = q1 - _av;
|
|
q0 = _ar + _br;
|
|
q1 = _x;
|
|
eptr += 1;
|
|
if(eptr < ne) {
|
|
ei = e[eptr];
|
|
}
|
|
}
|
|
while(fptr < nf) {
|
|
a = fi;
|
|
b = q0;
|
|
x = a + b;
|
|
bv = x - a;
|
|
y = b - bv;
|
|
if(y) {
|
|
g[count++] = y;
|
|
}
|
|
_x = q1 + x;
|
|
_bv = _x - q1;
|
|
_av = _x - _bv;
|
|
_br = x - _bv;
|
|
_ar = q1 - _av;
|
|
q0 = _ar + _br;
|
|
q1 = _x;
|
|
fptr += 1;
|
|
if(fptr < nf) {
|
|
fi = -f[fptr];
|
|
}
|
|
}
|
|
if(q0) {
|
|
g[count++] = q0;
|
|
}
|
|
if(q1) {
|
|
g[count++] = q1;
|
|
}
|
|
if(!count) {
|
|
g[count++] = 0.0;
|
|
}
|
|
g.length = count;
|
|
return g;
|
|
};
|
|
|
|
var cofactor = function(m, c) {
|
|
var result = new Array(m.length-1);
|
|
for(var i=1; i<m.length; ++i) {
|
|
var r = result[i-1] = new Array(m.length-1);
|
|
for(var j=0,k=0; j<m.length; ++j) {
|
|
if(j === c) {
|
|
continue;
|
|
}
|
|
r[k++] = m[i][j];
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
var matrix = function(n) {
|
|
var result = new Array(n);
|
|
for(var i=0; i<n; ++i) {
|
|
result[i] = new Array(n);
|
|
for(var j=0; j<n; ++j) {
|
|
result[i][j] = ["m", j, "[", (n-i-1), "]"].join("");
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
var sign = function(n) {
|
|
if(n & 1) {
|
|
return "-";
|
|
}
|
|
return "";
|
|
};
|
|
|
|
var generateSum = function(expr) {
|
|
if(expr.length === 1) {
|
|
return expr[0];
|
|
} else if(expr.length === 2) {
|
|
return ["sum(", expr[0], ",", expr[1], ")"].join("");
|
|
} else {
|
|
var m = expr.length>>1;
|
|
return ["sum(", generateSum(expr.slice(0, m)), ",", generateSum(expr.slice(m)), ")"].join("");
|
|
}
|
|
};
|
|
|
|
var determinant = function(m) {
|
|
if(m.length === 2) {
|
|
return [["sum(prod(", m[0][0], ",", m[1][1], "),prod(-", m[0][1], ",", m[1][0], "))"].join("")];
|
|
} else {
|
|
var expr = [];
|
|
for(var i=0; i<m.length; ++i) {
|
|
expr.push(["scale(", generateSum(determinant(cofactor(m, i))), ",", sign(i), m[0][i], ")"].join(""));
|
|
}
|
|
return expr;
|
|
}
|
|
};
|
|
|
|
var orientation = function(n) {
|
|
var pos = [];
|
|
var neg = [];
|
|
var m = matrix(n);
|
|
var args = [];
|
|
for(var i=0; i<n; ++i) {
|
|
if((i&1)===0) {
|
|
pos.push.apply(pos, determinant(cofactor(m, i)));
|
|
} else {
|
|
neg.push.apply(neg, determinant(cofactor(m, i)));
|
|
}
|
|
args.push("m" + i);
|
|
}
|
|
var posExpr = generateSum(pos);
|
|
var negExpr = generateSum(neg);
|
|
var funcName = "orientation" + n + "Exact";
|
|
var code = [
|
|
"function ",
|
|
funcName,
|
|
"(", args.join(), "){var p=",
|
|
posExpr,
|
|
",n=",
|
|
negExpr,
|
|
",d=sub(p,n);return d[d.length-1];};return ",
|
|
funcName
|
|
].join("");
|
|
var proc = new Function("sum", "prod", "scale", "sub", code);
|
|
return proc(robustSum, twoProduct, robustScale, robustSubtract);
|
|
};
|
|
|
|
var orient;
|
|
var orientation3Exact = orientation(3);
|
|
var orientation4Exact = orientation(4);
|
|
|
|
var CACHED = [
|
|
function orientation0() { return 0; },
|
|
function orientation1() { return 0; },
|
|
function orientation2(a, b) {
|
|
return b[0] - a[0];
|
|
},
|
|
function orientation3(a, b, c) {
|
|
var l = (a[1] - c[1]) * (b[0] - c[0]);
|
|
var r = (a[0] - c[0]) * (b[1] - c[1]);
|
|
var det = l - r;
|
|
var s;
|
|
if(l > 0) {
|
|
if(r <= 0) {
|
|
return det;
|
|
} else {
|
|
s = l + r;
|
|
}
|
|
} else if(l < 0) {
|
|
if(r >= 0) {
|
|
return det;
|
|
} else {
|
|
s = -(l + r);
|
|
}
|
|
} else {
|
|
return det;
|
|
}
|
|
var tol = ERRBOUND3 * s;
|
|
if(det >= tol || det <= -tol) {
|
|
return det;
|
|
}
|
|
return orientation3Exact(a, b, c);
|
|
},
|
|
function orientation4(a,b,c,d) {
|
|
var adx = a[0] - d[0];
|
|
var bdx = b[0] - d[0];
|
|
var cdx = c[0] - d[0];
|
|
var ady = a[1] - d[1];
|
|
var bdy = b[1] - d[1];
|
|
var cdy = c[1] - d[1];
|
|
var adz = a[2] - d[2];
|
|
var bdz = b[2] - d[2];
|
|
var cdz = c[2] - d[2];
|
|
var bdxcdy = bdx * cdy;
|
|
var cdxbdy = cdx * bdy;
|
|
var cdxady = cdx * ady;
|
|
var adxcdy = adx * cdy;
|
|
var adxbdy = adx * bdy;
|
|
var bdxady = bdx * ady;
|
|
var det = adz * (bdxcdy - cdxbdy) +
|
|
bdz * (cdxady - adxcdy) +
|
|
cdz * (adxbdy - bdxady);
|
|
var permanent = (Math.abs(bdxcdy) + Math.abs(cdxbdy)) * Math.abs(adz) +
|
|
(Math.abs(cdxady) + Math.abs(adxcdy)) * Math.abs(bdz) +
|
|
(Math.abs(adxbdy) + Math.abs(bdxady)) * Math.abs(cdz);
|
|
var tol = ERRBOUND4 * permanent;
|
|
if ((det > tol) || (-det > tol)) {
|
|
return det;
|
|
}
|
|
return orientation4Exact(a,b,c,d);
|
|
}
|
|
];
|
|
|
|
var slowOrient = function(args) {
|
|
var proc = CACHED[args.length];
|
|
if(!proc) {
|
|
proc = CACHED[args.length] = orientation(args.length);
|
|
}
|
|
return proc.apply(undefined, args);
|
|
};
|
|
|
|
var generateOrientationProc = function() {
|
|
while(CACHED.length <= NUM_EXPAND) {
|
|
CACHED.push(orientation(CACHED.length));
|
|
}
|
|
var args = [];
|
|
var procArgs = ["slow"];
|
|
for(var i=0; i<=NUM_EXPAND; ++i) {
|
|
args.push("a" + i);
|
|
procArgs.push("o" + i);
|
|
}
|
|
var code = [
|
|
"function getOrientation(",
|
|
args.join(),
|
|
"){switch(arguments.length){case 0:case 1:return 0;"
|
|
];
|
|
for(i=2; i<=NUM_EXPAND; ++i) {
|
|
code.push("case ", i, ":return o", i, "(", args.slice(0, i).join(), ");");
|
|
}
|
|
code.push("}var s=new Array(arguments.length);for(var i=0;i<arguments.length;++i){s[i]=arguments[i]};return slow(s);}return getOrientation");
|
|
procArgs.push(code.join(""));
|
|
|
|
var proc = Function.apply(undefined, procArgs);
|
|
orient = proc.apply(undefined, [slowOrient].concat(CACHED));
|
|
for(i=0; i<=NUM_EXPAND; ++i) {
|
|
orient[i] = CACHED[i];
|
|
}
|
|
};
|
|
|
|
generateOrientationProc();
|
|
|
|
var robustPointInPolygon = function(vs, point) {
|
|
// transform from geolib format to array syntax
|
|
var x = geolib.longitude(point);
|
|
var y = geolib.latitude(point);
|
|
var coords = vs.map(function(coords) {
|
|
return [geolib.longitude(coords), geolib.latitude(coords)];
|
|
});
|
|
|
|
vs = coords;
|
|
point = [x,y];
|
|
|
|
var n = vs.length;
|
|
var inside = 1;
|
|
var lim = n;
|
|
|
|
var s, c, yk, px, p;
|
|
|
|
for(var i = 0, j = n-1; i<lim; j=i++) {
|
|
var a = vs[i];
|
|
var b = vs[j];
|
|
var yi = a[1];
|
|
var yj = b[1];
|
|
if(yj < yi) {
|
|
if(yj < y && y < yi) {
|
|
s = orient(a, b, point);
|
|
if(s === 0) {
|
|
return 0;
|
|
} else {
|
|
inside ^= (0 < s)|0;
|
|
}
|
|
} else if(y === yi) {
|
|
c = vs[(i+1)%n];
|
|
yk = c[1];
|
|
if(yi < yk) {
|
|
s = orient(a, b, point);
|
|
if(s === 0) {
|
|
return 0;
|
|
} else {
|
|
inside ^= (0 < s)|0;
|
|
}
|
|
}
|
|
}
|
|
} else if(yi < yj) {
|
|
if(yi < y && y < yj) {
|
|
s = orient(a, b, point);
|
|
if(s === 0) {
|
|
return 0;
|
|
} else {
|
|
inside ^= (s < 0)|0;
|
|
}
|
|
} else if(y === yi) {
|
|
c = vs[(i+1)%n];
|
|
yk = c[1];
|
|
if(yk < yi) {
|
|
s = orient(a, b, point);
|
|
if(s === 0) {
|
|
return 0;
|
|
} else {
|
|
inside ^= (s < 0)|0;
|
|
}
|
|
}
|
|
}
|
|
} else if(y === yi) {
|
|
var x0 = Math.min(a[0], b[0]);
|
|
var x1 = Math.max(a[0], b[0]);
|
|
if(i === 0) {
|
|
while(j>0) {
|
|
var k = (j+n-1)%n;
|
|
p = vs[k];
|
|
if(p[1] !== y) {
|
|
break;
|
|
}
|
|
px = p[0];
|
|
x0 = Math.min(x0, px);
|
|
x1 = Math.max(x1, px);
|
|
j = k;
|
|
}
|
|
if(j === 0) {
|
|
if(x0 <= x && x <= x1) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
lim = j+1;
|
|
}
|
|
var y0 = vs[(j+n-1)%n][1];
|
|
while(i+1<lim) {
|
|
p = vs[i+1];
|
|
if(p[1] !== y) {
|
|
break;
|
|
}
|
|
px = p[0];
|
|
x0 = Math.min(x0, px);
|
|
x1 = Math.max(x1, px);
|
|
i += 1;
|
|
}
|
|
if(x0 <= x && x <= x1) {
|
|
return 0;
|
|
}
|
|
var y1 = vs[(i+1)%n][1];
|
|
if(x < x0 && (y0 < y !== y1 < y)) {
|
|
inside ^= 1;
|
|
}
|
|
}
|
|
}
|
|
return 2 * inside - 1;
|
|
};
|
|
|
|
return {
|
|
|
|
/**
|
|
* @param object coordinate to check e.g. {latitude: 51.5023, longitude: 7.3815}
|
|
* @param array array with coords e.g. [{latitude: 51.5143, longitude: 7.4138}, {latitude: 123, longitude: 123}, ...]
|
|
* @return integer -1 if point is inside, 0 if point is on boundaries, 1 if point is outside
|
|
*/
|
|
isPointInsideRobust: function(latlng, coords) {
|
|
return robustPointInPolygon(coords, latlng);
|
|
},
|
|
|
|
isInside: function() {
|
|
return this.isPointInsideRobust.apply(this, arguments);
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
// Node module
|
|
if (typeof module !== 'undefined' &&
|
|
typeof module.exports !== 'undefined') {
|
|
|
|
module.exports = function(geolib) {
|
|
geolib.extend(addOn(geolib), true);
|
|
return geolib;
|
|
};
|
|
|
|
// AMD module
|
|
} else if (typeof define === "function" && define.amd) {
|
|
|
|
define(["geolib"], function (geolib) {
|
|
geolib.extend(addOn(geolib), true);
|
|
return geolib;
|
|
});
|
|
|
|
// we're in a browser
|
|
} else {
|
|
|
|
geolib.extend(addOn(geolib), true);
|
|
|
|
}
|
|
|
|
}(this, this.geolib));
|