@placemarkio/turf-jsts
Version:
A JavaScript library of spatial predicates and functions for processing geometry
1,835 lines (1,661 loc) • 432 kB
JavaScript
class BufferParameters {
constructor() {
BufferParameters.constructor_.apply(this, arguments);
}
static constructor_() {
this._quadrantSegments = BufferParameters.DEFAULT_QUADRANT_SEGMENTS;
this._endCapStyle = BufferParameters.CAP_ROUND;
this._joinStyle = BufferParameters.JOIN_ROUND;
this._mitreLimit = BufferParameters.DEFAULT_MITRE_LIMIT;
this._isSingleSided = false;
this._simplifyFactor = BufferParameters.DEFAULT_SIMPLIFY_FACTOR;
if (arguments.length === 0) ; else if (arguments.length === 1) {
const quadrantSegments = arguments[0];
this.setQuadrantSegments(quadrantSegments);
} else if (arguments.length === 2) {
const quadrantSegments = arguments[0], endCapStyle = arguments[1];
this.setQuadrantSegments(quadrantSegments);
this.setEndCapStyle(endCapStyle);
} else if (arguments.length === 4) {
const quadrantSegments = arguments[0], endCapStyle = arguments[1], joinStyle = arguments[2], mitreLimit = arguments[3];
this.setQuadrantSegments(quadrantSegments);
this.setEndCapStyle(endCapStyle);
this.setJoinStyle(joinStyle);
this.setMitreLimit(mitreLimit);
}
}
static bufferDistanceError(quadSegs) {
const alpha = Math.PI / 2.0 / quadSegs;
return 1 - Math.cos(alpha / 2.0)
}
getEndCapStyle() {
return this._endCapStyle
}
isSingleSided() {
return this._isSingleSided
}
setQuadrantSegments(quadSegs) {
this._quadrantSegments = quadSegs;
if (this._quadrantSegments === 0) this._joinStyle = BufferParameters.JOIN_BEVEL;
if (this._quadrantSegments < 0) {
this._joinStyle = BufferParameters.JOIN_MITRE;
this._mitreLimit = Math.abs(this._quadrantSegments);
}
if (quadSegs <= 0)
this._quadrantSegments = 1;
if (this._joinStyle !== BufferParameters.JOIN_ROUND)
this._quadrantSegments = BufferParameters.DEFAULT_QUADRANT_SEGMENTS;
}
getJoinStyle() {
return this._joinStyle
}
setJoinStyle(joinStyle) {
this._joinStyle = joinStyle;
}
setSimplifyFactor(simplifyFactor) {
this._simplifyFactor = simplifyFactor < 0 ? 0 : simplifyFactor;
}
getSimplifyFactor() {
return this._simplifyFactor
}
getQuadrantSegments() {
return this._quadrantSegments
}
setEndCapStyle(endCapStyle) {
this._endCapStyle = endCapStyle;
}
getMitreLimit() {
return this._mitreLimit
}
setMitreLimit(mitreLimit) {
this._mitreLimit = mitreLimit;
}
setSingleSided(isSingleSided) {
this._isSingleSided = isSingleSided;
}
}
BufferParameters.CAP_ROUND = 1;
BufferParameters.CAP_FLAT = 2;
BufferParameters.CAP_SQUARE = 3;
BufferParameters.JOIN_ROUND = 1;
BufferParameters.JOIN_MITRE = 2;
BufferParameters.JOIN_BEVEL = 3;
BufferParameters.DEFAULT_QUADRANT_SEGMENTS = 8;
BufferParameters.DEFAULT_MITRE_LIMIT = 5.0;
BufferParameters.DEFAULT_SIMPLIFY_FACTOR = 0.01;
class Exception extends Error {
constructor(message) {
super(message);
this.name = Object.keys({ Exception })[0];
}
toString() {
return this.message
}
}
class IllegalArgumentException extends Exception {
constructor(message) {
super(message);
this.name = Object.keys({ IllegalArgumentException })[0];
}
}
class GeometryComponentFilter {
filter(geom) {}
}
function Comparable() {}
function Clonable() {}
function Serializable() {}
class NumberUtil {
static equalsWithTolerance(x1, x2, tolerance) {
return Math.abs(x1 - x2) <= tolerance
}
}
class Long {
constructor(high, low) {
this.low = low || 0;
this.high = high || 0;
}
static toBinaryString(i) {
let mask;
let result = '';
for (mask = 0x80000000; mask > 0; mask >>>= 1)
result += (i.high & mask) === mask ? '1' : '0';
for (mask = 0x80000000; mask > 0; mask >>>= 1)
result += (i.low & mask) === mask ? '1' : '0';
return result
}
}
function Double() { }
Double.NaN = NaN;
Double.isNaN = n => Number.isNaN(n);
Double.isInfinite = n => !Number.isFinite(n);
Double.MAX_VALUE = Number.MAX_VALUE;
Double.POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
Double.NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY;
if (typeof Float64Array === 'function' &&
typeof Int32Array === 'function')
// Simple and fast conversion between double and long bits
// using TypedArrays and ArrayViewBuffers.
(function() {
const EXP_BIT_MASK = 0x7ff00000;
const SIGNIF_BIT_MASK = 0xFFFFF;
const f64buf = new Float64Array(1);
const i32buf = new Int32Array(f64buf.buffer);
Double.doubleToLongBits = function(value) {
f64buf[0] = value;
let low = i32buf[0] | 0;
let high = i32buf[1] | 0;
// Check for NaN based on values of bit fields, maximum
// exponent and nonzero significand.
if (((high & EXP_BIT_MASK) === EXP_BIT_MASK) &&
((high & SIGNIF_BIT_MASK) !== 0) &&
(low !== 0)) {
low = 0 | 0;
high = 0x7ff80000 | 0;
}
return new Long(high, low)
};
Double.longBitsToDouble = function(bits) {
i32buf[0] = bits.low;
i32buf[1] = bits.high;
return f64buf[0]
};
})();
else
// More complex and slower fallback implementation using
// math and the divide-by-two and multiply-by-two algorithms.
(function() {
const BIAS = 1023;
const log2 = Math.log2;
const floor = Math.floor;
const pow = Math.pow;
const MAX_REL_BITS_INTEGER = (function() {
for (let i = 53; i > 0; i--) {
const bits = pow(2, i) - 1;
if (floor(log2(bits)) + 1 === i) return bits
}
return 0
})();
Double.doubleToLongBits = function(value) {
let x, y, f, bits, skip;
let sign, exp, high, low;
// Get the sign bit and absolute value.
if (value < 0 || 1 / value === Number.NEGATIVE_INFINITY) {
sign = (1 << 31);
value = (-value);
} else {
sign = 0;
}
// Handle some special values.
if (value === 0) {
// Handle zeros (+/-0).
low = 0 | 0;
high = sign; // exponent: 00..00, significand: 00..00
return new Long(high, low)
}
if (value === Infinity) {
// Handle infinity (only positive values for value possible).
low = 0 | 0;
high = sign | 0x7ff00000; // exponent: 11..11, significand: 00..00
return new Long(high, low)
}
if (value !== value) { // eslint-disable-line
// Handle NaNs (boiled down to only one distinct NaN).
low = 0 | 0;
high = 0x7ff80000; // exponent: 11..11, significand: 10..00
return new Long(high, low)
}
// Preinitialize variables, that are not neccessarily set by
// the algorithm.
bits = 0;
low = 0 | 0;
// Get the (always positive) integer part of value.
x = floor(value);
// Process the integer part if it's greater than 1. Zero requires
// no bits at all, 1 represents the implicit (hidden) leading bit,
// which must not be written as well.
if (x > 1)
// If we can reliably determine the number of bits required for
// the integer part,
if (x <= MAX_REL_BITS_INTEGER) {
// get the number of bits required to represent it minus 1
bits = floor(log2(x)); /* + 1 - 1 */
// and simply copy/shift the integer bits into low and high.
// That's much faster than the divide-by-two algorithm (saves
// up to ~60%).
// We always need to mask out the most significant bit, which
// is the implicit (aka hidden) bit.
if (bits <= 20) {
// The simple case in which the integer fits into the
// lower 20 bits of the high word is worth to be handled
// separately (saves ~25%).
low = 0 | 0;
high = (x << (20 - bits)) & 0xfffff;
} else {
// Here, the integer part is split into low and high.
// Since its value may require more than 32 bits, we
// cannot use bitwise operators (which implicitly cast
// to Int32), but use arithmetic operators % and / to
// get low and high parts. The uppper 20 bits go to high,
// the remaining bits (in f) to low.
f = bits - 20;
// Like (1 << f) but safe with even more than 32 bits.
y = pow(2, f);
low = (x % y) << (32 - f);
high = (x / y) & 0xfffff;
}
} else {
// For greater values, we must use the much slower divide-by-two
// algorithm. Bits are generated from right to left, that is from
// least to most significant bit. For each bit, we left-shift both
// low and high by one and carry bit #0 from high to #31 in low.
// The next bit is then copied into bit #19 in high, the leftmost
// bit of the double's significand.
// Preserve x for later user, so work with f.
f = x;
low = 0 | 0;
for (;;) {
y = f / 2;
f = floor(y);
if (f === 0)
// We just found the most signigicant (1-)bit, which
// is the implicit bit and so, not stored in the double
// value. So, it's time to leave the loop.
break
// Count this bit, shift low and carry bit #0 from high.
bits++;
low >>>= 1;
low |= (high & 0x1) << 31;
// Shift high.
high >>>= 1;
if (y !== f)
// Copy the new bit into bit #19 in high (only required if 1).
high |= 0x80000;
}
}
// Bias the exponent.
exp = bits + BIAS;
// If the integer part is zero, we've not yet seen the implicit
// leading bit. Variable skip is later used while processing the
// fractional part (if any).
skip = (x === 0);
// Get fraction only into x.
x = value - x;
// If some significand bits are still left to be filled and
// the fractional part is not zero, convert the fraction using
// the multiply-by-2 algorithm.
if (bits < 52 && x !== 0) {
// Initialize 'buffer' f, into which newly created bits get
// shifted from right to left.
f = 0;
for (;;) {
y = x * 2;
if (y >= 1) {
// This is a new 1-bit. Add and count this bit, if not
// prohibited by skip.
x = y - 1;
if (!skip) {
f <<= 1;
f |= 1;
bits++;
} else {
// Otherwise, decrement the exponent and unset
// skip, so that all following bits get written.
exp--;
skip = false;
}
} else {
// This is a new 0-bit. Add and count this bit, if not
// prohibited by skip.
x = y;
if (!skip) {
f <<= 1;
bits++;
} else if (--exp === 0) {
// Otherwise we've just decremented the exponent. If the
// biased exponent is zero now (-1023), we process a
// subnormal number, which has no impled leading 1-bit.
// So, count this 0-bit and unset skip to write out
// all the following bits.
bits++;
skip = false;
}
}
if (bits === 20) {
// When 20 bits have been created in total, we're done with
// the high word. Copy the bits from 'buffer' f into high
// and reset 'buffer' f. Following bits will end up in the
// low word.
high |= f;
f = 0;
} else if (bits === 52) {
// When 52 bits have been created in total, we're done with
// low word as well. Copy the bits from 'buffer' f into low
// and exit the loop.
low |= f;
break
}
if (y === 1) {
// When y is exactly 1, there is no remainder and the process
// is complete (the number is finite). Copy the bits from
// 'buffer' f into either low or high and exit the loop.
if (bits < 20)
high |= (f << (20 - bits));
else if (bits < 52) low |= (f << (52 - bits));
break
}
}
}
// Copy/shift the exponent and sign bits into the high word.
high |= (exp << 20);
high |= sign;
return new Long(high, low)
};
Double.longBitsToDouble = function(bits) {
let i;
let x, exp, fract;
const high = bits.high;
const low = bits.low;
// Extract the sign.
const sign = (high & (1 << 31)) ? -1 : 1;
// Extract the unbiased exponent.
exp = ((high & 0x7ff00000) >> 20) - BIAS;
// Calculate the fraction from left to right. Start
// off with the 20 lower bits from the high word.
fract = 0;
x = (1 << 19);
for (i = 1; i <= 20; i++) {
if (high & x) fract += pow(2, -i);
x >>>= 1;
}
// Continue with all 32 bits from the low word.
x = (1 << 31);
for (i = 21; i <= 52; i++) {
if (low & x) fract += pow(2, -i);
x >>>= 1;
}
// Handle special values.
// Check for zero and subnormal values.
if (exp === -BIAS) {
if (fract === 0)
// +/-1.0 * 0.0 => +/-0.0
return sign * 0
exp = -1022;
} else if (exp === BIAS + 1) { // Check for +/-Infinity or NaN.
if (fract === 0)
// +/-1.0 / 0.0 => +/-Infinity
return sign / 0
return NaN
} else { // Nothing special? Seems to be a normal number.
// Add the implicit leading bit (1*2^0).
fract += 1;
}
return sign * fract * pow(2, exp)
};
})();
function Comparator() {}
class RuntimeException extends Exception {
constructor(message) {
super(message);
this.name = Object.keys({ RuntimeException })[0];
}
}
class AssertionFailedException extends RuntimeException {
constructor() {
super();
AssertionFailedException.constructor_.apply(this, arguments);
}
static constructor_() {
if (arguments.length === 0) {
RuntimeException.constructor_.call(this);
} else if (arguments.length === 1) {
const message = arguments[0];
RuntimeException.constructor_.call(this, message);
}
}
}
class Assert {
static shouldNeverReachHere() {
if (arguments.length === 0) {
Assert.shouldNeverReachHere(null);
} else if (arguments.length === 1) {
const message = arguments[0];
throw new AssertionFailedException('Should never reach here' + (message !== null ? ': ' + message : ''))
}
}
static isTrue() {
if (arguments.length === 1) {
const assertion = arguments[0];
Assert.isTrue(assertion, null);
} else if (arguments.length === 2) {
const assertion = arguments[0], message = arguments[1];
if (!assertion)
if (message === null)
throw new AssertionFailedException()
else
throw new AssertionFailedException(message)
}
}
static equals() {
if (arguments.length === 2) {
const expectedValue = arguments[0], actualValue = arguments[1];
Assert.equals(expectedValue, actualValue, null);
} else if (arguments.length === 3) {
const expectedValue = arguments[0], actualValue = arguments[1], message = arguments[2];
if (!actualValue.equals(expectedValue))
throw new AssertionFailedException('Expected ' + expectedValue + ' but encountered ' + actualValue + (message !== null ? ': ' + message : ''))
}
}
}
const kBuf = new ArrayBuffer(8);
const kBufAsF64 = new Float64Array(kBuf);
const kBufAsI32 = new Int32Array(kBuf);
class Coordinate {
constructor() {
Coordinate.constructor_.apply(this, arguments);
}
static constructor_() {
this.x = null;
this.y = null;
this.z = null;
if (arguments.length === 0) {
Coordinate.constructor_.call(this, 0.0, 0.0);
} else if (arguments.length === 1) {
const c = arguments[0];
Coordinate.constructor_.call(this, c.x, c.y, c.getZ());
} else if (arguments.length === 2) {
const x = arguments[0], y = arguments[1];
Coordinate.constructor_.call(this, x, y, Coordinate.NULL_ORDINATE);
} else if (arguments.length === 3) {
const x = arguments[0], y = arguments[1], z = arguments[2];
this.x = x;
this.y = y;
this.z = z;
}
}
static hashCode(n) {
kBufAsF64[0] = n;
return kBufAsI32[0] ^ kBufAsI32[1]
}
getM() {
return Double.NaN
}
setOrdinate(ordinateIndex, value) {
switch (ordinateIndex) {
case Coordinate.X:
this.x = value;
break
case Coordinate.Y:
this.y = value;
break
case Coordinate.Z:
this.setZ(value);
break
default:
throw new IllegalArgumentException('Invalid ordinate index: ' + ordinateIndex)
}
}
equals2D() {
if (arguments.length === 1) {
const other = arguments[0];
if (this.x !== other.x)
return false
if (this.y !== other.y)
return false
return true
} else if (arguments.length === 2) {
const c = arguments[0], tolerance = arguments[1];
if (!NumberUtil.equalsWithTolerance(this.x, c.x, tolerance))
return false
if (!NumberUtil.equalsWithTolerance(this.y, c.y, tolerance))
return false
return true
}
}
setM(m) {
throw new IllegalArgumentException('Invalid ordinate index: ' + Coordinate.M)
}
getZ() {
return this.z
}
getOrdinate(ordinateIndex) {
switch (ordinateIndex) {
case Coordinate.X:
return this.x
case Coordinate.Y:
return this.y
case Coordinate.Z:
return this.getZ()
}
throw new IllegalArgumentException('Invalid ordinate index: ' + ordinateIndex)
}
equals3D(other) {
return this.x === other.x && this.y === other.y && (this.getZ() === other.getZ() || Double.isNaN(this.getZ()) && Double.isNaN(other.getZ()))
}
equals(other) {
if (!(other instanceof Coordinate))
return false
return this.equals2D(other)
}
equalInZ(c, tolerance) {
return NumberUtil.equalsWithTolerance(this.getZ(), c.getZ(), tolerance)
}
setX(x) {
this.x = x;
}
compareTo(o) {
const other = o;
if (this.x < other.x) return -1
if (this.x > other.x) return 1
if (this.y < other.y) return -1
if (this.y > other.y) return 1
return 0
}
getX() {
return this.x
}
setZ(z) {
this.z = z;
}
clone() {
try {
const coord = null;
return coord
} catch (e) {
if (e instanceof CloneNotSupportedException) {
Assert.shouldNeverReachHere('this shouldn\'t happen because this class is Cloneable');
return null
} else {
throw e
}
} finally {}
}
copy() {
return new Coordinate(this)
}
toString() {
return '(' + this.x + ', ' + this.y + ', ' + this.getZ() + ')'
}
distance3D(c) {
const dx = this.x - c.x;
const dy = this.y - c.y;
const dz = this.getZ() - c.getZ();
return Math.sqrt(dx * dx + dy * dy + dz * dz)
}
getY() {
return this.y
}
setY(y) {
this.y = y;
}
distance(c) {
const dx = this.x - c.x;
const dy = this.y - c.y;
return Math.sqrt(dx * dx + dy * dy)
}
hashCode() {
let result = 17;
result = 37 * result + Coordinate.hashCode(this.x);
result = 37 * result + Coordinate.hashCode(this.y);
return result
}
setCoordinate(other) {
this.x = other.x;
this.y = other.y;
this.z = other.getZ();
}
get interfaces_() {
return [Comparable, Clonable, Serializable]
}
}
class DimensionalComparator {
constructor() {
DimensionalComparator.constructor_.apply(this, arguments);
}
static constructor_() {
this._dimensionsToTest = 2;
if (arguments.length === 0) {
DimensionalComparator.constructor_.call(this, 2);
} else if (arguments.length === 1) {
const dimensionsToTest = arguments[0];
if (dimensionsToTest !== 2 && dimensionsToTest !== 3) throw new IllegalArgumentException('only 2 or 3 dimensions may be specified')
this._dimensionsToTest = dimensionsToTest;
}
}
static compare(a, b) {
if (a < b) return -1
if (a > b) return 1
if (Double.isNaN(a)) {
if (Double.isNaN(b)) return 0
return -1
}
if (Double.isNaN(b)) return 1
return 0
}
compare(c1, c2) {
const compX = DimensionalComparator.compare(c1.x, c2.x);
if (compX !== 0) return compX
const compY = DimensionalComparator.compare(c1.y, c2.y);
if (compY !== 0) return compY
if (this._dimensionsToTest <= 2) return 0
const compZ = DimensionalComparator.compare(c1.getZ(), c2.getZ());
return compZ
}
get interfaces_() {
return [Comparator]
}
}
Coordinate.DimensionalComparator = DimensionalComparator;
Coordinate.NULL_ORDINATE = Double.NaN;
Coordinate.X = 0;
Coordinate.Y = 1;
Coordinate.Z = 2;
Coordinate.M = 3;
class Envelope {
constructor() {
Envelope.constructor_.apply(this, arguments);
}
static constructor_() {
this._minx = null;
this._maxx = null;
this._miny = null;
this._maxy = null;
if (arguments.length === 0) {
this.init();
} else if (arguments.length === 1) {
if (arguments[0] instanceof Coordinate) {
const p = arguments[0];
this.init(p.x, p.x, p.y, p.y);
} else if (arguments[0] instanceof Envelope) {
const env = arguments[0];
this.init(env);
}
} else if (arguments.length === 2) {
const p1 = arguments[0], p2 = arguments[1];
this.init(p1.x, p2.x, p1.y, p2.y);
} else if (arguments.length === 4) {
const x1 = arguments[0], x2 = arguments[1], y1 = arguments[2], y2 = arguments[3];
this.init(x1, x2, y1, y2);
}
}
static intersects() {
if (arguments.length === 3) {
const p1 = arguments[0], p2 = arguments[1], q = arguments[2];
if (q.x >= (p1.x < p2.x ? p1.x : p2.x) && q.x <= (p1.x > p2.x ? p1.x : p2.x) && (q.y >= (p1.y < p2.y ? p1.y : p2.y) && q.y <= (p1.y > p2.y ? p1.y : p2.y)))
return true
return false
} else if (arguments.length === 4) {
const p1 = arguments[0], p2 = arguments[1], q1 = arguments[2], q2 = arguments[3];
let minq = Math.min(q1.x, q2.x);
let maxq = Math.max(q1.x, q2.x);
let minp = Math.min(p1.x, p2.x);
let maxp = Math.max(p1.x, p2.x);
if (minp > maxq) return false
if (maxp < minq) return false
minq = Math.min(q1.y, q2.y);
maxq = Math.max(q1.y, q2.y);
minp = Math.min(p1.y, p2.y);
maxp = Math.max(p1.y, p2.y);
if (minp > maxq) return false
if (maxp < minq) return false
return true
}
}
getArea() {
return this.getWidth() * this.getHeight()
}
equals(other) {
if (!(other instanceof Envelope))
return false
const otherEnvelope = other;
if (this.isNull())
return otherEnvelope.isNull()
return this._maxx === otherEnvelope.getMaxX() && this._maxy === otherEnvelope.getMaxY() && this._minx === otherEnvelope.getMinX() && this._miny === otherEnvelope.getMinY()
}
intersection(env) {
if (this.isNull() || env.isNull() || !this.intersects(env)) return new Envelope()
const intMinX = this._minx > env._minx ? this._minx : env._minx;
const intMinY = this._miny > env._miny ? this._miny : env._miny;
const intMaxX = this._maxx < env._maxx ? this._maxx : env._maxx;
const intMaxY = this._maxy < env._maxy ? this._maxy : env._maxy;
return new Envelope(intMinX, intMaxX, intMinY, intMaxY)
}
isNull() {
return this._maxx < this._minx
}
getMaxX() {
return this._maxx
}
covers() {
if (arguments.length === 1) {
if (arguments[0] instanceof Coordinate) {
const p = arguments[0];
return this.covers(p.x, p.y)
} else if (arguments[0] instanceof Envelope) {
const other = arguments[0];
if (this.isNull() || other.isNull())
return false
return other.getMinX() >= this._minx && other.getMaxX() <= this._maxx && other.getMinY() >= this._miny && other.getMaxY() <= this._maxy
}
} else if (arguments.length === 2) {
const x = arguments[0], y = arguments[1];
if (this.isNull()) return false
return x >= this._minx && x <= this._maxx && y >= this._miny && y <= this._maxy
}
}
intersects() {
if (arguments.length === 1) {
if (arguments[0] instanceof Envelope) {
const other = arguments[0];
if (this.isNull() || other.isNull())
return false
return !(other._minx > this._maxx || other._maxx < this._minx || other._miny > this._maxy || other._maxy < this._miny)
} else if (arguments[0] instanceof Coordinate) {
const p = arguments[0];
return this.intersects(p.x, p.y)
}
} else if (arguments.length === 2) {
if (arguments[0] instanceof Coordinate && arguments[1] instanceof Coordinate) {
const a = arguments[0], b = arguments[1];
if (this.isNull())
return false
const envminx = a.x < b.x ? a.x : b.x;
if (envminx > this._maxx) return false
const envmaxx = a.x > b.x ? a.x : b.x;
if (envmaxx < this._minx) return false
const envminy = a.y < b.y ? a.y : b.y;
if (envminy > this._maxy) return false
const envmaxy = a.y > b.y ? a.y : b.y;
if (envmaxy < this._miny) return false
return true
} else if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number') {
const x = arguments[0], y = arguments[1];
if (this.isNull()) return false
return !(x > this._maxx || x < this._minx || y > this._maxy || y < this._miny)
}
}
}
getMinY() {
return this._miny
}
getDiameter() {
if (this.isNull())
return 0
const w = this.getWidth();
const h = this.getHeight();
return Math.sqrt(w * w + h * h)
}
getMinX() {
return this._minx
}
expandToInclude() {
if (arguments.length === 1) {
if (arguments[0] instanceof Coordinate) {
const p = arguments[0];
this.expandToInclude(p.x, p.y);
} else if (arguments[0] instanceof Envelope) {
const other = arguments[0];
if (other.isNull())
return null
if (this.isNull()) {
this._minx = other.getMinX();
this._maxx = other.getMaxX();
this._miny = other.getMinY();
this._maxy = other.getMaxY();
} else {
if (other._minx < this._minx)
this._minx = other._minx;
if (other._maxx > this._maxx)
this._maxx = other._maxx;
if (other._miny < this._miny)
this._miny = other._miny;
if (other._maxy > this._maxy)
this._maxy = other._maxy;
}
}
} else if (arguments.length === 2) {
const x = arguments[0], y = arguments[1];
if (this.isNull()) {
this._minx = x;
this._maxx = x;
this._miny = y;
this._maxy = y;
} else {
if (x < this._minx)
this._minx = x;
if (x > this._maxx)
this._maxx = x;
if (y < this._miny)
this._miny = y;
if (y > this._maxy)
this._maxy = y;
}
}
}
minExtent() {
if (this.isNull()) return 0.0
const w = this.getWidth();
const h = this.getHeight();
if (w < h) return w
return h
}
getWidth() {
if (this.isNull())
return 0
return this._maxx - this._minx
}
compareTo(o) {
const env = o;
if (this.isNull()) {
if (env.isNull()) return 0
return -1
} else {
if (env.isNull()) return 1
}
if (this._minx < env._minx) return -1
if (this._minx > env._minx) return 1
if (this._miny < env._miny) return -1
if (this._miny > env._miny) return 1
if (this._maxx < env._maxx) return -1
if (this._maxx > env._maxx) return 1
if (this._maxy < env._maxy) return -1
if (this._maxy > env._maxy) return 1
return 0
}
translate(transX, transY) {
if (this.isNull())
return null
this.init(this.getMinX() + transX, this.getMaxX() + transX, this.getMinY() + transY, this.getMaxY() + transY);
}
copy() {
return new Envelope(this)
}
toString() {
return 'Env[' + this._minx + ' : ' + this._maxx + ', ' + this._miny + ' : ' + this._maxy + ']'
}
setToNull() {
this._minx = 0;
this._maxx = -1;
this._miny = 0;
this._maxy = -1;
}
disjoint(other) {
if (this.isNull() || other.isNull())
return true
return other._minx > this._maxx || other._maxx < this._minx || other._miny > this._maxy || other._maxy < this._miny
}
getHeight() {
if (this.isNull())
return 0
return this._maxy - this._miny
}
maxExtent() {
if (this.isNull()) return 0.0
const w = this.getWidth();
const h = this.getHeight();
if (w > h) return w
return h
}
expandBy() {
if (arguments.length === 1) {
const distance = arguments[0];
this.expandBy(distance, distance);
} else if (arguments.length === 2) {
const deltaX = arguments[0], deltaY = arguments[1];
if (this.isNull()) return null
this._minx -= deltaX;
this._maxx += deltaX;
this._miny -= deltaY;
this._maxy += deltaY;
if (this._minx > this._maxx || this._miny > this._maxy) this.setToNull();
}
}
contains() {
if (arguments.length === 1) {
if (arguments[0] instanceof Envelope) {
const other = arguments[0];
return this.covers(other)
} else if (arguments[0] instanceof Coordinate) {
const p = arguments[0];
return this.covers(p)
}
} else if (arguments.length === 2) {
const x = arguments[0], y = arguments[1];
return this.covers(x, y)
}
}
centre() {
if (this.isNull()) return null
return new Coordinate((this.getMinX() + this.getMaxX()) / 2.0, (this.getMinY() + this.getMaxY()) / 2.0)
}
init() {
if (arguments.length === 0) {
this.setToNull();
} else if (arguments.length === 1) {
if (arguments[0] instanceof Coordinate) {
const p = arguments[0];
this.init(p.x, p.x, p.y, p.y);
} else if (arguments[0] instanceof Envelope) {
const env = arguments[0];
this._minx = env._minx;
this._maxx = env._maxx;
this._miny = env._miny;
this._maxy = env._maxy;
}
} else if (arguments.length === 2) {
const p1 = arguments[0], p2 = arguments[1];
this.init(p1.x, p2.x, p1.y, p2.y);
} else if (arguments.length === 4) {
const x1 = arguments[0], x2 = arguments[1], y1 = arguments[2], y2 = arguments[3];
if (x1 < x2) {
this._minx = x1;
this._maxx = x2;
} else {
this._minx = x2;
this._maxx = x1;
}
if (y1 < y2) {
this._miny = y1;
this._maxy = y2;
} else {
this._miny = y2;
this._maxy = y1;
}
}
}
getMaxY() {
return this._maxy
}
distance(env) {
if (this.intersects(env)) return 0
let dx = 0.0;
if (this._maxx < env._minx) dx = env._minx - this._maxx; else if (this._minx > env._maxx) dx = this._minx - env._maxx;
let dy = 0.0;
if (this._maxy < env._miny) dy = env._miny - this._maxy; else if (this._miny > env._maxy) dy = this._miny - env._maxy;
if (dx === 0.0) return dy
if (dy === 0.0) return dx
return Math.sqrt(dx * dx + dy * dy)
}
hashCode() {
let result = 17;
result = 37 * result + Coordinate.hashCode(this._minx);
result = 37 * result + Coordinate.hashCode(this._maxx);
result = 37 * result + Coordinate.hashCode(this._miny);
result = 37 * result + Coordinate.hashCode(this._maxy);
return result
}
get interfaces_() {
return [Comparable, Serializable]
}
}
class Geometry {
constructor() {
Geometry.constructor_.apply(this, arguments);
}
isGeometryCollection() {
return this.getTypeCode() === Geometry.TYPECODE_GEOMETRYCOLLECTION
}
getFactory() {
return this._factory
}
getGeometryN(n) {
return this
}
getArea() {
return 0.0
}
isRectangle() {
return false
}
equalsExact(other) {
return this === other || this.equalsExact(other, 0)
}
geometryChanged() {
this.apply(Geometry.geometryChangedFilter);
}
geometryChangedAction() {
this._envelope = null;
}
equalsNorm(g) {
if (g === null) return false
return this.norm().equalsExact(g.norm())
}
getLength() {
return 0.0
}
getNumGeometries() {
return 1
}
compareTo() {
let other;
if (arguments.length === 1) {
const o = arguments[0];
other = o;
if (this.getTypeCode() !== other.getTypeCode()) return this.getTypeCode() - other.getTypeCode()
if (this.isEmpty() && other.isEmpty()) return 0
if (this.isEmpty()) return -1
if (other.isEmpty()) return 1
return this.compareToSameClass(o)
} else if (arguments.length === 2) {
const o = arguments[0]; const comp = arguments[1];
other = o;
if (this.getTypeCode() !== other.getTypeCode()) return this.getTypeCode() - other.getTypeCode()
if (this.isEmpty() && other.isEmpty()) return 0
if (this.isEmpty()) return -1
if (other.isEmpty()) return 1
return this.compareToSameClass(o, comp)
}
}
getUserData() {
return this._userData
}
getSRID() {
return this._SRID
}
getEnvelope() {
return this.getFactory().toGeometry(this.getEnvelopeInternal())
}
checkNotGeometryCollection(g) {
if (g.getTypeCode() === Geometry.TYPECODE_GEOMETRYCOLLECTION) throw new IllegalArgumentException('This method does not support GeometryCollection arguments')
}
equal(a, b, tolerance) {
if (tolerance === 0) return a.equals(b)
return a.distance(b) <= tolerance
}
norm() {
const copy = this.copy();
copy.normalize();
return copy
}
reverse() {
const res = this.reverseInternal();
if (this.envelope != null) res.envelope = this.envelope.copy();
res.setSRID(this.getSRID());
return res
}
copy() {
const copy = this.copyInternal();
copy.envelope = this._envelope == null ? null : this._envelope.copy();
copy._SRID = this._SRID;
copy._userData = this._userData;
return copy
}
getPrecisionModel() {
return this._factory.getPrecisionModel()
}
getEnvelopeInternal() {
if (this._envelope === null) this._envelope = this.computeEnvelopeInternal();
return new Envelope(this._envelope)
}
setSRID(SRID) {
this._SRID = SRID;
}
setUserData(userData) {
this._userData = userData;
}
compare(a, b) {
const i = a.iterator();
const j = b.iterator();
while (i.hasNext() && j.hasNext()) {
const aElement = i.next();
const bElement = j.next();
const comparison = aElement.compareTo(bElement);
if (comparison !== 0) return comparison
}
if (i.hasNext()) return 1
if (j.hasNext()) return -1
return 0
}
hashCode() {
return this.getEnvelopeInternal().hashCode()
}
isEquivalentClass(other) {
return this.getClass() === other.getClass()
}
isGeometryCollectionOrDerived() {
if (this.getTypeCode() === Geometry.TYPECODE_GEOMETRYCOLLECTION || this.getTypeCode() === Geometry.TYPECODE_MULTIPOINT || this.getTypeCode() === Geometry.TYPECODE_MULTILINESTRING || this.getTypeCode() === Geometry.TYPECODE_MULTIPOLYGON) return true
return false
}
get interfaces_() {
return [Clonable, Comparable, Serializable]
}
getClass() {
return Geometry
}
static hasNonEmptyElements(geometries) {
for (let i = 0; i < geometries.length; i++)
if (!geometries[i].isEmpty()) return true
return false
}
static hasNullElements(array) {
for (let i = 0; i < array.length; i++)
if (array[i] === null) return true
return false
}
}
Geometry.constructor_ = function(factory) {
if (!factory) return
this._envelope = null;
this._userData = null;
this._factory = factory;
this._SRID = factory.getSRID();
};
Geometry.TYPECODE_POINT = 0;
Geometry.TYPECODE_MULTIPOINT = 1;
Geometry.TYPECODE_LINESTRING = 2;
Geometry.TYPECODE_LINEARRING = 3;
Geometry.TYPECODE_MULTILINESTRING = 4;
Geometry.TYPECODE_POLYGON = 5;
Geometry.TYPECODE_MULTIPOLYGON = 6;
Geometry.TYPECODE_GEOMETRYCOLLECTION = 7;
Geometry.TYPENAME_POINT = 'Point';
Geometry.TYPENAME_MULTIPOINT = 'MultiPoint';
Geometry.TYPENAME_LINESTRING = 'LineString';
Geometry.TYPENAME_LINEARRING = 'LinearRing';
Geometry.TYPENAME_MULTILINESTRING = 'MultiLineString';
Geometry.TYPENAME_POLYGON = 'Polygon';
Geometry.TYPENAME_MULTIPOLYGON = 'MultiPolygon';
Geometry.TYPENAME_GEOMETRYCOLLECTION = 'GeometryCollection';
Geometry.geometryChangedFilter = {
get interfaces_() {
return [GeometryComponentFilter]
},
filter(geom) {
geom.geometryChangedAction();
}
};
class Location {
static toLocationSymbol(locationValue) {
switch (locationValue) {
case Location.EXTERIOR:
return 'e'
case Location.BOUNDARY:
return 'b'
case Location.INTERIOR:
return 'i'
case Location.NONE:
return '-'
}
throw new IllegalArgumentException('Unknown location value: ' + locationValue)
}
}
Location.INTERIOR = 0;
Location.BOUNDARY = 1;
Location.EXTERIOR = 2;
Location.NONE = -1;
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/Collection.html
*/
class Collection {
/**
* Ensures that this collection contains the specified element (optional
* operation).
* @param {Object} e
* @return {boolean}
*/
add() { }
/**
* Appends all of the elements in the specified collection to the end of this
* list, in the order that they are returned by the specified collection's
* iterator (optional operation).
* @param {javascript.util.Collection} c
* @return {boolean}
*/
addAll() { }
/**
* Returns true if this collection contains no elements.
* @return {boolean}
*/
isEmpty() { }
/**
* Returns an iterator over the elements in this collection.
* @return {javascript.util.Iterator}
*/
iterator() { }
/**
* Returns an iterator over the elements in this collection.
* @return {number}
*/
size() { }
/**
* Returns an array containing all of the elements in this collection.
* @return {Array}
*/
toArray() { }
/**
* Removes a single instance of the specified element from this collection if it
* is present. (optional)
* @param {Object} e
* @return {boolean}
*/
remove() { }
}
class NoSuchElementException extends Exception {
constructor(message) {
super(message);
this.name = Object.keys({ NoSuchElementException })[0];
}
}
class UnsupportedOperationException extends Exception {
constructor(message) {
super(message);
this.name = Object.keys({ UnsupportedOperationException })[0];
}
}
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/Set.html
*
* @extends {Collection}
* @constructor
* @private
*/
class Set extends Collection {
/**
* Returns true if this set contains the specified element. More formally,
* returns true if and only if this set contains an element e such that (o==null ?
* e==null : o.equals(e)).
* @param {Object} e
* @return {boolean}
*/
contains() { }
}
/**
* @see http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html
*/
class HashSet extends Set {
constructor(o) {
super();
this.map = new Map();
if (o instanceof Collection)
this.addAll(o);
}
contains(o) {
const hashCode = o.hashCode ? o.hashCode() : o;
if (this.map.has(hashCode))
return true
return false
}
add(o) {
const hashCode = o.hashCode ? o.hashCode() : o;
if (this.map.has(hashCode))
return false
return !!this.map.set(hashCode, o)
}
addAll(c) {
for (const e of c)
this.add(e);
return true
}
remove() {
throw new UnsupportedOperationException()
}
size() {
return this.map.size
}
isEmpty() {
return this.map.size === 0
}
toArray() {
return Array.from(this.map.values())
}
iterator() {
return new Iterator$3(this.map)
}
[Symbol.iterator]() {
return this.map
}
}
class Iterator$3 {
constructor(map) {
this.iterator = map.values();
const { done, value } = this.iterator.next();
this.done = done;
this.value = value;
}
next() {
if (this.done)
throw new NoSuchElementException()
const current = this.value;
const { done, value } = this.iterator.next();
this.done = done;
this.value = value;
return current
}
hasNext() {
return !this.done
}
remove() {
throw new UnsupportedOperationException()
}
}
class Position {
static opposite(position) {
if (position === Position.LEFT) return Position.RIGHT
if (position === Position.RIGHT) return Position.LEFT
return position
}
}
Position.ON = 0;
Position.LEFT = 1;
Position.RIGHT = 2;
class EmptyStackException extends Exception {
constructor(message) {
super(message);
this.name = Object.keys({ EmptyStackException })[0];
}
}
class IndexOutOfBoundsException extends Exception {
constructor(message) {
super(message);
this.name = Object.keys({ IndexOutOfBoundsException })[0];
}
}
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/List.html
*/
class List extends Collection {
/**
* Returns the element at the specified position in this list.
* @param {number} index
* @return {Object}
*/
get() { }
/**
* Replaces the element at the specified position in this list with the
* specified element (optional operation).
* @param {number} index
* @param {Object} e
* @return {Object}
*/
set() { }
/**
* Returns true if this collection contains no elements.
* @return {boolean}
*/
isEmpty() { }
}
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/Stack.html
*/
class Stack extends List {
constructor() {
super();
this.array = [];
}
add(e) {
this.array.push(e);
return true
}
get(index) {
if (index < 0 || index >= this.size())
throw new IndexOutOfBoundsException()
return this.array[index]
}
/**
* Pushes an item onto the top of this stack.
* @param {Object} e
* @return {Object}
*/
push(e) {
this.array.push(e);
return e
}
/**
* Removes the object at the top of this stack and returns that object as the value of this function.
* @return {Object}
*/
pop() {
if (this.array.length === 0)
throw new EmptyStackException()
return this.array.pop()
}
/**
* Looks at the object at the top of this stack without removing it from the
* stack.
* @return {Object}
*/
peek() {
if (this.array.length === 0)
throw new EmptyStackException()
return this.array[this.array.length - 1]
}
/**
* Tests if this stack is empty.
* @return {boolean} true if and only if this stack contains no items; false
* otherwise.
*/
empty() {
return this.array.length === 0
}
/**
* @return {boolean}
*/
isEmpty() {
return this.empty()
}
/**
* Returns the 1-based position where an object is on this stack. If the object
* o occurs as an item in this stack, this method returns the distance from the
* top of the stack of the occurrence nearest the top of the stack; the topmost
* item on the stack is considered to be at distance 1. The equals method is
* used to compare o to the items in this stack.
*
* NOTE: does not currently actually use equals. (=== is used)
*
* @param {Object} o
* @return {number} the 1-based position from the top of the stack where the
* object is located; the return value -1 indicates that the object is
* not on the stack.
*/
search(o) {
return this.array.indexOf(o)
}
/**
* @return {number}
*/
size() {
return this.array.length
}
/**
* @return {Array}
*/
toArray() {
return this.array.slice()
}
}
function hasInterface(o, i) {
return o.interfaces_ && o.interfaces_.indexOf(i) > -1
}
class StringBuffer {
constructor(str) {
this.str = str;
}
append(e) {
this.str += e;
}
setCharAt(i, c) {
this.str = this.str.substr(0, i) + c + this.str.substr(i + 1);
}
toString() {
return this.str
}
}
class Integer {
constructor(value) {
this.value = value;
}
intValue() {
return this.value
}
compareTo(o) {
if (this.value < o)
return -1
if (this.value > o)
return 1
return 0
}
static compare(x, y) {
if (x < y)
return -1
if (x > y)
return 1
return 0
}
static isNan(n) {
return Number.isNaN(n)
}
static valueOf(value) {
return new Integer(value)
}
}
class Character {
static isWhitespace(c) {
return ((c <= 32 && c >= 0) || c === 127)
}
static toUpperCase(c) {
return c.toUpperCase()
}
}
class DD {
constructor() {
DD.constructor_.apply(this, arguments);
}
static constructor_() {
this._hi = 0.0;
this._lo = 0.0;
if (arguments.length === 0) {
this.init(0.0);
} else if (arguments.length === 1) {
if (typeof arguments[0] === 'number') {
const x = arguments[0];
this.init(x);
} else if (arguments[0] instanceof DD) {
const dd = arguments[0];
this.init(dd);
} else if (typeof arguments[0] === 'string') {
const str = arguments[0];
DD.constructor_.call(this, DD.parse(str));
}
} else if (arguments.length === 2) {
const hi = arguments[0], lo = arguments[1];
this.init(hi, lo);
}
}
static determinant() {
if (typeof arguments[3] === 'number' && (typeof arguments[2] === 'number' && (typeof arguments[0] === 'number' && typeof arguments[1] === 'number'))) {
const x1 = arguments[0], y1 = arguments[1], x2 = arguments[2], y2 = arguments[3];
return DD.determinant(DD.valueOf(x1), DD.valueOf(y1), DD.valueOf(x2), DD.valueOf(y2))
} else if (arguments[3] instanceof DD && (arguments[2] instanceof DD && (arguments[0] instanceof DD && arguments[1] instanceof DD))) {
const x1 = arguments[0], y1 = arguments[1], x2 = arguments[2], y2 = arguments[3];
const det = x1.multiply(y2).selfSubtract(y1.multiply(x2));
return det
}
}
static sqr(x) {
return DD.valueOf(x).selfMultiply(x)
}
static valueOf() {
if (typeof arguments[0] === 'string') {
const str = arguments[0];
return DD.parse(str)
} else if (typeof arguments[0] === 'number') {
const x = arguments[0];
return new DD(x)
}
}
static sqrt(x) {
return DD.valueOf(x).sqrt()
}
static parse(str) {
let i = 0;
const strlen = str.length;
while (Character.isWhitespace(str.charAt(i))) i++;
let isNegative = false;
if (i < strlen) {
const signCh = str.charAt(i);
if (signCh === '-' || signCh === '+') {
i++;
if (signCh === '-') isNegative = true;
}
}
const val = new DD();
let numDigits = 0;
let numBeforeDec = 0;
let exp = 0;
let hasDecimalChar = false;
while (true) {
if (i >= strlen) break
const ch = str.charAt(i);
i++;
if (Character.isDigit(ch)) {
const d = ch - '0';
val.selfMultiply(DD.TEN);
val.selfAdd(d);
numDigits++;
continue
}
if (ch === '.') {
numBeforeDec = numDigits;
hasDecimalChar = true;
continue
}
if (ch === 'e' || ch === 'E') {
const expStr = str.substring(i);
try {
exp = Integer.parseInt(expStr);
} catch (ex) {
if (ex instanceof NumberFormatException)
throw new NumberFormatException('Invalid exponent ' + expStr + ' in string ' + str)
else throw ex
} finally {}
break
}
throw new NumberFormatException('Unexpected character \'' + ch + '\' at position ' + i + ' in string ' + str)
}
let val2 = val;
if (!hasDecimalChar) numBeforeDec = numDigits;
const numDecPlaces = numDigits - numBeforeDec - exp;
if (numDecPlaces === 0) {
val2 = val;
} else if (numDecPlaces > 0) {
const scale = DD.TEN.pow(numDecPlaces);
val2 = val.divide(scale);
} else if (numDecPlaces < 0) {
const scale = DD.TEN.pow(-numDecPlaces);
val2 = val.multiply(scale);
}
if (isNegative)
return val2.negate()
return val2
}
static createNaN() {
return new DD(Double.NaN, Double.NaN)
}
static copy(dd) {
return new DD(dd)
}
static magnitude(x) {
const xAbs = Math.abs(x);
const xLog10 = Math.log(xAbs) / Math.log(10);
let xMag = Math.trunc(Math.floor(xLog10));
const xApprox = Math.pow(10, xMag);
if (xApprox * 10 <= xAbs) xMag += 1;
return xMag
}
static stringOfChar(ch, len) {
const buf = new StringBuffer();
for (let i = 0; i < len; i++)
buf.append(ch);
return buf.toString()
}
le(y) {
return this._hi < y._hi || this._hi === y._hi && this._lo <= y._lo
}
extractSignificantDigits(insertDecimalPoint, magnitude) {
let y = this.abs();
let mag = DD.magnitude(y._hi);
const scale = DD.TEN.pow(mag);
y = y.divide(scale);
if (y.gt(DD.TEN)) {
y = y.divide(DD.TEN);
mag += 1;
} e