all these changes

This commit is contained in:
Jake Kasper
2026-04-09 13:19:47 -05:00
parent e83a51a051
commit 65315f36d1
39102 changed files with 7932979 additions and 567 deletions

36
frontend/node_modules/turf-jsts/src/Array.js generated vendored Normal file
View File

@@ -0,0 +1,36 @@
/* Polyfill service v3.13.0
* For detailed credits and licence information see http://github.com/financial-times/polyfill-service
*
* - Array.prototype.fill, License: CC0 */
if (!('fill' in Array.prototype)) {
Object.defineProperty(Array.prototype, 'fill', {
configurable: true,
value: function fill (value) {
if (this === undefined || this === null) {
throw new TypeError(this + ' is not an object')
}
var arrayLike = Object(this)
var length = Math.max(Math.min(arrayLike.length, 9007199254740991), 0) || 0
var relativeStart = 1 in arguments ? parseInt(Number(arguments[1]), 10) || 0 : 0
relativeStart = relativeStart < 0 ? Math.max(length + relativeStart, 0) : Math.min(relativeStart, length)
var relativeEnd = 2 in arguments && arguments[2] !== undefined ? parseInt(Number(arguments[2]), 10) || 0 : length
relativeEnd = relativeEnd < 0 ? Math.max(length + arguments[2], 0) : Math.min(relativeEnd, length)
while (relativeStart < relativeEnd) {
arrayLike[relativeStart] = value
++relativeStart
}
return arrayLike
},
writable: true
})
}

150
frontend/node_modules/turf-jsts/src/Map.js generated vendored Normal file
View File

@@ -0,0 +1,150 @@
// shared pointer
var i
// shortcuts
var defineProperty = Object.defineProperty
function is (a, b) { return (a === b) || (a !== a && b !== b) } // eslint-disable-line
export default createCollection({
// WeakMap#delete(key:void*):boolean
'delete': sharedDelete,
// :was Map#get(key:void*[, d3fault:void*]):void*
// Map#has(key:void*):boolean
has: mapHas,
// Map#get(key:void*):boolean
get: sharedGet,
// Map#set(key:void*, value:void*):void
set: sharedSet,
// Map#keys(void):Iterator
keys: sharedKeys,
// Map#values(void):Iterator
values: sharedValues,
// Map#entries(void):Iterator
entries: mapEntries,
// Map#forEach(callback:Function, context:void*):void ==> callback.call(context, key, value, mapObject) === not in specs`
forEach: sharedForEach,
// Map#clear():
clear: sharedClear
})
/**
* ES6 collection constructor
* @return {Function} a collection class
*/
function createCollection (proto, objectOnly) {
function Collection (a) {
if (!this || this.constructor !== Collection) return new Collection(a)
this._keys = []
this._values = []
this._itp = [] // iteration pointers
this.objectOnly = objectOnly
// parse initial iterable argument passed
if (a) init.call(this, a)
}
// define size for non object-only collections
if (!objectOnly) {
defineProperty(proto, 'size', {
get: sharedSize
})
}
// set prototype
proto.constructor = Collection
Collection.prototype = proto
return Collection
}
/** parse initial iterable argument passed */
function init (a) {
// init Set argument, like `[1,2,3,{}]`
if (this.add) a.forEach(this.add, this)
// init Map argument like `[[1,2], [{}, 4]]`
else a.forEach(function (a) { this.set(a[0], a[1]) }, this)
}
/** delete */
function sharedDelete (key) {
if (this.has(key)) {
this._keys.splice(i, 1)
this._values.splice(i, 1)
// update iteration pointers
this._itp.forEach(function (p) { if (i < p[0]) p[0]-- })
}
// Aurora here does it while Canary doesn't
return i > -1
}
function sharedGet (key) {
return this.has(key) ? this._values[i] : undefined
}
function has (list, key) {
if (this.objectOnly && key !== Object(key)) throw new TypeError('Invalid value used as weak collection key')
// NaN or 0 passed
if (key !== key || key === 0) for (i = list.length; i-- && !is(list[i], key);) {} // eslint-disable-line
else i = list.indexOf(key)
return i > -1
}
function mapHas (value) {
return has.call(this, this._keys, value)
}
/** @chainable */
function sharedSet (key, value) {
this.has(key) ? this._values[i] = value : this._values[this._keys.push(key) - 1] = value
return this
}
function sharedClear () {
(this._keys || 0).length =
this._values.length = 0
}
/** keys, values, and iterate related methods */
function sharedKeys () {
return sharedIterator(this._itp, this._keys)
}
function sharedValues () {
return sharedIterator(this._itp, this._values)
}
function mapEntries () {
return sharedIterator(this._itp, this._keys, this._values)
}
function sharedIterator (itp, array, array2) {
var p = [0]
var done = false
itp.push(p)
return {
next: function () {
var v
var k = p[0]
if (!done && k < array.length) {
v = array2 ? [array[k], array2[k]] : array[k]
p[0]++
} else {
done = true
itp.splice(itp.indexOf(p), 1)
}
return { done: done, value: v }
}
}
}
function sharedSize () {
return this._values.length
}
function sharedForEach (callback, context) {
var it = this.entries()
for (;;) {
var r = it.next()
if (r.done) break
callback.call(context, r.value[1], r.value[0], this)
}
}

6
frontend/node_modules/turf-jsts/src/Math.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
/**
* Polyfill for IE support
*/
Math.trunc = Math.trunc || function (x) {
return x < 0 ? Math.ceil(x) : Math.floor(x)
}

18
frontend/node_modules/turf-jsts/src/Number.js generated vendored Normal file
View File

@@ -0,0 +1,18 @@
/**
* Polyfill for IE support
*/
Number.isFinite = Number.isFinite || function (value) {
return typeof value === 'number' && isFinite(value)
}
Number.isInteger = Number.isInteger || function (val) {
return typeof val === 'number' &&
isFinite(val) &&
Math.floor(val) === val
}
Number.parseFloat = Number.parseFloat || parseFloat
Number.isNaN = Number.isNaN || function (value) {
return value !== value // eslint-disable-line
}

5
frontend/node_modules/turf-jsts/src/extend.js generated vendored Normal file
View File

@@ -0,0 +1,5 @@
export default function (target, source) {
for (let key in source) {
if (source.hasOwnProperty(key)) target[key] = source[key]
}
}

3
frontend/node_modules/turf-jsts/src/hasInterface.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
export default function (o, i) {
return o.interfaces_ && o.interfaces_().indexOf(i) > -1
}

18
frontend/node_modules/turf-jsts/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,18 @@
/**
* Polyfill for IE support
*/
import './Array'
import './Number'
import './Math'
/**
* Turf JSTS dependant modules
*
* GeoJSONReader => all modules
* GeoJSONWriter => all modules
* OverlayOp => @turf/intersect & @turf/difference
* UnionOp => @turf/union
* BufferOp => @turf/buffer
*/
export { GeoJSONReader, GeoJSONWriter } from './org/locationtech/jts/io'
export { OverlayOp, UnionOp, BufferOp } from './org/locationtech/jts/operation'

4
frontend/node_modules/turf-jsts/src/inherits.js generated vendored Normal file
View File

@@ -0,0 +1,4 @@
export default function (c, p) {
c.prototype = Object.create(p.prototype)
c.prototype.constructor = c
}

View File

@@ -0,0 +1 @@
export default function ByteArrayOutputStream () {}

View File

@@ -0,0 +1 @@
export default function IOException () {}

View File

@@ -0,0 +1 @@
export default function InputStream () {}

View File

@@ -0,0 +1 @@
export default function LineNumberReader () {}

View File

@@ -0,0 +1 @@
export default function OutputStream () {}

View File

@@ -0,0 +1 @@
export default function PrintStream () {}

View File

@@ -0,0 +1 @@
export default function Serializable () {}

View File

@@ -0,0 +1 @@
export default function StringReader () {}

View File

@@ -0,0 +1 @@
export default function StringWriter () {}

View File

@@ -0,0 +1 @@
export default function Writer () {}

View File

@@ -0,0 +1,4 @@
export default class Character {
static isWhitespace (c) { return ((c <= 32 && c >= 0) || c === 127) }
static toUpperCase (c) { return c.toUpperCase() }
}

View File

@@ -0,0 +1 @@
export default class Clonable {}

View File

@@ -0,0 +1 @@
export default class Comparable {}

View File

@@ -0,0 +1,7 @@
export default class Double {
static isNaN (n) { return Number.isNaN(n) }
static doubleToLongBits (n) { return n }
static longBitsToDouble (n) { return n }
static isInfinite (n) { return !Number.isFinite(n) }
static get MAX_VALUE () { return Number.MAX_VALUE }
}

View File

@@ -0,0 +1 @@
export default class Exception {}

View File

@@ -0,0 +1,8 @@
export default class IllegalArgumentException extends Error {
constructor (message) {
super(message)
this.name = 'IllegalArgumentException'
this.message = message
this.stack = (new Error()).stack
}
}

View File

@@ -0,0 +1,14 @@
export default 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 isNaN (n) { return Number.isNaN(n) }
}

View File

@@ -0,0 +1,8 @@
export default class RuntimeException extends Error {
constructor (message) {
super(message)
this.name = 'RuntimeException'
this.message = message
this.stack = (new Error()).stack
}
}

View File

@@ -0,0 +1,16 @@
export default 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 (e) {
return this.str
}
}

View File

@@ -0,0 +1,15 @@
export default class System {
static arraycopy (src, srcPos, dest, destPos, len) {
let c = 0
for (let i = srcPos; i < srcPos + len; i++) {
dest[destPos + c] = src[i]
c++
}
}
static getProperty (name) {
return {
'line.separator': '\n'
}[name]
}
}

View File

@@ -0,0 +1 @@
export default class DecimalFormat {}

View File

@@ -0,0 +1 @@
export default class DecimalFormatSymbols {}

View File

@@ -0,0 +1,181 @@
import Collection from './Collection'
import IndexOutOfBoundsException from './IndexOutOfBoundsException'
import Iterator from './Iterator'
import List from './List'
import NoSuchElementException from './NoSuchElementException'
// import OperationNotSupported from './OperationNotSupported'
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html
*
* @extends List
* @private
*/
export default class ArrayList extends List {
constructor () {
super()
this.array_ = []
if (arguments[0] instanceof Collection) {
this.addAll(arguments[0])
}
}
ensureCapacity () {}
interfaces_ () { return [List, Collection] }
/**
* @override
*/
add (e) {
if (arguments.length === 1) {
this.array_.push(e)
} else {
this.array_.splice(arguments[0], arguments[1])
}
return true
}
clear () {
this.array_ = []
}
/**
* @override
*/
addAll (c) {
for (var i = c.iterator(); i.hasNext();) {
this.add(i.next())
}
return true
}
/**
* @override
*/
set (index, element) {
var oldElement = this.array_[index]
this.array_[index] = element
return oldElement
}
/**
* @override
*/
iterator () {
return new Iterator_(this)
}
/**
* @override
*/
get (index) {
if (index < 0 || index >= this.size()) {
throw new IndexOutOfBoundsException()
}
return this.array_[index]
}
/**
* @override
*/
isEmpty () {
return this.array_.length === 0
}
/**
* @override
*/
size () {
return this.array_.length
}
/**
* @override
*/
toArray () {
var array = []
for (var i = 0, len = this.array_.length; i < len; i++) {
array.push(this.array_[i])
}
return array
}
/**
* @override
*/
remove (o) {
var found = false
for (var i = 0, len = this.array_.length; i < len; i++) {
if (this.array_[i] === o) {
this.array_.splice(i, 1)
found = true
break
}
}
return found
}
}
/**
* @extends {Iterator}
* @param {ArrayList} arrayList
* @constructor
* @private
*/
class Iterator_ extends Iterator {
constructor (arrayList) {
super()
/**
* @type {ArrayList}
* @private
*/
this.arrayList_ = arrayList
/**
* @type {number}
* @private
*/
this.position_ = 0
}
/**
* @override
*/
next () {
if (this.position_ === this.arrayList_.size()) {
throw new NoSuchElementException()
}
return this.arrayList_.get(this.position_++)
}
/**
* @override
*/
hasNext () {
if (this.position_ < this.arrayList_.size()) {
return true
} else {
return false
}
}
/**
* TODO: should be in ListIterator
* @override
*/
set (element) {
return this.arrayList_.set(this.position_ - 1, element)
}
/**
* @override
*/
remove () {
this.arrayList_.remove(this.arrayList_.get(this.position_))
}
}

View File

@@ -0,0 +1,60 @@
import ArrayList from './ArrayList'
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/Arrays.html
*
* @constructor
* @private
*/
export default class Arrays {
static sort () {
const a = arguments[0]
let i
let t
let comparator
let compare
if (arguments.length === 1) {
compare = function (a, b) {
return a.compareTo(b)
}
a.sort(compare)
} else if (arguments.length === 2) {
comparator = arguments[1]
compare = function (a, b) {
return comparator['compare'](a, b)
}
a.sort(compare)
} else if (arguments.length === 3) {
t = a.slice(arguments[1], arguments[2])
t.sort()
var r = a.slice(0, arguments[1]).concat(t, a.slice(arguments[2], a.length))
a.splice(0, a.length)
for (i = 0; i < r.length; i++) {
a.push(r[i])
}
} else if (arguments.length === 4) {
t = a.slice(arguments[1], arguments[2])
comparator = arguments[3]
compare = function (a, b) {
return comparator['compare'](a, b)
}
t.sort(compare)
r = a.slice(0, arguments[1]).concat(t, a.slice(arguments[2], a.length))
a.splice(0, a.length)
for (i = 0; i < r.length; i++) {
a.push(r[i])
}
}
}
/**
* @param {Array} array
* @return {ArrayList}
*/
static asList (array) {
var arrayList = new ArrayList()
for (var i = 0, len = array.length; i < len; i++) {
arrayList.add(array[i])
}
return arrayList
}
}

View File

@@ -0,0 +1,58 @@
// import Iterator from './Iterator'
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/Collection.html
*
* @constructor
* @private
*/
export default 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 () {}
}

View File

@@ -0,0 +1,34 @@
import Arrays from './Arrays'
import ArrayList from './ArrayList'
export default class Collections {
static reverseOrder () {
return {
compare (a, b) {
return b.compareTo(a)
}
}
}
static min (l) {
Collections.sort(l)
return l.get(0)
}
static sort (l, c) {
const a = l.toArray()
if (c) {
Arrays.sort(a, c)
} else {
Arrays.sort(a)
}
const i = l.iterator()
for (let pos = 0, alen = a.length; pos < alen; pos++) {
i.next()
i.set(a[pos])
}
}
static singletonList (o) {
const arrayList = new ArrayList()
arrayList.add(o)
return arrayList
}
}

View File

@@ -0,0 +1 @@
export default class Comparator {}

View File

@@ -0,0 +1,15 @@
/**
* @param {string=} message Optional message
* @extends {Error}
* @constructor
* @private
*/
export default function EmptyStackException (message) {
this.message = message || ''
};
EmptyStackException.prototype = new Error()
/**
* @type {string}
*/
EmptyStackException.prototype.name = 'EmptyStackException'

View File

@@ -0,0 +1,61 @@
import ArrayList from './ArrayList'
import MapInterface from './Map'
import HashSet from './HashSet'
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html
*
* @extends {javascript.util.Map}
* @constructor
* @private
*/
export default class HashMap extends MapInterface {
constructor () {
super()
this.map_ = new Map()
}
/**
* @override
*/
get (key) {
return this.map_.get(key) || null
}
/**
* @override
*/
put (key, value) {
this.map_.set(key, value)
return value
}
/**
* @override
*/
values () {
const arrayList = new ArrayList()
const it = this.map_.values()
let o = it.next()
while (!o.done) {
arrayList.add(o.value)
o = it.next()
}
return arrayList
}
/**
* @override
*/
entrySet () {
const hashSet = new HashSet()
this.map_.entries().forEach(entry => hashSet.add(entry))
return hashSet
}
/**
* @override
*/
size () {
return this.map_.size()
}
}

View File

@@ -0,0 +1,151 @@
import Collection from './Collection'
import Iterator from './Iterator'
import NoSuchElementException from './NoSuchElementException'
import OperationNotSupported from './OperationNotSupported'
import Set from './Set'
/**
* @see http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html
*
* @extends {javascript.util.Set}
* @constructor
* @private
*/
export default class HashSet extends Set {
constructor () {
super()
this.array_ = []
if (arguments[0] instanceof Collection) {
this.addAll(arguments[0])
}
}
/**
* @override
*/
contains (o) {
for (var i = 0, len = this.array_.length; i < len; i++) {
var e = this.array_[i]
if (e === o) {
return true
}
}
return false
}
/**
* @override
*/
add (o) {
if (this.contains(o)) {
return false
}
this.array_.push(o)
return true
}
/**
* @override
*/
addAll (c) {
for (var i = c.iterator(); i.hasNext();) {
this.add(i.next())
}
return true
}
/**
* @override
*/
remove (o) {
// throw new javascript.util.OperationNotSupported()
throw new Error()
}
/**
* @override
*/
size () {
return this.array_.length
}
/**
* @override
*/
isEmpty () {
return this.array_.length === 0
}
/**
* @override
*/
toArray () {
var array = []
for (var i = 0, len = this.array_.length; i < len; i++) {
array.push(this.array_[i])
}
return array
}
/**
* @override
*/
iterator () {
return new Iterator_(this)
}
}
/**
* @extends {Iterator}
* @param {HashSet} hashSet
* @constructor
* @private
*/
class Iterator_ extends Iterator {
constructor (hashSet) {
super()
/**
* @type {HashSet}
* @private
*/
this.hashSet_ = hashSet
/**
* @type {number}
* @private
*/
this.position_ = 0
}
/**
* @override
*/
next () {
if (this.position_ === this.hashSet_.size()) {
throw new NoSuchElementException()
}
return this.hashSet_.array_[this.position_++]
}
/**
* @override
*/
hasNext () {
if (this.position_ < this.hashSet_.size()) {
return true
} else {
return false
}
}
/**
* @override
*/
remove () {
throw new OperationNotSupported()
}
}

View File

@@ -0,0 +1,15 @@
/**
* @param {string=} message Optional message
* @extends {Error}
* @constructor
* @private
*/
export default function IndexOutOfBoundsException (message) {
this.message = message || ''
};
IndexOutOfBoundsException.prototype = new Error()
/**
* @type {string}
*/
IndexOutOfBoundsException.prototype.name = 'IndexOutOfBoundsException'

View File

@@ -0,0 +1,24 @@
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/Iterator.html
* @constructor
* @private
*/
export default class Iterator {
/**
* Returns true if the iteration has more elements.
* @return {boolean}
*/
hasNext () {}
/**
* Returns the next element in the iteration.
* @return {Object}
*/
next () {}
/**
* Removes from the underlying collection the last element returned by the
* iterator (optional operation).
*/
remove () {}
}

View File

@@ -0,0 +1,14 @@
export default class LinkedList {
constructor () {
this.array_ = []
}
addLast (e) {
this.array_.push(e)
}
removeFirst () {
return this.array_.shift()
}
isEmpty () {
return this.array_.length === 0
}
}

32
frontend/node_modules/turf-jsts/src/java/util/List.js generated vendored Normal file
View File

@@ -0,0 +1,32 @@
import Collection from './Collection'
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/List.html
*
* @extends {javascript.util.Collection}
* @constructor
* @private
*/
export default 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 () { }
}

53
frontend/node_modules/turf-jsts/src/java/util/Map.js generated vendored Normal file
View File

@@ -0,0 +1,53 @@
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/Map.html
*
* @constructor
* @private
*/
export default class Map {
/**
* Returns the value to which the specified key is mapped, or null if this map
* contains no mapping for the key.
* @param {Object} key
* @return {Object}
*/
get () {};
/**
* Associates the specified value with the specified key in this map (optional
* operation).
* @param {Object} key
* @param {Object} value
* @return {Object}
*/
put () {};
/**
* Returns the number of key-value mappings in this map.
* @return {number}
*/
size () {};
/**
* Returns a Collection view of the values contained in this map.
* @return {javascript.util.Collection}
*/
values () {};
/**
* Returns a {@link Set} view of the mappings contained in this map.
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is modified
* while an iteration over the set is in progress (except through
* the iterator's own <tt>remove</tt> operation, or through the
* <tt>setValue</tt> operation on a map entry returned by the
* iterator) the results of the iteration are undefined. The set
* supports element removal, which removes the corresponding
* mapping from the map, via the <tt>Iterator.remove</tt>,
* <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
* <tt>clear</tt> operations. It does not support the
* <tt>add</tt> or <tt>addAll</tt> operations.
*
* @return {Set} a set view of the mappings contained in this map
*/
entrySet () {};
}

View File

@@ -0,0 +1,15 @@
/**
* @param {string=} message Optional message
* @extends {Error}
* @constructor
* @private
*/
export default function NoSuchElementException (message) {
this.message = message || ''
};
NoSuchElementException.prototype = new Error()
/**
* @type {string}
*/
NoSuchElementException.prototype.name = 'NoSuchElementException'

View File

@@ -0,0 +1,15 @@
/**
* @param {string=} message Optional message
* @extends {Error}
* @constructor
* @private
*/
export default function OperationNotSupported (message) {
this.message = message || ''
};
OperationNotSupported.prototype = new Error()
/**
* @type {string}
*/
OperationNotSupported.prototype.name = 'OperationNotSupported'

21
frontend/node_modules/turf-jsts/src/java/util/Set.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import Collection from './Collection'
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/Set.html
*
* @extends {Collection}
* @constructor
* @private
*/
export default function Set() {};
Set.prototype = new 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}
*/
Set.prototype.contains = function() {};

View File

@@ -0,0 +1,10 @@
import Map from './Map'
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/SortedMap.html
*
* @extends {Map}
* @constructor
* @private
*/
export default class SortedMap extends Map {}

View File

@@ -0,0 +1,11 @@
import Set from './Set'
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/SortedSet.html
*
* @extends {Set}
* @constructor
* @private
*/
export default function SortedSet () {};
SortedSet.prototype = new Set()

132
frontend/node_modules/turf-jsts/src/java/util/Stack.js generated vendored Normal file
View File

@@ -0,0 +1,132 @@
import EmptyStackException from './EmptyStackException'
import List from './List'
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/Stack.html
*
* @extends {List}
* @constructor
* @private
*/
export default function Stack () {
/**
* @type {Array}
* @private
*/
this.array_ = []
};
Stack.prototype = new List()
/**
* @override
*/
Stack.prototype.add = function (e) {
this.array_.push(e)
return true
}
/**
* @override
*/
Stack.prototype.get = function (index) {
if (index < 0 || index >= this.size()) {
throw new Error()
}
return this.array_[index]
}
/**
* Pushes an item onto the top of this stack.
* @param {Object} e
* @return {Object}
*/
Stack.prototype.push = function (e) {
this.array_.push(e)
return e
}
/**
* Pushes an item onto the top of this stack.
* @param {Object} e
* @return {Object}
*/
Stack.prototype.pop = function (e) {
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}
*/
Stack.prototype.peek = function () {
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.
*/
Stack.prototype.empty = function () {
if (this.array_.length === 0) {
return true
} else {
return false
}
}
/**
* @return {boolean}
*/
Stack.prototype.isEmpty = function () {
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.
*/
Stack.prototype.search = function (o) {
return this.array_.indexOf(o)
}
/**
* @return {number}
* @export
*/
Stack.prototype.size = function () {
return this.array_.length
}
/**
* @return {Array}
*/
Stack.prototype.toArray = function () {
var array = []
for (var i = 0, len = this.array_.length; i < len; i++) {
array.push(this.array_[i])
}
return array
}

View File

@@ -0,0 +1,246 @@
import ArrayList from './ArrayList'
import SortedMap from './SortedMap'
import HashSet from './HashSet'
const BLACK = 0
const RED = 1
function colorOf (p) { return (p === null ? BLACK : p.color) }
function parentOf (p) { return (p === null ? null : p.parent) }
function setColor (p, c) { if (p !== null) p.color = c }
function leftOf (p) { return (p === null ? null : p.left) }
function rightOf (p) { return (p === null ? null : p.right) }
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/TreeMap.html
*
* @extends {SortedMap}
* @constructor
* @private
*/
export default function TreeMap () {
/**
* @type {Object}
* @private
*/
this.root_ = null
/**
* @type {number}
* @private
*/
this.size_ = 0
};
TreeMap.prototype = new SortedMap()
/**
* @override
*/
TreeMap.prototype.get = function (key) {
let p = this.root_
while (p !== null) {
const cmp = key['compareTo'](p.key)
if (cmp < 0) p = p.left
else if (cmp > 0) p = p.right
else return p.value
}
return null
}
/**
* @override
*/
TreeMap.prototype.put = function (key, value) {
if (this.root_ === null) {
this.root_ = {
key: key,
value: value,
left: null,
right: null,
parent: null,
color: BLACK,
getValue () { return this.value },
getKey () { return this.key }
}
this.size_ = 1
return null
}
let t = this.root_
let parent
let cmp
do {
parent = t
cmp = key['compareTo'](t.key)
if (cmp < 0) {
t = t.left
} else if (cmp > 0) {
t = t.right
} else {
const oldValue = t.value
t.value = value
return oldValue
}
} while (t !== null)
const e = {
key: key,
left: null,
right: null,
value: value,
parent: parent,
color: BLACK,
getValue () { return this.value },
getKey () { return this.key }
}
if (cmp < 0) {
parent.left = e
} else {
parent.right = e
}
this.fixAfterInsertion(e)
this.size_++
return null
}
/**
* @param {Object} x
*/
TreeMap.prototype.fixAfterInsertion = function (x) {
x.color = RED
while (x != null && x !== this.root_ && x.parent.color === RED) {
if (parentOf(x) === leftOf(parentOf(parentOf(x)))) {
const y = rightOf(parentOf(parentOf(x)))
if (colorOf(y) === RED) {
setColor(parentOf(x), BLACK)
setColor(y, BLACK)
setColor(parentOf(parentOf(x)), RED)
x = parentOf(parentOf(x))
} else {
if (x === rightOf(parentOf(x))) {
x = parentOf(x)
this.rotateLeft(x)
}
setColor(parentOf(x), BLACK)
setColor(parentOf(parentOf(x)), RED)
this.rotateRight(parentOf(parentOf(x)))
}
} else {
const y = leftOf(parentOf(parentOf(x)))
if (colorOf(y) === RED) {
setColor(parentOf(x), BLACK)
setColor(y, BLACK)
setColor(parentOf(parentOf(x)), RED)
x = parentOf(parentOf(x))
} else {
if (x === leftOf(parentOf(x))) {
x = parentOf(x)
this.rotateRight(x)
}
setColor(parentOf(x), BLACK)
setColor(parentOf(parentOf(x)), RED)
this.rotateLeft(parentOf(parentOf(x)))
}
}
}
this.root_.color = BLACK
}
/**
* @override
*/
TreeMap.prototype.values = function () {
const arrayList = new ArrayList()
let p = this.getFirstEntry()
if (p !== null) {
arrayList.add(p.value)
while ((p = TreeMap.successor(p)) !== null) {
arrayList.add(p.value)
}
}
return arrayList
}
/**
* @override
*/
TreeMap.prototype.entrySet = function () {
const hashSet = new HashSet()
let p = this.getFirstEntry()
if (p !== null) {
hashSet.add(p)
while ((p = TreeMap.successor(p)) !== null) {
hashSet.add(p)
}
}
return hashSet
}
/**
* @param {Object} p
*/
TreeMap.prototype.rotateLeft = function (p) {
if (p != null) {
const r = p.right
p.right = r.left
if (r.left != null) { r.left.parent = p }
r.parent = p.parent
if (p.parent === null) { this.root_ = r } else if (p.parent.left === p) { p.parent.left = r } else { p.parent.right = r }
r.left = p
p.parent = r
}
}
/**
* @param {Object} p
*/
TreeMap.prototype.rotateRight = function (p) {
if (p != null) {
const l = p.left
p.left = l.right
if (l.right != null) l.right.parent = p
l.parent = p.parent
if (p.parent === null) { this.root_ = l } else if (p.parent.right === p) { p.parent.right = l } else p.parent.left = l
l.right = p
p.parent = l
}
}
/**
* @return {Object}
*/
TreeMap.prototype.getFirstEntry = function () {
let p = this.root_
if (p != null) {
while (p.left != null) {
p = p.left
}
}
return p
}
/**
* @param {Object} t
* @return {Object}
* @private
*/
TreeMap.successor = function (t) {
if (t === null) { return null } else if (t.right !== null) {
let p = t.right
while (p.left !== null) {
p = p.left
}
return p
} else {
let p = t.parent
let ch = t
while (p !== null && ch === p.right) {
ch = p
p = p.parent
}
return p
}
}
/**
* @override
*/
TreeMap.prototype.size = function () {
return this.size_
}

View File

@@ -0,0 +1,157 @@
import Collection from './Collection'
// import Iterator from './Iterator'
import NoSuchElementException from './NoSuchElementException'
import OperationNotSupported from './OperationNotSupported'
import SortedSet from './SortedSet'
/**
* @see http://download.oracle.com/javase/6/docs/api/java/util/TreeSet.html
*
* @extends {SortedSet}
* @constructor
* @private
*/
export default function TreeSet () {
/**
* @type {Array}
* @private
*/
this.array_ = []
if (arguments[0] instanceof Collection) {
this.addAll(arguments[0])
}
};
TreeSet.prototype = new SortedSet()
/**
* @override
*/
TreeSet.prototype.contains = function (o) {
for (var i = 0, len = this.array_.length; i < len; i++) {
var e = this.array_[i]
if (e['compareTo'](o) === 0) {
return true
}
}
return false
}
/**
* @override
*/
TreeSet.prototype.add = function (o) {
if (this.contains(o)) {
return false
}
for (var i = 0, len = this.array_.length; i < len; i++) {
var e = this.array_[i]
if (e['compareTo'](o) === 1) {
this.array_.splice(i, 0, o)
return true
}
}
this.array_.push(o)
return true
}
/**
* @override
*/
TreeSet.prototype.addAll = function (c) {
for (var i = c.iterator(); i.hasNext();) {
this.add(i.next())
}
return true
}
/**
* @override
*/
TreeSet.prototype.remove = function (e) {
throw new OperationNotSupported()
}
/**
* @override
*/
TreeSet.prototype.size = function () {
return this.array_.length
}
/**
* @override
*/
TreeSet.prototype.isEmpty = function () {
return this.array_.length === 0
}
/**
* @override
*/
TreeSet.prototype.toArray = function () {
var array = []
for (var i = 0, len = this.array_.length; i < len; i++) {
array.push(this.array_[i])
}
return array
}
/**
* @override
*/
TreeSet.prototype.iterator = function () {
return new Iterator_(this)
}
/**
* @extends {javascript.util.Iterator}
* @param {javascript.util.TreeSet} treeSet
* @constructor
* @private
*/
var Iterator_ = function (treeSet) {
/**
* @type {javascript.util.TreeSet}
* @private
*/
this.treeSet_ = treeSet
/**
* @type {number}
* @private
*/
this.position_ = 0
}
/**
* @override
*/
Iterator_.prototype.next = function () {
if (this.position_ === this.treeSet_.size()) {
throw new NoSuchElementException()
}
return this.treeSet_.array_[this.position_++]
}
/**
* @override
*/
Iterator_.prototype.hasNext = function () {
if (this.position_ < this.treeSet_.size()) {
return true
} else {
return false
}
}
/**
* @override
*/
Iterator_.prototype.remove = function () {
throw new OperationNotSupported()
}

View File

@@ -0,0 +1,32 @@
import System from '../../../java/lang/System'
export default class JTSVersion {
getMajor () {
return JTSVersion.MAJOR
}
getPatch () {
return JTSVersion.PATCH
}
getMinor () {
return JTSVersion.MINOR
}
toString () {
var ver = JTSVersion.MAJOR + '.' + JTSVersion.MINOR + '.' + JTSVersion.PATCH
if (JTSVersion.releaseInfo !== null && JTSVersion.releaseInfo.length > 0) return ver + ' ' + JTSVersion.releaseInfo
return ver
}
interfaces_ () {
return []
}
getClass () {
return JTSVersion
}
static main (args) {
System.out.println(JTSVersion.CURRENT_VERSION)
}
static get CURRENT_VERSION () { return new JTSVersion() }
static get MAJOR () { return 1 }
static get MINOR () { return 14 }
static get PATCH () { return 0 }
static get releaseInfo () { return '' }
}

View File

@@ -0,0 +1,42 @@
// algorithm
export { default as Angle } from './algorithm/Angle'
export { default as BoundaryNodeRule } from './algorithm/BoundaryNodeRule'
export { default as CGAlgorithms } from './algorithm/CGAlgorithms'
export { default as CGAlgorithms3D } from './algorithm/CGAlgorithms3D'
export { default as CGAlgorithmsDD } from './algorithm/CGAlgorithmsDD'
export { default as Centroid } from './algorithm/Centroid'
export { default as ConvexHull } from './algorithm/ConvexHull'
export { default as HCoordinate } from './algorithm/HCoordinate'
export { default as InteriorPointArea } from './algorithm/InteriorPointArea'
export { default as InteriorPointLine } from './algorithm/InteriorPointLine'
export { default as InteriorPointPoint } from './algorithm/InteriorPointPoint'
export { default as LineIntersector } from './algorithm/LineIntersector'
export { default as MCPointInRing } from './algorithm/MCPointInRing'
export { default as MinimumBoundingCircle } from './algorithm/MinimumBoundingCircle'
export { default as MinimumDiameter } from './algorithm/MinimumDiameter'
export { default as NonRobustCGAlgorithms } from './algorithm/NonRobustCGAlgorithms'
export { default as NonRobustLineIntersector } from './algorithm/NonRobustLineIntersector'
export { default as NotRepresentableException } from './algorithm/NotRepresentableException'
export { default as PointInRing } from './algorithm/PointInRing'
export { default as PointLocator } from './algorithm/PointLocator'
export { default as RayCrossingCounter } from './algorithm/RayCrossingCounter'
export { default as RectangleLineIntersector } from './algorithm/RectangleLineIntersector'
export { default as RobustDeterminant } from './algorithm/RobustDeterminant'
export { default as RobustLineIntersector } from './algorithm/RobustLineIntersector'
export { default as SimplePointInRing } from './algorithm/SimplePointInRing'
// algorithm.distance
export { default as DiscreteHausdorffDistance } from './algorithm/distance/DiscreteHausdorffDistance'
export { default as DistanceToPoint } from './algorithm/distance/DistanceToPoint'
export { default as PointPairDistance } from './algorithm/distance/PointPairDistance'
// algorithm.locate
export { default as IndexedPointInAreaLocator } from './algorithm/locate/IndexedPointInAreaLocator'
export { default as PointOnGeometryLocator } from './algorithm/locate/PointOnGeometryLocator'
export { default as SimplePointInAreaLocator } from './algorithm/locate/SimplePointInAreaLocator'
// algorithm.match
export { default as AreaSimilarityMeasure } from './algorithm/match/AreaSimilarityMeasure'
export { default as HausdorffSimilarityMeasure } from './algorithm/match/HausdorffSimilarityMeasure'
export { default as SimilarityMeasure } from './algorithm/match/SimilarityMeasure'
export { default as SimilarityMeasureCombiner } from './algorithm/match/SimilarityMeasureCombiner'

View File

@@ -0,0 +1,105 @@
import CGAlgorithms from './CGAlgorithms'
export default class Angle {
interfaces_ () {
return []
}
getClass () {
return Angle
}
static toDegrees (radians) {
return radians * 180 / Math.PI
}
static normalize (angle) {
while (angle > Math.PI) angle -= Angle.PI_TIMES_2
while (angle <= -Math.PI) angle += Angle.PI_TIMES_2
return angle
}
static angle () {
if (arguments.length === 1) {
const p = arguments[0]
return Math.atan2(p.y, p.x)
} else if (arguments.length === 2) {
const p0 = arguments[0]
const p1 = arguments[1]
const dx = p1.x - p0.x
const dy = p1.y - p0.y
return Math.atan2(dy, dx)
}
}
static isAcute (p0, p1, p2) {
const dx0 = p0.x - p1.x
const dy0 = p0.y - p1.y
const dx1 = p2.x - p1.x
const dy1 = p2.y - p1.y
const dotprod = dx0 * dx1 + dy0 * dy1
return dotprod > 0
}
static isObtuse (p0, p1, p2) {
const dx0 = p0.x - p1.x
const dy0 = p0.y - p1.y
const dx1 = p2.x - p1.x
const dy1 = p2.y - p1.y
const dotprod = dx0 * dx1 + dy0 * dy1
return dotprod < 0
}
static interiorAngle (p0, p1, p2) {
const anglePrev = Angle.angle(p1, p0)
const angleNext = Angle.angle(p1, p2)
return Math.abs(angleNext - anglePrev)
}
static normalizePositive (angle) {
if (angle < 0.0) {
while (angle < 0.0) angle += Angle.PI_TIMES_2
if (angle >= Angle.PI_TIMES_2) angle = 0.0
} else {
while (angle >= Angle.PI_TIMES_2) angle -= Angle.PI_TIMES_2
if (angle < 0.0) angle = 0.0
}
return angle
}
static angleBetween (tip1, tail, tip2) {
const a1 = Angle.angle(tail, tip1)
const a2 = Angle.angle(tail, tip2)
return Angle.diff(a1, a2)
}
static diff (ang1, ang2) {
let delAngle = null
if (ang1 < ang2) {
delAngle = ang2 - ang1
} else {
delAngle = ang1 - ang2
}
if (delAngle > Math.PI) {
delAngle = 2 * Math.PI - delAngle
}
return delAngle
}
static toRadians (angleDegrees) {
return angleDegrees * Math.PI / 180.0
}
static getTurn (ang1, ang2) {
const crossproduct = Math.sin(ang2 - ang1)
if (crossproduct > 0) {
return Angle.COUNTERCLOCKWISE
}
if (crossproduct < 0) {
return Angle.CLOCKWISE
}
return Angle.NONE
}
static angleBetweenOriented (tip1, tail, tip2) {
const a1 = Angle.angle(tail, tip1)
const a2 = Angle.angle(tail, tip2)
const angDel = a2 - a1
if (angDel <= -Math.PI) return angDel + Angle.PI_TIMES_2
if (angDel > Math.PI) return angDel - Angle.PI_TIMES_2
return angDel
}
static get PI_TIMES_2 () { return 2.0 * Math.PI }
static get PI_OVER_2 () { return Math.PI / 2.0 }
static get PI_OVER_4 () { return Math.PI / 4.0 }
static get COUNTERCLOCKWISE () { return CGAlgorithms.COUNTERCLOCKWISE }
static get CLOCKWISE () { return CGAlgorithms.CLOCKWISE }
static get NONE () { return CGAlgorithms.COLLINEAR }
}

View File

@@ -0,0 +1,66 @@
export default class BoundaryNodeRule {
isInBoundary (boundaryCount) {}
interfaces_ () {
return []
}
getClass () {
return BoundaryNodeRule
}
static get Mod2BoundaryNodeRule () { return Mod2BoundaryNodeRule }
static get EndPointBoundaryNodeRule () { return EndPointBoundaryNodeRule }
static get MultiValentEndPointBoundaryNodeRule () { return MultiValentEndPointBoundaryNodeRule }
static get MonoValentEndPointBoundaryNodeRule () { return MonoValentEndPointBoundaryNodeRule }
static get MOD2_BOUNDARY_RULE () { return new Mod2BoundaryNodeRule() }
static get ENDPOINT_BOUNDARY_RULE () { return new EndPointBoundaryNodeRule() }
static get MULTIVALENT_ENDPOINT_BOUNDARY_RULE () { return new MultiValentEndPointBoundaryNodeRule() }
static get MONOVALENT_ENDPOINT_BOUNDARY_RULE () { return new MonoValentEndPointBoundaryNodeRule() }
static get OGC_SFS_BOUNDARY_RULE () { return BoundaryNodeRule.MOD2_BOUNDARY_RULE }
}
class Mod2BoundaryNodeRule {
isInBoundary (boundaryCount) {
return boundaryCount % 2 === 1
}
interfaces_ () {
return [BoundaryNodeRule]
}
getClass () {
return Mod2BoundaryNodeRule
}
}
class EndPointBoundaryNodeRule {
isInBoundary (boundaryCount) {
return boundaryCount > 0
}
interfaces_ () {
return [BoundaryNodeRule]
}
getClass () {
return EndPointBoundaryNodeRule
}
}
class MultiValentEndPointBoundaryNodeRule {
isInBoundary (boundaryCount) {
return boundaryCount > 1
}
interfaces_ () {
return [BoundaryNodeRule]
}
getClass () {
return MultiValentEndPointBoundaryNodeRule
}
}
class MonoValentEndPointBoundaryNodeRule {
isInBoundary (boundaryCount) {
return boundaryCount === 1
}
interfaces_ () {
return [BoundaryNodeRule]
}
getClass () {
return MonoValentEndPointBoundaryNodeRule
}
}

View File

@@ -0,0 +1,194 @@
import Location from '../geom/Location'
import hasInterface from '../../../../hasInterface'
import Coordinate from '../geom/Coordinate'
import IllegalArgumentException from '../../../../java/lang/IllegalArgumentException'
import MathUtil from '../math/MathUtil'
import CGAlgorithmsDD from './CGAlgorithmsDD'
import CoordinateSequence from '../geom/CoordinateSequence'
import RobustLineIntersector from './RobustLineIntersector'
import Envelope from '../geom/Envelope'
import RayCrossingCounter from './RayCrossingCounter'
export default class CGAlgorithms {
interfaces_ () {
return []
}
getClass () {
return CGAlgorithms
}
static orientationIndex (p1, p2, q) {
return CGAlgorithmsDD.orientationIndex(p1, p2, q)
}
static signedArea () {
if (arguments[0] instanceof Array) {
let ring = arguments[0]
if (ring.length < 3) return 0.0
let sum = 0.0
const x0 = ring[0].x
for (let i = 1; i < ring.length - 1; i++) {
const x = ring[i].x - x0
const y1 = ring[i + 1].y
const y2 = ring[i - 1].y
sum += x * (y2 - y1)
}
return sum / 2.0
} else if (hasInterface(arguments[0], CoordinateSequence)) {
let ring = arguments[0]
const n = ring.size()
if (n < 3) return 0.0
const p0 = new Coordinate()
const p1 = new Coordinate()
const p2 = new Coordinate()
ring.getCoordinate(0, p1)
ring.getCoordinate(1, p2)
const x0 = p1.x
p2.x -= x0
let sum = 0.0
for (let i = 1; i < n - 1; i++) {
p0.y = p1.y
p1.x = p2.x
p1.y = p2.y
ring.getCoordinate(i + 1, p2)
p2.x -= x0
sum += p1.x * (p0.y - p2.y)
}
return sum / 2.0
}
}
static distanceLineLine (A, B, C, D) {
if (A.equals(B)) return CGAlgorithms.distancePointLine(A, C, D)
if (C.equals(D)) return CGAlgorithms.distancePointLine(D, A, B)
let noIntersection = false
if (!Envelope.intersects(A, B, C, D)) {
noIntersection = true
} else {
const denom = (B.x - A.x) * (D.y - C.y) - (B.y - A.y) * (D.x - C.x)
if (denom === 0) {
noIntersection = true
} else {
const rNumb = (A.y - C.y) * (D.x - C.x) - (A.x - C.x) * (D.y - C.y)
const sNum = (A.y - C.y) * (B.x - A.x) - (A.x - C.x) * (B.y - A.y)
const s = sNum / denom
const r = rNumb / denom
if (r < 0 || r > 1 || s < 0 || s > 1) {
noIntersection = true
}
}
}
if (noIntersection) {
return MathUtil.min(CGAlgorithms.distancePointLine(A, C, D), CGAlgorithms.distancePointLine(B, C, D), CGAlgorithms.distancePointLine(C, A, B), CGAlgorithms.distancePointLine(D, A, B))
}
return 0.0
}
static isPointInRing (p, ring) {
return CGAlgorithms.locatePointInRing(p, ring) !== Location.EXTERIOR
}
static computeLength (pts) {
const n = pts.size()
if (n <= 1) return 0.0
let len = 0.0
const p = new Coordinate()
pts.getCoordinate(0, p)
let x0 = p.x
let y0 = p.y
for (let i = 1; i < n; i++) {
pts.getCoordinate(i, p)
const x1 = p.x
const y1 = p.y
const dx = x1 - x0
const dy = y1 - y0
len += Math.sqrt(dx * dx + dy * dy)
x0 = x1
y0 = y1
}
return len
}
static isCCW (ring) {
const nPts = ring.length - 1
if (nPts < 3) throw new IllegalArgumentException('Ring has fewer than 4 points, so orientation cannot be determined')
let hiPt = ring[0]
let hiIndex = 0
for (let i = 1; i <= nPts; i++) {
const p = ring[i]
if (p.y > hiPt.y) {
hiPt = p
hiIndex = i
}
}
let iPrev = hiIndex
do {
iPrev = iPrev - 1
if (iPrev < 0) iPrev = nPts
} while (ring[iPrev].equals2D(hiPt) && iPrev !== hiIndex)
let iNext = hiIndex
do {
iNext = (iNext + 1) % nPts
} while (ring[iNext].equals2D(hiPt) && iNext !== hiIndex)
const prev = ring[iPrev]
const next = ring[iNext]
if (prev.equals2D(hiPt) || next.equals2D(hiPt) || prev.equals2D(next)) return false
const disc = CGAlgorithms.computeOrientation(prev, hiPt, next)
let isCCW = false
if (disc === 0) {
isCCW = prev.x > next.x
} else {
isCCW = disc > 0
}
return isCCW
}
static locatePointInRing (p, ring) {
return RayCrossingCounter.locatePointInRing(p, ring)
}
static distancePointLinePerpendicular (p, A, B) {
const len2 = (B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y)
const s = ((A.y - p.y) * (B.x - A.x) - (A.x - p.x) * (B.y - A.y)) / len2
return Math.abs(s) * Math.sqrt(len2)
}
static computeOrientation (p1, p2, q) {
return CGAlgorithms.orientationIndex(p1, p2, q)
}
static distancePointLine () {
if (arguments.length === 2) {
const p = arguments[0]
const line = arguments[1]
if (line.length === 0) throw new IllegalArgumentException('Line array must contain at least one vertex')
let minDistance = p.distance(line[0])
for (let i = 0; i < line.length - 1; i++) {
const dist = CGAlgorithms.distancePointLine(p, line[i], line[i + 1])
if (dist < minDistance) {
minDistance = dist
}
}
return minDistance
} else if (arguments.length === 3) {
const p = arguments[0]
const A = arguments[1]
const B = arguments[2]
if (A.x === B.x && A.y === B.y) return p.distance(A)
const len2 = (B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y)
const r = ((p.x - A.x) * (B.x - A.x) + (p.y - A.y) * (B.y - A.y)) / len2
if (r <= 0.0) return p.distance(A)
if (r >= 1.0) return p.distance(B)
const s = ((A.y - p.y) * (B.x - A.x) - (A.x - p.x) * (B.y - A.y)) / len2
return Math.abs(s) * Math.sqrt(len2)
}
}
static isOnLine (p, pt) {
const lineIntersector = new RobustLineIntersector()
for (let i = 1; i < pt.length; i++) {
const p0 = pt[i - 1]
const p1 = pt[i]
lineIntersector.computeIntersection(p, p0, p1)
if (lineIntersector.hasIntersection()) {
return true
}
}
return false
}
static get CLOCKWISE () { return -1 }
static get RIGHT () { return CGAlgorithms.CLOCKWISE }
static get COUNTERCLOCKWISE () { return 1 }
static get LEFT () { return CGAlgorithms.COUNTERCLOCKWISE }
static get COLLINEAR () { return 0 }
static get STRAIGHT () { return CGAlgorithms.COLLINEAR }
}

View File

@@ -0,0 +1,65 @@
import Coordinate from '../geom/Coordinate'
import IllegalArgumentException from '../../../../java/lang/IllegalArgumentException'
import Double from '../../../../java/lang/Double'
import Vector3D from '../math/Vector3D'
export default class CGAlgorithms3D {
interfaces_ () {
return []
}
getClass () {
return CGAlgorithms3D
}
static distanceSegmentSegment (A, B, C, D) {
if (A.equals3D(B)) return CGAlgorithms3D.distancePointSegment(A, C, D)
if (C.equals3D(B)) return CGAlgorithms3D.distancePointSegment(C, A, B)
var a = Vector3D.dot(A, B, A, B)
var b = Vector3D.dot(A, B, C, D)
var c = Vector3D.dot(C, D, C, D)
var d = Vector3D.dot(A, B, C, A)
var e = Vector3D.dot(C, D, C, A)
var denom = a * c - b * b
if (Double.isNaN(denom)) throw new IllegalArgumentException('Ordinates must not be NaN')
var s = null
var t = null
if (denom <= 0.0) {
s = 0
if (b > c) t = d / b; else t = e / c
} else {
s = (b * e - c * d) / denom
t = (a * e - b * d) / denom
}
if (s < 0) return CGAlgorithms3D.distancePointSegment(A, C, D); else if (s > 1) return CGAlgorithms3D.distancePointSegment(B, C, D); else if (t < 0) return CGAlgorithms3D.distancePointSegment(C, A, B); else if (t > 1) {
return CGAlgorithms3D.distancePointSegment(D, A, B)
}
var x1 = A.x + s * (B.x - A.x)
var y1 = A.y + s * (B.y - A.y)
var z1 = A.z + s * (B.z - A.z)
var x2 = C.x + t * (D.x - C.x)
var y2 = C.y + t * (D.y - C.y)
var z2 = C.z + t * (D.z - C.z)
return CGAlgorithms3D.distance(new Coordinate(x1, y1, z1), new Coordinate(x2, y2, z2))
}
static distance (p0, p1) {
if (Double.isNaN(p0.z) || Double.isNaN(p1.z)) return p0.distance(p1)
var dx = p0.x - p1.x
var dy = p0.y - p1.y
var dz = p0.z - p1.z
return Math.sqrt(dx * dx + dy * dy + dz * dz)
}
static distancePointSegment (p, A, B) {
if (A.equals3D(B)) return CGAlgorithms3D.distance(p, A)
var len2 = (B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y) + (B.z - A.z) * (B.z - A.z)
if (Double.isNaN(len2)) throw new IllegalArgumentException('Ordinates must not be NaN')
var r = ((p.x - A.x) * (B.x - A.x) + (p.y - A.y) * (B.y - A.y) + (p.z - A.z) * (B.z - A.z)) / len2
if (r <= 0.0) return CGAlgorithms3D.distance(p, A)
if (r >= 1.0) return CGAlgorithms3D.distance(p, B)
var qx = A.x + r * (B.x - A.x)
var qy = A.y + r * (B.y - A.y)
var qz = A.z + r * (B.z - A.z)
var dx = p.x - qx
var dy = p.y - qy
var dz = p.z - qz
return Math.sqrt(dx * dx + dy * dy + dz * dz)
}
}

View File

@@ -0,0 +1,72 @@
import Coordinate from '../geom/Coordinate'
import DD from '../math/DD'
export default class CGAlgorithmsDD {
interfaces_ () {
return []
}
getClass () {
return CGAlgorithmsDD
}
static orientationIndex (p1, p2, q) {
const index = CGAlgorithmsDD.orientationIndexFilter(p1, p2, q)
if (index <= 1) return index
const dx1 = DD.valueOf(p2.x).selfAdd(-p1.x)
const dy1 = DD.valueOf(p2.y).selfAdd(-p1.y)
const dx2 = DD.valueOf(q.x).selfAdd(-p2.x)
const dy2 = DD.valueOf(q.y).selfAdd(-p2.y)
return dx1.selfMultiply(dy2).selfSubtract(dy1.selfMultiply(dx2)).signum()
}
static signOfDet2x2 (x1, y1, x2, y2) {
const det = x1.multiply(y2).selfSubtract(y1.multiply(x2))
return det.signum()
}
static intersection (p1, p2, q1, q2) {
const denom1 = DD.valueOf(q2.y).selfSubtract(q1.y).selfMultiply(DD.valueOf(p2.x).selfSubtract(p1.x))
const denom2 = DD.valueOf(q2.x).selfSubtract(q1.x).selfMultiply(DD.valueOf(p2.y).selfSubtract(p1.y))
const denom = denom1.subtract(denom2)
const numx1 = DD.valueOf(q2.x).selfSubtract(q1.x).selfMultiply(DD.valueOf(p1.y).selfSubtract(q1.y))
const numx2 = DD.valueOf(q2.y).selfSubtract(q1.y).selfMultiply(DD.valueOf(p1.x).selfSubtract(q1.x))
const numx = numx1.subtract(numx2)
const fracP = numx.selfDivide(denom).doubleValue()
const x = DD.valueOf(p1.x).selfAdd(DD.valueOf(p2.x).selfSubtract(p1.x).selfMultiply(fracP)).doubleValue()
const numy1 = DD.valueOf(p2.x).selfSubtract(p1.x).selfMultiply(DD.valueOf(p1.y).selfSubtract(q1.y))
const numy2 = DD.valueOf(p2.y).selfSubtract(p1.y).selfMultiply(DD.valueOf(p1.x).selfSubtract(q1.x))
const numy = numy1.subtract(numy2)
const fracQ = numy.selfDivide(denom).doubleValue()
const y = DD.valueOf(q1.y).selfAdd(DD.valueOf(q2.y).selfSubtract(q1.y).selfMultiply(fracQ)).doubleValue()
return new Coordinate(x, y)
}
static orientationIndexFilter (pa, pb, pc) {
let detsum = null
const detleft = (pa.x - pc.x) * (pb.y - pc.y)
const detright = (pa.y - pc.y) * (pb.x - pc.x)
const det = detleft - detright
if (detleft > 0.0) {
if (detright <= 0.0) {
return CGAlgorithmsDD.signum(det)
} else {
detsum = detleft + detright
}
} else if (detleft < 0.0) {
if (detright >= 0.0) {
return CGAlgorithmsDD.signum(det)
} else {
detsum = -detleft - detright
}
} else {
return CGAlgorithmsDD.signum(det)
}
const errbound = CGAlgorithmsDD.DP_SAFE_EPSILON * detsum
if (det >= errbound || -det >= errbound) {
return CGAlgorithmsDD.signum(det)
}
return 2
}
static signum (x) {
if (x > 0) return 1
if (x < 0) return -1
return 0
}
static get DP_SAFE_EPSILON () { return 1e-15 };
}

View File

@@ -0,0 +1,127 @@
import LineString from '../geom/LineString'
import CGAlgorithms from './CGAlgorithms'
import Geometry from '../geom/Geometry'
import Coordinate from '../geom/Coordinate'
import Point from '../geom/Point'
import Polygon from '../geom/Polygon'
import GeometryCollection from '../geom/GeometryCollection'
export default class Centroid {
constructor () {
this._areaBasePt = null
this._triangleCent3 = new Coordinate()
this._areasum2 = 0
this._cg3 = new Coordinate()
this._lineCentSum = new Coordinate()
this._totalLength = 0.0
this._ptCount = 0
this._ptCentSum = new Coordinate()
const geom = arguments[0]
this._areaBasePt = null
this.add(geom)
}
addPoint (pt) {
this._ptCount += 1
this._ptCentSum.x += pt.x
this._ptCentSum.y += pt.y
}
setBasePoint (basePt) {
if (this._areaBasePt === null) this._areaBasePt = basePt
}
addLineSegments (pts) {
let lineLen = 0.0
for (let i = 0; i < pts.length - 1; i++) {
const segmentLen = pts[i].distance(pts[i + 1])
if (segmentLen === 0.0) continue
lineLen += segmentLen
const midx = (pts[i].x + pts[i + 1].x) / 2
this._lineCentSum.x += segmentLen * midx
const midy = (pts[i].y + pts[i + 1].y) / 2
this._lineCentSum.y += segmentLen * midy
}
this._totalLength += lineLen
if (lineLen === 0.0 && pts.length > 0) this.addPoint(pts[0])
}
addHole (pts) {
const isPositiveArea = CGAlgorithms.isCCW(pts)
for (let i = 0; i < pts.length - 1; i++) {
this.addTriangle(this._areaBasePt, pts[i], pts[i + 1], isPositiveArea)
}
this.addLineSegments(pts)
}
getCentroid () {
const cent = new Coordinate()
if (Math.abs(this._areasum2) > 0.0) {
cent.x = this._cg3.x / 3 / this._areasum2
cent.y = this._cg3.y / 3 / this._areasum2
} else if (this._totalLength > 0.0) {
cent.x = this._lineCentSum.x / this._totalLength
cent.y = this._lineCentSum.y / this._totalLength
} else if (this._ptCount > 0) {
cent.x = this._ptCentSum.x / this._ptCount
cent.y = this._ptCentSum.y / this._ptCount
} else {
return null
}
return cent
}
addShell (pts) {
if (pts.length > 0) this.setBasePoint(pts[0])
const isPositiveArea = !CGAlgorithms.isCCW(pts)
for (let i = 0; i < pts.length - 1; i++) {
this.addTriangle(this._areaBasePt, pts[i], pts[i + 1], isPositiveArea)
}
this.addLineSegments(pts)
}
addTriangle (p0, p1, p2, isPositiveArea) {
const sign = isPositiveArea ? 1.0 : -1.0
Centroid.centroid3(p0, p1, p2, this._triangleCent3)
const area2 = Centroid.area2(p0, p1, p2)
this._cg3.x += sign * area2 * this._triangleCent3.x
this._cg3.y += sign * area2 * this._triangleCent3.y
this._areasum2 += sign * area2
}
add () {
if (arguments[0] instanceof Polygon) {
let poly = arguments[0]
this.addShell(poly.getExteriorRing().getCoordinates())
for (let i = 0; i < poly.getNumInteriorRing(); i++) {
this.addHole(poly.getInteriorRingN(i).getCoordinates())
}
} else if (arguments[0] instanceof Geometry) {
let geom = arguments[0]
if (geom.isEmpty()) return null
if (geom instanceof Point) {
this.addPoint(geom.getCoordinate())
} else if (geom instanceof LineString) {
this.addLineSegments(geom.getCoordinates())
} else if (geom instanceof Polygon) {
const poly = geom
this.add(poly)
} else if (geom instanceof GeometryCollection) {
const gc = geom
for (let i = 0; i < gc.getNumGeometries(); i++) {
this.add(gc.getGeometryN(i))
}
}
}
}
interfaces_ () {
return []
}
getClass () {
return Centroid
}
static area2 (p1, p2, p3) {
return (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y)
}
static centroid3 (p1, p2, p3, c) {
c.x = p1.x + p2.x + p3.x
c.y = p1.y + p2.y + p3.y
return null
}
static getCentroid (geom) {
const cent = new Centroid(geom)
return cent.getCentroid()
}
}

View File

@@ -0,0 +1,252 @@
import TreeSet from '../../../../java/util/TreeSet'
import CGAlgorithms from './CGAlgorithms'
import CoordinateList from '../geom/CoordinateList'
import Arrays from '../../../../java/util/Arrays'
import Stack from '../../../../java/util/Stack'
import CoordinateArrays from '../geom/CoordinateArrays'
import ArrayList from '../../../../java/util/ArrayList'
import Comparator from '../../../../java/util/Comparator'
import UniqueCoordinateArrayFilter from '../util/UniqueCoordinateArrayFilter'
import Assert from '../util/Assert'
export default class ConvexHull {
constructor () {
this._geomFactory = null
this._inputPts = null
if (arguments.length === 1) {
const geometry = arguments[0]
const pts = ConvexHull.extractCoordinates(geometry)
const geomFactory = geometry.getFactory()
this._inputPts = UniqueCoordinateArrayFilter.filterCoordinates(pts)
this._geomFactory = geomFactory
} else if (arguments.length === 2) {
const pts = arguments[0]
const geomFactory = arguments[1]
this._inputPts = UniqueCoordinateArrayFilter.filterCoordinates(pts)
this._geomFactory = geomFactory
}
}
preSort (pts) {
let t = null
for (let i = 1; i < pts.length; i++) {
if ((pts[i].y < pts[0].y || pts[i].y === pts[0].y) && pts[i].x < pts[0].x) {
t = pts[0]
pts[0] = pts[i]
pts[i] = t
}
}
Arrays.sort(pts, 1, pts.length, new RadialComparator(pts[0]))
return pts
}
computeOctRing (inputPts) {
const octPts = this.computeOctPts(inputPts)
const coordList = new CoordinateList()
coordList.add(octPts, false)
if (coordList.size() < 3) {
return null
}
coordList.closeRing()
return coordList.toCoordinateArray()
}
lineOrPolygon (coordinates) {
coordinates = this.cleanRing(coordinates)
if (coordinates.length === 3) {
return this._geomFactory.createLineString([coordinates[0], coordinates[1]])
}
const linearRing = this._geomFactory.createLinearRing(coordinates)
return this._geomFactory.createPolygon(linearRing, null)
}
cleanRing (original) {
Assert.equals(original[0], original[original.length - 1])
const cleanedRing = new ArrayList()
let previousDistinctCoordinate = null
for (let i = 0; i <= original.length - 2; i++) {
const currentCoordinate = original[i]
const nextCoordinate = original[i + 1]
if (currentCoordinate.equals(nextCoordinate)) {
continue
}
if (previousDistinctCoordinate !== null && this.isBetween(previousDistinctCoordinate, currentCoordinate, nextCoordinate)) {
continue
}
cleanedRing.add(currentCoordinate)
previousDistinctCoordinate = currentCoordinate
}
cleanedRing.add(original[original.length - 1])
const cleanedRingCoordinates = new Array(cleanedRing.size()).fill(null)
return cleanedRing.toArray(cleanedRingCoordinates)
}
isBetween (c1, c2, c3) {
if (CGAlgorithms.computeOrientation(c1, c2, c3) !== 0) {
return false
}
if (c1.x !== c3.x) {
if (c1.x <= c2.x && c2.x <= c3.x) {
return true
}
if (c3.x <= c2.x && c2.x <= c1.x) {
return true
}
}
if (c1.y !== c3.y) {
if (c1.y <= c2.y && c2.y <= c3.y) {
return true
}
if (c3.y <= c2.y && c2.y <= c1.y) {
return true
}
}
return false
}
reduce (inputPts) {
const polyPts = this.computeOctRing(inputPts)
if (polyPts === null) return inputPts
const reducedSet = new TreeSet()
for (let i = 0; i < polyPts.length; i++) {
reducedSet.add(polyPts[i])
}
for (let i = 0; i < inputPts.length; i++) {
if (!CGAlgorithms.isPointInRing(inputPts[i], polyPts)) {
reducedSet.add(inputPts[i])
}
}
const reducedPts = CoordinateArrays.toCoordinateArray(reducedSet)
if (reducedPts.length < 3) return this.padArray3(reducedPts)
return reducedPts
}
getConvexHull () {
if (this._inputPts.length === 0) {
return this._geomFactory.createGeometryCollection(null)
}
if (this._inputPts.length === 1) {
return this._geomFactory.createPoint(this._inputPts[0])
}
if (this._inputPts.length === 2) {
return this._geomFactory.createLineString(this._inputPts)
}
let reducedPts = this._inputPts
if (this._inputPts.length > 50) {
reducedPts = this.reduce(this._inputPts)
}
const sortedPts = this.preSort(reducedPts)
const cHS = this.grahamScan(sortedPts)
const cH = this.toCoordinateArray(cHS)
return this.lineOrPolygon(cH)
}
padArray3 (pts) {
const pad = new Array(3).fill(null)
for (let i = 0; i < pad.length; i++) {
if (i < pts.length) {
pad[i] = pts[i]
} else pad[i] = pts[0]
}
return pad
}
computeOctPts (inputPts) {
const pts = new Array(8).fill(null)
for (let j = 0; j < pts.length; j++) {
pts[j] = inputPts[0]
}
for (let i = 1; i < inputPts.length; i++) {
if (inputPts[i].x < pts[0].x) {
pts[0] = inputPts[i]
}
if (inputPts[i].x - inputPts[i].y < pts[1].x - pts[1].y) {
pts[1] = inputPts[i]
}
if (inputPts[i].y > pts[2].y) {
pts[2] = inputPts[i]
}
if (inputPts[i].x + inputPts[i].y > pts[3].x + pts[3].y) {
pts[3] = inputPts[i]
}
if (inputPts[i].x > pts[4].x) {
pts[4] = inputPts[i]
}
if (inputPts[i].x - inputPts[i].y > pts[5].x - pts[5].y) {
pts[5] = inputPts[i]
}
if (inputPts[i].y < pts[6].y) {
pts[6] = inputPts[i]
}
if (inputPts[i].x + inputPts[i].y < pts[7].x + pts[7].y) {
pts[7] = inputPts[i]
}
}
return pts
}
toCoordinateArray (stack) {
const coordinates = new Array(stack.size()).fill(null)
for (let i = 0; i < stack.size(); i++) {
const coordinate = stack.get(i)
coordinates[i] = coordinate
}
return coordinates
}
grahamScan (c) {
let p = null
const ps = new Stack()
p = ps.push(c[0])
p = ps.push(c[1])
p = ps.push(c[2])
for (let i = 3; i < c.length; i++) {
p = ps.pop()
while (!ps.empty() && CGAlgorithms.computeOrientation(ps.peek(), p, c[i]) > 0) {
p = ps.pop()
}
p = ps.push(p)
p = ps.push(c[i])
}
p = ps.push(c[0])
return ps
}
interfaces_ () {
return []
}
getClass () {
return ConvexHull
}
static extractCoordinates (geom) {
const filter = new UniqueCoordinateArrayFilter()
geom.apply(filter)
return filter.getCoordinates()
}
static get RadialComparator () { return RadialComparator }
}
class RadialComparator {
constructor () {
this._origin = null
const origin = arguments[0]
this._origin = origin
}
compare (o1, o2) {
const p1 = o1
const p2 = o2
return RadialComparator.polarCompare(this._origin, p1, p2)
}
interfaces_ () {
return [Comparator]
}
getClass () {
return RadialComparator
}
static polarCompare (o, p, q) {
const dxp = p.x - o.x
const dyp = p.y - o.y
const dxq = q.x - o.x
const dyq = q.y - o.y
const orient = CGAlgorithms.computeOrientation(o, p, q)
if (orient === CGAlgorithms.COUNTERCLOCKWISE) return 1
if (orient === CGAlgorithms.CLOCKWISE) return -1
const op = dxp * dxp + dyp * dyp
const oq = dxq * dxq + dyq * dyq
if (op < oq) {
return -1
}
if (op > oq) {
return 1
}
return 0
}
}

View File

@@ -0,0 +1,105 @@
import NotRepresentableException from './NotRepresentableException'
import Coordinate from '../geom/Coordinate'
import Double from '../../../../java/lang/Double'
export default class HCoordinate {
constructor () {
this.x = null
this.y = null
this.w = null
if (arguments.length === 0) {
this.x = 0.0
this.y = 0.0
this.w = 1.0
} else if (arguments.length === 1) {
const p = arguments[0]
this.x = p.x
this.y = p.y
this.w = 1.0
} else if (arguments.length === 2) {
if (typeof arguments[0] === 'number' && typeof arguments[1] === 'number') {
const _x = arguments[0]
const _y = arguments[1]
this.x = _x
this.y = _y
this.w = 1.0
} else if (arguments[0] instanceof HCoordinate && arguments[1] instanceof HCoordinate) {
const p1 = arguments[0]
const p2 = arguments[1]
this.x = p1.y * p2.w - p2.y * p1.w
this.y = p2.x * p1.w - p1.x * p2.w
this.w = p1.x * p2.y - p2.x * p1.y
} else if (arguments[0] instanceof Coordinate && arguments[1] instanceof Coordinate) {
const p1 = arguments[0]
const p2 = arguments[1]
this.x = p1.y - p2.y
this.y = p2.x - p1.x
this.w = p1.x * p2.y - p2.x * p1.y
}
} else if (arguments.length === 3) {
const _x = arguments[0]
const _y = arguments[1]
const _w = arguments[2]
this.x = _x
this.y = _y
this.w = _w
} else if (arguments.length === 4) {
const p1 = arguments[0]
const p2 = arguments[1]
const q1 = arguments[2]
const q2 = arguments[3]
const px = p1.y - p2.y
const py = p2.x - p1.x
const pw = p1.x * p2.y - p2.x * p1.y
const qx = q1.y - q2.y
const qy = q2.x - q1.x
const qw = q1.x * q2.y - q2.x * q1.y
this.x = py * qw - qy * pw
this.y = qx * pw - px * qw
this.w = px * qy - qx * py
}
}
getY () {
const a = this.y / this.w
if (Double.isNaN(a) || Double.isInfinite(a)) {
throw new NotRepresentableException()
}
return a
}
getX () {
const a = this.x / this.w
if (Double.isNaN(a) || Double.isInfinite(a)) {
throw new NotRepresentableException()
}
return a
}
getCoordinate () {
const p = new Coordinate()
p.x = this.getX()
p.y = this.getY()
return p
}
interfaces_ () {
return []
}
getClass () {
return HCoordinate
}
static intersection (p1, p2, q1, q2) {
const px = p1.y - p2.y
const py = p2.x - p1.x
const pw = p1.x * p2.y - p2.x * p1.y
const qx = q1.y - q2.y
const qy = q2.x - q1.x
const qw = q1.x * q2.y - q2.x * q1.y
const x = py * qw - qy * pw
const y = qx * pw - px * qw
const w = px * qy - qx * py
const xInt = x / w
const yInt = y / w
if (Double.isNaN(xInt) || (Double.isInfinite(xInt) || Double.isNaN(yInt)) || Double.isInfinite(yInt)) {
throw new NotRepresentableException()
}
return new Coordinate(xInt, yInt)
}
}

View File

@@ -0,0 +1,137 @@
import Geometry from '../geom/Geometry'
import Coordinate from '../geom/Coordinate'
import Polygon from '../geom/Polygon'
import SnapIfNeededOverlayOp from '../operation/overlay/snap/SnapIfNeededOverlayOp'
import Double from '../../../../java/lang/Double'
import GeometryCollection from '../geom/GeometryCollection'
import OverlayOp from '../operation/overlay/OverlayOp'
export default class InteriorPointArea {
constructor () {
this._factory = null
this._interiorPoint = null
this._maxWidth = 0.0
let g = arguments[0]
this._factory = g.getFactory()
this.add(g)
}
addPolygon (geometry) {
if (geometry.isEmpty()) return null
var intPt = null
var width = 0
var bisector = this.horizontalBisector(geometry)
if (bisector.getLength() === 0.0) {
width = 0
intPt = bisector.getCoordinate()
} else {
var intersections = SnapIfNeededOverlayOp.overlayOp(bisector, geometry, OverlayOp.INTERSECTION)
var widestIntersection = this.widestGeometry(intersections)
width = widestIntersection.getEnvelopeInternal().getWidth()
intPt = InteriorPointArea.centre(widestIntersection.getEnvelopeInternal())
}
if (this._interiorPoint === null || width > this._maxWidth) {
this._interiorPoint = intPt
this._maxWidth = width
}
}
getInteriorPoint () {
return this._interiorPoint
}
widestGeometry () {
if (arguments[0] instanceof GeometryCollection) {
let gc = arguments[0]
if (gc.isEmpty()) {
return gc
}
var widestGeometry = gc.getGeometryN(0)
for (var i = 1; i < gc.getNumGeometries(); i++) {
if (gc.getGeometryN(i).getEnvelopeInternal().getWidth() > widestGeometry.getEnvelopeInternal().getWidth()) {
widestGeometry = gc.getGeometryN(i)
}
}
return widestGeometry
} else if (arguments[0] instanceof Geometry) {
let geometry = arguments[0]
if (!(geometry instanceof GeometryCollection)) {
return geometry
}
return this.widestGeometry(geometry)
}
}
horizontalBisector (geometry) {
var envelope = geometry.getEnvelopeInternal()
var bisectY = SafeBisectorFinder.getBisectorY(geometry)
return this._factory.createLineString([new Coordinate(envelope.getMinX(), bisectY), new Coordinate(envelope.getMaxX(), bisectY)])
}
add (geom) {
if (geom instanceof Polygon) {
this.addPolygon(geom)
} else if (geom instanceof GeometryCollection) {
var gc = geom
for (var i = 0; i < gc.getNumGeometries(); i++) {
this.add(gc.getGeometryN(i))
}
}
}
interfaces_ () {
return []
}
getClass () {
return InteriorPointArea
}
static centre (envelope) {
return new Coordinate(InteriorPointArea.avg(envelope.getMinX(), envelope.getMaxX()), InteriorPointArea.avg(envelope.getMinY(), envelope.getMaxY()))
}
static avg (a, b) {
return (a + b) / 2.0
}
static get SafeBisectorFinder () { return SafeBisectorFinder }
}
class SafeBisectorFinder {
constructor () {
this._poly = null
this._centreY = null
this._hiY = Double.MAX_VALUE
this._loY = -Double.MAX_VALUE
let poly = arguments[0]
this._poly = poly
this._hiY = poly.getEnvelopeInternal().getMaxY()
this._loY = poly.getEnvelopeInternal().getMinY()
this._centreY = InteriorPointArea.avg(this._loY, this._hiY)
}
updateInterval (y) {
if (y <= this._centreY) {
if (y > this._loY) this._loY = y
} else if (y > this._centreY) {
if (y < this._hiY) {
this._hiY = y
}
}
}
getBisectorY () {
this.process(this._poly.getExteriorRing())
for (var i = 0; i < this._poly.getNumInteriorRing(); i++) {
this.process(this._poly.getInteriorRingN(i))
}
var bisectY = InteriorPointArea.avg(this._hiY, this._loY)
return bisectY
}
process (line) {
var seq = line.getCoordinateSequence()
for (var i = 0; i < seq.size(); i++) {
var y = seq.getY(i)
this.updateInterval(y)
}
}
interfaces_ () {
return []
}
getClass () {
return SafeBisectorFinder
}
static getBisectorY (poly) {
var finder = new SafeBisectorFinder(poly)
return finder.getBisectorY()
}
}

View File

@@ -0,0 +1,68 @@
import LineString from '../geom/LineString'
import Geometry from '../geom/Geometry'
import Coordinate from '../geom/Coordinate'
import Double from '../../../../java/lang/Double'
import GeometryCollection from '../geom/GeometryCollection'
export default class InteriorPointLine {
constructor () {
this._centroid = null
this._minDistance = Double.MAX_VALUE
this._interiorPoint = null
const g = arguments[0]
this._centroid = g.getCentroid().getCoordinate()
this.addInterior(g)
if (this._interiorPoint === null) this.addEndpoints(g)
}
addEndpoints () {
if (arguments[0] instanceof Geometry) {
const geom = arguments[0]
if (geom instanceof LineString) {
this.addEndpoints(geom.getCoordinates())
} else if (geom instanceof GeometryCollection) {
const gc = geom
for (let i = 0; i < gc.getNumGeometries(); i++) {
this.addEndpoints(gc.getGeometryN(i))
}
}
} else if (arguments[0] instanceof Array) {
const pts = arguments[0]
this.add(pts[0])
this.add(pts[pts.length - 1])
}
}
getInteriorPoint () {
return this._interiorPoint
}
addInterior () {
if (arguments[0] instanceof Geometry) {
const geom = arguments[0]
if (geom instanceof LineString) {
this.addInterior(geom.getCoordinates())
} else if (geom instanceof GeometryCollection) {
const gc = geom
for (let i = 0; i < gc.getNumGeometries(); i++) {
this.addInterior(gc.getGeometryN(i))
}
}
} else if (arguments[0] instanceof Array) {
const pts = arguments[0]
for (let i = 1; i < pts.length - 1; i++) {
this.add(pts[i])
}
}
}
add (point) {
const dist = point.distance(this._centroid)
if (dist < this._minDistance) {
this._interiorPoint = new Coordinate(point)
this._minDistance = dist
}
}
interfaces_ () {
return []
}
getClass () {
return InteriorPointLine
}
}

View File

@@ -0,0 +1,45 @@
import Geometry from '../geom/Geometry'
import Coordinate from '../geom/Coordinate'
import Point from '../geom/Point'
import Double from '../../../../java/lang/Double'
import GeometryCollection from '../geom/GeometryCollection'
export default class InteriorPointPoint {
constructor () {
this._centroid = null
this._minDistance = Double.MAX_VALUE
this._interiorPoint = null
let g = arguments[0]
this._centroid = g.getCentroid().getCoordinate()
this.add(g)
}
getInteriorPoint () {
return this._interiorPoint
}
add () {
if (arguments[0] instanceof Geometry) {
let geom = arguments[0]
if (geom instanceof Point) {
this.add(geom.getCoordinate())
} else if (geom instanceof GeometryCollection) {
var gc = geom
for (var i = 0; i < gc.getNumGeometries(); i++) {
this.add(gc.getGeometryN(i))
}
}
} else if (arguments[0] instanceof Coordinate) {
let point = arguments[0]
var dist = point.distance(this._centroid)
if (dist < this._minDistance) {
this._interiorPoint = new Coordinate(point)
this._minDistance = dist
}
}
}
interfaces_ () {
return []
}
getClass () {
return InteriorPointPoint
}
}

View File

@@ -0,0 +1,156 @@
import StringBuffer from '../../../../java/lang/StringBuffer'
import WKTWriter from '../io/WKTWriter'
import Coordinate from '../geom/Coordinate'
import Assert from '../util/Assert'
export default class LineIntersector {
constructor () {
this._result = null
this._inputLines = Array(2).fill().map(() => Array(2))
this._intPt = new Array(2).fill(null)
this._intLineIndex = null
this._isProper = null
this._pa = null
this._pb = null
this._precisionModel = null
this._intPt[0] = new Coordinate()
this._intPt[1] = new Coordinate()
this._pa = this._intPt[0]
this._pb = this._intPt[1]
this._result = 0
}
getIndexAlongSegment (segmentIndex, intIndex) {
this.computeIntLineIndex()
return this._intLineIndex[segmentIndex][intIndex]
}
getTopologySummary () {
var catBuf = new StringBuffer()
if (this.isEndPoint()) catBuf.append(' endpoint')
if (this._isProper) catBuf.append(' proper')
if (this.isCollinear()) catBuf.append(' collinear')
return catBuf.toString()
}
computeIntersection (p1, p2, p3, p4) {
this._inputLines[0][0] = p1
this._inputLines[0][1] = p2
this._inputLines[1][0] = p3
this._inputLines[1][1] = p4
this._result = this.computeIntersect(p1, p2, p3, p4)
}
getIntersectionNum () {
return this._result
}
computeIntLineIndex () {
if (arguments.length === 0) {
if (this._intLineIndex === null) {
this._intLineIndex = Array(2).fill().map(() => Array(2))
this.computeIntLineIndex(0)
this.computeIntLineIndex(1)
}
} else if (arguments.length === 1) {
let segmentIndex = arguments[0]
var dist0 = this.getEdgeDistance(segmentIndex, 0)
var dist1 = this.getEdgeDistance(segmentIndex, 1)
if (dist0 > dist1) {
this._intLineIndex[segmentIndex][0] = 0
this._intLineIndex[segmentIndex][1] = 1
} else {
this._intLineIndex[segmentIndex][0] = 1
this._intLineIndex[segmentIndex][1] = 0
}
}
}
isProper () {
return this.hasIntersection() && this._isProper
}
setPrecisionModel (precisionModel) {
this._precisionModel = precisionModel
}
isInteriorIntersection () {
if (arguments.length === 0) {
if (this.isInteriorIntersection(0)) return true
if (this.isInteriorIntersection(1)) return true
return false
} else if (arguments.length === 1) {
let inputLineIndex = arguments[0]
for (var i = 0; i < this._result; i++) {
if (!(this._intPt[i].equals2D(this._inputLines[inputLineIndex][0]) || this._intPt[i].equals2D(this._inputLines[inputLineIndex][1]))) {
return true
}
}
return false
}
}
getIntersection (intIndex) {
return this._intPt[intIndex]
}
isEndPoint () {
return this.hasIntersection() && !this._isProper
}
hasIntersection () {
return this._result !== LineIntersector.NO_INTERSECTION
}
getEdgeDistance (segmentIndex, intIndex) {
var dist = LineIntersector.computeEdgeDistance(this._intPt[intIndex], this._inputLines[segmentIndex][0], this._inputLines[segmentIndex][1])
return dist
}
isCollinear () {
return this._result === LineIntersector.COLLINEAR_INTERSECTION
}
toString () {
return WKTWriter.toLineString(this._inputLines[0][0], this._inputLines[0][1]) + ' - ' + WKTWriter.toLineString(this._inputLines[1][0], this._inputLines[1][1]) + this.getTopologySummary()
}
getEndpoint (segmentIndex, ptIndex) {
return this._inputLines[segmentIndex][ptIndex]
}
isIntersection (pt) {
for (var i = 0; i < this._result; i++) {
if (this._intPt[i].equals2D(pt)) {
return true
}
}
return false
}
getIntersectionAlongSegment (segmentIndex, intIndex) {
this.computeIntLineIndex()
return this._intPt[this._intLineIndex[segmentIndex][intIndex]]
}
interfaces_ () {
return []
}
getClass () {
return LineIntersector
}
static computeEdgeDistance (p, p0, p1) {
var dx = Math.abs(p1.x - p0.x)
var dy = Math.abs(p1.y - p0.y)
var dist = -1.0
if (p.equals(p0)) {
dist = 0.0
} else if (p.equals(p1)) {
if (dx > dy) dist = dx; else dist = dy
} else {
var pdx = Math.abs(p.x - p0.x)
var pdy = Math.abs(p.y - p0.y)
if (dx > dy) dist = pdx; else dist = pdy
if (dist === 0.0 && !p.equals(p0)) {
dist = Math.max(pdx, pdy)
}
}
Assert.isTrue(!(dist === 0.0 && !p.equals(p0)), 'Bad distance calculation')
return dist
}
static nonRobustComputeEdgeDistance (p, p1, p2) {
var dx = p.x - p1.x
var dy = p.y - p1.y
var dist = Math.sqrt(dx * dx + dy * dy)
Assert.isTrue(!(dist === 0.0 && !p.equals(p1)), 'Invalid distance calculation')
return dist
}
static get DONT_INTERSECT () { return 0 }
static get DO_INTERSECT () { return 1 }
static get COLLINEAR () { return 2 }
static get NO_INTERSECTION () { return 0 }
static get POINT_INTERSECTION () { return 1 }
static get COLLINEAR_INTERSECTION () { return 2 }
}

View File

@@ -0,0 +1,102 @@
import MonotoneChainSelectAction from '../index/chain/MonotoneChainSelectAction'
import Bintree from '../index/bintree/Bintree'
import Interval from '../index/bintree/Interval'
import Double from '../../../../java/lang/Double'
import MonotoneChainBuilder from '../index/chain/MonotoneChainBuilder'
import CoordinateArrays from '../geom/CoordinateArrays'
import RobustDeterminant from './RobustDeterminant'
import Envelope from '../geom/Envelope'
import PointInRing from './PointInRing'
export default class MCPointInRing {
constructor () {
this._ring = null
this._tree = null
this._crossings = 0
this._interval = new Interval()
const ring = arguments[0]
this._ring = ring
this.buildIndex()
}
testLineSegment (p, seg) {
let xInt = null
let x1 = null
let y1 = null
let x2 = null
let y2 = null
const p1 = seg.p0
const p2 = seg.p1
x1 = p1.x - p.x
y1 = p1.y - p.y
x2 = p2.x - p.x
y2 = p2.y - p.y
if ((y1 > 0 && y2 <= 0) || (y2 > 0 && y1 <= 0)) {
xInt = RobustDeterminant.signOfDet2x2(x1, y1, x2, y2) / (y2 - y1)
if (xInt > 0.0) {
this._crossings++
}
}
}
buildIndex () {
this._tree = new Bintree()
const pts = CoordinateArrays.removeRepeatedPoints(this._ring.getCoordinates())
const mcList = MonotoneChainBuilder.getChains(pts)
for (let i = 0; i < mcList.size(); i++) {
const mc = mcList.get(i)
const mcEnv = mc.getEnvelope()
this._interval.min = mcEnv.getMinY()
this._interval.max = mcEnv.getMaxY()
this._tree.insert(this._interval, mc)
}
}
testMonotoneChain (rayEnv, mcSelecter, mc) {
mc.select(rayEnv, mcSelecter)
}
isInside (pt) {
this._crossings = 0
const rayEnv = new Envelope(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, pt.y, pt.y)
this._interval.min = pt.y
this._interval.max = pt.y
const segs = this._tree.query(this._interval)
const mcSelecter = new MCSelecter(this, pt)
for (const i = segs.iterator(); i.hasNext();) {
const mc = i.next()
this.testMonotoneChain(rayEnv, mcSelecter, mc)
}
if (this._crossings % 2 === 1) {
return true
}
return false
}
interfaces_ () {
return [PointInRing]
}
getClass () {
return MCPointInRing
}
static get MCSelecter () { return MCSelecter }
}
class MCSelecter extends MonotoneChainSelectAction {
constructor () {
super()
this.mcp = null
this.p = null
const mcp = arguments[0]
const p = arguments[1]
this.mcp = mcp
this.p = p
}
select () {
if (arguments.length === 1) {
const ls = arguments[0]
this.mcp.testLineSegment(this.p, ls)
} else return MonotoneChainSelectAction.prototype.select.apply(this, arguments)
}
interfaces_ () {
return []
}
getClass () {
return MCSelecter
}
}

View File

@@ -0,0 +1,170 @@
import Coordinate from '../geom/Coordinate'
import Double from '../../../../java/lang/Double'
import CoordinateArrays from '../geom/CoordinateArrays'
import Angle from './Angle'
import Assert from '../util/Assert'
import Triangle from '../geom/Triangle'
export default class MinimumBoundingCircle {
constructor () {
this._input = null
this._extremalPts = null
this._centre = null
this._radius = 0.0
let geom = arguments[0]
this._input = geom
}
getRadius () {
this.compute()
return this._radius
}
getDiameter () {
this.compute()
switch (this._extremalPts.length) {
case 0:
return this._input.getFactory().createLineString()
case 1:
return this._input.getFactory().createPoint(this._centre)
}
const p0 = this._extremalPts[0]
const p1 = this._extremalPts[1]
return this._input.getFactory().createLineString([p0, p1])
}
getExtremalPoints () {
this.compute()
return this._extremalPts
}
computeCirclePoints () {
if (this._input.isEmpty()) {
this._extremalPts = new Array(0).fill(null)
return null
}
if (this._input.getNumPoints() === 1) {
const pts = this._input.getCoordinates()
this._extremalPts = [new Coordinate(pts[0])]
return null
}
const convexHull = this._input.convexHull()
const hullPts = convexHull.getCoordinates()
let pts = hullPts
if (hullPts[0].equals2D(hullPts[hullPts.length - 1])) {
pts = new Array(hullPts.length - 1).fill(null)
CoordinateArrays.copyDeep(hullPts, 0, pts, 0, hullPts.length - 1)
}
if (pts.length <= 2) {
this._extremalPts = CoordinateArrays.copyDeep(pts)
return null
}
let P = MinimumBoundingCircle.lowestPoint(pts)
let Q = MinimumBoundingCircle.pointWitMinAngleWithX(pts, P)
for (let i = 0; i < pts.length; i++) {
const R = MinimumBoundingCircle.pointWithMinAngleWithSegment(pts, P, Q)
if (Angle.isObtuse(P, R, Q)) {
this._extremalPts = [new Coordinate(P), new Coordinate(Q)]
return null
}
if (Angle.isObtuse(R, P, Q)) {
P = R
continue
}
if (Angle.isObtuse(R, Q, P)) {
Q = R
continue
}
this._extremalPts = [new Coordinate(P), new Coordinate(Q), new Coordinate(R)]
return null
}
Assert.shouldNeverReachHere('Logic failure in Minimum Bounding Circle algorithm!')
}
compute () {
if (this._extremalPts !== null) return null
this.computeCirclePoints()
this.computeCentre()
if (this._centre !== null) this._radius = this._centre.distance(this._extremalPts[0])
}
getFarthestPoints () {
this.compute()
switch (this._extremalPts.length) {
case 0:
return this._input.getFactory().createLineString()
case 1:
return this._input.getFactory().createPoint(this._centre)
}
const p0 = this._extremalPts[0]
const p1 = this._extremalPts[this._extremalPts.length - 1]
return this._input.getFactory().createLineString([p0, p1])
}
getCircle () {
this.compute()
if (this._centre === null) return this._input.getFactory().createPolygon()
const centrePoint = this._input.getFactory().createPoint(this._centre)
if (this._radius === 0.0) return centrePoint
return centrePoint.buffer(this._radius)
}
getCentre () {
this.compute()
return this._centre
}
computeCentre () {
switch (this._extremalPts.length) {
case 0:
this._centre = null
break
case 1:
this._centre = this._extremalPts[0]
break
case 2:
this._centre = new Coordinate((this._extremalPts[0].x + this._extremalPts[1].x) / 2.0, (this._extremalPts[0].y + this._extremalPts[1].y) / 2.0)
break
case 3:
this._centre = Triangle.circumcentre(this._extremalPts[0], this._extremalPts[1], this._extremalPts[2])
break
}
}
interfaces_ () {
return []
}
getClass () {
return MinimumBoundingCircle
}
static pointWitMinAngleWithX (pts, P) {
let minSin = Double.MAX_VALUE
let minAngPt = null
for (let i = 0; i < pts.length; i++) {
const p = pts[i]
if (p === P) continue
const dx = p.x - P.x
let dy = p.y - P.y
if (dy < 0) dy = -dy
const len = Math.sqrt(dx * dx + dy * dy)
const sin = dy / len
if (sin < minSin) {
minSin = sin
minAngPt = p
}
}
return minAngPt
}
static lowestPoint (pts) {
let min = pts[0]
for (let i = 1; i < pts.length; i++) {
if (pts[i].y < min.y) min = pts[i]
}
return min
}
static pointWithMinAngleWithSegment (pts, P, Q) {
let minAng = Double.MAX_VALUE
let minAngPt = null
for (let i = 0; i < pts.length; i++) {
const p = pts[i]
if (p === P) continue
if (p === Q) continue
const ang = Angle.angleBetween(P, p, Q)
if (ang < minAng) {
minAng = ang
minAngPt = p
}
}
return minAngPt
}
}

View File

@@ -0,0 +1,165 @@
import Coordinate from '../geom/Coordinate'
import Polygon from '../geom/Polygon'
import Double from '../../../../java/lang/Double'
import LineSegment from '../geom/LineSegment'
import ConvexHull from './ConvexHull'
export default class MinimumDiameter {
constructor () {
this._inputGeom = null
this._isConvex = null
this._convexHullPts = null
this._minBaseSeg = new LineSegment()
this._minWidthPt = null
this._minPtIndex = null
this._minWidth = 0.0
if (arguments.length === 1) {
const inputGeom = arguments[0]
const isConvex = false
this._inputGeom = inputGeom
this._isConvex = isConvex
} else if (arguments.length === 2) {
const inputGeom = arguments[0]
const isConvex = arguments[1]
this._inputGeom = inputGeom
this._isConvex = isConvex
}
}
getWidthCoordinate () {
this.computeMinimumDiameter()
return this._minWidthPt
}
getSupportingSegment () {
this.computeMinimumDiameter()
return this._inputGeom.getFactory().createLineString([this._minBaseSeg.p0, this._minBaseSeg.p1])
}
getDiameter () {
this.computeMinimumDiameter()
if (this._minWidthPt === null) return this._inputGeom.getFactory().createLineString(null)
const basePt = this._minBaseSeg.project(this._minWidthPt)
return this._inputGeom.getFactory().createLineString([basePt, this._minWidthPt])
}
computeWidthConvex (convexGeom) {
if (convexGeom instanceof Polygon) this._convexHullPts = convexGeom.getExteriorRing().getCoordinates(); else this._convexHullPts = convexGeom.getCoordinates()
if (this._convexHullPts.length === 0) {
this._minWidth = 0.0
this._minWidthPt = null
this._minBaseSeg = null
} else if (this._convexHullPts.length === 1) {
this._minWidth = 0.0
this._minWidthPt = this._convexHullPts[0]
this._minBaseSeg.p0 = this._convexHullPts[0]
this._minBaseSeg.p1 = this._convexHullPts[0]
} else if (this._convexHullPts.length === 2 || this._convexHullPts.length === 3) {
this._minWidth = 0.0
this._minWidthPt = this._convexHullPts[0]
this._minBaseSeg.p0 = this._convexHullPts[0]
this._minBaseSeg.p1 = this._convexHullPts[1]
} else this.computeConvexRingMinDiameter(this._convexHullPts)
}
computeConvexRingMinDiameter (pts) {
this._minWidth = Double.MAX_VALUE
let currMaxIndex = 1
const seg = new LineSegment()
for (let i = 0; i < pts.length - 1; i++) {
seg.p0 = pts[i]
seg.p1 = pts[i + 1]
currMaxIndex = this.findMaxPerpDistance(pts, seg, currMaxIndex)
}
}
computeMinimumDiameter () {
if (this._minWidthPt !== null) return null
if (this._isConvex) this.computeWidthConvex(this._inputGeom); else {
const convexGeom = new ConvexHull(this._inputGeom).getConvexHull()
this.computeWidthConvex(convexGeom)
}
}
getLength () {
this.computeMinimumDiameter()
return this._minWidth
}
findMaxPerpDistance (pts, seg, startIndex) {
let maxPerpDistance = seg.distancePerpendicular(pts[startIndex])
let nextPerpDistance = maxPerpDistance
let maxIndex = startIndex
let nextIndex = maxIndex
while (nextPerpDistance >= maxPerpDistance) {
maxPerpDistance = nextPerpDistance
maxIndex = nextIndex
nextIndex = MinimumDiameter.nextIndex(pts, maxIndex)
nextPerpDistance = seg.distancePerpendicular(pts[nextIndex])
}
if (maxPerpDistance < this._minWidth) {
this._minPtIndex = maxIndex
this._minWidth = maxPerpDistance
this._minWidthPt = pts[this._minPtIndex]
this._minBaseSeg = new LineSegment(seg)
}
return maxIndex
}
getMinimumRectangle () {
this.computeMinimumDiameter()
if (this._minWidth === 0.0) {
if (this._minBaseSeg.p0.equals2D(this._minBaseSeg.p1)) {
return this._inputGeom.getFactory().createPoint(this._minBaseSeg.p0)
}
return this._minBaseSeg.toGeometry(this._inputGeom.getFactory())
}
const dx = this._minBaseSeg.p1.x - this._minBaseSeg.p0.x
const dy = this._minBaseSeg.p1.y - this._minBaseSeg.p0.y
let minPara = Double.MAX_VALUE
let maxPara = -Double.MAX_VALUE
let minPerp = Double.MAX_VALUE
let maxPerp = -Double.MAX_VALUE
for (let i = 0; i < this._convexHullPts.length; i++) {
const paraC = MinimumDiameter.computeC(dx, dy, this._convexHullPts[i])
if (paraC > maxPara) maxPara = paraC
if (paraC < minPara) minPara = paraC
const perpC = MinimumDiameter.computeC(-dy, dx, this._convexHullPts[i])
if (perpC > maxPerp) maxPerp = perpC
if (perpC < minPerp) minPerp = perpC
}
const maxPerpLine = MinimumDiameter.computeSegmentForLine(-dx, -dy, maxPerp)
const minPerpLine = MinimumDiameter.computeSegmentForLine(-dx, -dy, minPerp)
const maxParaLine = MinimumDiameter.computeSegmentForLine(-dy, dx, maxPara)
const minParaLine = MinimumDiameter.computeSegmentForLine(-dy, dx, minPara)
const p0 = maxParaLine.lineIntersection(maxPerpLine)
const p1 = minParaLine.lineIntersection(maxPerpLine)
const p2 = minParaLine.lineIntersection(minPerpLine)
const p3 = maxParaLine.lineIntersection(minPerpLine)
const shell = this._inputGeom.getFactory().createLinearRing([p0, p1, p2, p3, p0])
return this._inputGeom.getFactory().createPolygon(shell, null)
}
interfaces_ () {
return []
}
getClass () {
return MinimumDiameter
}
static nextIndex (pts, index) {
index++
if (index >= pts.length) index = 0
return index
}
static computeC (a, b, p) {
return a * p.y - b * p.x
}
static getMinimumDiameter (geom) {
return new MinimumDiameter(geom).getDiameter()
}
static getMinimumRectangle (geom) {
return new MinimumDiameter(geom).getMinimumRectangle()
}
static computeSegmentForLine (a, b, c) {
let p0 = null
let p1 = null
if (Math.abs(b) > Math.abs(a)) {
p0 = new Coordinate(0.0, c / b)
p1 = new Coordinate(1.0, c / b - a / b)
} else {
p0 = new Coordinate(c / a, 0.0)
p1 = new Coordinate(c / a - b / a, 1.0)
}
return new LineSegment(p0, p1)
}
}

View File

@@ -0,0 +1,123 @@
import CGAlgorithms from './CGAlgorithms'
import IllegalArgumentException from '../../../../java/lang/IllegalArgumentException'
export default class NonRobustCGAlgorithms extends CGAlgorithms {
interfaces_ () {
return []
}
getClass () {
return NonRobustCGAlgorithms
}
static orientationIndex () {
if (arguments.length === 3) {
const p1 = arguments[0]
const p2 = arguments[1]
const q = arguments[2]
const dx1 = p2.x - p1.x
const dy1 = p2.y - p1.y
const dx2 = q.x - p2.x
const dy2 = q.y - p2.y
const det = dx1 * dy2 - dx2 * dy1
if (det > 0.0) return 1
if (det < 0.0) return -1
return 0
} else return CGAlgorithms.prototype.orientationIndex.apply(this, arguments)
}
static distanceLineLine () {
if (arguments.length === 4) {
const A = arguments[0]
const B = arguments[1]
const C = arguments[2]
const D = arguments[3]
if (A.equals(B)) return CGAlgorithms.distancePointLine(A, C, D)
if (C.equals(D)) return CGAlgorithms.distancePointLine(D, A, B)
const rTop = (A.y - C.y) * (D.x - C.x) - (A.x - C.x) * (D.y - C.y)
const rBot = (B.x - A.x) * (D.y - C.y) - (B.y - A.y) * (D.x - C.x)
const sTop = (A.y - C.y) * (B.x - A.x) - (A.x - C.x) * (B.y - A.y)
const sBot = (B.x - A.x) * (D.y - C.y) - (B.y - A.y) * (D.x - C.x)
if (rBot === 0 || sBot === 0) {
return Math.min(CGAlgorithms.distancePointLine(A, C, D), Math.min(CGAlgorithms.distancePointLine(B, C, D), Math.min(CGAlgorithms.distancePointLine(C, A, B), CGAlgorithms.distancePointLine(D, A, B))))
}
const s = sTop / sBot
const r = rTop / rBot
if (r < 0 || r > 1 || s < 0 || s > 1) {
return Math.min(CGAlgorithms.distancePointLine(A, C, D), Math.min(CGAlgorithms.distancePointLine(B, C, D), Math.min(CGAlgorithms.distancePointLine(C, A, B), CGAlgorithms.distancePointLine(D, A, B))))
}
return 0.0
} else return CGAlgorithms.prototype.distanceLineLine.apply(this, arguments)
}
static isPointInRing () {
if (arguments.length === 2) {
const p = arguments[0]
const ring = arguments[1]
let i = null
let i1 = null
let xInt = null
let crossings = 0
let x1 = null
let y1 = null
let x2 = null
let y2 = null
const nPts = ring.length
for ((i = 1); i < nPts; i++) {
i1 = i - 1
const p1 = ring[i]
const p2 = ring[i1]
x1 = p1.x - p.x
y1 = p1.y - p.y
x2 = p2.x - p.x
y2 = p2.y - p.y
if ((y1 > 0 && y2 <= 0) || (y2 > 0 && y1 <= 0)) {
xInt = (x1 * y2 - x2 * y1) / (y2 - y1)
if (xInt > 0.0) crossings++
}
}
if (crossings % 2 === 1) return true; else return false
} else return CGAlgorithms.prototype.isPointInRing.apply(this, arguments)
}
static isCCW () {
if (arguments.length === 1) {
const ring = arguments[0]
const nPts = ring.length - 1
if (nPts < 4) return false
let hip = ring[0]
let hii = 0
for (let i = 1; i <= nPts; i++) {
const p = ring[i]
if (p.y > hip.y) {
hip = p
hii = i
}
}
let iPrev = hii
do {
iPrev = (iPrev - 1) % nPts
} while (ring[iPrev].equals(hip) && iPrev !== hii)
let iNext = hii
do {
iNext = (iNext + 1) % nPts
} while (ring[iNext].equals(hip) && iNext !== hii)
const prev = ring[iPrev]
const next = ring[iNext]
if (prev.equals(hip) || next.equals(hip) || prev.equals(next)) throw new IllegalArgumentException('degenerate ring (does not contain 3 different points)')
const prev2x = prev.x - hip.x
const prev2y = prev.y - hip.y
const next2x = next.x - hip.x
const next2y = next.y - hip.y
const disc = next2x * prev2y - next2y * prev2x
if (disc === 0.0) {
return prev.x > next.x
} else {
return disc > 0.0
}
} else return CGAlgorithms.prototype.isCCW.apply(this, arguments)
}
static computeOrientation () {
if (arguments.length === 3) {
const p1 = arguments[0]
const p2 = arguments[1]
const q = arguments[2]
return NonRobustCGAlgorithms.orientationIndex(p1, p2, q)
} else return CGAlgorithms.prototype.computeOrientation.apply(this, arguments)
}
}

View File

@@ -0,0 +1,147 @@
import LineIntersector from './LineIntersector'
export default class NonRobustLineIntersector extends LineIntersector {
computeIntersection () {
if (arguments.length === 3) {
const p = arguments[0]
const p1 = arguments[1]
const p2 = arguments[2]
let a1 = null
let b1 = null
let c1 = null
let r = null
this._isProper = false
a1 = p2.y - p1.y
b1 = p1.x - p2.x
c1 = p2.x * p1.y - p1.x * p2.y
r = a1 * p.x + b1 * p.y + c1
if (r !== 0) {
this._result = LineIntersector.NO_INTERSECTION
return null
}
const dist = this.rParameter(p1, p2, p)
if (dist < 0.0 || dist > 1.0) {
this._result = LineIntersector.NO_INTERSECTION
return null
}
this._isProper = true
if (p.equals(p1) || p.equals(p2)) {
this._isProper = false
}
this._result = LineIntersector.POINT_INTERSECTION
} else return LineIntersector.prototype.computeIntersection.apply(this, arguments)
}
computeCollinearIntersection (p1, p2, p3, p4) {
let r1 = null
let r2 = null
let r3 = null
let r4 = null
let q3 = null
let q4 = null
let t3 = null
let t4 = null
r1 = 0
r2 = 1
r3 = this.rParameter(p1, p2, p3)
r4 = this.rParameter(p1, p2, p4)
if (r3 < r4) {
q3 = p3
t3 = r3
q4 = p4
t4 = r4
} else {
q3 = p4
t3 = r4
q4 = p3
t4 = r3
}
if (t3 > r2 || t4 < r1) {
return LineIntersector.NO_INTERSECTION
}
if (q4 === p1) {
this._pa.setCoordinate(p1)
return LineIntersector.POINT_INTERSECTION
}
if (q3 === p2) {
this._pa.setCoordinate(p2)
return LineIntersector.POINT_INTERSECTION
}
this._pa.setCoordinate(p1)
if (t3 > r1) {
this._pa.setCoordinate(q3)
}
this._pb.setCoordinate(p2)
if (t4 < r2) {
this._pb.setCoordinate(q4)
}
return LineIntersector.COLLINEAR_INTERSECTION
}
rParameter (p1, p2, p) {
let r = null
const dx = Math.abs(p2.x - p1.x)
const dy = Math.abs(p2.y - p1.y)
if (dx > dy) {
r = (p.x - p1.x) / (p2.x - p1.x)
} else {
r = (p.y - p1.y) / (p2.y - p1.y)
}
return r
}
computeIntersect (p1, p2, p3, p4) {
let a1 = null
let b1 = null
let c1 = null
let a2 = null
let b2 = null
let c2 = null
let r1 = null
let r2 = null
let r3 = null
let r4 = null
this._isProper = false
a1 = p2.y - p1.y
b1 = p1.x - p2.x
c1 = p2.x * p1.y - p1.x * p2.y
r3 = a1 * p3.x + b1 * p3.y + c1
r4 = a1 * p4.x + b1 * p4.y + c1
if (r3 !== 0 && r4 !== 0 && NonRobustLineIntersector.isSameSignAndNonZero(r3, r4)) {
return LineIntersector.NO_INTERSECTION
}
a2 = p4.y - p3.y
b2 = p3.x - p4.x
c2 = p4.x * p3.y - p3.x * p4.y
r1 = a2 * p1.x + b2 * p1.y + c2
r2 = a2 * p2.x + b2 * p2.y + c2
if (r1 !== 0 && r2 !== 0 && NonRobustLineIntersector.isSameSignAndNonZero(r1, r2)) {
return LineIntersector.NO_INTERSECTION
}
const denom = a1 * b2 - a2 * b1
if (denom === 0) {
return this.computeCollinearIntersection(p1, p2, p3, p4)
}
const numX = b1 * c2 - b2 * c1
this._pa.x = numX / denom
const numY = a2 * c1 - a1 * c2
this._pa.y = numY / denom
this._isProper = true
if (this._pa.equals(p1) || this._pa.equals(p2) || this._pa.equals(p3) || this._pa.equals(p4)) {
this._isProper = false
}
if (this._precisionModel !== null) {
this._precisionModel.makePrecise(this._pa)
}
return LineIntersector.POINT_INTERSECTION
}
interfaces_ () {
return []
}
getClass () {
return NonRobustLineIntersector
}
static isSameSignAndNonZero (a, b) {
if (a === 0 || b === 0) {
return false
}
return (a < 0 && b < 0) || (a > 0 && b > 0)
}
}

View File

@@ -0,0 +1,13 @@
import Exception from '../../../../java/lang/Exception'
export default class NotRepresentableException extends Exception {
constructor () {
super('Projective point not representable on the Cartesian plane.')
}
interfaces_ () {
return []
}
getClass () {
return NotRepresentableException
}
}

View File

@@ -0,0 +1,9 @@
export default class PointInRing {
isInside (pt) {}
interfaces_ () {
return []
}
getClass () {
return PointInRing
}
}

View File

@@ -0,0 +1,120 @@
import Location from '../geom/Location'
import LineString from '../geom/LineString'
import CGAlgorithms from './CGAlgorithms'
import Coordinate from '../geom/Coordinate'
import IllegalArgumentException from '../../../../java/lang/IllegalArgumentException'
import Point from '../geom/Point'
import Polygon from '../geom/Polygon'
import BoundaryNodeRule from './BoundaryNodeRule'
import MultiPolygon from '../geom/MultiPolygon'
import GeometryCollectionIterator from '../geom/GeometryCollectionIterator'
import GeometryCollection from '../geom/GeometryCollection'
import MultiLineString from '../geom/MultiLineString'
export default class PointLocator {
constructor () {
this._boundaryRule = BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE
this._isIn = null
this._numBoundaries = null
if (arguments.length === 0) {} else if (arguments.length === 1) {
let boundaryRule = arguments[0]
if (boundaryRule === null) throw new IllegalArgumentException('Rule must be non-null')
this._boundaryRule = boundaryRule
}
}
locateInternal () {
if (arguments[0] instanceof Coordinate && arguments[1] instanceof Polygon) {
const p = arguments[0]
const poly = arguments[1]
if (poly.isEmpty()) return Location.EXTERIOR
const shell = poly.getExteriorRing()
const shellLoc = this.locateInPolygonRing(p, shell)
if (shellLoc === Location.EXTERIOR) return Location.EXTERIOR
if (shellLoc === Location.BOUNDARY) return Location.BOUNDARY
for (let i = 0; i < poly.getNumInteriorRing(); i++) {
const hole = poly.getInteriorRingN(i)
const holeLoc = this.locateInPolygonRing(p, hole)
if (holeLoc === Location.INTERIOR) return Location.EXTERIOR
if (holeLoc === Location.BOUNDARY) return Location.BOUNDARY
}
return Location.INTERIOR
} else if (arguments[0] instanceof Coordinate && arguments[1] instanceof LineString) {
const p = arguments[0]
const l = arguments[1]
if (!l.getEnvelopeInternal().intersects(p)) return Location.EXTERIOR
const pt = l.getCoordinates()
if (!l.isClosed()) {
if (p.equals(pt[0]) || p.equals(pt[pt.length - 1])) {
return Location.BOUNDARY
}
}
if (CGAlgorithms.isOnLine(p, pt)) return Location.INTERIOR
return Location.EXTERIOR
} else if (arguments[0] instanceof Coordinate && arguments[1] instanceof Point) {
const p = arguments[0]
const pt = arguments[1]
const ptCoord = pt.getCoordinate()
if (ptCoord.equals2D(p)) return Location.INTERIOR
return Location.EXTERIOR
}
}
locateInPolygonRing (p, ring) {
if (!ring.getEnvelopeInternal().intersects(p)) return Location.EXTERIOR
return CGAlgorithms.locatePointInRing(p, ring.getCoordinates())
}
intersects (p, geom) {
return this.locate(p, geom) !== Location.EXTERIOR
}
updateLocationInfo (loc) {
if (loc === Location.INTERIOR) this._isIn = true
if (loc === Location.BOUNDARY) this._numBoundaries++
}
computeLocation (p, geom) {
if (geom instanceof Point) {
this.updateLocationInfo(this.locateInternal(p, geom))
}
if (geom instanceof LineString) {
this.updateLocationInfo(this.locateInternal(p, geom))
} else if (geom instanceof Polygon) {
this.updateLocationInfo(this.locateInternal(p, geom))
} else if (geom instanceof MultiLineString) {
const ml = geom
for (let i = 0; i < ml.getNumGeometries(); i++) {
const l = ml.getGeometryN(i)
this.updateLocationInfo(this.locateInternal(p, l))
}
} else if (geom instanceof MultiPolygon) {
const mpoly = geom
for (let i = 0; i < mpoly.getNumGeometries(); i++) {
const poly = mpoly.getGeometryN(i)
this.updateLocationInfo(this.locateInternal(p, poly))
}
} else if (geom instanceof GeometryCollection) {
const geomi = new GeometryCollectionIterator(geom)
while (geomi.hasNext()) {
const g2 = geomi.next()
if (g2 !== geom) this.computeLocation(p, g2)
}
}
}
locate (p, geom) {
if (geom.isEmpty()) return Location.EXTERIOR
if (geom instanceof LineString) {
return this.locateInternal(p, geom)
} else if (geom instanceof Polygon) {
return this.locateInternal(p, geom)
}
this._isIn = false
this._numBoundaries = 0
this.computeLocation(p, geom)
if (this._boundaryRule.isInBoundary(this._numBoundaries)) return Location.BOUNDARY
if (this._numBoundaries > 0 || this._isIn) return Location.INTERIOR
return Location.EXTERIOR
}
interfaces_ () {
return []
}
getClass () {
return PointLocator
}
}

View File

@@ -0,0 +1,95 @@
import Location from '../geom/Location'
import hasInterface from '../../../../hasInterface'
import Coordinate from '../geom/Coordinate'
import CoordinateSequence from '../geom/CoordinateSequence'
import RobustDeterminant from './RobustDeterminant'
export default class RayCrossingCounter {
constructor () {
this._p = null
this._crossingCount = 0
this._isPointOnSegment = false
const p = arguments[0]
this._p = p
}
countSegment (p1, p2) {
if (p1.x < this._p.x && p2.x < this._p.x) return null
if (this._p.x === p2.x && this._p.y === p2.y) {
this._isPointOnSegment = true
return null
}
if (p1.y === this._p.y && p2.y === this._p.y) {
let minx = p1.x
let maxx = p2.x
if (minx > maxx) {
minx = p2.x
maxx = p1.x
}
if (this._p.x >= minx && this._p.x <= maxx) {
this._isPointOnSegment = true
}
return null
}
if ((p1.y > this._p.y && p2.y <= this._p.y) || (p2.y > this._p.y && p1.y <= this._p.y)) {
const x1 = p1.x - this._p.x
const y1 = p1.y - this._p.y
const x2 = p2.x - this._p.x
const y2 = p2.y - this._p.y
let xIntSign = RobustDeterminant.signOfDet2x2(x1, y1, x2, y2)
if (xIntSign === 0.0) {
this._isPointOnSegment = true
return null
}
if (y2 < y1) xIntSign = -xIntSign
if (xIntSign > 0.0) {
this._crossingCount++
}
}
}
isPointInPolygon () {
return this.getLocation() !== Location.EXTERIOR
}
getLocation () {
if (this._isPointOnSegment) return Location.BOUNDARY
if (this._crossingCount % 2 === 1) {
return Location.INTERIOR
}
return Location.EXTERIOR
}
isOnSegment () {
return this._isPointOnSegment
}
interfaces_ () {
return []
}
getClass () {
return RayCrossingCounter
}
static locatePointInRing () {
if (arguments[0] instanceof Coordinate && hasInterface(arguments[1], CoordinateSequence)) {
const p = arguments[0]
const ring = arguments[1]
const counter = new RayCrossingCounter(p)
const p1 = new Coordinate()
const p2 = new Coordinate()
for (let i = 1; i < ring.size(); i++) {
ring.getCoordinate(i, p1)
ring.getCoordinate(i - 1, p2)
counter.countSegment(p1, p2)
if (counter.isOnSegment()) return counter.getLocation()
}
return counter.getLocation()
} else if (arguments[0] instanceof Coordinate && arguments[1] instanceof Array) {
const p = arguments[0]
const ring = arguments[1]
const counter = new RayCrossingCounter(p)
for (let i = 1; i < ring.length; i++) {
const p1 = ring[i]
const p2 = ring[i - 1]
counter.countSegment(p1, p2)
if (counter.isOnSegment()) return counter.getLocation()
}
return counter.getLocation()
}
}
}

View File

@@ -0,0 +1,46 @@
import Coordinate from '../geom/Coordinate'
import RobustLineIntersector from './RobustLineIntersector'
import Envelope from '../geom/Envelope'
export default class RectangleLineIntersector {
constructor () {
this._li = new RobustLineIntersector()
this._rectEnv = null
this._diagUp0 = null
this._diagUp1 = null
this._diagDown0 = null
this._diagDown1 = null
let rectEnv = arguments[0]
this._rectEnv = rectEnv
this._diagUp0 = new Coordinate(rectEnv.getMinX(), rectEnv.getMinY())
this._diagUp1 = new Coordinate(rectEnv.getMaxX(), rectEnv.getMaxY())
this._diagDown0 = new Coordinate(rectEnv.getMinX(), rectEnv.getMaxY())
this._diagDown1 = new Coordinate(rectEnv.getMaxX(), rectEnv.getMinY())
}
intersects (p0, p1) {
var segEnv = new Envelope(p0, p1)
if (!this._rectEnv.intersects(segEnv)) return false
if (this._rectEnv.intersects(p0)) return true
if (this._rectEnv.intersects(p1)) return true
if (p0.compareTo(p1) > 0) {
var tmp = p0
p0 = p1
p1 = tmp
}
var isSegUpwards = false
if (p1.y > p0.y) isSegUpwards = true
if (isSegUpwards) {
this._li.computeIntersection(p0, p1, this._diagDown0, this._diagDown1)
} else {
this._li.computeIntersection(p0, p1, this._diagUp0, this._diagUp1)
}
if (this._li.hasIntersection()) return true
return false
}
interfaces_ () {
return []
}
getClass () {
return RectangleLineIntersector
}
}

View File

@@ -0,0 +1,202 @@
export default class RobustDeterminant {
interfaces_ () {
return []
}
getClass () {
return RobustDeterminant
}
static orientationIndex (p1, p2, q) {
const dx1 = p2.x - p1.x
const dy1 = p2.y - p1.y
const dx2 = q.x - p2.x
const dy2 = q.y - p2.y
return RobustDeterminant.signOfDet2x2(dx1, dy1, dx2, dy2)
}
static signOfDet2x2 (x1, y1, x2, y2) {
let sign = null
let swap = null
let k = null
let count = 0
sign = 1
if (x1 === 0.0 || y2 === 0.0) {
if (y1 === 0.0 || x2 === 0.0) {
return 0
} else if (y1 > 0) {
if (x2 > 0) {
return -sign
} else {
return sign
}
} else {
if (x2 > 0) {
return sign
} else {
return -sign
}
}
}
if (y1 === 0.0 || x2 === 0.0) {
if (y2 > 0) {
if (x1 > 0) {
return sign
} else {
return -sign
}
} else {
if (x1 > 0) {
return -sign
} else {
return sign
}
}
}
if (y1 > 0.0) {
if (y2 > 0.0) {
if (y1 <= y2) {
;
} else {
sign = -sign
swap = x1
x1 = x2
x2 = swap
swap = y1
y1 = y2
y2 = swap
}
} else {
if (y1 <= -y2) {
sign = -sign
x2 = -x2
y2 = -y2
} else {
swap = x1
x1 = -x2
x2 = swap
swap = y1
y1 = -y2
y2 = swap
}
}
} else {
if (y2 > 0.0) {
if (-y1 <= y2) {
sign = -sign
x1 = -x1
y1 = -y1
} else {
swap = -x1
x1 = x2
x2 = swap
swap = -y1
y1 = y2
y2 = swap
}
} else {
if (y1 >= y2) {
x1 = -x1
y1 = -y1
x2 = -x2
y2 = -y2
} else {
sign = -sign
swap = -x1
x1 = -x2
x2 = swap
swap = -y1
y1 = -y2
y2 = swap
}
}
}
if (x1 > 0.0) {
if (x2 > 0.0) {
if (x1 <= x2) {
;
} else {
return sign
}
} else {
return sign
}
} else {
if (x2 > 0.0) {
return -sign
} else {
if (x1 >= x2) {
sign = -sign
x1 = -x1
x2 = -x2
} else {
return -sign
}
}
}
while (true) {
count = count + 1
k = Math.floor(x2 / x1)
x2 = x2 - k * x1
y2 = y2 - k * y1
if (y2 < 0.0) {
return -sign
}
if (y2 > y1) {
return sign
}
if (x1 > x2 + x2) {
if (y1 < y2 + y2) {
return sign
}
} else {
if (y1 > y2 + y2) {
return -sign
} else {
x2 = x1 - x2
y2 = y1 - y2
sign = -sign
}
}
if (y2 === 0.0) {
if (x2 === 0.0) {
return 0
} else {
return -sign
}
}
if (x2 === 0.0) {
return sign
}
k = Math.floor(x1 / x2)
x1 = x1 - k * x2
y1 = y1 - k * y2
if (y1 < 0.0) {
return sign
}
if (y1 > y2) {
return -sign
}
if (x2 > x1 + x1) {
if (y2 < y1 + y1) {
return -sign
}
} else {
if (y2 > y1 + y1) {
return sign
} else {
x1 = x2 - x1
y1 = y2 - y1
sign = -sign
}
}
if (y1 === 0.0) {
if (x1 === 0.0) {
return 0
} else {
return sign
}
}
if (x1 === 0.0) {
return -sign
}
}
}
}

View File

@@ -0,0 +1,231 @@
import NotRepresentableException from './NotRepresentableException'
import CGAlgorithms from './CGAlgorithms'
import Coordinate from '../geom/Coordinate'
import CGAlgorithmsDD from './CGAlgorithmsDD'
import System from '../../../../java/lang/System'
import HCoordinate from './HCoordinate'
import Envelope from '../geom/Envelope'
import LineIntersector from './LineIntersector'
export default class RobustLineIntersector extends LineIntersector {
isInSegmentEnvelopes (intPt) {
const env0 = new Envelope(this._inputLines[0][0], this._inputLines[0][1])
const env1 = new Envelope(this._inputLines[1][0], this._inputLines[1][1])
return env0.contains(intPt) && env1.contains(intPt)
}
computeIntersection () {
if (arguments.length === 3) {
const p = arguments[0]
const p1 = arguments[1]
const p2 = arguments[2]
this._isProper = false
if (Envelope.intersects(p1, p2, p)) {
if (CGAlgorithms.orientationIndex(p1, p2, p) === 0 && CGAlgorithms.orientationIndex(p2, p1, p) === 0) {
this._isProper = true
if (p.equals(p1) || p.equals(p2)) {
this._isProper = false
}
this._result = LineIntersector.POINT_INTERSECTION
return null
}
}
this._result = LineIntersector.NO_INTERSECTION
} else return LineIntersector.prototype.computeIntersection.apply(this, arguments)
}
normalizeToMinimum (n1, n2, n3, n4, normPt) {
normPt.x = this.smallestInAbsValue(n1.x, n2.x, n3.x, n4.x)
normPt.y = this.smallestInAbsValue(n1.y, n2.y, n3.y, n4.y)
n1.x -= normPt.x
n1.y -= normPt.y
n2.x -= normPt.x
n2.y -= normPt.y
n3.x -= normPt.x
n3.y -= normPt.y
n4.x -= normPt.x
n4.y -= normPt.y
}
safeHCoordinateIntersection (p1, p2, q1, q2) {
let intPt = null
try {
intPt = HCoordinate.intersection(p1, p2, q1, q2)
} catch (e) {
if (e instanceof NotRepresentableException) {
intPt = RobustLineIntersector.nearestEndpoint(p1, p2, q1, q2)
} else throw e
} finally {}
return intPt
}
intersection (p1, p2, q1, q2) {
let intPt = this.intersectionWithNormalization(p1, p2, q1, q2)
if (!this.isInSegmentEnvelopes(intPt)) {
intPt = new Coordinate(RobustLineIntersector.nearestEndpoint(p1, p2, q1, q2))
}
if (this._precisionModel !== null) {
this._precisionModel.makePrecise(intPt)
}
return intPt
}
smallestInAbsValue (x1, x2, x3, x4) {
let x = x1
let xabs = Math.abs(x)
if (Math.abs(x2) < xabs) {
x = x2
xabs = Math.abs(x2)
}
if (Math.abs(x3) < xabs) {
x = x3
xabs = Math.abs(x3)
}
if (Math.abs(x4) < xabs) {
x = x4
}
return x
}
checkDD (p1, p2, q1, q2, intPt) {
const intPtDD = CGAlgorithmsDD.intersection(p1, p2, q1, q2)
const isIn = this.isInSegmentEnvelopes(intPtDD)
System.out.println('DD in env = ' + isIn + ' --------------------- ' + intPtDD)
if (intPt.distance(intPtDD) > 0.0001) {
System.out.println('Distance = ' + intPt.distance(intPtDD))
}
}
intersectionWithNormalization (p1, p2, q1, q2) {
const n1 = new Coordinate(p1)
const n2 = new Coordinate(p2)
const n3 = new Coordinate(q1)
const n4 = new Coordinate(q2)
const normPt = new Coordinate()
this.normalizeToEnvCentre(n1, n2, n3, n4, normPt)
const intPt = this.safeHCoordinateIntersection(n1, n2, n3, n4)
intPt.x += normPt.x
intPt.y += normPt.y
return intPt
}
computeCollinearIntersection (p1, p2, q1, q2) {
const p1q1p2 = Envelope.intersects(p1, p2, q1)
const p1q2p2 = Envelope.intersects(p1, p2, q2)
const q1p1q2 = Envelope.intersects(q1, q2, p1)
const q1p2q2 = Envelope.intersects(q1, q2, p2)
if (p1q1p2 && p1q2p2) {
this._intPt[0] = q1
this._intPt[1] = q2
return LineIntersector.COLLINEAR_INTERSECTION
}
if (q1p1q2 && q1p2q2) {
this._intPt[0] = p1
this._intPt[1] = p2
return LineIntersector.COLLINEAR_INTERSECTION
}
if (p1q1p2 && q1p1q2) {
this._intPt[0] = q1
this._intPt[1] = p1
return q1.equals(p1) && !p1q2p2 && !q1p2q2 ? LineIntersector.POINT_INTERSECTION : LineIntersector.COLLINEAR_INTERSECTION
}
if (p1q1p2 && q1p2q2) {
this._intPt[0] = q1
this._intPt[1] = p2
return q1.equals(p2) && !p1q2p2 && !q1p1q2 ? LineIntersector.POINT_INTERSECTION : LineIntersector.COLLINEAR_INTERSECTION
}
if (p1q2p2 && q1p1q2) {
this._intPt[0] = q2
this._intPt[1] = p1
return q2.equals(p1) && !p1q1p2 && !q1p2q2 ? LineIntersector.POINT_INTERSECTION : LineIntersector.COLLINEAR_INTERSECTION
}
if (p1q2p2 && q1p2q2) {
this._intPt[0] = q2
this._intPt[1] = p2
return q2.equals(p2) && !p1q1p2 && !q1p1q2 ? LineIntersector.POINT_INTERSECTION : LineIntersector.COLLINEAR_INTERSECTION
}
return LineIntersector.NO_INTERSECTION
}
normalizeToEnvCentre (n00, n01, n10, n11, normPt) {
const minX0 = n00.x < n01.x ? n00.x : n01.x
const minY0 = n00.y < n01.y ? n00.y : n01.y
const maxX0 = n00.x > n01.x ? n00.x : n01.x
const maxY0 = n00.y > n01.y ? n00.y : n01.y
const minX1 = n10.x < n11.x ? n10.x : n11.x
const minY1 = n10.y < n11.y ? n10.y : n11.y
const maxX1 = n10.x > n11.x ? n10.x : n11.x
const maxY1 = n10.y > n11.y ? n10.y : n11.y
const intMinX = minX0 > minX1 ? minX0 : minX1
const intMaxX = maxX0 < maxX1 ? maxX0 : maxX1
const intMinY = minY0 > minY1 ? minY0 : minY1
const intMaxY = maxY0 < maxY1 ? maxY0 : maxY1
const intMidX = (intMinX + intMaxX) / 2.0
const intMidY = (intMinY + intMaxY) / 2.0
normPt.x = intMidX
normPt.y = intMidY
n00.x -= normPt.x
n00.y -= normPt.y
n01.x -= normPt.x
n01.y -= normPt.y
n10.x -= normPt.x
n10.y -= normPt.y
n11.x -= normPt.x
n11.y -= normPt.y
}
computeIntersect (p1, p2, q1, q2) {
this._isProper = false
if (!Envelope.intersects(p1, p2, q1, q2)) return LineIntersector.NO_INTERSECTION
const Pq1 = CGAlgorithms.orientationIndex(p1, p2, q1)
const Pq2 = CGAlgorithms.orientationIndex(p1, p2, q2)
if ((Pq1 > 0 && Pq2 > 0) || (Pq1 < 0 && Pq2 < 0)) {
return LineIntersector.NO_INTERSECTION
}
const Qp1 = CGAlgorithms.orientationIndex(q1, q2, p1)
const Qp2 = CGAlgorithms.orientationIndex(q1, q2, p2)
if ((Qp1 > 0 && Qp2 > 0) || (Qp1 < 0 && Qp2 < 0)) {
return LineIntersector.NO_INTERSECTION
}
const collinear = Pq1 === 0 && Pq2 === 0 && Qp1 === 0 && Qp2 === 0
if (collinear) {
return this.computeCollinearIntersection(p1, p2, q1, q2)
}
if (Pq1 === 0 || Pq2 === 0 || Qp1 === 0 || Qp2 === 0) {
this._isProper = false
if (p1.equals2D(q1) || p1.equals2D(q2)) {
this._intPt[0] = p1
} else if (p2.equals2D(q1) || p2.equals2D(q2)) {
this._intPt[0] = p2
} else if (Pq1 === 0) {
this._intPt[0] = new Coordinate(q1)
} else if (Pq2 === 0) {
this._intPt[0] = new Coordinate(q2)
} else if (Qp1 === 0) {
this._intPt[0] = new Coordinate(p1)
} else if (Qp2 === 0) {
this._intPt[0] = new Coordinate(p2)
}
} else {
this._isProper = true
this._intPt[0] = this.intersection(p1, p2, q1, q2)
}
return LineIntersector.POINT_INTERSECTION
}
interfaces_ () {
return []
}
getClass () {
return RobustLineIntersector
}
static nearestEndpoint (p1, p2, q1, q2) {
let nearestPt = p1
let minDist = CGAlgorithms.distancePointLine(p1, q1, q2)
let dist = CGAlgorithms.distancePointLine(p2, q1, q2)
if (dist < minDist) {
minDist = dist
nearestPt = p2
}
dist = CGAlgorithms.distancePointLine(q1, p1, p2)
if (dist < minDist) {
minDist = dist
nearestPt = q1
}
dist = CGAlgorithms.distancePointLine(q2, p1, p2)
if (dist < minDist) {
minDist = dist
nearestPt = q2
}
return nearestPt
}
}

View File

@@ -0,0 +1,19 @@
import CGAlgorithms from './CGAlgorithms'
import PointInRing from './PointInRing'
export default class SimplePointInRing {
constructor () {
this._pts = null
let ring = arguments[0]
this._pts = ring.getCoordinates()
}
isInside (pt) {
return CGAlgorithms.isPointInRing(pt, this._pts)
}
interfaces_ () {
return [PointInRing]
}
getClass () {
return SimplePointInRing
}
}

View File

@@ -0,0 +1,139 @@
import DistanceToPoint from './DistanceToPoint'
import CoordinateFilter from '../../geom/CoordinateFilter'
import Coordinate from '../../geom/Coordinate'
import IllegalArgumentException from '../../../../../java/lang/IllegalArgumentException'
import PointPairDistance from './PointPairDistance'
import CoordinateSequenceFilter from '../../geom/CoordinateSequenceFilter'
export default class DiscreteHausdorffDistance {
constructor () {
this._g0 = null
this._g1 = null
this._ptDist = new PointPairDistance()
this._densifyFrac = 0.0
const g0 = arguments[0]
const g1 = arguments[1]
this._g0 = g0
this._g1 = g1
}
getCoordinates () {
return this._ptDist.getCoordinates()
}
setDensifyFraction (densifyFrac) {
if (densifyFrac > 1.0 || densifyFrac <= 0.0) throw new IllegalArgumentException('Fraction is not in range (0.0 - 1.0]')
this._densifyFrac = densifyFrac
}
compute (g0, g1) {
this.computeOrientedDistance(g0, g1, this._ptDist)
this.computeOrientedDistance(g1, g0, this._ptDist)
}
distance () {
this.compute(this._g0, this._g1)
return this._ptDist.getDistance()
}
computeOrientedDistance (discreteGeom, geom, ptDist) {
const distFilter = new MaxPointDistanceFilter(geom)
discreteGeom.apply(distFilter)
ptDist.setMaximum(distFilter.getMaxPointDistance())
if (this._densifyFrac > 0) {
const fracFilter = new MaxDensifiedByFractionDistanceFilter(geom, this._densifyFrac)
discreteGeom.apply(fracFilter)
ptDist.setMaximum(fracFilter.getMaxPointDistance())
}
}
orientedDistance () {
this.computeOrientedDistance(this._g0, this._g1, this._ptDist)
return this._ptDist.getDistance()
}
interfaces_ () {
return []
}
getClass () {
return DiscreteHausdorffDistance
}
static distance () {
if (arguments.length === 2) {
const g0 = arguments[0]
const g1 = arguments[1]
const dist = new DiscreteHausdorffDistance(g0, g1)
return dist.distance()
} else if (arguments.length === 3) {
const g0 = arguments[0]
const g1 = arguments[1]
const densifyFrac = arguments[2]
const dist = new DiscreteHausdorffDistance(g0, g1)
dist.setDensifyFraction(densifyFrac)
return dist.distance()
}
}
static get MaxPointDistanceFilter () { return MaxPointDistanceFilter }
static get MaxDensifiedByFractionDistanceFilter () { return MaxDensifiedByFractionDistanceFilter }
}
class MaxPointDistanceFilter {
constructor () {
this._maxPtDist = new PointPairDistance()
this._minPtDist = new PointPairDistance()
this._euclideanDist = new DistanceToPoint()
this._geom = null
let geom = arguments[0]
this._geom = geom
}
filter (pt) {
this._minPtDist.initialize()
DistanceToPoint.computeDistance(this._geom, pt, this._minPtDist)
this._maxPtDist.setMaximum(this._minPtDist)
}
getMaxPointDistance () {
return this._maxPtDist
}
interfaces_ () {
return [CoordinateFilter]
}
getClass () {
return MaxPointDistanceFilter
}
}
class MaxDensifiedByFractionDistanceFilter {
constructor () {
this._maxPtDist = new PointPairDistance()
this._minPtDist = new PointPairDistance()
this._geom = null
this._numSubSegs = 0
const geom = arguments[0]
const fraction = arguments[1]
this._geom = geom
this._numSubSegs = Math.trunc(Math.round(1.0 / fraction))
}
filter (seq, index) {
if (index === 0) return null
const p0 = seq.getCoordinate(index - 1)
const p1 = seq.getCoordinate(index)
const delx = (p1.x - p0.x) / this._numSubSegs
const dely = (p1.y - p0.y) / this._numSubSegs
for (let i = 0; i < this._numSubSegs; i++) {
const x = p0.x + i * delx
const y = p0.y + i * dely
const pt = new Coordinate(x, y)
this._minPtDist.initialize()
DistanceToPoint.computeDistance(this._geom, pt, this._minPtDist)
this._maxPtDist.setMaximum(this._minPtDist)
}
}
isDone () {
return false
}
isGeometryChanged () {
return false
}
getMaxPointDistance () {
return this._maxPtDist
}
interfaces_ () {
return [CoordinateSequenceFilter]
}
getClass () {
return MaxDensifiedByFractionDistanceFilter
}
}

View File

@@ -0,0 +1,61 @@
import LineString from '../../geom/LineString'
import Geometry from '../../geom/Geometry'
import Coordinate from '../../geom/Coordinate'
import Polygon from '../../geom/Polygon'
import LineSegment from '../../geom/LineSegment'
import PointPairDistance from './PointPairDistance'
import GeometryCollection from '../../geom/GeometryCollection'
export default class DistanceToPoint {
interfaces_ () {
return []
}
getClass () {
return DistanceToPoint
}
static computeDistance () {
if (arguments[2] instanceof PointPairDistance && (arguments[0] instanceof LineString && arguments[1] instanceof Coordinate)) {
const line = arguments[0]
const pt = arguments[1]
const ptDist = arguments[2]
const tempSegment = new LineSegment()
const coords = line.getCoordinates()
for (let i = 0; i < coords.length - 1; i++) {
tempSegment.setCoordinates(coords[i], coords[i + 1])
const closestPt = tempSegment.closestPoint(pt)
ptDist.setMinimum(closestPt, pt)
}
} else if (arguments[2] instanceof PointPairDistance && (arguments[0] instanceof Polygon && arguments[1] instanceof Coordinate)) {
const poly = arguments[0]
const pt = arguments[1]
const ptDist = arguments[2]
DistanceToPoint.computeDistance(poly.getExteriorRing(), pt, ptDist)
for (let i = 0; i < poly.getNumInteriorRing(); i++) {
DistanceToPoint.computeDistance(poly.getInteriorRingN(i), pt, ptDist)
}
} else if (arguments[2] instanceof PointPairDistance && (arguments[0] instanceof Geometry && arguments[1] instanceof Coordinate)) {
const geom = arguments[0]
const pt = arguments[1]
const ptDist = arguments[2]
if (geom instanceof LineString) {
DistanceToPoint.computeDistance(geom, pt, ptDist)
} else if (geom instanceof Polygon) {
DistanceToPoint.computeDistance(geom, pt, ptDist)
} else if (geom instanceof GeometryCollection) {
const gc = geom
for (let i = 0; i < gc.getNumGeometries(); i++) {
const g = gc.getGeometryN(i)
DistanceToPoint.computeDistance(g, pt, ptDist)
}
} else {
ptDist.setMinimum(geom.getCoordinate(), pt)
}
} else if (arguments[2] instanceof PointPairDistance && (arguments[0] instanceof LineSegment && arguments[1] instanceof Coordinate)) {
const segment = arguments[0]
const pt = arguments[1]
const ptDist = arguments[2]
const closestPt = segment.closestPoint(pt)
ptDist.setMinimum(closestPt, pt)
}
}
}

View File

@@ -0,0 +1,79 @@
import WKTWriter from '../../io/WKTWriter'
import Coordinate from '../../geom/Coordinate'
import Double from '../../../../../java/lang/Double'
export default class PointPairDistance {
constructor () {
this._pt = [new Coordinate(), new Coordinate()]
this._distance = Double.NaN
this._isNull = true
}
getCoordinates () {
return this._pt
}
getCoordinate (i) {
return this._pt[i]
}
setMinimum () {
if (arguments.length === 1) {
const ptDist = arguments[0]
this.setMinimum(ptDist._pt[0], ptDist._pt[1])
} else if (arguments.length === 2) {
const p0 = arguments[0]
const p1 = arguments[1]
if (this._isNull) {
this.initialize(p0, p1)
return null
}
var dist = p0.distance(p1)
if (dist < this._distance) this.initialize(p0, p1, dist)
}
}
initialize () {
if (arguments.length === 0) {
this._isNull = true
} else if (arguments.length === 2) {
const p0 = arguments[0]
const p1 = arguments[1]
this._pt[0].setCoordinate(p0)
this._pt[1].setCoordinate(p1)
this._distance = p0.distance(p1)
this._isNull = false
} else if (arguments.length === 3) {
const p0 = arguments[0]
const p1 = arguments[1]
const distance = arguments[2]
this._pt[0].setCoordinate(p0)
this._pt[1].setCoordinate(p1)
this._distance = distance
this._isNull = false
}
}
toString () {
return WKTWriter.toLineString(this._pt[0], this._pt[1])
}
getDistance () {
return this._distance
}
setMaximum () {
if (arguments.length === 1) {
const ptDist = arguments[0]
this.setMaximum(ptDist._pt[0], ptDist._pt[1])
} else if (arguments.length === 2) {
const p0 = arguments[0]
const p1 = arguments[1]
if (this._isNull) {
this.initialize(p0, p1)
return null
}
var dist = p0.distance(p1)
if (dist > this._distance) this.initialize(p0, p1, dist)
}
}
interfaces_ () {
return []
}
getClass () {
return PointPairDistance
}
}

View File

@@ -0,0 +1,95 @@
import hasInterface from '../../../../../hasInterface'
import IllegalArgumentException from '../../../../../java/lang/IllegalArgumentException'
import ItemVisitor from '../../index/ItemVisitor'
import PointOnGeometryLocator from './PointOnGeometryLocator'
import SortedPackedIntervalRTree from '../../index/intervalrtree/SortedPackedIntervalRTree'
import LineSegment from '../../geom/LineSegment'
import Polygonal from '../../geom/Polygonal'
import LinearComponentExtracter from '../../geom/util/LinearComponentExtracter'
import ArrayListVisitor from '../../index/ArrayListVisitor'
import RayCrossingCounter from '../RayCrossingCounter'
export default class IndexedPointInAreaLocator {
constructor () {
this._index = null
const g = arguments[0]
if (!hasInterface(g, Polygonal)) throw new IllegalArgumentException('Argument must be Polygonal')
this._index = new IntervalIndexedGeometry(g)
}
locate (p) {
var rcc = new RayCrossingCounter(p)
var visitor = new SegmentVisitor(rcc)
this._index.query(p.y, p.y, visitor)
return rcc.getLocation()
}
interfaces_ () {
return [PointOnGeometryLocator]
}
getClass () {
return IndexedPointInAreaLocator
}
static get SegmentVisitor () { return SegmentVisitor }
static get IntervalIndexedGeometry () { return IntervalIndexedGeometry }
}
class SegmentVisitor {
constructor () {
this._counter = null
const counter = arguments[0]
this._counter = counter
}
visitItem (item) {
var seg = item
this._counter.countSegment(seg.getCoordinate(0), seg.getCoordinate(1))
}
interfaces_ () {
return [ItemVisitor]
}
getClass () {
return SegmentVisitor
}
}
class IntervalIndexedGeometry {
constructor () {
this._index = new SortedPackedIntervalRTree()
const geom = arguments[0]
this.init(geom)
}
init (geom) {
var lines = LinearComponentExtracter.getLines(geom)
for (var i = lines.iterator(); i.hasNext();) {
var line = i.next()
var pts = line.getCoordinates()
this.addLine(pts)
}
}
addLine (pts) {
for (var i = 1; i < pts.length; i++) {
var seg = new LineSegment(pts[i - 1], pts[i])
var min = Math.min(seg.p0.y, seg.p1.y)
var max = Math.max(seg.p0.y, seg.p1.y)
this._index.insert(min, max, seg)
}
}
query () {
if (arguments.length === 2) {
const min = arguments[0]
const max = arguments[1]
var visitor = new ArrayListVisitor()
this._index.query(min, max, visitor)
return visitor.getItems()
} else if (arguments.length === 3) {
const min = arguments[0]
const max = arguments[1]
const visitor = arguments[2]
this._index.query(min, max, visitor)
}
}
interfaces_ () {
return []
}
getClass () {
return IntervalIndexedGeometry
}
}

View File

@@ -0,0 +1,9 @@
export default class PointOnGeometryLocator {
locate (p) {}
interfaces_ () {
return []
}
getClass () {
return PointOnGeometryLocator
}
}

View File

@@ -0,0 +1,54 @@
import Location from '../../geom/Location'
import CGAlgorithms from '../CGAlgorithms'
import Polygon from '../../geom/Polygon'
import PointOnGeometryLocator from './PointOnGeometryLocator'
import GeometryCollectionIterator from '../../geom/GeometryCollectionIterator'
import GeometryCollection from '../../geom/GeometryCollection'
export default class SimplePointInAreaLocator {
constructor () {
this._geom = null
const geom = arguments[0]
this._geom = geom
}
locate (p) {
return SimplePointInAreaLocator.locate(p, this._geom)
}
interfaces_ () {
return [PointOnGeometryLocator]
}
getClass () {
return SimplePointInAreaLocator
}
static isPointInRing (p, ring) {
if (!ring.getEnvelopeInternal().intersects(p)) return false
return CGAlgorithms.isPointInRing(p, ring.getCoordinates())
}
static containsPointInPolygon (p, poly) {
if (poly.isEmpty()) return false
const shell = poly.getExteriorRing()
if (!SimplePointInAreaLocator.isPointInRing(p, shell)) return false
for (let i = 0; i < poly.getNumInteriorRing(); i++) {
const hole = poly.getInteriorRingN(i)
if (SimplePointInAreaLocator.isPointInRing(p, hole)) return false
}
return true
}
static containsPoint (p, geom) {
if (geom instanceof Polygon) {
return SimplePointInAreaLocator.containsPointInPolygon(p, geom)
} else if (geom instanceof GeometryCollection) {
const geomi = new GeometryCollectionIterator(geom)
while (geomi.hasNext()) {
const g2 = geomi.next()
if (g2 !== geom) if (SimplePointInAreaLocator.containsPoint(p, g2)) return true
}
}
return false
}
static locate (p, geom) {
if (geom.isEmpty()) return Location.EXTERIOR
if (SimplePointInAreaLocator.containsPoint(p, geom)) return Location.INTERIOR
return Location.EXTERIOR
}
}

View File

@@ -0,0 +1,15 @@
import SimilarityMeasure from './SimilarityMeasure'
export default class AreaSimilarityMeasure {
measure (g1, g2) {
var areaInt = g1.intersection(g2).getArea()
var areaUnion = g1.union(g2).getArea()
return areaInt / areaUnion
}
interfaces_ () {
return [SimilarityMeasure]
}
getClass () {
return AreaSimilarityMeasure
}
}

View File

@@ -0,0 +1,27 @@
import SimilarityMeasure from './SimilarityMeasure'
import Envelope from '../../geom/Envelope'
import DiscreteHausdorffDistance from '../distance/DiscreteHausdorffDistance'
export default class HausdorffSimilarityMeasure {
measure (g1, g2) {
var distance = DiscreteHausdorffDistance.distance(g1, g2, HausdorffSimilarityMeasure.DENSIFY_FRACTION)
var env = new Envelope(g1.getEnvelopeInternal())
env.expandToInclude(g2.getEnvelopeInternal())
var envSize = HausdorffSimilarityMeasure.diagonalSize(env)
var measure = 1 - distance / envSize
return measure
}
interfaces_ () {
return [SimilarityMeasure]
}
getClass () {
return HausdorffSimilarityMeasure
}
static diagonalSize (env) {
if (env.isNull()) return 0.0
var width = env.getWidth()
var hgt = env.getHeight()
return Math.sqrt(width * width + hgt * hgt)
}
static get DENSIFY_FRACTION () { return 0.25 }
}

View File

@@ -0,0 +1,9 @@
export default class SimilarityMeasure {
measure (g1, g2) {}
interfaces_ () {
return []
}
getClass () {
return SimilarityMeasure
}
}

View File

@@ -0,0 +1,11 @@
export default class SimilarityMeasureCombiner {
interfaces_ () {
return []
}
getClass () {
return SimilarityMeasureCombiner
}
static combine (measure1, measure2) {
return Math.min(measure1, measure2)
}
}

View File

@@ -0,0 +1,2 @@
// densify
export { default as Densifier } from './densify/Densifier'

View File

@@ -0,0 +1,93 @@
import LineString from '../geom/LineString'
import CoordinateList from '../geom/CoordinateList'
import GeometryTransformer from '../geom/util/GeometryTransformer'
import IllegalArgumentException from '../../../../java/lang/IllegalArgumentException'
import MultiPolygon from '../geom/MultiPolygon'
import LineSegment from '../geom/LineSegment'
export default class Densifier {
constructor () {
this._inputGeom = null
this._distanceTolerance = null
let inputGeom = arguments[0]
this._inputGeom = inputGeom
}
getResultGeometry () {
return new DensifyTransformer(this._distanceTolerance).transform(this._inputGeom)
}
setDistanceTolerance (distanceTolerance) {
if (distanceTolerance <= 0.0) throw new IllegalArgumentException('Tolerance must be positive')
this._distanceTolerance = distanceTolerance
}
interfaces_ () {
return []
}
getClass () {
return Densifier
}
static densifyPoints (pts, distanceTolerance, precModel) {
const seg = new LineSegment()
const coordList = new CoordinateList()
for (let i = 0; i < pts.length - 1; i++) {
seg.p0 = pts[i]
seg.p1 = pts[i + 1]
coordList.add(seg.p0, false)
const len = seg.getLength()
const densifiedSegCount = Math.trunc(len / distanceTolerance) + 1
if (densifiedSegCount > 1) {
const densifiedSegLen = len / densifiedSegCount
for (let j = 1; j < densifiedSegCount; j++) {
const segFract = j * densifiedSegLen / len
const p = seg.pointAlong(segFract)
precModel.makePrecise(p)
coordList.add(p, false)
}
}
}
coordList.add(pts[pts.length - 1], false)
return coordList.toCoordinateArray()
}
static densify (geom, distanceTolerance) {
const densifier = new Densifier(geom)
densifier.setDistanceTolerance(distanceTolerance)
return densifier.getResultGeometry()
}
static get DensifyTransformer () { return DensifyTransformer }
}
class DensifyTransformer extends GeometryTransformer {
constructor () {
super()
this.distanceTolerance = null
let distanceTolerance = arguments[0]
this.distanceTolerance = distanceTolerance
}
transformMultiPolygon (geom, parent) {
const roughGeom = GeometryTransformer.prototype.transformMultiPolygon.call(this, geom, parent)
return this.createValidArea(roughGeom)
}
transformPolygon (geom, parent) {
const roughGeom = GeometryTransformer.prototype.transformPolygon.call(this, geom, parent)
if (parent instanceof MultiPolygon) {
return roughGeom
}
return this.createValidArea(roughGeom)
}
transformCoordinates (coords, parent) {
const inputPts = coords.toCoordinateArray()
let newPts = Densifier.densifyPoints(inputPts, this.distanceTolerance, parent.getPrecisionModel())
if (parent instanceof LineString && newPts.length === 1) {
newPts = new Array(0).fill(null)
}
return this._factory.getCoordinateSequenceFactory().create(newPts)
}
createValidArea (roughAreaGeom) {
return roughAreaGeom.buffer(0.0)
}
interfaces_ () {
return []
}
getClass () {
return DensifyTransformer
}
}

View File

@@ -0,0 +1,4 @@
// dissolve
export { default as DissolveEdgeGraph } from './dissolve/DissolveEdgeGraph'
export { default as DissolveHalfEdge } from './dissolve/DissolveHalfEdge'
export { default as LineDissolver } from './dissolve/LineDissolver'

View File

@@ -0,0 +1,14 @@
import EdgeGraph from '../edgegraph/EdgeGraph'
import DissolveHalfEdge from './DissolveHalfEdge'
export default class DissolveEdgeGraph extends EdgeGraph {
createEdge (p0) {
return new DissolveHalfEdge(p0)
}
interfaces_ () {
return []
}
getClass () {
return DissolveEdgeGraph
}
}

View File

@@ -0,0 +1,21 @@
import MarkHalfEdge from '../edgegraph/MarkHalfEdge'
export default class DissolveHalfEdge extends MarkHalfEdge {
constructor () {
const orig = arguments[0]
super(orig)
this._isStart = false
}
setStart () {
this._isStart = true
}
isStart () {
return this._isStart
}
interfaces_ () {
return []
}
getClass () {
return DissolveHalfEdge
}
}

View File

@@ -0,0 +1,152 @@
import LineString from '../geom/LineString'
import CoordinateList from '../geom/CoordinateList'
import Geometry from '../geom/Geometry'
import hasInterface from '../../../../hasInterface'
import Collection from '../../../../java/util/Collection'
import Stack from '../../../../java/util/Stack'
import MarkHalfEdge from '../edgegraph/MarkHalfEdge'
import DissolveEdgeGraph from './DissolveEdgeGraph'
import GeometryComponentFilter from '../geom/GeometryComponentFilter'
import ArrayList from '../../../../java/util/ArrayList'
export default class LineDissolver {
constructor () {
this._result = null
this._factory = null
this._graph = null
this._lines = new ArrayList()
this._nodeEdgeStack = new Stack()
this._ringStartEdge = null
this._graph = new DissolveEdgeGraph()
}
addLine (line) {
this._lines.add(this._factory.createLineString(line.toCoordinateArray()))
}
updateRingStartEdge (e) {
if (!e.isStart()) {
e = e.sym()
if (!e.isStart()) return null
}
if (this._ringStartEdge === null) {
this._ringStartEdge = e
return null
}
if (e.orig().compareTo(this._ringStartEdge.orig()) < 0) {
this._ringStartEdge = e
}
}
getResult () {
if (this._result === null) this.computeResult()
return this._result
}
process (e) {
let eNode = e.prevNode()
if (eNode === null) eNode = e
this.stackEdges(eNode)
this.buildLines()
}
buildRing (eStartRing) {
const line = new CoordinateList()
let e = eStartRing
line.add(e.orig().copy(), false)
while (e.sym().degree() === 2) {
const eNext = e.next()
if (eNext === eStartRing) break
line.add(eNext.orig().copy(), false)
e = eNext
}
line.add(e.dest().copy(), false)
this.addLine(line)
}
buildLine (eStart) {
const line = new CoordinateList()
let e = eStart
this._ringStartEdge = null
MarkHalfEdge.markBoth(e)
line.add(e.orig().copy(), false)
while (e.sym().degree() === 2) {
this.updateRingStartEdge(e)
const eNext = e.next()
if (eNext === eStart) {
this.buildRing(this._ringStartEdge)
return null
}
line.add(eNext.orig().copy(), false)
e = eNext
MarkHalfEdge.markBoth(e)
}
line.add(e.dest().copy(), false)
this.stackEdges(e.sym())
this.addLine(line)
}
stackEdges (node) {
let e = node
do {
if (!MarkHalfEdge.isMarked(e)) this._nodeEdgeStack.add(e)
e = e.oNext()
} while (e !== node)
}
computeResult () {
const edges = this._graph.getVertexEdges()
for (const i = edges.iterator(); i.hasNext();) {
const e = i.next()
if (MarkHalfEdge.isMarked(e)) continue
this.process(e)
}
this._result = this._factory.buildGeometry(this._lines)
}
buildLines () {
while (!this._nodeEdgeStack.empty()) {
const e = this._nodeEdgeStack.pop()
if (MarkHalfEdge.isMarked(e)) continue
this.buildLine(e)
}
}
add () {
if (arguments[0] instanceof Geometry) {
let geometry = arguments[0]
geometry.appy({
interfaces_: function () {
return [GeometryComponentFilter]
},
filter: function (component) {
if (component instanceof LineString) {
this.add(component)
}
}
})
} else if (hasInterface(arguments[0], Collection)) {
let geometries = arguments[0]
for (const i = geometries.iterator(); i.hasNext();) {
const geometry = i.next()
this.add(geometry)
}
} else if (arguments[0] instanceof LineString) {
let lineString = arguments[0]
if (this._factory === null) {
this._factory = lineString.getFactory()
}
const seq = lineString.getCoordinateSequence()
let doneStart = false
for (let i = 1; i < seq.size(); i++) {
const e = this._graph.addEdge(seq.getCoordinate(i - 1), seq.getCoordinate(i))
if (e === null) continue
if (!doneStart) {
e.setStart()
doneStart = true
}
}
}
}
interfaces_ () {
return []
}
getClass () {
return LineDissolver
}
static dissolve (g) {
const d = new LineDissolver()
d.add(g)
return d.getResult()
}
}

View File

@@ -0,0 +1,5 @@
// edgegraph
export { default as EdgeGraph } from './edgegraph/EdgeGraph'
export { default as EdgeGraphBuilder } from './edgegraph/EdgeGraphBuilder'
export { default as HalfEdge } from './edgegraph/HalfEdge'
export { default as MarkHalfEdge } from './edgegraph/MarkHalfEdge'

View File

@@ -0,0 +1,63 @@
import HashMap from '../../../../java/util/HashMap'
import HalfEdge from './HalfEdge'
export default class EdgeGraph {
constructor () {
this._vertexMap = new HashMap()
}
insert (orig, dest, eAdj) {
const e = this.create(orig, dest)
if (eAdj !== null) {
eAdj.insert(e)
} else {
this._vertexMap.put(orig, e)
}
const eAdjDest = this._vertexMap.get(dest)
if (eAdjDest !== null) {
eAdjDest.insert(e.sym())
} else {
this._vertexMap.put(dest, e.sym())
}
return e
}
create (p0, p1) {
const e0 = this.createEdge(p0)
const e1 = this.createEdge(p1)
HalfEdge.init(e0, e1)
return e0
}
createEdge (orig) {
return new HalfEdge(orig)
}
addEdge (orig, dest) {
if (!EdgeGraph.isValidEdge(orig, dest)) return null
const eAdj = this._vertexMap.get(orig)
let eSame = null
if (eAdj !== null) {
eSame = eAdj.find(dest)
}
if (eSame !== null) {
return eSame
}
const e = this.insert(orig, dest, eAdj)
return e
}
getVertexEdges () {
return this._vertexMap.values()
}
findEdge (orig, dest) {
const e = this._vertexMap.get(orig)
if (e === null) return null
return e.find(dest)
}
interfaces_ () {
return []
}
getClass () {
return EdgeGraph
}
static isValidEdge (orig, dest) {
const cmp = dest.compareTo(orig)
return cmp !== 0
}
}

View File

@@ -0,0 +1,53 @@
import LineString from '../geom/LineString'
import Geometry from '../geom/Geometry'
import hasInterface from '../../../../hasInterface'
import Collection from '../../../../java/util/Collection'
import EdgeGraph from './EdgeGraph'
import GeometryComponentFilter from '../geom/GeometryComponentFilter'
export default class EdgeGraphBuilder {
constructor () {
this._graph = new EdgeGraph()
}
add () {
if (arguments[0] instanceof Geometry) {
const geometry = arguments[0]
geometry.apply({
interfaces_: function () {
return [GeometryComponentFilter]
},
filter: function (component) {
if (component instanceof LineString) {
this.add(component)
}
}
})
} else if (hasInterface(arguments[0], Collection)) {
const geometries = arguments[0]
for (const i = geometries.iterator(); i.hasNext();) {
const geometry = i.next()
this.add(geometry)
}
} else if (arguments[0] instanceof LineString) {
const lineString = arguments[0]
const seq = lineString.getCoordinateSequence()
for (let i = 1; i < seq.size(); i++) {
this._graph.addEdge(seq.getCoordinate(i - 1), seq.getCoordinate(i))
}
}
}
getGraph () {
return this._graph
}
interfaces_ () {
return []
}
getClass () {
return EdgeGraphBuilder
}
static build (geoms) {
const builder = new EdgeGraphBuilder()
builder.add(geoms)
return builder.getGraph()
}
}

View File

@@ -0,0 +1,143 @@
import CGAlgorithms from '../algorithm/CGAlgorithms'
import Quadrant from '../geomgraph/Quadrant'
import Assert from '../util/Assert'
export default class HalfEdge {
constructor () {
this._orig = null
this._sym = null
this._next = null
const orig = arguments[0]
this._orig = orig
}
find (dest) {
let oNext = this
do {
if (oNext === null) return null
if (oNext.dest().equals2D(dest)) return oNext
oNext = oNext.oNext()
} while (oNext !== this)
return null
}
dest () {
return this._sym._orig
}
oNext () {
return this._sym._next
}
insert (e) {
if (this.oNext() === this) {
this.insertAfter(e)
return null
}
const ecmp = this.compareTo(e)
let ePrev = this
do {
const oNext = ePrev.oNext()
const cmp = oNext.compareTo(e)
if (cmp !== ecmp || oNext === this) {
ePrev.insertAfter(e)
return null
}
ePrev = oNext
} while (ePrev !== this)
Assert.shouldNeverReachHere()
}
insertAfter (e) {
Assert.equals(this._orig, e.orig())
const save = this.oNext()
this._sym.setNext(e)
e.sym().setNext(save)
}
degree () {
let degree = 0
let e = this
do {
degree++
e = e.oNext()
} while (e !== this)
return degree
}
equals () {
if (arguments.length === 2) {
const p0 = arguments[0]
const p1 = arguments[1]
return this._orig.equals2D(p0) && this._sym._orig.equals(p1)
}
}
deltaY () {
return this._sym._orig.y - this._orig.y
}
sym () {
return this._sym
}
prev () {
return this._sym.next()._sym
}
compareAngularDirection (e) {
const dx = this.deltaX()
const dy = this.deltaY()
const dx2 = e.deltaX()
const dy2 = e.deltaY()
if (dx === dx2 && dy === dy2) return 0
const quadrant = Quadrant.quadrant(dx, dy)
const quadrant2 = Quadrant.quadrant(dx2, dy2)
if (quadrant > quadrant2) return 1
if (quadrant < quadrant2) return -1
return CGAlgorithms.computeOrientation(e._orig, e.dest(), this.dest())
}
prevNode () {
let e = this
while (e.degree() === 2) {
e = e.prev()
if (e === this) return null
}
return e
}
compareTo (obj) {
const e = obj
const comp = this.compareAngularDirection(e)
return comp
}
next () {
return this._next
}
setSym (e) {
this._sym = e
}
orig () {
return this._orig
}
toString () {
return 'HE(' + this._orig.x + ' ' + this._orig.y + ', ' + this._sym._orig.x + ' ' + this._sym._orig.y + ')'
}
setNext (e) {
this._next = e
}
init (e) {
this.setSym(e)
e.setSym(this)
this.setNext(e)
e.setNext(this)
}
deltaX () {
return this._sym._orig.x - this._orig.x
}
interfaces_ () {
return []
}
getClass () {
return HalfEdge
}
static init (e0, e1) {
if (e0._sym !== null || e1._sym !== null || e0._next !== null || e1._next !== null) throw new Error('Edges are already initialized')
e0.init(e1)
return e0
}
static create (p0, p1) {
const e0 = new HalfEdge(p0)
const e1 = new HalfEdge(p1)
e0.init(e1)
return e0
}
}

View File

@@ -0,0 +1,41 @@
import HalfEdge from './HalfEdge'
export default class MarkHalfEdge extends HalfEdge {
constructor () {
let orig = arguments[0]
super(orig)
this._isMarked = false
}
mark () {
this._isMarked = true
}
setMark (isMarked) {
this._isMarked = isMarked
}
isMarked () {
return this._isMarked
}
interfaces_ () {
return []
}
getClass () {
return MarkHalfEdge
}
static setMarkBoth (e, isMarked) {
e.setMark(isMarked)
e.sym().setMark(isMarked)
}
static isMarked (e) {
return e.isMarked()
}
static setMark (e, isMarked) {
e.setMark(isMarked)
}
static markBoth (e) {
e.mark()
e.sym().mark()
}
static mark (e) {
e.mark()
}
}

View File

@@ -0,0 +1,73 @@
// geom
export { default as Coordinate } from './geom/Coordinate'
export { default as CoordinateArrays } from './geom/CoordinateArrays'
export { default as CoordinateFilter } from './geom/CoordinateFilter'
export { default as CoordinateList } from './geom/CoordinateList'
export { default as CoordinateSequence } from './geom/CoordinateSequence'
export { default as CoordinateSequenceComparator } from './geom/CoordinateSequenceComparator'
export { default as CoordinateSequenceFactory } from './geom/CoordinateSequenceFactory'
export { default as CoordinateSequenceFilter } from './geom/CoordinateSequenceFilter'
export { default as CoordinateSequences } from './geom/CoordinateSequences'
export { default as Dimension } from './geom/Dimension'
export { default as Envelope } from './geom/Envelope'
export { default as Geometry } from './geom/Geometry'
export { default as GeometryCollection } from './geom/GeometryCollection'
export { default as GeometryCollectionIterator } from './geom/GeometryCollectionIterator'
export { default as GeometryComponentFilter } from './geom/GeometryComponentFilter'
export { default as GeometryFactory } from './geom/GeometryFactory'
export { default as GeometryFilter } from './geom/GeometryFilter'
export { default as IntersectionMatrix } from './geom/IntersectionMatrix'
export { default as LineSegment } from './geom/LineSegment'
export { default as LineString } from './geom/LineString'
export { default as Lineal } from './geom/Lineal'
export { default as LinearRing } from './geom/LinearRing'
export { default as Location } from './geom/Location'
export { default as MultiLineString } from './geom/MultiLineString'
export { default as MultiPoint } from './geom/MultiPoint'
export { default as MultiPolygon } from './geom/MultiPolygon'
export { default as OctagonalEnvelope } from './geom/OctagonalEnvelope'
export { default as Point } from './geom/Point'
export { default as Polygon } from './geom/Polygon'
export { default as Polygonal } from './geom/Polygonal'
export { default as PrecisionModel } from './geom/PrecisionModel'
export { default as Puntal } from './geom/Puntal'
export { default as TopologyException } from './geom/TopologyException'
export { default as Triangle } from './geom/Triangle'
// geom.impl
export { default as CoordinateArraySequence } from './geom/impl/CoordinateArraySequence'
export { default as CoordinateArraySequenceFactory } from './geom/impl/CoordinateArraySequenceFactory'
// geom.prep
export { default as AbstractPreparedPolygonContains } from './geom/prep/AbstractPreparedPolygonContains'
export { default as BasicPreparedGeometry } from './geom/prep/BasicPreparedGeometry'
export { default as PreparedGeometry } from './geom/prep/PreparedGeometry'
export { default as PreparedGeometryFactory } from './geom/prep/PreparedGeometryFactory'
export { default as PreparedLineString } from './geom/prep/PreparedLineString'
export { default as PreparedLineStringIntersects } from './geom/prep/PreparedLineStringIntersects'
export { default as PreparedPoint } from './geom/prep/PreparedPoint'
export { default as PreparedPolygon } from './geom/prep/PreparedPolygon'
export { default as PreparedPolygonContains } from './geom/prep/PreparedPolygonContains'
export { default as PreparedPolygonContainsProperly } from './geom/prep/PreparedPolygonContainsProperly'
export { default as PreparedPolygonCovers } from './geom/prep/PreparedPolygonCovers'
export { default as PreparedPolygonIntersects } from './geom/prep/PreparedPolygonIntersects'
export { default as PreparedPolygonPredicate } from './geom/prep/PreparedPolygonPredicate'
// geom.util
export { default as AffineTransformation } from './geom/util/AffineTransformation'
export { default as AffineTransformationBuilder } from './geom/util/AffineTransformationBuilder'
export { default as AffineTransformationFactory } from './geom/util/AffineTransformationFactory'
export { default as ComponentCoordinateExtracter } from './geom/util/ComponentCoordinateExtracter'
export { default as GeometryCollectionMapper } from './geom/util/GeometryCollectionMapper'
export { default as GeometryCombiner } from './geom/util/GeometryCombiner'
export { default as GeometryEditor } from './geom/util/GeometryEditor'
export { default as GeometryExtracter } from './geom/util/GeometryExtracter'
export { default as GeometryMapper } from './geom/util/GeometryMapper'
export { default as GeometryTransformer } from './geom/util/GeometryTransformer'
export { default as LineStringExtracter } from './geom/util/LineStringExtracter'
export { default as LinearComponentExtracter } from './geom/util/LinearComponentExtracter'
export { default as NoninvertibleTransformationException } from './geom/util/NoninvertibleTransformationException'
export { default as PointExtracter } from './geom/util/PointExtracter'
export { default as PolygonExtracter } from './geom/util/PolygonExtracter'
export { default as ShortCircuitedGeometryVisitor } from './geom/util/ShortCircuitedGeometryVisitor'
export { default as SineStarFactory } from './geom/util/SineStarFactory'

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