node-red-contrib-tak-registration 0.11.4 → 0.11.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/buffer.d.ts +8 -7
- package/node_modules/@types/node/crypto.d.ts +38 -7
- package/node_modules/@types/node/dgram.d.ts +10 -0
- package/node_modules/@types/node/diagnostics_channel.d.ts +355 -1
- package/node_modules/@types/node/fs.d.ts +28 -8
- package/node_modules/@types/node/globals.d.ts +26 -0
- package/node_modules/@types/node/http.d.ts +6 -7
- package/node_modules/@types/node/module.d.ts +14 -0
- package/node_modules/@types/node/net.d.ts +8 -3
- package/node_modules/@types/node/package.json +3 -4
- package/node_modules/@types/node/perf_hooks.d.ts +12 -6
- package/node_modules/@types/node/process.d.ts +25 -3
- package/node_modules/@types/node/querystring.d.ts +3 -3
- package/node_modules/@types/node/stream/web.d.ts +17 -1
- package/node_modules/@types/node/string_decoder.d.ts +2 -2
- package/node_modules/@types/node/test.d.ts +98 -15
- package/node_modules/@types/node/tls.d.ts +1 -1
- package/node_modules/@types/node/ts4.8/buffer.d.ts +8 -7
- package/node_modules/@types/node/ts4.8/crypto.d.ts +41 -9
- package/node_modules/@types/node/ts4.8/dgram.d.ts +10 -0
- package/node_modules/@types/node/ts4.8/diagnostics_channel.d.ts +355 -1
- package/node_modules/@types/node/ts4.8/fs.d.ts +28 -8
- package/node_modules/@types/node/ts4.8/globals.d.ts +26 -0
- package/node_modules/@types/node/ts4.8/http.d.ts +6 -7
- package/node_modules/@types/node/ts4.8/module.d.ts +14 -0
- package/node_modules/@types/node/ts4.8/net.d.ts +8 -3
- package/node_modules/@types/node/ts4.8/perf_hooks.d.ts +13 -7
- package/node_modules/@types/node/ts4.8/process.d.ts +25 -3
- package/node_modules/@types/node/ts4.8/querystring.d.ts +3 -3
- package/node_modules/@types/node/ts4.8/stream/web.d.ts +17 -1
- package/node_modules/@types/node/ts4.8/string_decoder.d.ts +2 -2
- package/node_modules/@types/node/ts4.8/test.d.ts +98 -15
- package/node_modules/@types/node/ts4.8/tls.d.ts +1 -1
- package/node_modules/@types/node/ts4.8/url.d.ts +59 -42
- package/node_modules/@types/node/ts4.8/util.d.ts +1 -1
- package/node_modules/@types/node/ts4.8/v8.d.ts +134 -5
- package/node_modules/@types/node/ts4.8/wasi.d.ts +26 -5
- package/node_modules/@types/node/url.d.ts +59 -42
- package/node_modules/@types/node/v8.d.ts +134 -5
- package/node_modules/@types/node/wasi.d.ts +26 -5
- package/node_modules/axios/CHANGELOG.md +53 -0
- package/node_modules/axios/README.md +47 -5
- package/node_modules/axios/dist/axios.js +368 -4
- package/node_modules/axios/dist/axios.js.map +1 -1
- package/node_modules/axios/dist/axios.min.js +1 -1
- package/node_modules/axios/dist/axios.min.js.map +1 -1
- package/node_modules/axios/dist/browser/axios.cjs +28 -4
- package/node_modules/axios/dist/browser/axios.cjs.map +1 -1
- package/node_modules/axios/dist/esm/axios.js +28 -4
- package/node_modules/axios/dist/esm/axios.js.map +1 -1
- package/node_modules/axios/dist/esm/axios.min.js +1 -1
- package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
- package/node_modules/axios/dist/node/axios.cjs +34 -6
- package/node_modules/axios/dist/node/axios.cjs.map +1 -1
- package/node_modules/axios/index.d.cts +1 -1
- package/node_modules/axios/index.d.ts +1 -1
- package/node_modules/axios/lib/adapters/http.js +6 -2
- package/node_modules/axios/lib/core/Axios.js +22 -1
- package/node_modules/axios/lib/env/data.js +1 -1
- package/node_modules/axios/lib/helpers/combineURLs.js +1 -1
- package/node_modules/axios/lib/helpers/formDataToJSON.js +3 -0
- package/node_modules/axios/package.json +2 -2
- package/node_modules/call-bind/CHANGELOG.md +16 -0
- package/node_modules/call-bind/index.js +2 -11
- package/node_modules/call-bind/package.json +11 -6
- package/node_modules/define-data-property/CHANGELOG.md +29 -0
- package/node_modules/define-data-property/index.d.ts +12 -3
- package/node_modules/define-data-property/index.js +4 -16
- package/node_modules/define-data-property/package.json +26 -33
- package/node_modules/define-data-property/test/index.js +10 -10
- package/node_modules/es-define-property/.eslintrc +13 -0
- package/node_modules/es-define-property/.github/FUNDING.yml +12 -0
- package/node_modules/es-define-property/.nycrc +9 -0
- package/node_modules/es-define-property/CHANGELOG.md +15 -0
- package/node_modules/es-define-property/LICENSE +21 -0
- package/node_modules/es-define-property/README.md +49 -0
- package/node_modules/es-define-property/index.d.ts +3 -0
- package/node_modules/es-define-property/index.js +16 -0
- package/node_modules/es-define-property/package.json +81 -0
- package/node_modules/es-define-property/test/index.js +55 -0
- package/node_modules/es-define-property/tsconfig.json +50 -0
- package/node_modules/es-errors/.eslintrc +5 -0
- package/node_modules/es-errors/.github/FUNDING.yml +12 -0
- package/node_modules/es-errors/CHANGELOG.md +40 -0
- package/node_modules/es-errors/LICENSE +21 -0
- package/node_modules/es-errors/README.md +55 -0
- package/node_modules/es-errors/eval.d.ts +3 -0
- package/node_modules/es-errors/eval.js +4 -0
- package/node_modules/es-errors/index.d.ts +3 -0
- package/node_modules/es-errors/index.js +4 -0
- package/node_modules/es-errors/package.json +80 -0
- package/node_modules/es-errors/range.d.ts +3 -0
- package/node_modules/es-errors/range.js +4 -0
- package/node_modules/es-errors/ref.d.ts +3 -0
- package/node_modules/es-errors/ref.js +4 -0
- package/node_modules/es-errors/syntax.d.ts +3 -0
- package/node_modules/es-errors/syntax.js +4 -0
- package/node_modules/es-errors/test/index.js +19 -0
- package/node_modules/es-errors/tsconfig.json +49 -0
- package/node_modules/es-errors/type.d.ts +3 -0
- package/node_modules/es-errors/type.js +4 -0
- package/node_modules/es-errors/uri.d.ts +3 -0
- package/node_modules/es-errors/uri.js +4 -0
- package/node_modules/fast-xml-parser/CHANGELOG.md +3 -0
- package/node_modules/fast-xml-parser/README.md +2 -1
- package/node_modules/fast-xml-parser/package.json +4 -1
- package/node_modules/fast-xml-parser/src/fxp.d.ts +363 -69
- package/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js +5 -5
- package/node_modules/follow-redirects/index.js +114 -75
- package/node_modules/follow-redirects/package.json +1 -1
- package/node_modules/get-intrinsic/CHANGELOG.md +18 -0
- package/node_modules/get-intrinsic/index.js +15 -7
- package/node_modules/get-intrinsic/package.json +12 -12
- package/node_modules/has-property-descriptors/CHANGELOG.md +8 -0
- package/node_modules/has-property-descriptors/index.js +3 -14
- package/node_modules/has-property-descriptors/package.json +5 -5
- package/node_modules/has-proto/CHANGELOG.md +15 -0
- package/node_modules/has-proto/index.d.ts +3 -0
- package/node_modules/has-proto/index.js +5 -1
- package/node_modules/has-proto/package.json +9 -5
- package/node_modules/has-proto/tsconfig.json +49 -0
- package/node_modules/has-tostringtag/.eslintrc +0 -6
- package/node_modules/has-tostringtag/.nycrc +13 -0
- package/node_modules/has-tostringtag/CHANGELOG.md +22 -0
- package/node_modules/has-tostringtag/index.d.ts +3 -0
- package/node_modules/has-tostringtag/index.js +1 -0
- package/node_modules/has-tostringtag/package.json +37 -13
- package/node_modules/has-tostringtag/shams.d.ts +3 -0
- package/node_modules/has-tostringtag/shams.js +1 -0
- package/node_modules/has-tostringtag/test/shams/core-js.js +3 -0
- package/node_modules/has-tostringtag/test/shams/get-own-property-symbols.js +2 -0
- package/node_modules/has-tostringtag/test/tests.js +2 -1
- package/node_modules/has-tostringtag/tsconfig.json +49 -0
- package/node_modules/hasown/CHANGELOG.md +8 -0
- package/node_modules/hasown/index.d.ts +3 -3
- package/node_modules/hasown/index.js +1 -1
- package/node_modules/hasown/package.json +13 -15
- package/node_modules/polygon-clipping/README.md +29 -26
- package/node_modules/polygon-clipping/dist/polygon-clipping.cjs.js +1398 -1421
- package/node_modules/polygon-clipping/dist/polygon-clipping.d.ts +13 -10
- package/node_modules/polygon-clipping/dist/polygon-clipping.esm.js +1139 -1427
- package/node_modules/polygon-clipping/dist/polygon-clipping.umd.js +1770 -1831
- package/node_modules/polygon-clipping/dist/polygon-clipping.umd.min.js +22 -8
- package/node_modules/polygon-clipping/dist/polygon-clipping.umd.min.js.map +1 -1
- package/node_modules/polygon-clipping/node_modules/robust-predicates/LICENSE +24 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/README.md +82 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/esm/incircle.js +765 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/esm/insphere.js +766 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/esm/orient2d.js +184 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/esm/orient3d.js +462 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/esm/util.js +138 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/index.d.ts +49 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/index.js +5 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/package.json +75 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/umd/incircle.js +908 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/umd/incircle.min.js +1 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/umd/insphere.js +914 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/umd/insphere.min.js +1 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/umd/orient2d.js +280 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/umd/orient2d.min.js +1 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/umd/orient3d.js +601 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/umd/orient3d.min.js +1 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/umd/predicates.js +2328 -0
- package/node_modules/polygon-clipping/node_modules/robust-predicates/umd/predicates.min.js +1 -0
- package/node_modules/polygon-clipping/package.json +30 -25
- package/node_modules/protobufjs/dist/light/protobuf.js +4 -4
- package/node_modules/protobufjs/dist/light/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/light/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/light/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/dist/minimal/protobuf.js +2 -2
- package/node_modules/protobufjs/dist/minimal/protobuf.min.js +2 -2
- package/node_modules/protobufjs/dist/protobuf.js +4 -4
- package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/package.json +1 -1
- package/node_modules/protobufjs/src/root.js +2 -2
- package/node_modules/regexp.prototype.flags/CHANGELOG.md +13 -0
- package/node_modules/regexp.prototype.flags/implementation.js +2 -2
- package/node_modules/regexp.prototype.flags/package.json +11 -10
- package/node_modules/regexp.prototype.flags/test/tests.js +13 -13
- package/node_modules/set-function-length/CHANGELOG.md +18 -0
- package/node_modules/set-function-length/env.d.ts +6 -0
- package/node_modules/set-function-length/env.d.ts.map +1 -0
- package/node_modules/set-function-length/env.js +9 -4
- package/node_modules/set-function-length/index.d.ts +7 -0
- package/node_modules/set-function-length/index.d.ts.map +1 -0
- package/node_modules/set-function-length/index.js +6 -3
- package/node_modules/set-function-length/package.json +33 -13
- package/node_modules/set-function-length/tsconfig.json +59 -0
- package/node_modules/set-function-name/.eslintrc +1 -0
- package/node_modules/set-function-name/CHANGELOG.md +9 -0
- package/node_modules/set-function-name/index.d.ts +5 -0
- package/node_modules/set-function-name/index.js +4 -3
- package/node_modules/set-function-name/package.json +28 -9
- package/node_modules/set-function-name/tsconfig.json +59 -0
- package/package.json +4 -4
- package/tak-ingest.js +15 -7
- package/node_modules/define-data-property/index.d.ts.map +0 -1
- package/node_modules/hasown/index.d.ts.map +0 -1
- package/node_modules/polygon-clipping/CHANGELOG.md +0 -129
|
@@ -1,1115 +1,1279 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}(this, (function () { 'use strict';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
var descriptor = props[i];
|
|
16
|
-
descriptor.enumerable = descriptor.enumerable || false;
|
|
17
|
-
descriptor.configurable = true;
|
|
18
|
-
if ("value" in descriptor) descriptor.writable = true;
|
|
19
|
-
Object.defineProperty(target, descriptor.key, descriptor);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function _createClass(Constructor, protoProps, staticProps) {
|
|
24
|
-
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
25
|
-
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
26
|
-
return Constructor;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* splaytree v3.1.0
|
|
31
|
-
* Fast Splay tree for Node and browser
|
|
32
|
-
*
|
|
33
|
-
* @author Alexander Milevski <info@w8r.name>
|
|
34
|
-
* @license MIT
|
|
35
|
-
* @preserve
|
|
36
|
-
*/
|
|
37
|
-
var Node =
|
|
38
|
-
/** @class */
|
|
39
|
-
function () {
|
|
40
|
-
function Node(key, data) {
|
|
41
|
-
this.next = null;
|
|
42
|
-
this.key = key;
|
|
43
|
-
this.data = data;
|
|
44
|
-
this.left = null;
|
|
45
|
-
this.right = null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return Node;
|
|
49
|
-
}();
|
|
50
|
-
/* follows "An implementation of top-down splaying"
|
|
51
|
-
* by D. Sleator <sleator@cs.cmu.edu> March 1992
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
function DEFAULT_COMPARE(a, b) {
|
|
56
|
-
return a > b ? 1 : a < b ? -1 : 0;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Simple top down splay, not requiring i to be in the tree t.
|
|
60
|
-
*/
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
function splay(i, t, comparator) {
|
|
64
|
-
var N = new Node(null, null);
|
|
65
|
-
var l = N;
|
|
66
|
-
var r = N;
|
|
67
|
-
|
|
68
|
-
while (true) {
|
|
69
|
-
var cmp = comparator(i, t.key); //if (i < t.key) {
|
|
70
|
-
|
|
71
|
-
if (cmp < 0) {
|
|
72
|
-
if (t.left === null) break; //if (i < t.left.key) {
|
|
73
|
-
|
|
74
|
-
if (comparator(i, t.left.key) < 0) {
|
|
75
|
-
var y = t.left;
|
|
76
|
-
/* rotate right */
|
|
77
|
-
|
|
78
|
-
t.left = y.right;
|
|
79
|
-
y.right = t;
|
|
80
|
-
t = y;
|
|
81
|
-
if (t.left === null) break;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
r.left = t;
|
|
85
|
-
/* link right */
|
|
86
|
-
|
|
87
|
-
r = t;
|
|
88
|
-
t = t.left; //} else if (i > t.key) {
|
|
89
|
-
} else if (cmp > 0) {
|
|
90
|
-
if (t.right === null) break; //if (i > t.right.key) {
|
|
91
|
-
|
|
92
|
-
if (comparator(i, t.right.key) > 0) {
|
|
93
|
-
var y = t.right;
|
|
94
|
-
/* rotate left */
|
|
95
|
-
|
|
96
|
-
t.right = y.left;
|
|
97
|
-
y.left = t;
|
|
98
|
-
t = y;
|
|
99
|
-
if (t.right === null) break;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
l.right = t;
|
|
103
|
-
/* link left */
|
|
104
|
-
|
|
105
|
-
l = t;
|
|
106
|
-
t = t.right;
|
|
107
|
-
} else break;
|
|
108
|
-
}
|
|
109
|
-
/* assemble */
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
l.right = t.left;
|
|
113
|
-
r.left = t.right;
|
|
114
|
-
t.left = N.right;
|
|
115
|
-
t.right = N.left;
|
|
116
|
-
return t;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function insert(i, data, t, comparator) {
|
|
120
|
-
var node = new Node(i, data);
|
|
121
|
-
|
|
122
|
-
if (t === null) {
|
|
123
|
-
node.left = node.right = null;
|
|
124
|
-
return node;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
t = splay(i, t, comparator);
|
|
128
|
-
var cmp = comparator(i, t.key);
|
|
129
|
-
|
|
130
|
-
if (cmp < 0) {
|
|
131
|
-
node.left = t.left;
|
|
132
|
-
node.right = t;
|
|
133
|
-
t.left = null;
|
|
134
|
-
} else if (cmp >= 0) {
|
|
135
|
-
node.right = t.right;
|
|
136
|
-
node.left = t;
|
|
137
|
-
t.right = null;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return node;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function split(key, v, comparator) {
|
|
144
|
-
var left = null;
|
|
145
|
-
var right = null;
|
|
146
|
-
|
|
147
|
-
if (v) {
|
|
148
|
-
v = splay(key, v, comparator);
|
|
149
|
-
var cmp = comparator(v.key, key);
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.polygonClipping = factory());
|
|
5
|
+
})(this, (function () { 'use strict';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* splaytree v3.1.2
|
|
9
|
+
* Fast Splay tree for Node and browser
|
|
10
|
+
*
|
|
11
|
+
* @author Alexander Milevski <info@w8r.name>
|
|
12
|
+
* @license MIT
|
|
13
|
+
* @preserve
|
|
14
|
+
*/
|
|
150
15
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
16
|
+
/*! *****************************************************************************
|
|
17
|
+
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
18
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
19
|
+
this file except in compliance with the License. You may obtain a copy of the
|
|
20
|
+
License at http://www.apache.org/licenses/LICENSE-2.0
|
|
21
|
+
|
|
22
|
+
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
23
|
+
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
|
24
|
+
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
|
25
|
+
MERCHANTABLITY OR NON-INFRINGEMENT.
|
|
26
|
+
|
|
27
|
+
See the Apache Version 2.0 License for specific language governing permissions
|
|
28
|
+
and limitations under the License.
|
|
29
|
+
***************************************************************************** */
|
|
30
|
+
|
|
31
|
+
function __generator(thisArg, body) {
|
|
32
|
+
var _ = {
|
|
33
|
+
label: 0,
|
|
34
|
+
sent: function () {
|
|
35
|
+
if (t[0] & 1) throw t[1];
|
|
36
|
+
return t[1];
|
|
37
|
+
},
|
|
38
|
+
trys: [],
|
|
39
|
+
ops: []
|
|
40
|
+
},
|
|
41
|
+
f,
|
|
42
|
+
y,
|
|
43
|
+
t,
|
|
44
|
+
g;
|
|
45
|
+
return g = {
|
|
46
|
+
next: verb(0),
|
|
47
|
+
"throw": verb(1),
|
|
48
|
+
"return": verb(2)
|
|
49
|
+
}, typeof Symbol === "function" && (g[Symbol.iterator] = function () {
|
|
50
|
+
return this;
|
|
51
|
+
}), g;
|
|
52
|
+
function verb(n) {
|
|
53
|
+
return function (v) {
|
|
54
|
+
return step([n, v]);
|
|
55
|
+
};
|
|
162
56
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
57
|
+
function step(op) {
|
|
58
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
59
|
+
while (_) try {
|
|
60
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
61
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
62
|
+
switch (op[0]) {
|
|
63
|
+
case 0:
|
|
64
|
+
case 1:
|
|
65
|
+
t = op;
|
|
66
|
+
break;
|
|
67
|
+
case 4:
|
|
68
|
+
_.label++;
|
|
69
|
+
return {
|
|
70
|
+
value: op[1],
|
|
71
|
+
done: false
|
|
72
|
+
};
|
|
73
|
+
case 5:
|
|
74
|
+
_.label++;
|
|
75
|
+
y = op[1];
|
|
76
|
+
op = [0];
|
|
77
|
+
continue;
|
|
78
|
+
case 7:
|
|
79
|
+
op = _.ops.pop();
|
|
80
|
+
_.trys.pop();
|
|
81
|
+
continue;
|
|
82
|
+
default:
|
|
83
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
84
|
+
_ = 0;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
88
|
+
_.label = op[1];
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
if (op[0] === 6 && _.label < t[1]) {
|
|
92
|
+
_.label = t[1];
|
|
93
|
+
t = op;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
if (t && _.label < t[2]) {
|
|
97
|
+
_.label = t[2];
|
|
98
|
+
_.ops.push(op);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
if (t[2]) _.ops.pop();
|
|
102
|
+
_.trys.pop();
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
op = body.call(thisArg, _);
|
|
106
|
+
} catch (e) {
|
|
107
|
+
op = [6, e];
|
|
108
|
+
y = 0;
|
|
109
|
+
} finally {
|
|
110
|
+
f = t = 0;
|
|
111
|
+
}
|
|
112
|
+
if (op[0] & 5) throw op[1];
|
|
113
|
+
return {
|
|
114
|
+
value: op[0] ? op[1] : void 0,
|
|
115
|
+
done: true
|
|
116
|
+
};
|
|
198
117
|
}
|
|
199
|
-
|
|
200
|
-
this._root = null;
|
|
201
|
-
this._size = 0;
|
|
202
|
-
this._comparator = comparator;
|
|
203
118
|
}
|
|
204
|
-
/**
|
|
205
|
-
|
|
119
|
+
var Node = /** @class */function () {
|
|
120
|
+
function Node(key, data) {
|
|
121
|
+
this.next = null;
|
|
122
|
+
this.key = key;
|
|
123
|
+
this.data = data;
|
|
124
|
+
this.left = null;
|
|
125
|
+
this.right = null;
|
|
126
|
+
}
|
|
127
|
+
return Node;
|
|
128
|
+
}();
|
|
129
|
+
|
|
130
|
+
/* follows "An implementation of top-down splaying"
|
|
131
|
+
* by D. Sleator <sleator@cs.cmu.edu> March 1992
|
|
206
132
|
*/
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
this._size++;
|
|
211
|
-
return this._root = insert(key, data, this._root, this._comparator);
|
|
212
|
-
};
|
|
133
|
+
function DEFAULT_COMPARE(a, b) {
|
|
134
|
+
return a > b ? 1 : a < b ? -1 : 0;
|
|
135
|
+
}
|
|
213
136
|
/**
|
|
214
|
-
*
|
|
137
|
+
* Simple top down splay, not requiring i to be in the tree t.
|
|
215
138
|
*/
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
var
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
this._size++;
|
|
224
|
-
this._root = node;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
var comparator = this._comparator;
|
|
228
|
-
var t = splay(key, this._root, comparator);
|
|
229
|
-
var cmp = comparator(key, t.key);
|
|
230
|
-
if (cmp === 0) this._root = t;else {
|
|
139
|
+
function splay(i, t, comparator) {
|
|
140
|
+
var N = new Node(null, null);
|
|
141
|
+
var l = N;
|
|
142
|
+
var r = N;
|
|
143
|
+
while (true) {
|
|
144
|
+
var cmp = comparator(i, t.key);
|
|
145
|
+
//if (i < t.key) {
|
|
231
146
|
if (cmp < 0) {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
t.left
|
|
147
|
+
if (t.left === null) break;
|
|
148
|
+
//if (i < t.left.key) {
|
|
149
|
+
if (comparator(i, t.left.key) < 0) {
|
|
150
|
+
var y = t.left; /* rotate right */
|
|
151
|
+
t.left = y.right;
|
|
152
|
+
y.right = t;
|
|
153
|
+
t = y;
|
|
154
|
+
if (t.left === null) break;
|
|
155
|
+
}
|
|
156
|
+
r.left = t; /* link right */
|
|
157
|
+
r = t;
|
|
158
|
+
t = t.left;
|
|
159
|
+
//} else if (i > t.key) {
|
|
235
160
|
} else if (cmp > 0) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
t.right
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
161
|
+
if (t.right === null) break;
|
|
162
|
+
//if (i > t.right.key) {
|
|
163
|
+
if (comparator(i, t.right.key) > 0) {
|
|
164
|
+
var y = t.right; /* rotate left */
|
|
165
|
+
t.right = y.left;
|
|
166
|
+
y.left = t;
|
|
167
|
+
t = y;
|
|
168
|
+
if (t.right === null) break;
|
|
169
|
+
}
|
|
170
|
+
l.right = t; /* link left */
|
|
171
|
+
l = t;
|
|
172
|
+
t = t.right;
|
|
173
|
+
} else break;
|
|
174
|
+
}
|
|
175
|
+
/* assemble */
|
|
176
|
+
l.right = t.left;
|
|
177
|
+
r.left = t.right;
|
|
178
|
+
t.left = N.right;
|
|
179
|
+
t.right = N.left;
|
|
180
|
+
return t;
|
|
181
|
+
}
|
|
182
|
+
function insert(i, data, t, comparator) {
|
|
183
|
+
var node = new Node(i, data);
|
|
184
|
+
if (t === null) {
|
|
185
|
+
node.left = node.right = null;
|
|
186
|
+
return node;
|
|
243
187
|
}
|
|
244
|
-
return this._root;
|
|
245
|
-
};
|
|
246
|
-
/**
|
|
247
|
-
* @param {Key} key
|
|
248
|
-
* @return {Node|null}
|
|
249
|
-
*/
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
Tree.prototype.remove = function (key) {
|
|
253
|
-
this._root = this._remove(key, this._root, this._comparator);
|
|
254
|
-
};
|
|
255
|
-
/**
|
|
256
|
-
* Deletes i from the tree if it's there
|
|
257
|
-
*/
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
Tree.prototype._remove = function (i, t, comparator) {
|
|
261
|
-
var x;
|
|
262
|
-
if (t === null) return null;
|
|
263
188
|
t = splay(i, t, comparator);
|
|
264
189
|
var cmp = comparator(i, t.key);
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
this._size--;
|
|
276
|
-
return x;
|
|
190
|
+
if (cmp < 0) {
|
|
191
|
+
node.left = t.left;
|
|
192
|
+
node.right = t;
|
|
193
|
+
t.left = null;
|
|
194
|
+
} else if (cmp >= 0) {
|
|
195
|
+
node.right = t.right;
|
|
196
|
+
node.left = t;
|
|
197
|
+
t.right = null;
|
|
277
198
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
199
|
+
return node;
|
|
200
|
+
}
|
|
201
|
+
function split(key, v, comparator) {
|
|
202
|
+
var left = null;
|
|
203
|
+
var right = null;
|
|
204
|
+
if (v) {
|
|
205
|
+
v = splay(key, v, comparator);
|
|
206
|
+
var cmp = comparator(v.key, key);
|
|
207
|
+
if (cmp === 0) {
|
|
208
|
+
left = v.left;
|
|
209
|
+
right = v.right;
|
|
210
|
+
} else if (cmp < 0) {
|
|
211
|
+
right = v.right;
|
|
212
|
+
v.right = null;
|
|
213
|
+
left = v;
|
|
214
|
+
} else {
|
|
215
|
+
left = v.left;
|
|
216
|
+
v.left = null;
|
|
217
|
+
right = v;
|
|
293
218
|
}
|
|
294
|
-
|
|
295
|
-
this._root = splay(node.key, this._root, this._comparator);
|
|
296
|
-
this._root = this._remove(node.key, this._root, this._comparator);
|
|
297
|
-
return {
|
|
298
|
-
key: node.key,
|
|
299
|
-
data: node.data
|
|
300
|
-
};
|
|
301
219
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
220
|
+
return {
|
|
221
|
+
left: left,
|
|
222
|
+
right: right
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function merge(left, right, comparator) {
|
|
226
|
+
if (right === null) return left;
|
|
227
|
+
if (left === null) return right;
|
|
228
|
+
right = splay(left.key, right, comparator);
|
|
229
|
+
right.left = left;
|
|
230
|
+
return right;
|
|
231
|
+
}
|
|
305
232
|
/**
|
|
306
|
-
*
|
|
233
|
+
* Prints level of the tree
|
|
307
234
|
*/
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
while (current) {
|
|
315
|
-
var cmp = compare(key, current.key);
|
|
316
|
-
if (cmp === 0) return current;else if (cmp < 0) current = current.left;else current = current.right;
|
|
235
|
+
function printRow(root, prefix, isTail, out, printNode) {
|
|
236
|
+
if (root) {
|
|
237
|
+
out("" + prefix + (isTail ? '└── ' : '├── ') + printNode(root) + "\n");
|
|
238
|
+
var indent = prefix + (isTail ? ' ' : '│ ');
|
|
239
|
+
if (root.left) printRow(root.left, indent, false, out, printNode);
|
|
240
|
+
if (root.right) printRow(root.right, indent, true, out, printNode);
|
|
317
241
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if (this._root) {
|
|
324
|
-
this._root = splay(key, this._root, this._comparator);
|
|
325
|
-
if (this._comparator(key, this._root.key) !== 0) return null;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return this._root;
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
Tree.prototype.contains = function (key) {
|
|
332
|
-
var current = this._root;
|
|
333
|
-
var compare = this._comparator;
|
|
334
|
-
|
|
335
|
-
while (current) {
|
|
336
|
-
var cmp = compare(key, current.key);
|
|
337
|
-
if (cmp === 0) return true;else if (cmp < 0) current = current.left;else current = current.right;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return false;
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
Tree.prototype.forEach = function (visitor, ctx) {
|
|
344
|
-
var current = this._root;
|
|
345
|
-
var Q = [];
|
|
346
|
-
/* Initialize stack s */
|
|
347
|
-
|
|
348
|
-
var done = false;
|
|
349
|
-
|
|
350
|
-
while (!done) {
|
|
351
|
-
if (current !== null) {
|
|
352
|
-
Q.push(current);
|
|
353
|
-
current = current.left;
|
|
354
|
-
} else {
|
|
355
|
-
if (Q.length !== 0) {
|
|
356
|
-
current = Q.pop();
|
|
357
|
-
visitor.call(ctx, current);
|
|
358
|
-
current = current.right;
|
|
359
|
-
} else done = true;
|
|
242
|
+
}
|
|
243
|
+
var Tree = /** @class */function () {
|
|
244
|
+
function Tree(comparator) {
|
|
245
|
+
if (comparator === void 0) {
|
|
246
|
+
comparator = DEFAULT_COMPARE;
|
|
360
247
|
}
|
|
248
|
+
this._root = null;
|
|
249
|
+
this._size = 0;
|
|
250
|
+
this._comparator = comparator;
|
|
361
251
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
252
|
+
/**
|
|
253
|
+
* Inserts a key, allows duplicates
|
|
254
|
+
*/
|
|
255
|
+
Tree.prototype.insert = function (key, data) {
|
|
256
|
+
this._size++;
|
|
257
|
+
return this._root = insert(key, data, this._root, this._comparator);
|
|
258
|
+
};
|
|
259
|
+
/**
|
|
260
|
+
* Adds a key, if it is not present in the tree
|
|
261
|
+
*/
|
|
262
|
+
Tree.prototype.add = function (key, data) {
|
|
263
|
+
var node = new Node(key, data);
|
|
264
|
+
if (this._root === null) {
|
|
265
|
+
node.left = node.right = null;
|
|
266
|
+
this._size++;
|
|
267
|
+
this._root = node;
|
|
268
|
+
}
|
|
269
|
+
var comparator = this._comparator;
|
|
270
|
+
var t = splay(key, this._root, comparator);
|
|
271
|
+
var cmp = comparator(key, t.key);
|
|
272
|
+
if (cmp === 0) this._root = t;else {
|
|
273
|
+
if (cmp < 0) {
|
|
274
|
+
node.left = t.left;
|
|
275
|
+
node.right = t;
|
|
276
|
+
t.left = null;
|
|
277
|
+
} else if (cmp > 0) {
|
|
278
|
+
node.right = t.right;
|
|
279
|
+
node.left = t;
|
|
280
|
+
t.right = null;
|
|
281
|
+
}
|
|
282
|
+
this._size++;
|
|
283
|
+
this._root = node;
|
|
284
|
+
}
|
|
285
|
+
return this._root;
|
|
286
|
+
};
|
|
287
|
+
/**
|
|
288
|
+
* @param {Key} key
|
|
289
|
+
* @return {Node|null}
|
|
290
|
+
*/
|
|
291
|
+
Tree.prototype.remove = function (key) {
|
|
292
|
+
this._root = this._remove(key, this._root, this._comparator);
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* Deletes i from the tree if it's there
|
|
296
|
+
*/
|
|
297
|
+
Tree.prototype._remove = function (i, t, comparator) {
|
|
298
|
+
var x;
|
|
299
|
+
if (t === null) return null;
|
|
300
|
+
t = splay(i, t, comparator);
|
|
301
|
+
var cmp = comparator(i, t.key);
|
|
302
|
+
if (cmp === 0) {
|
|
303
|
+
/* found it */
|
|
304
|
+
if (t.left === null) {
|
|
305
|
+
x = t.right;
|
|
306
|
+
} else {
|
|
307
|
+
x = splay(i, t.left, comparator);
|
|
308
|
+
x.right = t.right;
|
|
309
|
+
}
|
|
310
|
+
this._size--;
|
|
311
|
+
return x;
|
|
312
|
+
}
|
|
313
|
+
return t; /* It wasn't there */
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* Removes and returns the node with smallest key
|
|
317
|
+
*/
|
|
318
|
+
Tree.prototype.pop = function () {
|
|
319
|
+
var node = this._root;
|
|
377
320
|
if (node) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
321
|
+
while (node.left) node = node.left;
|
|
322
|
+
this._root = splay(node.key, this._root, this._comparator);
|
|
323
|
+
this._root = this._remove(node.key, this._root, this._comparator);
|
|
324
|
+
return {
|
|
325
|
+
key: node.key,
|
|
326
|
+
data: node.data
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
return null;
|
|
330
|
+
};
|
|
331
|
+
/**
|
|
332
|
+
* Find without splaying
|
|
333
|
+
*/
|
|
334
|
+
Tree.prototype.findStatic = function (key) {
|
|
335
|
+
var current = this._root;
|
|
336
|
+
var compare = this._comparator;
|
|
337
|
+
while (current) {
|
|
338
|
+
var cmp = compare(key, current.key);
|
|
339
|
+
if (cmp === 0) return current;else if (cmp < 0) current = current.left;else current = current.right;
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
342
|
+
};
|
|
343
|
+
Tree.prototype.find = function (key) {
|
|
344
|
+
if (this._root) {
|
|
345
|
+
this._root = splay(key, this._root, this._comparator);
|
|
346
|
+
if (this._comparator(key, this._root.key) !== 0) return null;
|
|
347
|
+
}
|
|
348
|
+
return this._root;
|
|
349
|
+
};
|
|
350
|
+
Tree.prototype.contains = function (key) {
|
|
351
|
+
var current = this._root;
|
|
352
|
+
var compare = this._comparator;
|
|
353
|
+
while (current) {
|
|
354
|
+
var cmp = compare(key, current.key);
|
|
355
|
+
if (cmp === 0) return true;else if (cmp < 0) current = current.left;else current = current.right;
|
|
356
|
+
}
|
|
357
|
+
return false;
|
|
358
|
+
};
|
|
359
|
+
Tree.prototype.forEach = function (visitor, ctx) {
|
|
360
|
+
var current = this._root;
|
|
361
|
+
var Q = []; /* Initialize stack s */
|
|
362
|
+
var done = false;
|
|
363
|
+
while (!done) {
|
|
364
|
+
if (current !== null) {
|
|
365
|
+
Q.push(current);
|
|
366
|
+
current = current.left;
|
|
367
|
+
} else {
|
|
368
|
+
if (Q.length !== 0) {
|
|
369
|
+
current = Q.pop();
|
|
370
|
+
visitor.call(ctx, current);
|
|
371
|
+
current = current.right;
|
|
372
|
+
} else done = true;
|
|
388
373
|
}
|
|
389
|
-
|
|
390
|
-
node = node.right;
|
|
391
374
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
375
|
+
return this;
|
|
376
|
+
};
|
|
377
|
+
/**
|
|
378
|
+
* Walk key range from `low` to `high`. Stops if `fn` returns a value.
|
|
379
|
+
*/
|
|
380
|
+
Tree.prototype.range = function (low, high, fn, ctx) {
|
|
381
|
+
var Q = [];
|
|
382
|
+
var compare = this._comparator;
|
|
383
|
+
var node = this._root;
|
|
384
|
+
var cmp;
|
|
385
|
+
while (Q.length !== 0 || node) {
|
|
386
|
+
if (node) {
|
|
387
|
+
Q.push(node);
|
|
388
|
+
node = node.left;
|
|
389
|
+
} else {
|
|
390
|
+
node = Q.pop();
|
|
391
|
+
cmp = compare(node.key, high);
|
|
392
|
+
if (cmp > 0) {
|
|
393
|
+
break;
|
|
394
|
+
} else if (compare(node.key, low) >= 0) {
|
|
395
|
+
if (fn.call(ctx, node)) return this; // stop if smth is returned
|
|
396
|
+
}
|
|
397
|
+
node = node.right;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return this;
|
|
401
|
+
};
|
|
402
|
+
/**
|
|
403
|
+
* Returns array of keys
|
|
404
|
+
*/
|
|
405
|
+
Tree.prototype.keys = function () {
|
|
406
|
+
var keys = [];
|
|
407
|
+
this.forEach(function (_a) {
|
|
408
|
+
var key = _a.key;
|
|
409
|
+
return keys.push(key);
|
|
410
|
+
});
|
|
411
|
+
return keys;
|
|
412
|
+
};
|
|
413
|
+
/**
|
|
414
|
+
* Returns array of all the data in the nodes
|
|
415
|
+
*/
|
|
416
|
+
Tree.prototype.values = function () {
|
|
417
|
+
var values = [];
|
|
418
|
+
this.forEach(function (_a) {
|
|
419
|
+
var data = _a.data;
|
|
420
|
+
return values.push(data);
|
|
421
|
+
});
|
|
422
|
+
return values;
|
|
423
|
+
};
|
|
424
|
+
Tree.prototype.min = function () {
|
|
425
|
+
if (this._root) return this.minNode(this._root).key;
|
|
426
|
+
return null;
|
|
427
|
+
};
|
|
428
|
+
Tree.prototype.max = function () {
|
|
429
|
+
if (this._root) return this.maxNode(this._root).key;
|
|
430
|
+
return null;
|
|
431
|
+
};
|
|
432
|
+
Tree.prototype.minNode = function (t) {
|
|
433
|
+
if (t === void 0) {
|
|
434
|
+
t = this._root;
|
|
435
|
+
}
|
|
436
|
+
if (t) while (t.left) t = t.left;
|
|
437
|
+
return t;
|
|
438
|
+
};
|
|
439
|
+
Tree.prototype.maxNode = function (t) {
|
|
440
|
+
if (t === void 0) {
|
|
441
|
+
t = this._root;
|
|
442
|
+
}
|
|
443
|
+
if (t) while (t.right) t = t.right;
|
|
444
|
+
return t;
|
|
445
|
+
};
|
|
446
|
+
/**
|
|
447
|
+
* Returns node at given index
|
|
448
|
+
*/
|
|
449
|
+
Tree.prototype.at = function (index) {
|
|
450
|
+
var current = this._root;
|
|
451
|
+
var done = false;
|
|
452
|
+
var i = 0;
|
|
453
|
+
var Q = [];
|
|
454
|
+
while (!done) {
|
|
455
|
+
if (current) {
|
|
456
|
+
Q.push(current);
|
|
457
|
+
current = current.left;
|
|
458
|
+
} else {
|
|
459
|
+
if (Q.length > 0) {
|
|
460
|
+
current = Q.pop();
|
|
461
|
+
if (i === index) return current;
|
|
462
|
+
i++;
|
|
463
|
+
current = current.right;
|
|
464
|
+
} else done = true;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
};
|
|
469
|
+
Tree.prototype.next = function (d) {
|
|
470
|
+
var root = this._root;
|
|
471
|
+
var successor = null;
|
|
472
|
+
if (d.right) {
|
|
473
|
+
successor = d.right;
|
|
474
|
+
while (successor.left) successor = successor.left;
|
|
475
|
+
return successor;
|
|
476
|
+
}
|
|
477
|
+
var comparator = this._comparator;
|
|
478
|
+
while (root) {
|
|
479
|
+
var cmp = comparator(d.key, root.key);
|
|
480
|
+
if (cmp === 0) break;else if (cmp < 0) {
|
|
481
|
+
successor = root;
|
|
482
|
+
root = root.left;
|
|
483
|
+
} else root = root.right;
|
|
484
|
+
}
|
|
485
|
+
return successor;
|
|
486
|
+
};
|
|
487
|
+
Tree.prototype.prev = function (d) {
|
|
488
|
+
var root = this._root;
|
|
489
|
+
var predecessor = null;
|
|
490
|
+
if (d.left !== null) {
|
|
491
|
+
predecessor = d.left;
|
|
492
|
+
while (predecessor.right) predecessor = predecessor.right;
|
|
493
|
+
return predecessor;
|
|
494
|
+
}
|
|
495
|
+
var comparator = this._comparator;
|
|
496
|
+
while (root) {
|
|
497
|
+
var cmp = comparator(d.key, root.key);
|
|
498
|
+
if (cmp === 0) break;else if (cmp < 0) root = root.left;else {
|
|
499
|
+
predecessor = root;
|
|
500
|
+
root = root.right;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return predecessor;
|
|
504
|
+
};
|
|
505
|
+
Tree.prototype.clear = function () {
|
|
506
|
+
this._root = null;
|
|
507
|
+
this._size = 0;
|
|
508
|
+
return this;
|
|
509
|
+
};
|
|
510
|
+
Tree.prototype.toList = function () {
|
|
511
|
+
return toList(this._root);
|
|
512
|
+
};
|
|
513
|
+
/**
|
|
514
|
+
* Bulk-load items. Both array have to be same size
|
|
515
|
+
*/
|
|
516
|
+
Tree.prototype.load = function (keys, values, presort) {
|
|
517
|
+
if (values === void 0) {
|
|
518
|
+
values = [];
|
|
519
|
+
}
|
|
520
|
+
if (presort === void 0) {
|
|
521
|
+
presort = false;
|
|
522
|
+
}
|
|
523
|
+
var size = keys.length;
|
|
524
|
+
var comparator = this._comparator;
|
|
525
|
+
// sort if needed
|
|
526
|
+
if (presort) sort(keys, values, 0, size - 1, comparator);
|
|
527
|
+
if (this._root === null) {
|
|
528
|
+
// empty tree
|
|
529
|
+
this._root = loadRecursive(keys, values, 0, size);
|
|
530
|
+
this._size = size;
|
|
531
|
+
} else {
|
|
532
|
+
// that re-builds the whole tree from two in-order traversals
|
|
533
|
+
var mergedList = mergeLists(this.toList(), createList(keys, values), comparator);
|
|
534
|
+
size = this._size + size;
|
|
535
|
+
this._root = sortedListToBST({
|
|
536
|
+
head: mergedList
|
|
537
|
+
}, 0, size);
|
|
538
|
+
}
|
|
539
|
+
return this;
|
|
540
|
+
};
|
|
541
|
+
Tree.prototype.isEmpty = function () {
|
|
542
|
+
return this._root === null;
|
|
543
|
+
};
|
|
544
|
+
Object.defineProperty(Tree.prototype, "size", {
|
|
545
|
+
get: function () {
|
|
546
|
+
return this._size;
|
|
547
|
+
},
|
|
548
|
+
enumerable: true,
|
|
549
|
+
configurable: true
|
|
406
550
|
});
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
Tree.prototype.values = function () {
|
|
415
|
-
var values = [];
|
|
416
|
-
this.forEach(function (_a) {
|
|
417
|
-
var data = _a.data;
|
|
418
|
-
return values.push(data);
|
|
551
|
+
Object.defineProperty(Tree.prototype, "root", {
|
|
552
|
+
get: function () {
|
|
553
|
+
return this._root;
|
|
554
|
+
},
|
|
555
|
+
enumerable: true,
|
|
556
|
+
configurable: true
|
|
419
557
|
});
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
558
|
+
Tree.prototype.toString = function (printNode) {
|
|
559
|
+
if (printNode === void 0) {
|
|
560
|
+
printNode = function (n) {
|
|
561
|
+
return String(n.key);
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
var out = [];
|
|
565
|
+
printRow(this._root, '', true, function (v) {
|
|
566
|
+
return out.push(v);
|
|
567
|
+
}, printNode);
|
|
568
|
+
return out.join('');
|
|
569
|
+
};
|
|
570
|
+
Tree.prototype.update = function (key, newKey, newData) {
|
|
571
|
+
var comparator = this._comparator;
|
|
572
|
+
var _a = split(key, this._root, comparator),
|
|
573
|
+
left = _a.left,
|
|
574
|
+
right = _a.right;
|
|
575
|
+
if (comparator(key, newKey) < 0) {
|
|
576
|
+
right = insert(newKey, newData, right, comparator);
|
|
577
|
+
} else {
|
|
578
|
+
left = insert(newKey, newData, left, comparator);
|
|
579
|
+
}
|
|
580
|
+
this._root = merge(left, right, comparator);
|
|
581
|
+
};
|
|
582
|
+
Tree.prototype.split = function (key) {
|
|
583
|
+
return split(key, this._root, this._comparator);
|
|
584
|
+
};
|
|
585
|
+
Tree.prototype[Symbol.iterator] = function () {
|
|
586
|
+
var current, Q, done;
|
|
587
|
+
return __generator(this, function (_a) {
|
|
588
|
+
switch (_a.label) {
|
|
589
|
+
case 0:
|
|
590
|
+
current = this._root;
|
|
591
|
+
Q = [];
|
|
592
|
+
done = false;
|
|
593
|
+
_a.label = 1;
|
|
594
|
+
case 1:
|
|
595
|
+
if (!!done) return [3 /*break*/, 6];
|
|
596
|
+
if (!(current !== null)) return [3 /*break*/, 2];
|
|
597
|
+
Q.push(current);
|
|
598
|
+
current = current.left;
|
|
599
|
+
return [3 /*break*/, 5];
|
|
600
|
+
case 2:
|
|
601
|
+
if (!(Q.length !== 0)) return [3 /*break*/, 4];
|
|
602
|
+
current = Q.pop();
|
|
603
|
+
return [4 /*yield*/, current];
|
|
604
|
+
case 3:
|
|
605
|
+
_a.sent();
|
|
606
|
+
current = current.right;
|
|
607
|
+
return [3 /*break*/, 5];
|
|
608
|
+
case 4:
|
|
609
|
+
done = true;
|
|
610
|
+
_a.label = 5;
|
|
611
|
+
case 5:
|
|
612
|
+
return [3 /*break*/, 1];
|
|
613
|
+
case 6:
|
|
614
|
+
return [2 /*return*/];
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
};
|
|
618
|
+
return Tree;
|
|
619
|
+
}();
|
|
620
|
+
function loadRecursive(keys, values, start, end) {
|
|
621
|
+
var size = end - start;
|
|
622
|
+
if (size > 0) {
|
|
623
|
+
var middle = start + Math.floor(size / 2);
|
|
624
|
+
var key = keys[middle];
|
|
625
|
+
var data = values[middle];
|
|
626
|
+
var node = new Node(key, data);
|
|
627
|
+
node.left = loadRecursive(keys, values, start, middle);
|
|
628
|
+
node.right = loadRecursive(keys, values, middle + 1, end);
|
|
629
|
+
return node;
|
|
451
630
|
}
|
|
452
|
-
return
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
633
|
+
function createList(keys, values) {
|
|
634
|
+
var head = new Node(null, null);
|
|
635
|
+
var p = head;
|
|
636
|
+
for (var i = 0; i < keys.length; i++) {
|
|
637
|
+
p = p.next = new Node(keys[i], values[i]);
|
|
638
|
+
}
|
|
639
|
+
p.next = null;
|
|
640
|
+
return head.next;
|
|
641
|
+
}
|
|
642
|
+
function toList(root) {
|
|
643
|
+
var current = root;
|
|
463
644
|
var Q = [];
|
|
464
|
-
|
|
645
|
+
var done = false;
|
|
646
|
+
var head = new Node(null, null);
|
|
647
|
+
var p = head;
|
|
465
648
|
while (!done) {
|
|
466
649
|
if (current) {
|
|
467
650
|
Q.push(current);
|
|
468
651
|
current = current.left;
|
|
469
652
|
} else {
|
|
470
653
|
if (Q.length > 0) {
|
|
471
|
-
current = Q.pop();
|
|
472
|
-
if (i === index) return current;
|
|
473
|
-
i++;
|
|
654
|
+
current = p = p.next = Q.pop();
|
|
474
655
|
current = current.right;
|
|
475
|
-
} else done = true;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
return
|
|
480
|
-
};
|
|
481
|
-
|
|
482
|
-
Tree.prototype.next = function (d) {
|
|
483
|
-
var root = this._root;
|
|
484
|
-
var successor = null;
|
|
485
|
-
|
|
486
|
-
if (d.right) {
|
|
487
|
-
successor = d.right;
|
|
488
|
-
|
|
489
|
-
while (successor.left) {
|
|
490
|
-
successor = successor.left;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
return successor;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
var comparator = this._comparator;
|
|
497
|
-
|
|
498
|
-
while (root) {
|
|
499
|
-
var cmp = comparator(d.key, root.key);
|
|
500
|
-
if (cmp === 0) break;else if (cmp < 0) {
|
|
501
|
-
successor = root;
|
|
502
|
-
root = root.left;
|
|
503
|
-
} else root = root.right;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
return successor;
|
|
507
|
-
};
|
|
508
|
-
|
|
509
|
-
Tree.prototype.prev = function (d) {
|
|
510
|
-
var root = this._root;
|
|
511
|
-
var predecessor = null;
|
|
512
|
-
|
|
513
|
-
if (d.left !== null) {
|
|
514
|
-
predecessor = d.left;
|
|
515
|
-
|
|
516
|
-
while (predecessor.right) {
|
|
517
|
-
predecessor = predecessor.right;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
return predecessor;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
var comparator = this._comparator;
|
|
524
|
-
|
|
525
|
-
while (root) {
|
|
526
|
-
var cmp = comparator(d.key, root.key);
|
|
527
|
-
if (cmp === 0) break;else if (cmp < 0) root = root.left;else {
|
|
528
|
-
predecessor = root;
|
|
529
|
-
root = root.right;
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
return predecessor;
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
Tree.prototype.clear = function () {
|
|
537
|
-
this._root = null;
|
|
538
|
-
this._size = 0;
|
|
539
|
-
return this;
|
|
540
|
-
};
|
|
541
|
-
|
|
542
|
-
Tree.prototype.toList = function () {
|
|
543
|
-
return toList(this._root);
|
|
544
|
-
};
|
|
545
|
-
/**
|
|
546
|
-
* Bulk-load items. Both array have to be same size
|
|
547
|
-
*/
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
Tree.prototype.load = function (keys, values, presort) {
|
|
551
|
-
if (values === void 0) {
|
|
552
|
-
values = [];
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
if (presort === void 0) {
|
|
556
|
-
presort = false;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
var size = keys.length;
|
|
560
|
-
var comparator = this._comparator; // sort if needed
|
|
561
|
-
|
|
562
|
-
if (presort) sort(keys, values, 0, size - 1, comparator);
|
|
563
|
-
|
|
564
|
-
if (this._root === null) {
|
|
565
|
-
// empty tree
|
|
566
|
-
this._root = loadRecursive(keys, values, 0, size);
|
|
567
|
-
this._size = size;
|
|
568
|
-
} else {
|
|
569
|
-
// that re-builds the whole tree from two in-order traversals
|
|
570
|
-
var mergedList = mergeLists(this.toList(), createList(keys, values), comparator);
|
|
571
|
-
size = this._size + size;
|
|
572
|
-
this._root = sortedListToBST({
|
|
573
|
-
head: mergedList
|
|
574
|
-
}, 0, size);
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
return this;
|
|
578
|
-
};
|
|
579
|
-
|
|
580
|
-
Tree.prototype.isEmpty = function () {
|
|
581
|
-
return this._root === null;
|
|
582
|
-
};
|
|
583
|
-
|
|
584
|
-
Object.defineProperty(Tree.prototype, "size", {
|
|
585
|
-
get: function get() {
|
|
586
|
-
return this._size;
|
|
587
|
-
},
|
|
588
|
-
enumerable: true,
|
|
589
|
-
configurable: true
|
|
590
|
-
});
|
|
591
|
-
Object.defineProperty(Tree.prototype, "root", {
|
|
592
|
-
get: function get() {
|
|
593
|
-
return this._root;
|
|
594
|
-
},
|
|
595
|
-
enumerable: true,
|
|
596
|
-
configurable: true
|
|
597
|
-
});
|
|
598
|
-
|
|
599
|
-
Tree.prototype.toString = function (printNode) {
|
|
600
|
-
if (printNode === void 0) {
|
|
601
|
-
printNode = function printNode(n) {
|
|
602
|
-
return String(n.key);
|
|
603
|
-
};
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
var out = [];
|
|
607
|
-
printRow(this._root, '', true, function (v) {
|
|
608
|
-
return out.push(v);
|
|
609
|
-
}, printNode);
|
|
610
|
-
return out.join('');
|
|
611
|
-
};
|
|
612
|
-
|
|
613
|
-
Tree.prototype.update = function (key, newKey, newData) {
|
|
614
|
-
var comparator = this._comparator;
|
|
615
|
-
|
|
616
|
-
var _a = split(key, this._root, comparator),
|
|
617
|
-
left = _a.left,
|
|
618
|
-
right = _a.right;
|
|
619
|
-
|
|
620
|
-
if (comparator(key, newKey) < 0) {
|
|
621
|
-
right = insert(newKey, newData, right, comparator);
|
|
622
|
-
} else {
|
|
623
|
-
left = insert(newKey, newData, left, comparator);
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
this._root = merge(left, right, comparator);
|
|
627
|
-
};
|
|
628
|
-
|
|
629
|
-
Tree.prototype.split = function (key) {
|
|
630
|
-
return split(key, this._root, this._comparator);
|
|
631
|
-
};
|
|
632
|
-
|
|
633
|
-
return Tree;
|
|
634
|
-
}();
|
|
635
|
-
|
|
636
|
-
function loadRecursive(keys, values, start, end) {
|
|
637
|
-
var size = end - start;
|
|
638
|
-
|
|
639
|
-
if (size > 0) {
|
|
640
|
-
var middle = start + Math.floor(size / 2);
|
|
641
|
-
var key = keys[middle];
|
|
642
|
-
var data = values[middle];
|
|
643
|
-
var node = new Node(key, data);
|
|
644
|
-
node.left = loadRecursive(keys, values, start, middle);
|
|
645
|
-
node.right = loadRecursive(keys, values, middle + 1, end);
|
|
646
|
-
return node;
|
|
656
|
+
} else done = true;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
p.next = null; // that'll work even if the tree was empty
|
|
660
|
+
return head.next;
|
|
647
661
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
662
|
+
function sortedListToBST(list, start, end) {
|
|
663
|
+
var size = end - start;
|
|
664
|
+
if (size > 0) {
|
|
665
|
+
var middle = start + Math.floor(size / 2);
|
|
666
|
+
var left = sortedListToBST(list, start, middle);
|
|
667
|
+
var root = list.head;
|
|
668
|
+
root.left = left;
|
|
669
|
+
list.head = list.head.next;
|
|
670
|
+
root.right = sortedListToBST(list, middle + 1, end);
|
|
671
|
+
return root;
|
|
672
|
+
}
|
|
673
|
+
return null;
|
|
658
674
|
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
Q.push(current);
|
|
674
|
-
current = current.left;
|
|
675
|
-
} else {
|
|
676
|
-
if (Q.length > 0) {
|
|
677
|
-
current = p = p.next = Q.pop();
|
|
678
|
-
current = current.right;
|
|
679
|
-
} else done = true;
|
|
675
|
+
function mergeLists(l1, l2, compare) {
|
|
676
|
+
var head = new Node(null, null); // dummy
|
|
677
|
+
var p = head;
|
|
678
|
+
var p1 = l1;
|
|
679
|
+
var p2 = l2;
|
|
680
|
+
while (p1 !== null && p2 !== null) {
|
|
681
|
+
if (compare(p1.key, p2.key) < 0) {
|
|
682
|
+
p.next = p1;
|
|
683
|
+
p1 = p1.next;
|
|
684
|
+
} else {
|
|
685
|
+
p.next = p2;
|
|
686
|
+
p2 = p2.next;
|
|
687
|
+
}
|
|
688
|
+
p = p.next;
|
|
680
689
|
}
|
|
690
|
+
if (p1 !== null) {
|
|
691
|
+
p.next = p1;
|
|
692
|
+
} else if (p2 !== null) {
|
|
693
|
+
p.next = p2;
|
|
694
|
+
}
|
|
695
|
+
return head.next;
|
|
696
|
+
}
|
|
697
|
+
function sort(keys, values, left, right, compare) {
|
|
698
|
+
if (left >= right) return;
|
|
699
|
+
var pivot = keys[left + right >> 1];
|
|
700
|
+
var i = left - 1;
|
|
701
|
+
var j = right + 1;
|
|
702
|
+
while (true) {
|
|
703
|
+
do i++; while (compare(keys[i], pivot) < 0);
|
|
704
|
+
do j--; while (compare(keys[j], pivot) > 0);
|
|
705
|
+
if (i >= j) break;
|
|
706
|
+
var tmp = keys[i];
|
|
707
|
+
keys[i] = keys[j];
|
|
708
|
+
keys[j] = tmp;
|
|
709
|
+
tmp = values[i];
|
|
710
|
+
values[i] = values[j];
|
|
711
|
+
values[j] = tmp;
|
|
712
|
+
}
|
|
713
|
+
sort(keys, values, left, j, compare);
|
|
714
|
+
sort(keys, values, j + 1, right, compare);
|
|
681
715
|
}
|
|
682
716
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
var size = end - start;
|
|
717
|
+
/**
|
|
718
|
+
* A bounding box has the format:
|
|
719
|
+
*
|
|
720
|
+
* { ll: { x: xmin, y: ymin }, ur: { x: xmax, y: ymax } }
|
|
721
|
+
*
|
|
722
|
+
*/
|
|
690
723
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
var root = list.head;
|
|
695
|
-
root.left = left;
|
|
696
|
-
list.head = list.head.next;
|
|
697
|
-
root.right = sortedListToBST(list, middle + 1, end);
|
|
698
|
-
return root;
|
|
699
|
-
}
|
|
724
|
+
const isInBbox = (bbox, point) => {
|
|
725
|
+
return bbox.ll.x <= point.x && point.x <= bbox.ur.x && bbox.ll.y <= point.y && point.y <= bbox.ur.y;
|
|
726
|
+
};
|
|
700
727
|
|
|
701
|
-
|
|
702
|
-
|
|
728
|
+
/* Returns either null, or a bbox (aka an ordered pair of points)
|
|
729
|
+
* If there is only one point of overlap, a bbox with identical points
|
|
730
|
+
* will be returned */
|
|
731
|
+
const getBboxOverlap = (b1, b2) => {
|
|
732
|
+
// check if the bboxes overlap at all
|
|
733
|
+
if (b2.ur.x < b1.ll.x || b1.ur.x < b2.ll.x || b2.ur.y < b1.ll.y || b1.ur.y < b2.ll.y) return null;
|
|
703
734
|
|
|
704
|
-
|
|
705
|
-
|
|
735
|
+
// find the middle two X values
|
|
736
|
+
const lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
|
|
737
|
+
const upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x;
|
|
706
738
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
739
|
+
// find the middle two Y values
|
|
740
|
+
const lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
|
|
741
|
+
const upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y;
|
|
710
742
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
743
|
+
// put those middle values together to get the overlap
|
|
744
|
+
return {
|
|
745
|
+
ll: {
|
|
746
|
+
x: lowerX,
|
|
747
|
+
y: lowerY
|
|
748
|
+
},
|
|
749
|
+
ur: {
|
|
750
|
+
x: upperX,
|
|
751
|
+
y: upperY
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
};
|
|
719
755
|
|
|
720
|
-
|
|
721
|
-
|
|
756
|
+
/* Javascript doesn't do integer math. Everything is
|
|
757
|
+
* floating point with percision Number.EPSILON.
|
|
758
|
+
*
|
|
759
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
|
|
760
|
+
*/
|
|
722
761
|
|
|
723
|
-
|
|
724
|
-
p.next = p1;
|
|
725
|
-
} else if (p2 !== null) {
|
|
726
|
-
p.next = p2;
|
|
727
|
-
}
|
|
762
|
+
let epsilon$1 = Number.EPSILON;
|
|
728
763
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
function sort(keys, values, left, right, compare) {
|
|
733
|
-
if (left >= right) return;
|
|
734
|
-
var pivot = keys[left + right >> 1];
|
|
735
|
-
var i = left - 1;
|
|
736
|
-
var j = right + 1;
|
|
737
|
-
|
|
738
|
-
while (true) {
|
|
739
|
-
do {
|
|
740
|
-
i++;
|
|
741
|
-
} while (compare(keys[i], pivot) < 0);
|
|
742
|
-
|
|
743
|
-
do {
|
|
744
|
-
j--;
|
|
745
|
-
} while (compare(keys[j], pivot) > 0);
|
|
746
|
-
|
|
747
|
-
if (i >= j) break;
|
|
748
|
-
var tmp = keys[i];
|
|
749
|
-
keys[i] = keys[j];
|
|
750
|
-
keys[j] = tmp;
|
|
751
|
-
tmp = values[i];
|
|
752
|
-
values[i] = values[j];
|
|
753
|
-
values[j] = tmp;
|
|
754
|
-
}
|
|
764
|
+
// IE Polyfill
|
|
765
|
+
if (epsilon$1 === undefined) epsilon$1 = Math.pow(2, -52);
|
|
766
|
+
const EPSILON_SQ = epsilon$1 * epsilon$1;
|
|
755
767
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
* { ll: { x: xmin, y: ymin }, ur: { x: xmax, y: ymax } }
|
|
764
|
-
*
|
|
765
|
-
*/
|
|
766
|
-
var isInBbox = function isInBbox(bbox, point) {
|
|
767
|
-
return bbox.ll.x <= point.x && point.x <= bbox.ur.x && bbox.ll.y <= point.y && point.y <= bbox.ur.y;
|
|
768
|
-
};
|
|
769
|
-
/* Returns either null, or a bbox (aka an ordered pair of points)
|
|
770
|
-
* If there is only one point of overlap, a bbox with identical points
|
|
771
|
-
* will be returned */
|
|
772
|
-
|
|
773
|
-
var getBboxOverlap = function getBboxOverlap(b1, b2) {
|
|
774
|
-
// check if the bboxes overlap at all
|
|
775
|
-
if (b2.ur.x < b1.ll.x || b1.ur.x < b2.ll.x || b2.ur.y < b1.ll.y || b1.ur.y < b2.ll.y) return null; // find the middle two X values
|
|
776
|
-
|
|
777
|
-
var lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
|
|
778
|
-
var upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x; // find the middle two Y values
|
|
779
|
-
|
|
780
|
-
var lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
|
|
781
|
-
var upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y; // put those middle values together to get the overlap
|
|
782
|
-
|
|
783
|
-
return {
|
|
784
|
-
ll: {
|
|
785
|
-
x: lowerX,
|
|
786
|
-
y: lowerY
|
|
787
|
-
},
|
|
788
|
-
ur: {
|
|
789
|
-
x: upperX,
|
|
790
|
-
y: upperY
|
|
768
|
+
/* FLP comparator */
|
|
769
|
+
const cmp = (a, b) => {
|
|
770
|
+
// check if they're both 0
|
|
771
|
+
if (-epsilon$1 < a && a < epsilon$1) {
|
|
772
|
+
if (-epsilon$1 < b && b < epsilon$1) {
|
|
773
|
+
return 0;
|
|
774
|
+
}
|
|
791
775
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
* floating point with percision Number.EPSILON.
|
|
797
|
-
*
|
|
798
|
-
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
|
|
799
|
-
*/
|
|
800
|
-
var epsilon = Number.EPSILON; // IE Polyfill
|
|
801
|
-
|
|
802
|
-
if (epsilon === undefined) epsilon = Math.pow(2, -52);
|
|
803
|
-
var EPSILON_SQ = epsilon * epsilon;
|
|
804
|
-
/* FLP comparator */
|
|
805
|
-
|
|
806
|
-
var cmp = function cmp(a, b) {
|
|
807
|
-
// check if they're both 0
|
|
808
|
-
if (-epsilon < a && a < epsilon) {
|
|
809
|
-
if (-epsilon < b && b < epsilon) {
|
|
776
|
+
|
|
777
|
+
// check if they're flp equal
|
|
778
|
+
const ab = a - b;
|
|
779
|
+
if (ab * ab < EPSILON_SQ * a * b) {
|
|
810
780
|
return 0;
|
|
811
781
|
}
|
|
812
|
-
} // check if they're flp equal
|
|
813
|
-
|
|
814
782
|
|
|
815
|
-
|
|
783
|
+
// normal comparison
|
|
784
|
+
return a < b ? -1 : 1;
|
|
785
|
+
};
|
|
816
786
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
* Incoming points are have their x & y values tested against
|
|
830
|
-
* all previously seen x & y values. If either is 'too close'
|
|
831
|
-
* to a previously seen value, it's value is 'snapped' to the
|
|
832
|
-
* previously seen value.
|
|
833
|
-
*
|
|
834
|
-
* All points should be rounded by this class before being
|
|
835
|
-
* stored in any data structures in the rest of this algorithm.
|
|
836
|
-
*/
|
|
837
|
-
|
|
838
|
-
var PtRounder = /*#__PURE__*/function () {
|
|
839
|
-
function PtRounder() {
|
|
840
|
-
_classCallCheck(this, PtRounder);
|
|
841
|
-
|
|
842
|
-
this.reset();
|
|
843
|
-
}
|
|
787
|
+
/**
|
|
788
|
+
* This class rounds incoming values sufficiently so that
|
|
789
|
+
* floating points problems are, for the most part, avoided.
|
|
790
|
+
*
|
|
791
|
+
* Incoming points are have their x & y values tested against
|
|
792
|
+
* all previously seen x & y values. If either is 'too close'
|
|
793
|
+
* to a previously seen value, it's value is 'snapped' to the
|
|
794
|
+
* previously seen value.
|
|
795
|
+
*
|
|
796
|
+
* All points should be rounded by this class before being
|
|
797
|
+
* stored in any data structures in the rest of this algorithm.
|
|
798
|
+
*/
|
|
844
799
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
800
|
+
class PtRounder {
|
|
801
|
+
constructor() {
|
|
802
|
+
this.reset();
|
|
803
|
+
}
|
|
804
|
+
reset() {
|
|
848
805
|
this.xRounder = new CoordRounder();
|
|
849
806
|
this.yRounder = new CoordRounder();
|
|
850
807
|
}
|
|
851
|
-
|
|
852
|
-
key: "round",
|
|
853
|
-
value: function round(x, y) {
|
|
808
|
+
round(x, y) {
|
|
854
809
|
return {
|
|
855
810
|
x: this.xRounder.round(x),
|
|
856
811
|
y: this.yRounder.round(y)
|
|
857
812
|
};
|
|
858
813
|
}
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
// angle for t-intersections).
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
_createClass(CoordRounder, [{
|
|
881
|
-
key: "round",
|
|
882
|
-
value: function round(coord) {
|
|
883
|
-
var node = this.tree.add(coord);
|
|
884
|
-
var prevNode = this.tree.prev(node);
|
|
885
|
-
|
|
814
|
+
}
|
|
815
|
+
class CoordRounder {
|
|
816
|
+
constructor() {
|
|
817
|
+
this.tree = new Tree();
|
|
818
|
+
// preseed with 0 so we don't end up with values < Number.EPSILON
|
|
819
|
+
this.round(0);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Note: this can rounds input values backwards or forwards.
|
|
823
|
+
// You might ask, why not restrict this to just rounding
|
|
824
|
+
// forwards? Wouldn't that allow left endpoints to always
|
|
825
|
+
// remain left endpoints during splitting (never change to
|
|
826
|
+
// right). No - it wouldn't, because we snap intersections
|
|
827
|
+
// to endpoints (to establish independence from the segment
|
|
828
|
+
// angle for t-intersections).
|
|
829
|
+
round(coord) {
|
|
830
|
+
const node = this.tree.add(coord);
|
|
831
|
+
const prevNode = this.tree.prev(node);
|
|
886
832
|
if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
|
|
887
833
|
this.tree.remove(coord);
|
|
888
834
|
return prevNode.key;
|
|
889
835
|
}
|
|
890
|
-
|
|
891
|
-
var nextNode = this.tree.next(node);
|
|
892
|
-
|
|
836
|
+
const nextNode = this.tree.next(node);
|
|
893
837
|
if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
|
|
894
838
|
this.tree.remove(coord);
|
|
895
839
|
return nextNode.key;
|
|
896
840
|
}
|
|
897
|
-
|
|
898
841
|
return coord;
|
|
899
842
|
}
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
return CoordRounder;
|
|
903
|
-
}(); // singleton available by import
|
|
904
|
-
|
|
843
|
+
}
|
|
905
844
|
|
|
906
|
-
|
|
845
|
+
// singleton available by import
|
|
846
|
+
const rounder = new PtRounder();
|
|
847
|
+
|
|
848
|
+
const epsilon = 1.1102230246251565e-16;
|
|
849
|
+
const splitter = 134217729;
|
|
850
|
+
const resulterrbound = (3 + 8 * epsilon) * epsilon;
|
|
851
|
+
|
|
852
|
+
// fast_expansion_sum_zeroelim routine from oritinal code
|
|
853
|
+
function sum(elen, e, flen, f, h) {
|
|
854
|
+
let Q, Qnew, hh, bvirt;
|
|
855
|
+
let enow = e[0];
|
|
856
|
+
let fnow = f[0];
|
|
857
|
+
let eindex = 0;
|
|
858
|
+
let findex = 0;
|
|
859
|
+
if (fnow > enow === fnow > -enow) {
|
|
860
|
+
Q = enow;
|
|
861
|
+
enow = e[++eindex];
|
|
862
|
+
} else {
|
|
863
|
+
Q = fnow;
|
|
864
|
+
fnow = f[++findex];
|
|
865
|
+
}
|
|
866
|
+
let hindex = 0;
|
|
867
|
+
if (eindex < elen && findex < flen) {
|
|
868
|
+
if (fnow > enow === fnow > -enow) {
|
|
869
|
+
Qnew = enow + Q;
|
|
870
|
+
hh = Q - (Qnew - enow);
|
|
871
|
+
enow = e[++eindex];
|
|
872
|
+
} else {
|
|
873
|
+
Qnew = fnow + Q;
|
|
874
|
+
hh = Q - (Qnew - fnow);
|
|
875
|
+
fnow = f[++findex];
|
|
876
|
+
}
|
|
877
|
+
Q = Qnew;
|
|
878
|
+
if (hh !== 0) {
|
|
879
|
+
h[hindex++] = hh;
|
|
880
|
+
}
|
|
881
|
+
while (eindex < elen && findex < flen) {
|
|
882
|
+
if (fnow > enow === fnow > -enow) {
|
|
883
|
+
Qnew = Q + enow;
|
|
884
|
+
bvirt = Qnew - Q;
|
|
885
|
+
hh = Q - (Qnew - bvirt) + (enow - bvirt);
|
|
886
|
+
enow = e[++eindex];
|
|
887
|
+
} else {
|
|
888
|
+
Qnew = Q + fnow;
|
|
889
|
+
bvirt = Qnew - Q;
|
|
890
|
+
hh = Q - (Qnew - bvirt) + (fnow - bvirt);
|
|
891
|
+
fnow = f[++findex];
|
|
892
|
+
}
|
|
893
|
+
Q = Qnew;
|
|
894
|
+
if (hh !== 0) {
|
|
895
|
+
h[hindex++] = hh;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
while (eindex < elen) {
|
|
900
|
+
Qnew = Q + enow;
|
|
901
|
+
bvirt = Qnew - Q;
|
|
902
|
+
hh = Q - (Qnew - bvirt) + (enow - bvirt);
|
|
903
|
+
enow = e[++eindex];
|
|
904
|
+
Q = Qnew;
|
|
905
|
+
if (hh !== 0) {
|
|
906
|
+
h[hindex++] = hh;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
while (findex < flen) {
|
|
910
|
+
Qnew = Q + fnow;
|
|
911
|
+
bvirt = Qnew - Q;
|
|
912
|
+
hh = Q - (Qnew - bvirt) + (fnow - bvirt);
|
|
913
|
+
fnow = f[++findex];
|
|
914
|
+
Q = Qnew;
|
|
915
|
+
if (hh !== 0) {
|
|
916
|
+
h[hindex++] = hh;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
if (Q !== 0 || hindex === 0) {
|
|
920
|
+
h[hindex++] = Q;
|
|
921
|
+
}
|
|
922
|
+
return hindex;
|
|
923
|
+
}
|
|
924
|
+
function estimate(elen, e) {
|
|
925
|
+
let Q = e[0];
|
|
926
|
+
for (let i = 1; i < elen; i++) Q += e[i];
|
|
927
|
+
return Q;
|
|
928
|
+
}
|
|
929
|
+
function vec(n) {
|
|
930
|
+
return new Float64Array(n);
|
|
931
|
+
}
|
|
907
932
|
|
|
908
|
-
|
|
933
|
+
const ccwerrboundA = (3 + 16 * epsilon) * epsilon;
|
|
934
|
+
const ccwerrboundB = (2 + 12 * epsilon) * epsilon;
|
|
935
|
+
const ccwerrboundC = (9 + 64 * epsilon) * epsilon * epsilon;
|
|
936
|
+
const B = vec(4);
|
|
937
|
+
const C1 = vec(8);
|
|
938
|
+
const C2 = vec(12);
|
|
939
|
+
const D = vec(16);
|
|
940
|
+
const u = vec(4);
|
|
941
|
+
function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) {
|
|
942
|
+
let acxtail, acytail, bcxtail, bcytail;
|
|
943
|
+
let bvirt, c, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3;
|
|
944
|
+
const acx = ax - cx;
|
|
945
|
+
const bcx = bx - cx;
|
|
946
|
+
const acy = ay - cy;
|
|
947
|
+
const bcy = by - cy;
|
|
948
|
+
s1 = acx * bcy;
|
|
949
|
+
c = splitter * acx;
|
|
950
|
+
ahi = c - (c - acx);
|
|
951
|
+
alo = acx - ahi;
|
|
952
|
+
c = splitter * bcy;
|
|
953
|
+
bhi = c - (c - bcy);
|
|
954
|
+
blo = bcy - bhi;
|
|
955
|
+
s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
|
|
956
|
+
t1 = acy * bcx;
|
|
957
|
+
c = splitter * acy;
|
|
958
|
+
ahi = c - (c - acy);
|
|
959
|
+
alo = acy - ahi;
|
|
960
|
+
c = splitter * bcx;
|
|
961
|
+
bhi = c - (c - bcx);
|
|
962
|
+
blo = bcx - bhi;
|
|
963
|
+
t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
|
|
964
|
+
_i = s0 - t0;
|
|
965
|
+
bvirt = s0 - _i;
|
|
966
|
+
B[0] = s0 - (_i + bvirt) + (bvirt - t0);
|
|
967
|
+
_j = s1 + _i;
|
|
968
|
+
bvirt = _j - s1;
|
|
969
|
+
_0 = s1 - (_j - bvirt) + (_i - bvirt);
|
|
970
|
+
_i = _0 - t1;
|
|
971
|
+
bvirt = _0 - _i;
|
|
972
|
+
B[1] = _0 - (_i + bvirt) + (bvirt - t1);
|
|
973
|
+
u3 = _j + _i;
|
|
974
|
+
bvirt = u3 - _j;
|
|
975
|
+
B[2] = _j - (u3 - bvirt) + (_i - bvirt);
|
|
976
|
+
B[3] = u3;
|
|
977
|
+
let det = estimate(4, B);
|
|
978
|
+
let errbound = ccwerrboundB * detsum;
|
|
979
|
+
if (det >= errbound || -det >= errbound) {
|
|
980
|
+
return det;
|
|
981
|
+
}
|
|
982
|
+
bvirt = ax - acx;
|
|
983
|
+
acxtail = ax - (acx + bvirt) + (bvirt - cx);
|
|
984
|
+
bvirt = bx - bcx;
|
|
985
|
+
bcxtail = bx - (bcx + bvirt) + (bvirt - cx);
|
|
986
|
+
bvirt = ay - acy;
|
|
987
|
+
acytail = ay - (acy + bvirt) + (bvirt - cy);
|
|
988
|
+
bvirt = by - bcy;
|
|
989
|
+
bcytail = by - (bcy + bvirt) + (bvirt - cy);
|
|
990
|
+
if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) {
|
|
991
|
+
return det;
|
|
992
|
+
}
|
|
993
|
+
errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
|
|
994
|
+
det += acx * bcytail + bcy * acxtail - (acy * bcxtail + bcx * acytail);
|
|
995
|
+
if (det >= errbound || -det >= errbound) return det;
|
|
996
|
+
s1 = acxtail * bcy;
|
|
997
|
+
c = splitter * acxtail;
|
|
998
|
+
ahi = c - (c - acxtail);
|
|
999
|
+
alo = acxtail - ahi;
|
|
1000
|
+
c = splitter * bcy;
|
|
1001
|
+
bhi = c - (c - bcy);
|
|
1002
|
+
blo = bcy - bhi;
|
|
1003
|
+
s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
|
|
1004
|
+
t1 = acytail * bcx;
|
|
1005
|
+
c = splitter * acytail;
|
|
1006
|
+
ahi = c - (c - acytail);
|
|
1007
|
+
alo = acytail - ahi;
|
|
1008
|
+
c = splitter * bcx;
|
|
1009
|
+
bhi = c - (c - bcx);
|
|
1010
|
+
blo = bcx - bhi;
|
|
1011
|
+
t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
|
|
1012
|
+
_i = s0 - t0;
|
|
1013
|
+
bvirt = s0 - _i;
|
|
1014
|
+
u[0] = s0 - (_i + bvirt) + (bvirt - t0);
|
|
1015
|
+
_j = s1 + _i;
|
|
1016
|
+
bvirt = _j - s1;
|
|
1017
|
+
_0 = s1 - (_j - bvirt) + (_i - bvirt);
|
|
1018
|
+
_i = _0 - t1;
|
|
1019
|
+
bvirt = _0 - _i;
|
|
1020
|
+
u[1] = _0 - (_i + bvirt) + (bvirt - t1);
|
|
1021
|
+
u3 = _j + _i;
|
|
1022
|
+
bvirt = u3 - _j;
|
|
1023
|
+
u[2] = _j - (u3 - bvirt) + (_i - bvirt);
|
|
1024
|
+
u[3] = u3;
|
|
1025
|
+
const C1len = sum(4, B, 4, u, C1);
|
|
1026
|
+
s1 = acx * bcytail;
|
|
1027
|
+
c = splitter * acx;
|
|
1028
|
+
ahi = c - (c - acx);
|
|
1029
|
+
alo = acx - ahi;
|
|
1030
|
+
c = splitter * bcytail;
|
|
1031
|
+
bhi = c - (c - bcytail);
|
|
1032
|
+
blo = bcytail - bhi;
|
|
1033
|
+
s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
|
|
1034
|
+
t1 = acy * bcxtail;
|
|
1035
|
+
c = splitter * acy;
|
|
1036
|
+
ahi = c - (c - acy);
|
|
1037
|
+
alo = acy - ahi;
|
|
1038
|
+
c = splitter * bcxtail;
|
|
1039
|
+
bhi = c - (c - bcxtail);
|
|
1040
|
+
blo = bcxtail - bhi;
|
|
1041
|
+
t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
|
|
1042
|
+
_i = s0 - t0;
|
|
1043
|
+
bvirt = s0 - _i;
|
|
1044
|
+
u[0] = s0 - (_i + bvirt) + (bvirt - t0);
|
|
1045
|
+
_j = s1 + _i;
|
|
1046
|
+
bvirt = _j - s1;
|
|
1047
|
+
_0 = s1 - (_j - bvirt) + (_i - bvirt);
|
|
1048
|
+
_i = _0 - t1;
|
|
1049
|
+
bvirt = _0 - _i;
|
|
1050
|
+
u[1] = _0 - (_i + bvirt) + (bvirt - t1);
|
|
1051
|
+
u3 = _j + _i;
|
|
1052
|
+
bvirt = u3 - _j;
|
|
1053
|
+
u[2] = _j - (u3 - bvirt) + (_i - bvirt);
|
|
1054
|
+
u[3] = u3;
|
|
1055
|
+
const C2len = sum(C1len, C1, 4, u, C2);
|
|
1056
|
+
s1 = acxtail * bcytail;
|
|
1057
|
+
c = splitter * acxtail;
|
|
1058
|
+
ahi = c - (c - acxtail);
|
|
1059
|
+
alo = acxtail - ahi;
|
|
1060
|
+
c = splitter * bcytail;
|
|
1061
|
+
bhi = c - (c - bcytail);
|
|
1062
|
+
blo = bcytail - bhi;
|
|
1063
|
+
s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
|
|
1064
|
+
t1 = acytail * bcxtail;
|
|
1065
|
+
c = splitter * acytail;
|
|
1066
|
+
ahi = c - (c - acytail);
|
|
1067
|
+
alo = acytail - ahi;
|
|
1068
|
+
c = splitter * bcxtail;
|
|
1069
|
+
bhi = c - (c - bcxtail);
|
|
1070
|
+
blo = bcxtail - bhi;
|
|
1071
|
+
t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
|
|
1072
|
+
_i = s0 - t0;
|
|
1073
|
+
bvirt = s0 - _i;
|
|
1074
|
+
u[0] = s0 - (_i + bvirt) + (bvirt - t0);
|
|
1075
|
+
_j = s1 + _i;
|
|
1076
|
+
bvirt = _j - s1;
|
|
1077
|
+
_0 = s1 - (_j - bvirt) + (_i - bvirt);
|
|
1078
|
+
_i = _0 - t1;
|
|
1079
|
+
bvirt = _0 - _i;
|
|
1080
|
+
u[1] = _0 - (_i + bvirt) + (bvirt - t1);
|
|
1081
|
+
u3 = _j + _i;
|
|
1082
|
+
bvirt = u3 - _j;
|
|
1083
|
+
u[2] = _j - (u3 - bvirt) + (_i - bvirt);
|
|
1084
|
+
u[3] = u3;
|
|
1085
|
+
const Dlen = sum(C2len, C2, 4, u, D);
|
|
1086
|
+
return D[Dlen - 1];
|
|
1087
|
+
}
|
|
1088
|
+
function orient2d(ax, ay, bx, by, cx, cy) {
|
|
1089
|
+
const detleft = (ay - cy) * (bx - cx);
|
|
1090
|
+
const detright = (ax - cx) * (by - cy);
|
|
1091
|
+
const det = detleft - detright;
|
|
1092
|
+
const detsum = Math.abs(detleft + detright);
|
|
1093
|
+
if (Math.abs(det) >= ccwerrboundA * detsum) return det;
|
|
1094
|
+
return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
|
|
1095
|
+
}
|
|
909
1096
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
};
|
|
913
|
-
/* Dot Product of two vectors with first point at origin */
|
|
1097
|
+
/* Cross Product of two vectors with first point at origin */
|
|
1098
|
+
const crossProduct = (a, b) => a.x * b.y - a.y * b.x;
|
|
914
1099
|
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
};
|
|
918
|
-
/* Comparator for two vectors with same starting point */
|
|
1100
|
+
/* Dot Product of two vectors with first point at origin */
|
|
1101
|
+
const dotProduct = (a, b) => a.x * b.x + a.y * b.y;
|
|
919
1102
|
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
x
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
x: endPt2.x - basePt.x,
|
|
927
|
-
y: endPt2.y - basePt.y
|
|
928
|
-
};
|
|
929
|
-
var kross = crossProduct(v1, v2);
|
|
930
|
-
return cmp(kross, 0);
|
|
931
|
-
};
|
|
932
|
-
var length = function length(v) {
|
|
933
|
-
return Math.sqrt(dotProduct(v, v));
|
|
934
|
-
};
|
|
935
|
-
/* Get the sine of the angle from pShared -> pAngle to pShaed -> pBase */
|
|
936
|
-
|
|
937
|
-
var sineOfAngle = function sineOfAngle(pShared, pBase, pAngle) {
|
|
938
|
-
var vBase = {
|
|
939
|
-
x: pBase.x - pShared.x,
|
|
940
|
-
y: pBase.y - pShared.y
|
|
941
|
-
};
|
|
942
|
-
var vAngle = {
|
|
943
|
-
x: pAngle.x - pShared.x,
|
|
944
|
-
y: pAngle.y - pShared.y
|
|
945
|
-
};
|
|
946
|
-
return crossProduct(vAngle, vBase) / length(vAngle) / length(vBase);
|
|
947
|
-
};
|
|
948
|
-
/* Get the cosine of the angle from pShared -> pAngle to pShaed -> pBase */
|
|
949
|
-
|
|
950
|
-
var cosineOfAngle = function cosineOfAngle(pShared, pBase, pAngle) {
|
|
951
|
-
var vBase = {
|
|
952
|
-
x: pBase.x - pShared.x,
|
|
953
|
-
y: pBase.y - pShared.y
|
|
1103
|
+
/* Comparator for two vectors with same starting point */
|
|
1104
|
+
const compareVectorAngles = (basePt, endPt1, endPt2) => {
|
|
1105
|
+
const res = orient2d(basePt.x, basePt.y, endPt1.x, endPt1.y, endPt2.x, endPt2.y);
|
|
1106
|
+
if (res > 0) return -1;
|
|
1107
|
+
if (res < 0) return 1;
|
|
1108
|
+
return 0;
|
|
954
1109
|
};
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1110
|
+
const length = v => Math.sqrt(dotProduct(v, v));
|
|
1111
|
+
|
|
1112
|
+
/* Get the sine of the angle from pShared -> pAngle to pShaed -> pBase */
|
|
1113
|
+
const sineOfAngle = (pShared, pBase, pAngle) => {
|
|
1114
|
+
const vBase = {
|
|
1115
|
+
x: pBase.x - pShared.x,
|
|
1116
|
+
y: pBase.y - pShared.y
|
|
1117
|
+
};
|
|
1118
|
+
const vAngle = {
|
|
1119
|
+
x: pAngle.x - pShared.x,
|
|
1120
|
+
y: pAngle.y - pShared.y
|
|
1121
|
+
};
|
|
1122
|
+
return crossProduct(vAngle, vBase) / length(vAngle) / length(vBase);
|
|
958
1123
|
};
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1124
|
+
|
|
1125
|
+
/* Get the cosine of the angle from pShared -> pAngle to pShaed -> pBase */
|
|
1126
|
+
const cosineOfAngle = (pShared, pBase, pAngle) => {
|
|
1127
|
+
const vBase = {
|
|
1128
|
+
x: pBase.x - pShared.x,
|
|
1129
|
+
y: pBase.y - pShared.y
|
|
1130
|
+
};
|
|
1131
|
+
const vAngle = {
|
|
1132
|
+
x: pAngle.x - pShared.x,
|
|
1133
|
+
y: pAngle.y - pShared.y
|
|
1134
|
+
};
|
|
1135
|
+
return dotProduct(vAngle, vBase) / length(vAngle) / length(vBase);
|
|
970
1136
|
};
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1137
|
+
|
|
1138
|
+
/* Get the x coordinate where the given line (defined by a point and vector)
|
|
1139
|
+
* crosses the horizontal line with the given y coordiante.
|
|
1140
|
+
* In the case of parrallel lines (including overlapping ones) returns null. */
|
|
1141
|
+
const horizontalIntersection = (pt, v, y) => {
|
|
1142
|
+
if (v.y === 0) return null;
|
|
1143
|
+
return {
|
|
1144
|
+
x: pt.x + v.x / v.y * (y - pt.y),
|
|
1145
|
+
y: y
|
|
1146
|
+
};
|
|
981
1147
|
};
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
if (v1.y === 0) return horizontalIntersection(pt2, v2, pt1.y);
|
|
993
|
-
if (v2.y === 0) return horizontalIntersection(pt1, v1, pt2.y); // General case for non-overlapping segments.
|
|
994
|
-
// This algorithm is based on Schneider and Eberly.
|
|
995
|
-
// http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf - pg 244
|
|
996
|
-
|
|
997
|
-
var kross = crossProduct(v1, v2);
|
|
998
|
-
if (kross == 0) return null;
|
|
999
|
-
var ve = {
|
|
1000
|
-
x: pt2.x - pt1.x,
|
|
1001
|
-
y: pt2.y - pt1.y
|
|
1148
|
+
|
|
1149
|
+
/* Get the y coordinate where the given line (defined by a point and vector)
|
|
1150
|
+
* crosses the vertical line with the given x coordiante.
|
|
1151
|
+
* In the case of parrallel lines (including overlapping ones) returns null. */
|
|
1152
|
+
const verticalIntersection = (pt, v, x) => {
|
|
1153
|
+
if (v.x === 0) return null;
|
|
1154
|
+
return {
|
|
1155
|
+
x: x,
|
|
1156
|
+
y: pt.y + v.y / v.x * (x - pt.x)
|
|
1157
|
+
};
|
|
1002
1158
|
};
|
|
1003
|
-
var d1 = crossProduct(ve, v1) / kross;
|
|
1004
|
-
var d2 = crossProduct(ve, v2) / kross; // take the average of the two calculations to minimize rounding error
|
|
1005
1159
|
|
|
1006
|
-
|
|
1160
|
+
/* Get the intersection of two lines, each defined by a base point and a vector.
|
|
1161
|
+
* In the case of parrallel lines (including overlapping ones) returns null. */
|
|
1162
|
+
const intersection$1 = (pt1, v1, pt2, v2) => {
|
|
1163
|
+
// take some shortcuts for vertical and horizontal lines
|
|
1164
|
+
// this also ensures we don't calculate an intersection and then discover
|
|
1165
|
+
// it's actually outside the bounding box of the line
|
|
1166
|
+
if (v1.x === 0) return verticalIntersection(pt2, v2, pt1.x);
|
|
1167
|
+
if (v2.x === 0) return verticalIntersection(pt1, v1, pt2.x);
|
|
1168
|
+
if (v1.y === 0) return horizontalIntersection(pt2, v2, pt1.y);
|
|
1169
|
+
if (v2.y === 0) return horizontalIntersection(pt1, v1, pt2.y);
|
|
1170
|
+
|
|
1171
|
+
// General case for non-overlapping segments.
|
|
1172
|
+
// This algorithm is based on Schneider and Eberly.
|
|
1173
|
+
// http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf - pg 244
|
|
1174
|
+
|
|
1175
|
+
const kross = crossProduct(v1, v2);
|
|
1176
|
+
if (kross == 0) return null;
|
|
1177
|
+
const ve = {
|
|
1178
|
+
x: pt2.x - pt1.x,
|
|
1179
|
+
y: pt2.y - pt1.y
|
|
1180
|
+
};
|
|
1181
|
+
const d1 = crossProduct(ve, v1) / kross;
|
|
1182
|
+
const d2 = crossProduct(ve, v2) / kross;
|
|
1183
|
+
|
|
1184
|
+
// take the average of the two calculations to minimize rounding error
|
|
1185
|
+
const x1 = pt1.x + d2 * v1.x,
|
|
1007
1186
|
x2 = pt2.x + d1 * v2.x;
|
|
1008
|
-
|
|
1187
|
+
const y1 = pt1.y + d2 * v1.y,
|
|
1009
1188
|
y2 = pt2.y + d1 * v2.y;
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1189
|
+
const x = (x1 + x2) / 2;
|
|
1190
|
+
const y = (y1 + y2) / 2;
|
|
1191
|
+
return {
|
|
1192
|
+
x: x,
|
|
1193
|
+
y: y
|
|
1194
|
+
};
|
|
1015
1195
|
};
|
|
1016
|
-
};
|
|
1017
1196
|
|
|
1018
|
-
|
|
1019
|
-
_createClass(SweepEvent, null, [{
|
|
1020
|
-
key: "compare",
|
|
1197
|
+
class SweepEvent {
|
|
1021
1198
|
// for ordering sweep events in the sweep event queue
|
|
1022
|
-
|
|
1199
|
+
static compare(a, b) {
|
|
1023
1200
|
// favor event with a point that the sweep line hits first
|
|
1024
|
-
|
|
1025
|
-
if (ptCmp !== 0) return ptCmp;
|
|
1201
|
+
const ptCmp = SweepEvent.comparePoints(a.point, b.point);
|
|
1202
|
+
if (ptCmp !== 0) return ptCmp;
|
|
1026
1203
|
|
|
1027
|
-
|
|
1204
|
+
// the points are the same, so link them if needed
|
|
1205
|
+
if (a.point !== b.point) a.link(b);
|
|
1028
1206
|
|
|
1029
|
-
|
|
1030
|
-
|
|
1207
|
+
// favor right events over left
|
|
1208
|
+
if (a.isLeft !== b.isLeft) return a.isLeft ? 1 : -1;
|
|
1031
1209
|
|
|
1210
|
+
// we have two matching left or right endpoints
|
|
1211
|
+
// ordering of this case is the same as for their segments
|
|
1032
1212
|
return Segment.compare(a.segment, b.segment);
|
|
1033
|
-
}
|
|
1213
|
+
}
|
|
1034
1214
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
value: function comparePoints(aPt, bPt) {
|
|
1215
|
+
// for ordering points in sweep line order
|
|
1216
|
+
static comparePoints(aPt, bPt) {
|
|
1038
1217
|
if (aPt.x < bPt.x) return -1;
|
|
1039
1218
|
if (aPt.x > bPt.x) return 1;
|
|
1040
1219
|
if (aPt.y < bPt.y) return -1;
|
|
1041
1220
|
if (aPt.y > bPt.y) return 1;
|
|
1042
1221
|
return 0;
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
}]);
|
|
1046
|
-
|
|
1047
|
-
function SweepEvent(point, isLeft) {
|
|
1048
|
-
_classCallCheck(this, SweepEvent);
|
|
1049
|
-
|
|
1050
|
-
if (point.events === undefined) point.events = [this];else point.events.push(this);
|
|
1051
|
-
this.point = point;
|
|
1052
|
-
this.isLeft = isLeft; // this.segment, this.otherSE set by factory
|
|
1053
|
-
}
|
|
1222
|
+
}
|
|
1054
1223
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1224
|
+
// Warning: 'point' input will be modified and re-used (for performance)
|
|
1225
|
+
constructor(point, isLeft) {
|
|
1226
|
+
if (point.events === undefined) point.events = [this];else point.events.push(this);
|
|
1227
|
+
this.point = point;
|
|
1228
|
+
this.isLeft = isLeft;
|
|
1229
|
+
// this.segment, this.otherSE set by factory
|
|
1230
|
+
}
|
|
1231
|
+
link(other) {
|
|
1058
1232
|
if (other.point === this.point) {
|
|
1059
|
-
throw new Error(
|
|
1233
|
+
throw new Error("Tried to link already linked events");
|
|
1060
1234
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
for (var i = 0, iMax = otherEvents.length; i < iMax; i++) {
|
|
1065
|
-
var evt = otherEvents[i];
|
|
1235
|
+
const otherEvents = other.point.events;
|
|
1236
|
+
for (let i = 0, iMax = otherEvents.length; i < iMax; i++) {
|
|
1237
|
+
const evt = otherEvents[i];
|
|
1066
1238
|
this.point.events.push(evt);
|
|
1067
1239
|
evt.point = this.point;
|
|
1068
1240
|
}
|
|
1069
|
-
|
|
1070
1241
|
this.checkForConsuming();
|
|
1071
1242
|
}
|
|
1243
|
+
|
|
1072
1244
|
/* Do a pass over our linked events and check to see if any pair
|
|
1073
1245
|
* of segments match, and should be consumed. */
|
|
1074
|
-
|
|
1075
|
-
}, {
|
|
1076
|
-
key: "checkForConsuming",
|
|
1077
|
-
value: function checkForConsuming() {
|
|
1246
|
+
checkForConsuming() {
|
|
1078
1247
|
// FIXME: The loops in this method run O(n^2) => no good.
|
|
1079
1248
|
// Maintain little ordered sweep event trees?
|
|
1080
1249
|
// Can we maintaining an ordering that avoids the need
|
|
1081
1250
|
// for the re-sorting with getLeftmostComparator in geom-out?
|
|
1082
|
-
// Compare each pair of events to see if other events also match
|
|
1083
|
-
var numEvents = this.point.events.length;
|
|
1084
1251
|
|
|
1085
|
-
|
|
1086
|
-
|
|
1252
|
+
// Compare each pair of events to see if other events also match
|
|
1253
|
+
const numEvents = this.point.events.length;
|
|
1254
|
+
for (let i = 0; i < numEvents; i++) {
|
|
1255
|
+
const evt1 = this.point.events[i];
|
|
1087
1256
|
if (evt1.segment.consumedBy !== undefined) continue;
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
var evt2 = this.point.events[j];
|
|
1257
|
+
for (let j = i + 1; j < numEvents; j++) {
|
|
1258
|
+
const evt2 = this.point.events[j];
|
|
1091
1259
|
if (evt2.consumedBy !== undefined) continue;
|
|
1092
1260
|
if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
|
|
1093
1261
|
evt1.segment.consume(evt2.segment);
|
|
1094
1262
|
}
|
|
1095
1263
|
}
|
|
1096
1264
|
}
|
|
1097
|
-
|
|
1098
|
-
key: "getAvailableLinkedEvents",
|
|
1099
|
-
value: function getAvailableLinkedEvents() {
|
|
1265
|
+
getAvailableLinkedEvents() {
|
|
1100
1266
|
// point.events is always of length 2 or greater
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
var evt = this.point.events[i];
|
|
1105
|
-
|
|
1267
|
+
const events = [];
|
|
1268
|
+
for (let i = 0, iMax = this.point.events.length; i < iMax; i++) {
|
|
1269
|
+
const evt = this.point.events[i];
|
|
1106
1270
|
if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
|
|
1107
1271
|
events.push(evt);
|
|
1108
1272
|
}
|
|
1109
1273
|
}
|
|
1110
|
-
|
|
1111
1274
|
return events;
|
|
1112
1275
|
}
|
|
1276
|
+
|
|
1113
1277
|
/**
|
|
1114
1278
|
* Returns a comparator function for sorting linked events that will
|
|
1115
1279
|
* favor the event that will give us the smallest left-side angle.
|
|
@@ -1120,67 +1284,53 @@
|
|
|
1120
1284
|
* The comparator function has a compute cache such that it avoids
|
|
1121
1285
|
* re-computing already-computed values.
|
|
1122
1286
|
*/
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
var _this = this;
|
|
1128
|
-
|
|
1129
|
-
var cache = new Map();
|
|
1130
|
-
|
|
1131
|
-
var fillCache = function fillCache(linkedEvent) {
|
|
1132
|
-
var nextEvent = linkedEvent.otherSE;
|
|
1287
|
+
getLeftmostComparator(baseEvent) {
|
|
1288
|
+
const cache = new Map();
|
|
1289
|
+
const fillCache = linkedEvent => {
|
|
1290
|
+
const nextEvent = linkedEvent.otherSE;
|
|
1133
1291
|
cache.set(linkedEvent, {
|
|
1134
|
-
sine: sineOfAngle(
|
|
1135
|
-
cosine: cosineOfAngle(
|
|
1292
|
+
sine: sineOfAngle(this.point, baseEvent.point, nextEvent.point),
|
|
1293
|
+
cosine: cosineOfAngle(this.point, baseEvent.point, nextEvent.point)
|
|
1136
1294
|
});
|
|
1137
1295
|
};
|
|
1138
|
-
|
|
1139
|
-
return function (a, b) {
|
|
1296
|
+
return (a, b) => {
|
|
1140
1297
|
if (!cache.has(a)) fillCache(a);
|
|
1141
1298
|
if (!cache.has(b)) fillCache(b);
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1299
|
+
const {
|
|
1300
|
+
sine: asine,
|
|
1301
|
+
cosine: acosine
|
|
1302
|
+
} = cache.get(a);
|
|
1303
|
+
const {
|
|
1304
|
+
sine: bsine,
|
|
1305
|
+
cosine: bcosine
|
|
1306
|
+
} = cache.get(b);
|
|
1307
|
+
|
|
1308
|
+
// both on or above x-axis
|
|
1152
1309
|
if (asine >= 0 && bsine >= 0) {
|
|
1153
1310
|
if (acosine < bcosine) return 1;
|
|
1154
1311
|
if (acosine > bcosine) return -1;
|
|
1155
1312
|
return 0;
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1313
|
+
}
|
|
1158
1314
|
|
|
1315
|
+
// both below x-axis
|
|
1159
1316
|
if (asine < 0 && bsine < 0) {
|
|
1160
1317
|
if (acosine < bcosine) return -1;
|
|
1161
1318
|
if (acosine > bcosine) return 1;
|
|
1162
1319
|
return 0;
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1320
|
+
}
|
|
1165
1321
|
|
|
1322
|
+
// one above x-axis, one below
|
|
1166
1323
|
if (bsine < asine) return -1;
|
|
1167
1324
|
if (bsine > asine) return 1;
|
|
1168
1325
|
return 0;
|
|
1169
1326
|
};
|
|
1170
1327
|
}
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
return SweepEvent;
|
|
1174
|
-
}();
|
|
1175
|
-
|
|
1176
|
-
// segments and sweep events when all else is identical
|
|
1177
|
-
|
|
1178
|
-
var segmentId = 0;
|
|
1179
|
-
|
|
1180
|
-
var Segment = /*#__PURE__*/function () {
|
|
1181
|
-
_createClass(Segment, null, [{
|
|
1182
|
-
key: "compare",
|
|
1328
|
+
}
|
|
1183
1329
|
|
|
1330
|
+
// Give segments unique ID's to get consistent sorting of
|
|
1331
|
+
// segments and sweep events when all else is identical
|
|
1332
|
+
let segmentId = 0;
|
|
1333
|
+
class Segment {
|
|
1184
1334
|
/* This compare() function is for ordering segments in the sweep
|
|
1185
1335
|
* line tree, and does so according to the following criteria:
|
|
1186
1336
|
*
|
|
@@ -1194,135 +1344,157 @@
|
|
|
1194
1344
|
* or more of the segments are vertical) then the line to be considered
|
|
1195
1345
|
* is directly on the right-more of the two left inputs.
|
|
1196
1346
|
*/
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1347
|
+
static compare(a, b) {
|
|
1348
|
+
const alx = a.leftSE.point.x;
|
|
1349
|
+
const blx = b.leftSE.point.x;
|
|
1350
|
+
const arx = a.rightSE.point.x;
|
|
1351
|
+
const brx = b.rightSE.point.x;
|
|
1202
1352
|
|
|
1353
|
+
// check if they're even in the same vertical plane
|
|
1203
1354
|
if (brx < alx) return 1;
|
|
1204
1355
|
if (arx < blx) return -1;
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1356
|
+
const aly = a.leftSE.point.y;
|
|
1357
|
+
const bly = b.leftSE.point.y;
|
|
1358
|
+
const ary = a.rightSE.point.y;
|
|
1359
|
+
const bry = b.rightSE.point.y;
|
|
1209
1360
|
|
|
1361
|
+
// is left endpoint of segment B the right-more?
|
|
1210
1362
|
if (alx < blx) {
|
|
1211
1363
|
// are the two segments in the same horizontal plane?
|
|
1212
1364
|
if (bly < aly && bly < ary) return 1;
|
|
1213
|
-
if (bly > aly && bly > ary) return -1;
|
|
1365
|
+
if (bly > aly && bly > ary) return -1;
|
|
1214
1366
|
|
|
1215
|
-
|
|
1367
|
+
// is the B left endpoint colinear to segment A?
|
|
1368
|
+
const aCmpBLeft = a.comparePoint(b.leftSE.point);
|
|
1216
1369
|
if (aCmpBLeft < 0) return 1;
|
|
1217
|
-
if (aCmpBLeft > 0) return -1;
|
|
1370
|
+
if (aCmpBLeft > 0) return -1;
|
|
1218
1371
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1372
|
+
// is the A right endpoint colinear to segment B ?
|
|
1373
|
+
const bCmpARight = b.comparePoint(a.rightSE.point);
|
|
1374
|
+
if (bCmpARight !== 0) return bCmpARight;
|
|
1222
1375
|
|
|
1376
|
+
// colinear segments, consider the one with left-more
|
|
1377
|
+
// left endpoint to be first (arbitrary?)
|
|
1223
1378
|
return -1;
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1379
|
+
}
|
|
1226
1380
|
|
|
1381
|
+
// is left endpoint of segment A the right-more?
|
|
1227
1382
|
if (alx > blx) {
|
|
1228
1383
|
if (aly < bly && aly < bry) return -1;
|
|
1229
|
-
if (aly > bly && aly > bry) return 1;
|
|
1384
|
+
if (aly > bly && aly > bry) return 1;
|
|
1230
1385
|
|
|
1231
|
-
|
|
1232
|
-
|
|
1386
|
+
// is the A left endpoint colinear to segment B?
|
|
1387
|
+
const bCmpALeft = b.comparePoint(a.leftSE.point);
|
|
1388
|
+
if (bCmpALeft !== 0) return bCmpALeft;
|
|
1233
1389
|
|
|
1234
|
-
|
|
1390
|
+
// is the B right endpoint colinear to segment A?
|
|
1391
|
+
const aCmpBRight = a.comparePoint(b.rightSE.point);
|
|
1235
1392
|
if (aCmpBRight < 0) return 1;
|
|
1236
|
-
if (aCmpBRight > 0) return -1;
|
|
1237
|
-
// left endpoint to be first (arbitrary?)
|
|
1393
|
+
if (aCmpBRight > 0) return -1;
|
|
1238
1394
|
|
|
1395
|
+
// colinear segments, consider the one with left-more
|
|
1396
|
+
// left endpoint to be first (arbitrary?)
|
|
1239
1397
|
return 1;
|
|
1240
|
-
}
|
|
1241
|
-
// vertical plane, ie alx === blx
|
|
1242
|
-
// consider the lower left-endpoint to come first
|
|
1398
|
+
}
|
|
1243
1399
|
|
|
1400
|
+
// if we get here, the two left endpoints are in the same
|
|
1401
|
+
// vertical plane, ie alx === blx
|
|
1244
1402
|
|
|
1403
|
+
// consider the lower left-endpoint to come first
|
|
1245
1404
|
if (aly < bly) return -1;
|
|
1246
|
-
if (aly > bly) return 1;
|
|
1405
|
+
if (aly > bly) return 1;
|
|
1406
|
+
|
|
1407
|
+
// left endpoints are identical
|
|
1247
1408
|
// check for colinearity by using the left-more right endpoint
|
|
1248
|
-
// is the A right endpoint more left-more?
|
|
1249
1409
|
|
|
1410
|
+
// is the A right endpoint more left-more?
|
|
1250
1411
|
if (arx < brx) {
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
} // is the B right endpoint more left-more?
|
|
1255
|
-
|
|
1412
|
+
const bCmpARight = b.comparePoint(a.rightSE.point);
|
|
1413
|
+
if (bCmpARight !== 0) return bCmpARight;
|
|
1414
|
+
}
|
|
1256
1415
|
|
|
1416
|
+
// is the B right endpoint more left-more?
|
|
1257
1417
|
if (arx > brx) {
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
if (
|
|
1261
|
-
if (_aCmpBRight > 0) return -1;
|
|
1418
|
+
const aCmpBRight = a.comparePoint(b.rightSE.point);
|
|
1419
|
+
if (aCmpBRight < 0) return 1;
|
|
1420
|
+
if (aCmpBRight > 0) return -1;
|
|
1262
1421
|
}
|
|
1263
|
-
|
|
1264
1422
|
if (arx !== brx) {
|
|
1265
1423
|
// are these two [almost] vertical segments with opposite orientation?
|
|
1266
1424
|
// if so, the one with the lower right endpoint comes first
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1425
|
+
const ay = ary - aly;
|
|
1426
|
+
const ax = arx - alx;
|
|
1427
|
+
const by = bry - bly;
|
|
1428
|
+
const bx = brx - blx;
|
|
1271
1429
|
if (ay > ax && by < bx) return 1;
|
|
1272
1430
|
if (ay < ax && by > bx) return -1;
|
|
1273
|
-
}
|
|
1274
|
-
// consider the one with more left-more right endpoint to be first
|
|
1275
|
-
|
|
1431
|
+
}
|
|
1276
1432
|
|
|
1433
|
+
// we have colinear segments with matching orientation
|
|
1434
|
+
// consider the one with more left-more right endpoint to be first
|
|
1277
1435
|
if (arx > brx) return 1;
|
|
1278
|
-
if (arx < brx) return -1;
|
|
1436
|
+
if (arx < brx) return -1;
|
|
1437
|
+
|
|
1438
|
+
// if we get here, two two right endpoints are in the same
|
|
1279
1439
|
// vertical plane, ie arx === brx
|
|
1280
|
-
// consider the lower right-endpoint to come first
|
|
1281
1440
|
|
|
1441
|
+
// consider the lower right-endpoint to come first
|
|
1282
1442
|
if (ary < bry) return -1;
|
|
1283
|
-
if (ary > bry) return 1;
|
|
1284
|
-
// fall back on creation order as consistent tie-breaker
|
|
1443
|
+
if (ary > bry) return 1;
|
|
1285
1444
|
|
|
1445
|
+
// right endpoints identical as well, so the segments are idential
|
|
1446
|
+
// fall back on creation order as consistent tie-breaker
|
|
1286
1447
|
if (a.id < b.id) return -1;
|
|
1287
|
-
if (a.id > b.id) return 1;
|
|
1448
|
+
if (a.id > b.id) return 1;
|
|
1288
1449
|
|
|
1450
|
+
// identical segment, ie a === b
|
|
1289
1451
|
return 0;
|
|
1290
1452
|
}
|
|
1453
|
+
|
|
1291
1454
|
/* Warning: a reference to ringWindings input will be stored,
|
|
1292
1455
|
* and possibly will be later modified */
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1456
|
+
constructor(leftSE, rightSE, rings, windings) {
|
|
1457
|
+
this.id = ++segmentId;
|
|
1458
|
+
this.leftSE = leftSE;
|
|
1459
|
+
leftSE.segment = this;
|
|
1460
|
+
leftSE.otherSE = rightSE;
|
|
1461
|
+
this.rightSE = rightSE;
|
|
1462
|
+
rightSE.segment = this;
|
|
1463
|
+
rightSE.otherSE = leftSE;
|
|
1464
|
+
this.rings = rings;
|
|
1465
|
+
this.windings = windings;
|
|
1466
|
+
// left unset for performance, set later in algorithm
|
|
1467
|
+
// this.ringOut, this.consumedBy, this.prev
|
|
1468
|
+
}
|
|
1469
|
+
static fromRing(pt1, pt2, ring) {
|
|
1470
|
+
let leftPt, rightPt, winding;
|
|
1471
|
+
|
|
1472
|
+
// ordering the two points according to sweep line ordering
|
|
1473
|
+
const cmpPts = SweepEvent.comparePoints(pt1, pt2);
|
|
1474
|
+
if (cmpPts < 0) {
|
|
1475
|
+
leftPt = pt1;
|
|
1476
|
+
rightPt = pt2;
|
|
1477
|
+
winding = 1;
|
|
1478
|
+
} else if (cmpPts > 0) {
|
|
1479
|
+
leftPt = pt2;
|
|
1480
|
+
rightPt = pt1;
|
|
1481
|
+
winding = -1;
|
|
1482
|
+
} else throw new Error(`Tried to create degenerate segment at [${pt1.x}, ${pt1.y}]`);
|
|
1483
|
+
const leftSE = new SweepEvent(leftPt, true);
|
|
1484
|
+
const rightSE = new SweepEvent(rightPt, false);
|
|
1485
|
+
return new Segment(leftSE, rightSE, [ring], [winding]);
|
|
1486
|
+
}
|
|
1313
1487
|
|
|
1314
1488
|
/* When a segment is split, the rightSE is replaced with a new sweep event */
|
|
1315
|
-
|
|
1489
|
+
replaceRightSE(newRightSE) {
|
|
1316
1490
|
this.rightSE = newRightSE;
|
|
1317
1491
|
this.rightSE.segment = this;
|
|
1318
1492
|
this.rightSE.otherSE = this.leftSE;
|
|
1319
1493
|
this.leftSE.otherSE = this.rightSE;
|
|
1320
1494
|
}
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
var y1 = this.leftSE.point.y;
|
|
1325
|
-
var y2 = this.rightSE.point.y;
|
|
1495
|
+
bbox() {
|
|
1496
|
+
const y1 = this.leftSE.point.y;
|
|
1497
|
+
const y2 = this.rightSE.point.y;
|
|
1326
1498
|
return {
|
|
1327
1499
|
ll: {
|
|
1328
1500
|
x: this.leftSE.point.x,
|
|
@@ -1334,21 +1506,18 @@
|
|
|
1334
1506
|
}
|
|
1335
1507
|
};
|
|
1336
1508
|
}
|
|
1337
|
-
/* A vector from the left point to the right */
|
|
1338
1509
|
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
value: function vector() {
|
|
1510
|
+
/* A vector from the left point to the right */
|
|
1511
|
+
vector() {
|
|
1342
1512
|
return {
|
|
1343
1513
|
x: this.rightSE.point.x - this.leftSE.point.x,
|
|
1344
1514
|
y: this.rightSE.point.y - this.leftSE.point.y
|
|
1345
1515
|
};
|
|
1346
1516
|
}
|
|
1347
|
-
|
|
1348
|
-
key: "isAnEndpoint",
|
|
1349
|
-
value: function isAnEndpoint(pt) {
|
|
1517
|
+
isAnEndpoint(pt) {
|
|
1350
1518
|
return pt.x === this.leftSE.point.x && pt.y === this.leftSE.point.y || pt.x === this.rightSE.point.x && pt.y === this.rightSE.point.y;
|
|
1351
1519
|
}
|
|
1520
|
+
|
|
1352
1521
|
/* Compare this segment with a point.
|
|
1353
1522
|
*
|
|
1354
1523
|
* A point P is considered to be colinear to a segment if there
|
|
@@ -1362,32 +1531,32 @@
|
|
|
1362
1531
|
* 0: point is colinear to segment
|
|
1363
1532
|
* -1: point lies below the segment (to the right of vertical)
|
|
1364
1533
|
*/
|
|
1365
|
-
|
|
1366
|
-
}, {
|
|
1367
|
-
key: "comparePoint",
|
|
1368
|
-
value: function comparePoint(point) {
|
|
1534
|
+
comparePoint(point) {
|
|
1369
1535
|
if (this.isAnEndpoint(point)) return 0;
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1536
|
+
const lPt = this.leftSE.point;
|
|
1537
|
+
const rPt = this.rightSE.point;
|
|
1538
|
+
const v = this.vector();
|
|
1373
1539
|
|
|
1540
|
+
// Exactly vertical segments.
|
|
1374
1541
|
if (lPt.x === rPt.x) {
|
|
1375
1542
|
if (point.x === lPt.x) return 0;
|
|
1376
1543
|
return point.x < lPt.x ? 1 : -1;
|
|
1377
|
-
}
|
|
1378
|
-
// Check to see where a point on the line with matching Y coordinate is.
|
|
1544
|
+
}
|
|
1379
1545
|
|
|
1546
|
+
// Nearly vertical segments with an intersection.
|
|
1547
|
+
// Check to see where a point on the line with matching Y coordinate is.
|
|
1548
|
+
const yDist = (point.y - lPt.y) / v.y;
|
|
1549
|
+
const xFromYDist = lPt.x + yDist * v.x;
|
|
1550
|
+
if (point.x === xFromYDist) return 0;
|
|
1380
1551
|
|
|
1381
|
-
|
|
1382
|
-
var xFromYDist = lPt.x + yDist * v.x;
|
|
1383
|
-
if (point.x === xFromYDist) return 0; // General case.
|
|
1552
|
+
// General case.
|
|
1384
1553
|
// Check to see where a point on the line with matching X coordinate is.
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
var yFromXDist = lPt.y + xDist * v.y;
|
|
1554
|
+
const xDist = (point.x - lPt.x) / v.x;
|
|
1555
|
+
const yFromXDist = lPt.y + xDist * v.y;
|
|
1388
1556
|
if (point.y === yFromXDist) return 0;
|
|
1389
1557
|
return point.y < yFromXDist ? -1 : 1;
|
|
1390
1558
|
}
|
|
1559
|
+
|
|
1391
1560
|
/**
|
|
1392
1561
|
* Given another segment, returns the first non-trivial intersection
|
|
1393
1562
|
* between the two segments (in terms of sweep line ordering), if it exists.
|
|
@@ -1403,78 +1572,83 @@
|
|
|
1403
1572
|
* If no non-trivial intersection exists, return null
|
|
1404
1573
|
* Else, return null.
|
|
1405
1574
|
*/
|
|
1406
|
-
|
|
1407
|
-
}, {
|
|
1408
|
-
key: "getIntersection",
|
|
1409
|
-
value: function getIntersection(other) {
|
|
1575
|
+
getIntersection(other) {
|
|
1410
1576
|
// If bboxes don't overlap, there can't be any intersections
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
if (bboxOverlap === null) return null;
|
|
1577
|
+
const tBbox = this.bbox();
|
|
1578
|
+
const oBbox = other.bbox();
|
|
1579
|
+
const bboxOverlap = getBboxOverlap(tBbox, oBbox);
|
|
1580
|
+
if (bboxOverlap === null) return null;
|
|
1581
|
+
|
|
1582
|
+
// We first check to see if the endpoints can be considered intersections.
|
|
1415
1583
|
// This will 'snap' intersections to endpoints if possible, and will
|
|
1416
1584
|
// handle cases of colinearity.
|
|
1417
1585
|
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1586
|
+
const tlp = this.leftSE.point;
|
|
1587
|
+
const trp = this.rightSE.point;
|
|
1588
|
+
const olp = other.leftSE.point;
|
|
1589
|
+
const orp = other.rightSE.point;
|
|
1590
|
+
|
|
1591
|
+
// does each endpoint touch the other segment?
|
|
1422
1592
|
// note that we restrict the 'touching' definition to only allow segments
|
|
1423
1593
|
// to touch endpoints that lie forward from where we are in the sweep line pass
|
|
1594
|
+
const touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
|
|
1595
|
+
const touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
|
|
1596
|
+
const touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
|
|
1597
|
+
const touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0;
|
|
1424
1598
|
|
|
1425
|
-
|
|
1426
|
-
var touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
|
|
1427
|
-
var touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
|
|
1428
|
-
var touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0; // do left endpoints match?
|
|
1429
|
-
|
|
1599
|
+
// do left endpoints match?
|
|
1430
1600
|
if (touchesThisLSE && touchesOtherLSE) {
|
|
1431
1601
|
// these two cases are for colinear segments with matching left
|
|
1432
1602
|
// endpoints, and one segment being longer than the other
|
|
1433
1603
|
if (touchesThisRSE && !touchesOtherRSE) return trp;
|
|
1434
|
-
if (!touchesThisRSE && touchesOtherRSE) return orp;
|
|
1604
|
+
if (!touchesThisRSE && touchesOtherRSE) return orp;
|
|
1605
|
+
// either the two segments match exactly (two trival intersections)
|
|
1435
1606
|
// or just on their left endpoint (one trivial intersection
|
|
1436
|
-
|
|
1437
1607
|
return null;
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1608
|
+
}
|
|
1440
1609
|
|
|
1610
|
+
// does this left endpoint matches (other doesn't)
|
|
1441
1611
|
if (touchesThisLSE) {
|
|
1442
1612
|
// check for segments that just intersect on opposing endpoints
|
|
1443
1613
|
if (touchesOtherRSE) {
|
|
1444
1614
|
if (tlp.x === orp.x && tlp.y === orp.y) return null;
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
|
|
1615
|
+
}
|
|
1616
|
+
// t-intersection on left endpoint
|
|
1448
1617
|
return tlp;
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1618
|
+
}
|
|
1451
1619
|
|
|
1620
|
+
// does other left endpoint matches (this doesn't)
|
|
1452
1621
|
if (touchesOtherLSE) {
|
|
1453
1622
|
// check for segments that just intersect on opposing endpoints
|
|
1454
1623
|
if (touchesThisRSE) {
|
|
1455
1624
|
if (trp.x === olp.x && trp.y === olp.y) return null;
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
|
|
1625
|
+
}
|
|
1626
|
+
// t-intersection on left endpoint
|
|
1459
1627
|
return olp;
|
|
1460
|
-
}
|
|
1461
|
-
|
|
1628
|
+
}
|
|
1462
1629
|
|
|
1463
|
-
|
|
1630
|
+
// trivial intersection on right endpoints
|
|
1631
|
+
if (touchesThisRSE && touchesOtherRSE) return null;
|
|
1464
1632
|
|
|
1633
|
+
// t-intersections on just one right endpoint
|
|
1465
1634
|
if (touchesThisRSE) return trp;
|
|
1466
|
-
if (touchesOtherRSE) return orp;
|
|
1635
|
+
if (touchesOtherRSE) return orp;
|
|
1636
|
+
|
|
1637
|
+
// None of our endpoints intersect. Look for a general intersection between
|
|
1467
1638
|
// infinite lines laid over the segments
|
|
1639
|
+
const pt = intersection$1(tlp, this.vector(), olp, other.vector());
|
|
1468
1640
|
|
|
1469
|
-
|
|
1641
|
+
// are the segments parrallel? Note that if they were colinear with overlap,
|
|
1470
1642
|
// they would have an endpoint intersection and that case was already handled above
|
|
1643
|
+
if (pt === null) return null;
|
|
1471
1644
|
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
if (!isInBbox(bboxOverlap, pt)) return null; // round the the computed point if needed
|
|
1645
|
+
// is the intersection found between the lines not on the segments?
|
|
1646
|
+
if (!isInBbox(bboxOverlap, pt)) return null;
|
|
1475
1647
|
|
|
1648
|
+
// round the the computed point if needed
|
|
1476
1649
|
return rounder.round(pt.x, pt.y);
|
|
1477
1650
|
}
|
|
1651
|
+
|
|
1478
1652
|
/**
|
|
1479
1653
|
* Split the given segment into multiple segments on the given points.
|
|
1480
1654
|
* * Each existing segment will retain its leftSE and a new rightSE will be
|
|
@@ -1487,215 +1661,180 @@
|
|
|
1487
1661
|
*
|
|
1488
1662
|
* Warning: input array of points is modified
|
|
1489
1663
|
*/
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
var newLeftSE = new SweepEvent(point, true);
|
|
1497
|
-
var newRightSE = new SweepEvent(point, false);
|
|
1498
|
-
var oldRightSE = this.rightSE;
|
|
1664
|
+
split(point) {
|
|
1665
|
+
const newEvents = [];
|
|
1666
|
+
const alreadyLinked = point.events !== undefined;
|
|
1667
|
+
const newLeftSE = new SweepEvent(point, true);
|
|
1668
|
+
const newRightSE = new SweepEvent(point, false);
|
|
1669
|
+
const oldRightSE = this.rightSE;
|
|
1499
1670
|
this.replaceRightSE(newRightSE);
|
|
1500
1671
|
newEvents.push(newRightSE);
|
|
1501
1672
|
newEvents.push(newLeftSE);
|
|
1502
|
-
|
|
1673
|
+
const newSeg = new Segment(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice());
|
|
1674
|
+
|
|
1675
|
+
// when splitting a nearly vertical downward-facing segment,
|
|
1503
1676
|
// sometimes one of the resulting new segments is vertical, in which
|
|
1504
1677
|
// case its left and right events may need to be swapped
|
|
1505
|
-
|
|
1506
1678
|
if (SweepEvent.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
|
|
1507
1679
|
newSeg.swapEvents();
|
|
1508
1680
|
}
|
|
1509
|
-
|
|
1510
1681
|
if (SweepEvent.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
|
|
1511
1682
|
this.swapEvents();
|
|
1512
|
-
}
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
// in the point we just used to create new sweep events with was already
|
|
1513
1686
|
// linked to other events, we need to check if either of the affected
|
|
1514
1687
|
// segments should be consumed
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
1688
|
if (alreadyLinked) {
|
|
1518
1689
|
newLeftSE.checkForConsuming();
|
|
1519
1690
|
newRightSE.checkForConsuming();
|
|
1520
1691
|
}
|
|
1521
|
-
|
|
1522
1692
|
return newEvents;
|
|
1523
1693
|
}
|
|
1524
|
-
/* Swap which event is left and right */
|
|
1525
1694
|
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
var tmpEvt = this.rightSE;
|
|
1695
|
+
/* Swap which event is left and right */
|
|
1696
|
+
swapEvents() {
|
|
1697
|
+
const tmpEvt = this.rightSE;
|
|
1530
1698
|
this.rightSE = this.leftSE;
|
|
1531
1699
|
this.leftSE = tmpEvt;
|
|
1532
1700
|
this.leftSE.isLeft = true;
|
|
1533
1701
|
this.rightSE.isLeft = false;
|
|
1534
|
-
|
|
1535
|
-
for (var i = 0, iMax = this.windings.length; i < iMax; i++) {
|
|
1702
|
+
for (let i = 0, iMax = this.windings.length; i < iMax; i++) {
|
|
1536
1703
|
this.windings[i] *= -1;
|
|
1537
1704
|
}
|
|
1538
1705
|
}
|
|
1706
|
+
|
|
1539
1707
|
/* Consume another segment. We take their rings under our wing
|
|
1540
1708
|
* and mark them as consumed. Use for perfectly overlapping segments */
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
while (consumer.consumedBy) {
|
|
1549
|
-
consumer = consumer.consumedBy;
|
|
1550
|
-
}
|
|
1551
|
-
|
|
1552
|
-
while (consumee.consumedBy) {
|
|
1553
|
-
consumee = consumee.consumedBy;
|
|
1554
|
-
}
|
|
1555
|
-
|
|
1556
|
-
var cmp = Segment.compare(consumer, consumee);
|
|
1709
|
+
consume(other) {
|
|
1710
|
+
let consumer = this;
|
|
1711
|
+
let consumee = other;
|
|
1712
|
+
while (consumer.consumedBy) consumer = consumer.consumedBy;
|
|
1713
|
+
while (consumee.consumedBy) consumee = consumee.consumedBy;
|
|
1714
|
+
const cmp = Segment.compare(consumer, consumee);
|
|
1557
1715
|
if (cmp === 0) return; // already consumed
|
|
1558
1716
|
// the winner of the consumption is the earlier segment
|
|
1559
1717
|
// according to sweep line ordering
|
|
1560
|
-
|
|
1561
1718
|
if (cmp > 0) {
|
|
1562
|
-
|
|
1719
|
+
const tmp = consumer;
|
|
1563
1720
|
consumer = consumee;
|
|
1564
1721
|
consumee = tmp;
|
|
1565
|
-
}
|
|
1566
|
-
|
|
1722
|
+
}
|
|
1567
1723
|
|
|
1724
|
+
// make sure a segment doesn't consume it's prev
|
|
1568
1725
|
if (consumer.prev === consumee) {
|
|
1569
|
-
|
|
1726
|
+
const tmp = consumer;
|
|
1570
1727
|
consumer = consumee;
|
|
1571
|
-
consumee =
|
|
1728
|
+
consumee = tmp;
|
|
1572
1729
|
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
var index = consumer.rings.indexOf(ring);
|
|
1578
|
-
|
|
1730
|
+
for (let i = 0, iMax = consumee.rings.length; i < iMax; i++) {
|
|
1731
|
+
const ring = consumee.rings[i];
|
|
1732
|
+
const winding = consumee.windings[i];
|
|
1733
|
+
const index = consumer.rings.indexOf(ring);
|
|
1579
1734
|
if (index === -1) {
|
|
1580
1735
|
consumer.rings.push(ring);
|
|
1581
1736
|
consumer.windings.push(winding);
|
|
1582
1737
|
} else consumer.windings[index] += winding;
|
|
1583
1738
|
}
|
|
1584
|
-
|
|
1585
1739
|
consumee.rings = null;
|
|
1586
1740
|
consumee.windings = null;
|
|
1587
|
-
consumee.consumedBy = consumer;
|
|
1741
|
+
consumee.consumedBy = consumer;
|
|
1588
1742
|
|
|
1743
|
+
// mark sweep events consumed as to maintain ordering in sweep event queue
|
|
1589
1744
|
consumee.leftSE.consumedBy = consumer.leftSE;
|
|
1590
1745
|
consumee.rightSE.consumedBy = consumer.rightSE;
|
|
1591
1746
|
}
|
|
1592
|
-
/* The first segment previous segment chain that is in the result */
|
|
1593
1747
|
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
value: function prevInResult() {
|
|
1748
|
+
/* The first segment previous segment chain that is in the result */
|
|
1749
|
+
prevInResult() {
|
|
1597
1750
|
if (this._prevInResult !== undefined) return this._prevInResult;
|
|
1598
1751
|
if (!this.prev) this._prevInResult = null;else if (this.prev.isInResult()) this._prevInResult = this.prev;else this._prevInResult = this.prev.prevInResult();
|
|
1599
1752
|
return this._prevInResult;
|
|
1600
1753
|
}
|
|
1601
|
-
|
|
1602
|
-
key: "beforeState",
|
|
1603
|
-
value: function beforeState() {
|
|
1754
|
+
beforeState() {
|
|
1604
1755
|
if (this._beforeState !== undefined) return this._beforeState;
|
|
1605
1756
|
if (!this.prev) this._beforeState = {
|
|
1606
1757
|
rings: [],
|
|
1607
1758
|
windings: [],
|
|
1608
1759
|
multiPolys: []
|
|
1609
1760
|
};else {
|
|
1610
|
-
|
|
1761
|
+
const seg = this.prev.consumedBy || this.prev;
|
|
1611
1762
|
this._beforeState = seg.afterState();
|
|
1612
1763
|
}
|
|
1613
1764
|
return this._beforeState;
|
|
1614
1765
|
}
|
|
1615
|
-
|
|
1616
|
-
key: "afterState",
|
|
1617
|
-
value: function afterState() {
|
|
1766
|
+
afterState() {
|
|
1618
1767
|
if (this._afterState !== undefined) return this._afterState;
|
|
1619
|
-
|
|
1768
|
+
const beforeState = this.beforeState();
|
|
1620
1769
|
this._afterState = {
|
|
1621
1770
|
rings: beforeState.rings.slice(0),
|
|
1622
1771
|
windings: beforeState.windings.slice(0),
|
|
1623
1772
|
multiPolys: []
|
|
1624
1773
|
};
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1774
|
+
const ringsAfter = this._afterState.rings;
|
|
1775
|
+
const windingsAfter = this._afterState.windings;
|
|
1776
|
+
const mpsAfter = this._afterState.multiPolys;
|
|
1777
|
+
|
|
1778
|
+
// calculate ringsAfter, windingsAfter
|
|
1779
|
+
for (let i = 0, iMax = this.rings.length; i < iMax; i++) {
|
|
1780
|
+
const ring = this.rings[i];
|
|
1781
|
+
const winding = this.windings[i];
|
|
1782
|
+
const index = ringsAfter.indexOf(ring);
|
|
1634
1783
|
if (index === -1) {
|
|
1635
1784
|
ringsAfter.push(ring);
|
|
1636
1785
|
windingsAfter.push(winding);
|
|
1637
1786
|
} else windingsAfter[index] += winding;
|
|
1638
|
-
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
var polysAfter = [];
|
|
1642
|
-
var polysExclude = [];
|
|
1643
|
-
|
|
1644
|
-
for (var _i = 0, _iMax = ringsAfter.length; _i < _iMax; _i++) {
|
|
1645
|
-
if (windingsAfter[_i] === 0) continue; // non-zero rule
|
|
1787
|
+
}
|
|
1646
1788
|
|
|
1647
|
-
|
|
1648
|
-
|
|
1789
|
+
// calcualte polysAfter
|
|
1790
|
+
const polysAfter = [];
|
|
1791
|
+
const polysExclude = [];
|
|
1792
|
+
for (let i = 0, iMax = ringsAfter.length; i < iMax; i++) {
|
|
1793
|
+
if (windingsAfter[i] === 0) continue; // non-zero rule
|
|
1794
|
+
const ring = ringsAfter[i];
|
|
1795
|
+
const poly = ring.poly;
|
|
1649
1796
|
if (polysExclude.indexOf(poly) !== -1) continue;
|
|
1650
|
-
if (
|
|
1797
|
+
if (ring.isExterior) polysAfter.push(poly);else {
|
|
1651
1798
|
if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
if (_index !== -1) polysAfter.splice(_index, 1);
|
|
1799
|
+
const index = polysAfter.indexOf(ring.poly);
|
|
1800
|
+
if (index !== -1) polysAfter.splice(index, 1);
|
|
1656
1801
|
}
|
|
1657
|
-
}
|
|
1658
|
-
|
|
1802
|
+
}
|
|
1659
1803
|
|
|
1660
|
-
|
|
1661
|
-
|
|
1804
|
+
// calculate multiPolysAfter
|
|
1805
|
+
for (let i = 0, iMax = polysAfter.length; i < iMax; i++) {
|
|
1806
|
+
const mp = polysAfter[i].multiPoly;
|
|
1662
1807
|
if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
|
|
1663
1808
|
}
|
|
1664
|
-
|
|
1665
1809
|
return this._afterState;
|
|
1666
1810
|
}
|
|
1667
|
-
/* Is this segment part of the final result? */
|
|
1668
1811
|
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
value: function isInResult() {
|
|
1812
|
+
/* Is this segment part of the final result? */
|
|
1813
|
+
isInResult() {
|
|
1672
1814
|
// if we've been consumed, we're not in the result
|
|
1673
1815
|
if (this.consumedBy) return false;
|
|
1674
1816
|
if (this._isInResult !== undefined) return this._isInResult;
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1817
|
+
const mpsBefore = this.beforeState().multiPolys;
|
|
1818
|
+
const mpsAfter = this.afterState().multiPolys;
|
|
1678
1819
|
switch (operation.type) {
|
|
1679
|
-
case
|
|
1820
|
+
case "union":
|
|
1680
1821
|
{
|
|
1681
1822
|
// UNION - included iff:
|
|
1682
1823
|
// * On one side of us there is 0 poly interiors AND
|
|
1683
1824
|
// * On the other side there is 1 or more.
|
|
1684
|
-
|
|
1685
|
-
|
|
1825
|
+
const noBefores = mpsBefore.length === 0;
|
|
1826
|
+
const noAfters = mpsAfter.length === 0;
|
|
1686
1827
|
this._isInResult = noBefores !== noAfters;
|
|
1687
1828
|
break;
|
|
1688
1829
|
}
|
|
1689
|
-
|
|
1690
|
-
case 'intersection':
|
|
1830
|
+
case "intersection":
|
|
1691
1831
|
{
|
|
1692
1832
|
// INTERSECTION - included iff:
|
|
1693
1833
|
// * on one side of us all multipolys are rep. with poly interiors AND
|
|
1694
1834
|
// * on the other side of us, not all multipolys are repsented
|
|
1695
1835
|
// with poly interiors
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1836
|
+
let least;
|
|
1837
|
+
let most;
|
|
1699
1838
|
if (mpsBefore.length < mpsAfter.length) {
|
|
1700
1839
|
least = mpsBefore.length;
|
|
1701
1840
|
most = mpsAfter.length;
|
|
@@ -1703,630 +1842,472 @@
|
|
|
1703
1842
|
least = mpsAfter.length;
|
|
1704
1843
|
most = mpsBefore.length;
|
|
1705
1844
|
}
|
|
1706
|
-
|
|
1707
1845
|
this._isInResult = most === operation.numMultiPolys && least < most;
|
|
1708
1846
|
break;
|
|
1709
1847
|
}
|
|
1710
|
-
|
|
1711
|
-
case 'xor':
|
|
1848
|
+
case "xor":
|
|
1712
1849
|
{
|
|
1713
1850
|
// XOR - included iff:
|
|
1714
1851
|
// * the difference between the number of multipolys represented
|
|
1715
1852
|
// with poly interiors on our two sides is an odd number
|
|
1716
|
-
|
|
1853
|
+
const diff = Math.abs(mpsBefore.length - mpsAfter.length);
|
|
1717
1854
|
this._isInResult = diff % 2 === 1;
|
|
1718
1855
|
break;
|
|
1719
1856
|
}
|
|
1720
|
-
|
|
1721
|
-
case 'difference':
|
|
1857
|
+
case "difference":
|
|
1722
1858
|
{
|
|
1723
1859
|
// DIFFERENCE included iff:
|
|
1724
1860
|
// * on exactly one side, we have just the subject
|
|
1725
|
-
|
|
1726
|
-
return mps.length === 1 && mps[0].isSubject;
|
|
1727
|
-
};
|
|
1728
|
-
|
|
1861
|
+
const isJustSubject = mps => mps.length === 1 && mps[0].isSubject;
|
|
1729
1862
|
this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
|
|
1730
1863
|
break;
|
|
1731
1864
|
}
|
|
1732
|
-
|
|
1733
1865
|
default:
|
|
1734
|
-
throw new Error(
|
|
1866
|
+
throw new Error(`Unrecognized operation type found ${operation.type}`);
|
|
1735
1867
|
}
|
|
1736
|
-
|
|
1737
1868
|
return this._isInResult;
|
|
1738
1869
|
}
|
|
1739
|
-
}
|
|
1740
|
-
key: "fromRing",
|
|
1741
|
-
value: function fromRing(pt1, pt2, ring) {
|
|
1742
|
-
var leftPt, rightPt, winding; // ordering the two points according to sweep line ordering
|
|
1743
|
-
|
|
1744
|
-
var cmpPts = SweepEvent.comparePoints(pt1, pt2);
|
|
1745
|
-
|
|
1746
|
-
if (cmpPts < 0) {
|
|
1747
|
-
leftPt = pt1;
|
|
1748
|
-
rightPt = pt2;
|
|
1749
|
-
winding = 1;
|
|
1750
|
-
} else if (cmpPts > 0) {
|
|
1751
|
-
leftPt = pt2;
|
|
1752
|
-
rightPt = pt1;
|
|
1753
|
-
winding = -1;
|
|
1754
|
-
} else throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
|
|
1755
|
-
|
|
1756
|
-
var leftSE = new SweepEvent(leftPt, true);
|
|
1757
|
-
var rightSE = new SweepEvent(rightPt, false);
|
|
1758
|
-
return new Segment(leftSE, rightSE, [ring], [winding]);
|
|
1759
|
-
}
|
|
1760
|
-
}]);
|
|
1761
|
-
|
|
1762
|
-
return Segment;
|
|
1763
|
-
}();
|
|
1764
|
-
|
|
1765
|
-
var RingIn = /*#__PURE__*/function () {
|
|
1766
|
-
function RingIn(geomRing, poly, isExterior) {
|
|
1767
|
-
_classCallCheck(this, RingIn);
|
|
1768
|
-
|
|
1769
|
-
if (!Array.isArray(geomRing) || geomRing.length === 0) {
|
|
1770
|
-
throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
|
|
1771
|
-
}
|
|
1772
|
-
|
|
1773
|
-
this.poly = poly;
|
|
1774
|
-
this.isExterior = isExterior;
|
|
1775
|
-
this.segments = [];
|
|
1776
|
-
|
|
1777
|
-
if (typeof geomRing[0][0] !== 'number' || typeof geomRing[0][1] !== 'number') {
|
|
1778
|
-
throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
|
|
1779
|
-
}
|
|
1870
|
+
}
|
|
1780
1871
|
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
y: firstPoint.y
|
|
1786
|
-
},
|
|
1787
|
-
ur: {
|
|
1788
|
-
x: firstPoint.x,
|
|
1789
|
-
y: firstPoint.y
|
|
1872
|
+
class RingIn {
|
|
1873
|
+
constructor(geomRing, poly, isExterior) {
|
|
1874
|
+
if (!Array.isArray(geomRing) || geomRing.length === 0) {
|
|
1875
|
+
throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
|
|
1790
1876
|
}
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1877
|
+
this.poly = poly;
|
|
1878
|
+
this.isExterior = isExterior;
|
|
1879
|
+
this.segments = [];
|
|
1880
|
+
if (typeof geomRing[0][0] !== "number" || typeof geomRing[0][1] !== "number") {
|
|
1881
|
+
throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
|
|
1882
|
+
}
|
|
1883
|
+
const firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
|
|
1884
|
+
this.bbox = {
|
|
1885
|
+
ll: {
|
|
1886
|
+
x: firstPoint.x,
|
|
1887
|
+
y: firstPoint.y
|
|
1888
|
+
},
|
|
1889
|
+
ur: {
|
|
1890
|
+
x: firstPoint.x,
|
|
1891
|
+
y: firstPoint.y
|
|
1892
|
+
}
|
|
1893
|
+
};
|
|
1894
|
+
let prevPoint = firstPoint;
|
|
1895
|
+
for (let i = 1, iMax = geomRing.length; i < iMax; i++) {
|
|
1896
|
+
if (typeof geomRing[i][0] !== "number" || typeof geomRing[i][1] !== "number") {
|
|
1897
|
+
throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
|
|
1898
|
+
}
|
|
1899
|
+
let point = rounder.round(geomRing[i][0], geomRing[i][1]);
|
|
1900
|
+
// skip repeated points
|
|
1901
|
+
if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
|
|
1902
|
+
this.segments.push(Segment.fromRing(prevPoint, point, this));
|
|
1903
|
+
if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
|
|
1904
|
+
if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
|
|
1905
|
+
if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
|
|
1906
|
+
if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
|
|
1907
|
+
prevPoint = point;
|
|
1908
|
+
}
|
|
1909
|
+
// add segment from last to first if last is not the same as first
|
|
1910
|
+
if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
|
|
1911
|
+
this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
|
|
1797
1912
|
}
|
|
1798
|
-
|
|
1799
|
-
var point = rounder.round(geomRing[i][0], geomRing[i][1]); // skip repeated points
|
|
1800
|
-
|
|
1801
|
-
if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
|
|
1802
|
-
this.segments.push(Segment.fromRing(prevPoint, point, this));
|
|
1803
|
-
if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
|
|
1804
|
-
if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
|
|
1805
|
-
if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
|
|
1806
|
-
if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
|
|
1807
|
-
prevPoint = point;
|
|
1808
|
-
} // add segment from last to first if last is not the same as first
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
|
|
1812
|
-
this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
|
|
1813
1913
|
}
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
value: function getSweepEvents() {
|
|
1819
|
-
var sweepEvents = [];
|
|
1820
|
-
|
|
1821
|
-
for (var i = 0, iMax = this.segments.length; i < iMax; i++) {
|
|
1822
|
-
var segment = this.segments[i];
|
|
1914
|
+
getSweepEvents() {
|
|
1915
|
+
const sweepEvents = [];
|
|
1916
|
+
for (let i = 0, iMax = this.segments.length; i < iMax; i++) {
|
|
1917
|
+
const segment = this.segments[i];
|
|
1823
1918
|
sweepEvents.push(segment.leftSE);
|
|
1824
1919
|
sweepEvents.push(segment.rightSE);
|
|
1825
1920
|
}
|
|
1826
|
-
|
|
1827
1921
|
return sweepEvents;
|
|
1828
1922
|
}
|
|
1829
|
-
}
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
function PolyIn(geomPoly, multiPoly) {
|
|
1835
|
-
_classCallCheck(this, PolyIn);
|
|
1836
|
-
|
|
1837
|
-
if (!Array.isArray(geomPoly)) {
|
|
1838
|
-
throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
|
|
1839
|
-
}
|
|
1840
|
-
|
|
1841
|
-
this.exteriorRing = new RingIn(geomPoly[0], this, true); // copy by value
|
|
1842
|
-
|
|
1843
|
-
this.bbox = {
|
|
1844
|
-
ll: {
|
|
1845
|
-
x: this.exteriorRing.bbox.ll.x,
|
|
1846
|
-
y: this.exteriorRing.bbox.ll.y
|
|
1847
|
-
},
|
|
1848
|
-
ur: {
|
|
1849
|
-
x: this.exteriorRing.bbox.ur.x,
|
|
1850
|
-
y: this.exteriorRing.bbox.ur.y
|
|
1923
|
+
}
|
|
1924
|
+
class PolyIn {
|
|
1925
|
+
constructor(geomPoly, multiPoly) {
|
|
1926
|
+
if (!Array.isArray(geomPoly)) {
|
|
1927
|
+
throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
|
|
1851
1928
|
}
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1929
|
+
this.exteriorRing = new RingIn(geomPoly[0], this, true);
|
|
1930
|
+
// copy by value
|
|
1931
|
+
this.bbox = {
|
|
1932
|
+
ll: {
|
|
1933
|
+
x: this.exteriorRing.bbox.ll.x,
|
|
1934
|
+
y: this.exteriorRing.bbox.ll.y
|
|
1935
|
+
},
|
|
1936
|
+
ur: {
|
|
1937
|
+
x: this.exteriorRing.bbox.ur.x,
|
|
1938
|
+
y: this.exteriorRing.bbox.ur.y
|
|
1939
|
+
}
|
|
1940
|
+
};
|
|
1941
|
+
this.interiorRings = [];
|
|
1942
|
+
for (let i = 1, iMax = geomPoly.length; i < iMax; i++) {
|
|
1943
|
+
const ring = new RingIn(geomPoly[i], this, false);
|
|
1944
|
+
if (ring.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = ring.bbox.ll.x;
|
|
1945
|
+
if (ring.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = ring.bbox.ll.y;
|
|
1946
|
+
if (ring.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = ring.bbox.ur.x;
|
|
1947
|
+
if (ring.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = ring.bbox.ur.y;
|
|
1948
|
+
this.interiorRings.push(ring);
|
|
1949
|
+
}
|
|
1950
|
+
this.multiPoly = multiPoly;
|
|
1862
1951
|
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
key: "getSweepEvents",
|
|
1869
|
-
value: function getSweepEvents() {
|
|
1870
|
-
var sweepEvents = this.exteriorRing.getSweepEvents();
|
|
1871
|
-
|
|
1872
|
-
for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
|
|
1873
|
-
var ringSweepEvents = this.interiorRings[i].getSweepEvents();
|
|
1874
|
-
|
|
1875
|
-
for (var j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
|
|
1952
|
+
getSweepEvents() {
|
|
1953
|
+
const sweepEvents = this.exteriorRing.getSweepEvents();
|
|
1954
|
+
for (let i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
|
|
1955
|
+
const ringSweepEvents = this.interiorRings[i].getSweepEvents();
|
|
1956
|
+
for (let j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
|
|
1876
1957
|
sweepEvents.push(ringSweepEvents[j]);
|
|
1877
1958
|
}
|
|
1878
1959
|
}
|
|
1879
|
-
|
|
1880
1960
|
return sweepEvents;
|
|
1881
1961
|
}
|
|
1882
|
-
}
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
function MultiPolyIn(geom, isSubject) {
|
|
1888
|
-
_classCallCheck(this, MultiPolyIn);
|
|
1889
|
-
|
|
1890
|
-
if (!Array.isArray(geom)) {
|
|
1891
|
-
throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
|
|
1892
|
-
}
|
|
1893
|
-
|
|
1894
|
-
try {
|
|
1895
|
-
// if the input looks like a polygon, convert it to a multipolygon
|
|
1896
|
-
if (typeof geom[0][0][0] === 'number') geom = [geom];
|
|
1897
|
-
} catch (ex) {// The input is either malformed or has empty arrays.
|
|
1898
|
-
// In either case, it will be handled later on.
|
|
1899
|
-
}
|
|
1900
|
-
|
|
1901
|
-
this.polys = [];
|
|
1902
|
-
this.bbox = {
|
|
1903
|
-
ll: {
|
|
1904
|
-
x: Number.POSITIVE_INFINITY,
|
|
1905
|
-
y: Number.POSITIVE_INFINITY
|
|
1906
|
-
},
|
|
1907
|
-
ur: {
|
|
1908
|
-
x: Number.NEGATIVE_INFINITY,
|
|
1909
|
-
y: Number.NEGATIVE_INFINITY
|
|
1962
|
+
}
|
|
1963
|
+
class MultiPolyIn {
|
|
1964
|
+
constructor(geom, isSubject) {
|
|
1965
|
+
if (!Array.isArray(geom)) {
|
|
1966
|
+
throw new Error("Input geometry is not a valid Polygon or MultiPolygon");
|
|
1910
1967
|
}
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
this.
|
|
1968
|
+
try {
|
|
1969
|
+
// if the input looks like a polygon, convert it to a multipolygon
|
|
1970
|
+
if (typeof geom[0][0][0] === "number") geom = [geom];
|
|
1971
|
+
} catch (ex) {
|
|
1972
|
+
// The input is either malformed or has empty arrays.
|
|
1973
|
+
// In either case, it will be handled later on.
|
|
1974
|
+
}
|
|
1975
|
+
this.polys = [];
|
|
1976
|
+
this.bbox = {
|
|
1977
|
+
ll: {
|
|
1978
|
+
x: Number.POSITIVE_INFINITY,
|
|
1979
|
+
y: Number.POSITIVE_INFINITY
|
|
1980
|
+
},
|
|
1981
|
+
ur: {
|
|
1982
|
+
x: Number.NEGATIVE_INFINITY,
|
|
1983
|
+
y: Number.NEGATIVE_INFINITY
|
|
1984
|
+
}
|
|
1985
|
+
};
|
|
1986
|
+
for (let i = 0, iMax = geom.length; i < iMax; i++) {
|
|
1987
|
+
const poly = new PolyIn(geom[i], this);
|
|
1988
|
+
if (poly.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = poly.bbox.ll.x;
|
|
1989
|
+
if (poly.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = poly.bbox.ll.y;
|
|
1990
|
+
if (poly.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = poly.bbox.ur.x;
|
|
1991
|
+
if (poly.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = poly.bbox.ur.y;
|
|
1992
|
+
this.polys.push(poly);
|
|
1993
|
+
}
|
|
1994
|
+
this.isSubject = isSubject;
|
|
1920
1995
|
}
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
key: "getSweepEvents",
|
|
1927
|
-
value: function getSweepEvents() {
|
|
1928
|
-
var sweepEvents = [];
|
|
1929
|
-
|
|
1930
|
-
for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
|
|
1931
|
-
var polySweepEvents = this.polys[i].getSweepEvents();
|
|
1932
|
-
|
|
1933
|
-
for (var j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
|
|
1996
|
+
getSweepEvents() {
|
|
1997
|
+
const sweepEvents = [];
|
|
1998
|
+
for (let i = 0, iMax = this.polys.length; i < iMax; i++) {
|
|
1999
|
+
const polySweepEvents = this.polys[i].getSweepEvents();
|
|
2000
|
+
for (let j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
|
|
1934
2001
|
sweepEvents.push(polySweepEvents[j]);
|
|
1935
2002
|
}
|
|
1936
2003
|
}
|
|
1937
|
-
|
|
1938
2004
|
return sweepEvents;
|
|
1939
2005
|
}
|
|
1940
|
-
}
|
|
1941
|
-
|
|
1942
|
-
return MultiPolyIn;
|
|
1943
|
-
}();
|
|
1944
|
-
|
|
1945
|
-
var RingOut = /*#__PURE__*/function () {
|
|
1946
|
-
_createClass(RingOut, null, [{
|
|
1947
|
-
key: "factory",
|
|
2006
|
+
}
|
|
1948
2007
|
|
|
2008
|
+
class RingOut {
|
|
1949
2009
|
/* Given the segments from the sweep line pass, compute & return a series
|
|
1950
2010
|
* of closed rings from all the segments marked to be part of the result */
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
var segment = allSegments[i];
|
|
2011
|
+
static factory(allSegments) {
|
|
2012
|
+
const ringsOut = [];
|
|
2013
|
+
for (let i = 0, iMax = allSegments.length; i < iMax; i++) {
|
|
2014
|
+
const segment = allSegments[i];
|
|
1956
2015
|
if (!segment.isInResult() || segment.ringOut) continue;
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
/* Walk the chain of linked events to form a closed ring */
|
|
2016
|
+
let prevEvent = null;
|
|
2017
|
+
let event = segment.leftSE;
|
|
2018
|
+
let nextEvent = segment.rightSE;
|
|
2019
|
+
const events = [event];
|
|
2020
|
+
const startingPoint = event.point;
|
|
2021
|
+
const intersectionLEs = [];
|
|
1964
2022
|
|
|
2023
|
+
/* Walk the chain of linked events to form a closed ring */
|
|
1965
2024
|
while (true) {
|
|
1966
2025
|
prevEvent = event;
|
|
1967
2026
|
event = nextEvent;
|
|
1968
2027
|
events.push(event);
|
|
1969
|
-
/* Is the ring complete? */
|
|
1970
2028
|
|
|
2029
|
+
/* Is the ring complete? */
|
|
1971
2030
|
if (event.point === startingPoint) break;
|
|
1972
|
-
|
|
1973
2031
|
while (true) {
|
|
1974
|
-
|
|
1975
|
-
/* Did we hit a dead end? This shouldn't happen. Indicates some earlier
|
|
1976
|
-
* part of the algorithm malfunctioned... please file a bug report. */
|
|
2032
|
+
const availableLEs = event.getAvailableLinkedEvents();
|
|
1977
2033
|
|
|
2034
|
+
/* Did we hit a dead end? This shouldn't happen.
|
|
2035
|
+
* Indicates some earlier part of the algorithm malfunctioned. */
|
|
1978
2036
|
if (availableLEs.length === 0) {
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
throw new Error(
|
|
2037
|
+
const firstPt = events[0].point;
|
|
2038
|
+
const lastPt = events[events.length - 1].point;
|
|
2039
|
+
throw new Error(`Unable to complete output ring starting at [${firstPt.x},` + ` ${firstPt.y}]. Last matching segment found ends at` + ` [${lastPt.x}, ${lastPt.y}].`);
|
|
1982
2040
|
}
|
|
1983
|
-
/* Only one way to go, so cotinue on the path */
|
|
1984
|
-
|
|
1985
2041
|
|
|
2042
|
+
/* Only one way to go, so cotinue on the path */
|
|
1986
2043
|
if (availableLEs.length === 1) {
|
|
1987
2044
|
nextEvent = availableLEs[0].otherSE;
|
|
1988
2045
|
break;
|
|
1989
2046
|
}
|
|
1990
|
-
/* We must have an intersection. Check for a completed loop */
|
|
1991
2047
|
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
for (var j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
|
|
2048
|
+
/* We must have an intersection. Check for a completed loop */
|
|
2049
|
+
let indexLE = null;
|
|
2050
|
+
for (let j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
|
|
1996
2051
|
if (intersectionLEs[j].point === event.point) {
|
|
1997
2052
|
indexLE = j;
|
|
1998
2053
|
break;
|
|
1999
2054
|
}
|
|
2000
2055
|
}
|
|
2001
2056
|
/* Found a completed loop. Cut that off and make a ring */
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
2057
|
if (indexLE !== null) {
|
|
2005
|
-
|
|
2006
|
-
|
|
2058
|
+
const intersectionLE = intersectionLEs.splice(indexLE)[0];
|
|
2059
|
+
const ringEvents = events.splice(intersectionLE.index);
|
|
2007
2060
|
ringEvents.unshift(ringEvents[0].otherSE);
|
|
2008
2061
|
ringsOut.push(new RingOut(ringEvents.reverse()));
|
|
2009
2062
|
continue;
|
|
2010
2063
|
}
|
|
2011
2064
|
/* register the intersection */
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
2065
|
intersectionLEs.push({
|
|
2015
2066
|
index: events.length,
|
|
2016
2067
|
point: event.point
|
|
2017
2068
|
});
|
|
2018
2069
|
/* Choose the left-most option to continue the walk */
|
|
2019
|
-
|
|
2020
|
-
var comparator = event.getLeftmostComparator(prevEvent);
|
|
2070
|
+
const comparator = event.getLeftmostComparator(prevEvent);
|
|
2021
2071
|
nextEvent = availableLEs.sort(comparator)[0].otherSE;
|
|
2022
2072
|
break;
|
|
2023
2073
|
}
|
|
2024
2074
|
}
|
|
2025
|
-
|
|
2026
2075
|
ringsOut.push(new RingOut(events));
|
|
2027
2076
|
}
|
|
2028
|
-
|
|
2029
2077
|
return ringsOut;
|
|
2030
2078
|
}
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
for (var i = 0, iMax = events.length; i < iMax; i++) {
|
|
2039
|
-
events[i].segment.ringOut = this;
|
|
2079
|
+
constructor(events) {
|
|
2080
|
+
this.events = events;
|
|
2081
|
+
for (let i = 0, iMax = events.length; i < iMax; i++) {
|
|
2082
|
+
events[i].segment.ringOut = this;
|
|
2083
|
+
}
|
|
2084
|
+
this.poly = null;
|
|
2040
2085
|
}
|
|
2041
|
-
|
|
2042
|
-
this.poly = null;
|
|
2043
|
-
}
|
|
2044
|
-
|
|
2045
|
-
_createClass(RingOut, [{
|
|
2046
|
-
key: "getGeom",
|
|
2047
|
-
value: function getGeom() {
|
|
2086
|
+
getGeom() {
|
|
2048
2087
|
// Remove superfluous points (ie extra points along a straight line),
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
} // ring was all (within rounding error of angle calc) colinear points
|
|
2059
|
-
|
|
2088
|
+
let prevPt = this.events[0].point;
|
|
2089
|
+
const points = [prevPt];
|
|
2090
|
+
for (let i = 1, iMax = this.events.length - 1; i < iMax; i++) {
|
|
2091
|
+
const pt = this.events[i].point;
|
|
2092
|
+
const nextPt = this.events[i + 1].point;
|
|
2093
|
+
if (compareVectorAngles(pt, prevPt, nextPt) === 0) continue;
|
|
2094
|
+
points.push(pt);
|
|
2095
|
+
prevPt = pt;
|
|
2096
|
+
}
|
|
2060
2097
|
|
|
2061
|
-
|
|
2098
|
+
// ring was all (within rounding error of angle calc) colinear points
|
|
2099
|
+
if (points.length === 1) return null;
|
|
2062
2100
|
|
|
2063
|
-
|
|
2064
|
-
|
|
2101
|
+
// check if the starting point is necessary
|
|
2102
|
+
const pt = points[0];
|
|
2103
|
+
const nextPt = points[1];
|
|
2065
2104
|
if (compareVectorAngles(pt, prevPt, nextPt) === 0) points.shift();
|
|
2066
2105
|
points.push(points[0]);
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
for (var _i = iStart; _i != iEnd; _i += step) {
|
|
2073
|
-
orderedPoints.push([points[_i].x, points[_i].y]);
|
|
2074
|
-
}
|
|
2075
|
-
|
|
2106
|
+
const step = this.isExteriorRing() ? 1 : -1;
|
|
2107
|
+
const iStart = this.isExteriorRing() ? 0 : points.length - 1;
|
|
2108
|
+
const iEnd = this.isExteriorRing() ? points.length : -1;
|
|
2109
|
+
const orderedPoints = [];
|
|
2110
|
+
for (let i = iStart; i != iEnd; i += step) orderedPoints.push([points[i].x, points[i].y]);
|
|
2076
2111
|
return orderedPoints;
|
|
2077
2112
|
}
|
|
2078
|
-
|
|
2079
|
-
key: "isExteriorRing",
|
|
2080
|
-
value: function isExteriorRing() {
|
|
2113
|
+
isExteriorRing() {
|
|
2081
2114
|
if (this._isExteriorRing === undefined) {
|
|
2082
|
-
|
|
2115
|
+
const enclosing = this.enclosingRing();
|
|
2083
2116
|
this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
|
|
2084
2117
|
}
|
|
2085
|
-
|
|
2086
2118
|
return this._isExteriorRing;
|
|
2087
2119
|
}
|
|
2088
|
-
|
|
2089
|
-
key: "enclosingRing",
|
|
2090
|
-
value: function enclosingRing() {
|
|
2120
|
+
enclosingRing() {
|
|
2091
2121
|
if (this._enclosingRing === undefined) {
|
|
2092
2122
|
this._enclosingRing = this._calcEnclosingRing();
|
|
2093
2123
|
}
|
|
2094
|
-
|
|
2095
2124
|
return this._enclosingRing;
|
|
2096
2125
|
}
|
|
2097
|
-
/* Returns the ring that encloses this one, if any */
|
|
2098
2126
|
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
value: function _calcEnclosingRing() {
|
|
2127
|
+
/* Returns the ring that encloses this one, if any */
|
|
2128
|
+
_calcEnclosingRing() {
|
|
2102
2129
|
// start with the ealier sweep line event so that the prevSeg
|
|
2103
2130
|
// chain doesn't lead us inside of a loop of ours
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
var evt = this.events[i];
|
|
2131
|
+
let leftMostEvt = this.events[0];
|
|
2132
|
+
for (let i = 1, iMax = this.events.length; i < iMax; i++) {
|
|
2133
|
+
const evt = this.events[i];
|
|
2108
2134
|
if (SweepEvent.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
|
|
2109
2135
|
}
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
var prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
|
|
2113
|
-
|
|
2136
|
+
let prevSeg = leftMostEvt.segment.prevInResult();
|
|
2137
|
+
let prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
|
|
2114
2138
|
while (true) {
|
|
2115
2139
|
// no segment found, thus no ring can enclose us
|
|
2116
|
-
if (!prevSeg) return null;
|
|
2140
|
+
if (!prevSeg) return null;
|
|
2141
|
+
|
|
2142
|
+
// no segments below prev segment found, thus the ring of the prev
|
|
2117
2143
|
// segment must loop back around and enclose us
|
|
2144
|
+
if (!prevPrevSeg) return prevSeg.ringOut;
|
|
2118
2145
|
|
|
2119
|
-
|
|
2146
|
+
// if the two segments are of different rings, the ring of the prev
|
|
2120
2147
|
// segment must either loop around us or the ring of the prev prev
|
|
2121
2148
|
// seg, which would make us and the ring of the prev peers
|
|
2122
|
-
|
|
2123
2149
|
if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
|
|
2124
2150
|
if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
|
|
2125
2151
|
return prevSeg.ringOut;
|
|
2126
2152
|
} else return prevSeg.ringOut.enclosingRing();
|
|
2127
|
-
}
|
|
2128
|
-
// of that ring. iterate downward, keep searching
|
|
2129
|
-
|
|
2153
|
+
}
|
|
2130
2154
|
|
|
2155
|
+
// two segments are from the same ring, so this was a penisula
|
|
2156
|
+
// of that ring. iterate downward, keep searching
|
|
2131
2157
|
prevSeg = prevPrevSeg.prevInResult();
|
|
2132
2158
|
prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
|
|
2133
2159
|
}
|
|
2134
2160
|
}
|
|
2135
|
-
}]);
|
|
2136
|
-
|
|
2137
|
-
return RingOut;
|
|
2138
|
-
}();
|
|
2139
|
-
var PolyOut = /*#__PURE__*/function () {
|
|
2140
|
-
function PolyOut(exteriorRing) {
|
|
2141
|
-
_classCallCheck(this, PolyOut);
|
|
2142
|
-
|
|
2143
|
-
this.exteriorRing = exteriorRing;
|
|
2144
|
-
exteriorRing.poly = this;
|
|
2145
|
-
this.interiorRings = [];
|
|
2146
2161
|
}
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2162
|
+
class PolyOut {
|
|
2163
|
+
constructor(exteriorRing) {
|
|
2164
|
+
this.exteriorRing = exteriorRing;
|
|
2165
|
+
exteriorRing.poly = this;
|
|
2166
|
+
this.interiorRings = [];
|
|
2167
|
+
}
|
|
2168
|
+
addInterior(ring) {
|
|
2151
2169
|
this.interiorRings.push(ring);
|
|
2152
2170
|
ring.poly = this;
|
|
2153
2171
|
}
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
var geom = [this.exteriorRing.getGeom()]; // exterior ring was all (within rounding error of angle calc) colinear points
|
|
2158
|
-
|
|
2172
|
+
getGeom() {
|
|
2173
|
+
const geom = [this.exteriorRing.getGeom()];
|
|
2174
|
+
// exterior ring was all (within rounding error of angle calc) colinear points
|
|
2159
2175
|
if (geom[0] === null) return null;
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2176
|
+
for (let i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
|
|
2177
|
+
const ringGeom = this.interiorRings[i].getGeom();
|
|
2178
|
+
// interior ring was all (within rounding error of angle calc) colinear points
|
|
2164
2179
|
if (ringGeom === null) continue;
|
|
2165
2180
|
geom.push(ringGeom);
|
|
2166
2181
|
}
|
|
2167
|
-
|
|
2168
2182
|
return geom;
|
|
2169
2183
|
}
|
|
2170
|
-
}]);
|
|
2171
|
-
|
|
2172
|
-
return PolyOut;
|
|
2173
|
-
}();
|
|
2174
|
-
var MultiPolyOut = /*#__PURE__*/function () {
|
|
2175
|
-
function MultiPolyOut(rings) {
|
|
2176
|
-
_classCallCheck(this, MultiPolyOut);
|
|
2177
|
-
|
|
2178
|
-
this.rings = rings;
|
|
2179
|
-
this.polys = this._composePolys(rings);
|
|
2180
2184
|
}
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2185
|
+
class MultiPolyOut {
|
|
2186
|
+
constructor(rings) {
|
|
2187
|
+
this.rings = rings;
|
|
2188
|
+
this.polys = this._composePolys(rings);
|
|
2189
|
+
}
|
|
2190
|
+
getGeom() {
|
|
2191
|
+
const geom = [];
|
|
2192
|
+
for (let i = 0, iMax = this.polys.length; i < iMax; i++) {
|
|
2193
|
+
const polyGeom = this.polys[i].getGeom();
|
|
2194
|
+
// exterior ring was all (within rounding error of angle calc) colinear points
|
|
2190
2195
|
if (polyGeom === null) continue;
|
|
2191
2196
|
geom.push(polyGeom);
|
|
2192
2197
|
}
|
|
2193
|
-
|
|
2194
2198
|
return geom;
|
|
2195
2199
|
}
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
for (var i = 0, iMax = rings.length; i < iMax; i++) {
|
|
2202
|
-
var ring = rings[i];
|
|
2200
|
+
_composePolys(rings) {
|
|
2201
|
+
const polys = [];
|
|
2202
|
+
for (let i = 0, iMax = rings.length; i < iMax; i++) {
|
|
2203
|
+
const ring = rings[i];
|
|
2203
2204
|
if (ring.poly) continue;
|
|
2204
2205
|
if (ring.isExteriorRing()) polys.push(new PolyOut(ring));else {
|
|
2205
|
-
|
|
2206
|
+
const enclosingRing = ring.enclosingRing();
|
|
2206
2207
|
if (!enclosingRing.poly) polys.push(new PolyOut(enclosingRing));
|
|
2207
2208
|
enclosingRing.poly.addInterior(ring);
|
|
2208
2209
|
}
|
|
2209
2210
|
}
|
|
2210
|
-
|
|
2211
2211
|
return polys;
|
|
2212
2212
|
}
|
|
2213
|
-
}
|
|
2214
|
-
|
|
2215
|
-
return MultiPolyOut;
|
|
2216
|
-
}();
|
|
2217
|
-
|
|
2218
|
-
/**
|
|
2219
|
-
* NOTE: We must be careful not to change any segments while
|
|
2220
|
-
* they are in the SplayTree. AFAIK, there's no way to tell
|
|
2221
|
-
* the tree to rebalance itself - thus before splitting
|
|
2222
|
-
* a segment that's in the tree, we remove it from the tree,
|
|
2223
|
-
* do the split, then re-insert it. (Even though splitting a
|
|
2224
|
-
* segment *shouldn't* change its correct position in the
|
|
2225
|
-
* sweep line tree, the reality is because of rounding errors,
|
|
2226
|
-
* it sometimes does.)
|
|
2227
|
-
*/
|
|
2228
|
-
|
|
2229
|
-
var SweepLine = /*#__PURE__*/function () {
|
|
2230
|
-
function SweepLine(queue) {
|
|
2231
|
-
var comparator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Segment.compare;
|
|
2213
|
+
}
|
|
2232
2214
|
|
|
2233
|
-
|
|
2215
|
+
/**
|
|
2216
|
+
* NOTE: We must be careful not to change any segments while
|
|
2217
|
+
* they are in the SplayTree. AFAIK, there's no way to tell
|
|
2218
|
+
* the tree to rebalance itself - thus before splitting
|
|
2219
|
+
* a segment that's in the tree, we remove it from the tree,
|
|
2220
|
+
* do the split, then re-insert it. (Even though splitting a
|
|
2221
|
+
* segment *shouldn't* change its correct position in the
|
|
2222
|
+
* sweep line tree, the reality is because of rounding errors,
|
|
2223
|
+
* it sometimes does.)
|
|
2224
|
+
*/
|
|
2234
2225
|
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2226
|
+
class SweepLine {
|
|
2227
|
+
constructor(queue) {
|
|
2228
|
+
let comparator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Segment.compare;
|
|
2229
|
+
this.queue = queue;
|
|
2230
|
+
this.tree = new Tree(comparator);
|
|
2231
|
+
this.segments = [];
|
|
2232
|
+
}
|
|
2233
|
+
process(event) {
|
|
2234
|
+
const segment = event.segment;
|
|
2235
|
+
const newEvents = [];
|
|
2239
2236
|
|
|
2240
|
-
|
|
2241
|
-
key: "process",
|
|
2242
|
-
value: function process(event) {
|
|
2243
|
-
var segment = event.segment;
|
|
2244
|
-
var newEvents = []; // if we've already been consumed by another segment,
|
|
2237
|
+
// if we've already been consumed by another segment,
|
|
2245
2238
|
// clean up our body parts and get out
|
|
2246
|
-
|
|
2247
2239
|
if (event.consumedBy) {
|
|
2248
2240
|
if (event.isLeft) this.queue.remove(event.otherSE);else this.tree.remove(segment);
|
|
2249
2241
|
return newEvents;
|
|
2250
2242
|
}
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2243
|
+
const node = event.isLeft ? this.tree.add(segment) : this.tree.find(segment);
|
|
2244
|
+
if (!node) throw new Error(`Unable to find segment #${segment.id} ` + `[${segment.leftSE.point.x}, ${segment.leftSE.point.y}] -> ` + `[${segment.rightSE.point.x}, ${segment.rightSE.point.y}] ` + "in SweepLine tree.");
|
|
2245
|
+
let prevNode = node;
|
|
2246
|
+
let nextNode = node;
|
|
2247
|
+
let prevSeg = undefined;
|
|
2248
|
+
let nextSeg = undefined;
|
|
2249
|
+
|
|
2250
|
+
// skip consumed segments still in tree
|
|
2259
2251
|
while (prevSeg === undefined) {
|
|
2260
2252
|
prevNode = this.tree.prev(prevNode);
|
|
2261
2253
|
if (prevNode === null) prevSeg = null;else if (prevNode.key.consumedBy === undefined) prevSeg = prevNode.key;
|
|
2262
|
-
}
|
|
2263
|
-
|
|
2254
|
+
}
|
|
2264
2255
|
|
|
2256
|
+
// skip consumed segments still in tree
|
|
2265
2257
|
while (nextSeg === undefined) {
|
|
2266
2258
|
nextNode = this.tree.next(nextNode);
|
|
2267
2259
|
if (nextNode === null) nextSeg = null;else if (nextNode.key.consumedBy === undefined) nextSeg = nextNode.key;
|
|
2268
2260
|
}
|
|
2269
|
-
|
|
2270
2261
|
if (event.isLeft) {
|
|
2271
2262
|
// Check for intersections against the previous segment in the sweep line
|
|
2272
|
-
|
|
2273
|
-
|
|
2263
|
+
let prevMySplitter = null;
|
|
2274
2264
|
if (prevSeg) {
|
|
2275
|
-
|
|
2276
|
-
|
|
2265
|
+
const prevInter = prevSeg.getIntersection(segment);
|
|
2277
2266
|
if (prevInter !== null) {
|
|
2278
2267
|
if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
|
|
2279
|
-
|
|
2280
2268
|
if (!prevSeg.isAnEndpoint(prevInter)) {
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
for (var i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
|
|
2269
|
+
const newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
|
|
2270
|
+
for (let i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
|
|
2284
2271
|
newEvents.push(newEventsFromSplit[i]);
|
|
2285
2272
|
}
|
|
2286
2273
|
}
|
|
2287
2274
|
}
|
|
2288
|
-
}
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
var nextMySplitter = null;
|
|
2275
|
+
}
|
|
2292
2276
|
|
|
2277
|
+
// Check for intersections against the next segment in the sweep line
|
|
2278
|
+
let nextMySplitter = null;
|
|
2293
2279
|
if (nextSeg) {
|
|
2294
|
-
|
|
2295
|
-
|
|
2280
|
+
const nextInter = nextSeg.getIntersection(segment);
|
|
2296
2281
|
if (nextInter !== null) {
|
|
2297
2282
|
if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
|
|
2298
|
-
|
|
2299
2283
|
if (!nextSeg.isAnEndpoint(nextInter)) {
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
newEvents.push(_newEventsFromSplit[_i]);
|
|
2284
|
+
const newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
|
|
2285
|
+
for (let i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
|
|
2286
|
+
newEvents.push(newEventsFromSplit[i]);
|
|
2304
2287
|
}
|
|
2305
2288
|
}
|
|
2306
2289
|
}
|
|
2307
|
-
}
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
// For simplicity, even if we find more than one intersection we only
|
|
2308
2293
|
// spilt on the 'earliest' (sweep-line style) of the intersections.
|
|
2309
2294
|
// The other intersection will be handled in a future process().
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
2295
|
if (prevMySplitter !== null || nextMySplitter !== null) {
|
|
2313
|
-
|
|
2296
|
+
let mySplitter = null;
|
|
2314
2297
|
if (prevMySplitter === null) mySplitter = nextMySplitter;else if (nextMySplitter === null) mySplitter = prevMySplitter;else {
|
|
2315
|
-
|
|
2298
|
+
const cmpSplitters = SweepEvent.comparePoints(prevMySplitter, nextMySplitter);
|
|
2316
2299
|
mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
|
|
2317
|
-
}
|
|
2318
|
-
// so remove afected segments and right sweep events before splitting
|
|
2300
|
+
}
|
|
2319
2301
|
|
|
2302
|
+
// Rounding errors can cause changes in ordering,
|
|
2303
|
+
// so remove afected segments and right sweep events before splitting
|
|
2320
2304
|
this.queue.remove(segment.rightSE);
|
|
2321
2305
|
newEvents.push(segment.rightSE);
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
for (var _i2 = 0, _iMax2 = _newEventsFromSplit2.length; _i2 < _iMax2; _i2++) {
|
|
2326
|
-
newEvents.push(_newEventsFromSplit2[_i2]);
|
|
2306
|
+
const newEventsFromSplit = segment.split(mySplitter);
|
|
2307
|
+
for (let i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
|
|
2308
|
+
newEvents.push(newEventsFromSplit[i]);
|
|
2327
2309
|
}
|
|
2328
2310
|
}
|
|
2329
|
-
|
|
2330
2311
|
if (newEvents.length > 0) {
|
|
2331
2312
|
// We found some intersections, so re-do the current event to
|
|
2332
2313
|
// make sure sweep line ordering is totally consistent for later
|
|
@@ -2340,218 +2321,176 @@
|
|
|
2340
2321
|
}
|
|
2341
2322
|
} else {
|
|
2342
2323
|
// event.isRight
|
|
2324
|
+
|
|
2343
2325
|
// since we're about to be removed from the sweep line, check for
|
|
2344
2326
|
// intersections between our previous and next segments
|
|
2345
2327
|
if (prevSeg && nextSeg) {
|
|
2346
|
-
|
|
2347
|
-
|
|
2328
|
+
const inter = prevSeg.getIntersection(nextSeg);
|
|
2348
2329
|
if (inter !== null) {
|
|
2349
2330
|
if (!prevSeg.isAnEndpoint(inter)) {
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
newEvents.push(_newEventsFromSplit3[_i3]);
|
|
2331
|
+
const newEventsFromSplit = this._splitSafely(prevSeg, inter);
|
|
2332
|
+
for (let i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
|
|
2333
|
+
newEvents.push(newEventsFromSplit[i]);
|
|
2354
2334
|
}
|
|
2355
2335
|
}
|
|
2356
|
-
|
|
2357
2336
|
if (!nextSeg.isAnEndpoint(inter)) {
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
newEvents.push(_newEventsFromSplit4[_i4]);
|
|
2337
|
+
const newEventsFromSplit = this._splitSafely(nextSeg, inter);
|
|
2338
|
+
for (let i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
|
|
2339
|
+
newEvents.push(newEventsFromSplit[i]);
|
|
2362
2340
|
}
|
|
2363
2341
|
}
|
|
2364
2342
|
}
|
|
2365
2343
|
}
|
|
2366
|
-
|
|
2367
2344
|
this.tree.remove(segment);
|
|
2368
2345
|
}
|
|
2369
|
-
|
|
2370
2346
|
return newEvents;
|
|
2371
2347
|
}
|
|
2348
|
+
|
|
2372
2349
|
/* Safely split a segment that is currently in the datastructures
|
|
2373
2350
|
* IE - a segment other than the one that is currently being processed. */
|
|
2374
|
-
|
|
2375
|
-
}, {
|
|
2376
|
-
key: "_splitSafely",
|
|
2377
|
-
value: function _splitSafely(seg, pt) {
|
|
2351
|
+
_splitSafely(seg, pt) {
|
|
2378
2352
|
// Rounding errors can cause changes in ordering,
|
|
2379
2353
|
// so remove afected segments and right sweep events before splitting
|
|
2380
2354
|
// removeNode() doesn't work, so have re-find the seg
|
|
2381
2355
|
// https://github.com/w8r/splay-tree/pull/5
|
|
2382
2356
|
this.tree.remove(seg);
|
|
2383
|
-
|
|
2357
|
+
const rightSE = seg.rightSE;
|
|
2384
2358
|
this.queue.remove(rightSE);
|
|
2385
|
-
|
|
2386
|
-
newEvents.push(rightSE);
|
|
2387
|
-
|
|
2388
|
-
if (seg.consumedBy === undefined) this.tree.
|
|
2359
|
+
const newEvents = seg.split(pt);
|
|
2360
|
+
newEvents.push(rightSE);
|
|
2361
|
+
// splitting can trigger consumption
|
|
2362
|
+
if (seg.consumedBy === undefined) this.tree.add(seg);
|
|
2389
2363
|
return newEvents;
|
|
2390
2364
|
}
|
|
2391
|
-
}]);
|
|
2392
|
-
|
|
2393
|
-
return SweepLine;
|
|
2394
|
-
}();
|
|
2395
|
-
|
|
2396
|
-
var POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1000000;
|
|
2397
|
-
var POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1000000;
|
|
2398
|
-
var Operation = /*#__PURE__*/function () {
|
|
2399
|
-
function Operation() {
|
|
2400
|
-
_classCallCheck(this, Operation);
|
|
2401
2365
|
}
|
|
2402
2366
|
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2367
|
+
// Limits on iterative processes to prevent infinite loops - usually caused by floating-point math round-off errors.
|
|
2368
|
+
const POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== "undefined" && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1000000;
|
|
2369
|
+
const POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== "undefined" && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1000000;
|
|
2370
|
+
class Operation {
|
|
2371
|
+
run(type, geom, moreGeoms) {
|
|
2406
2372
|
operation.type = type;
|
|
2407
2373
|
rounder.reset();
|
|
2408
|
-
/* Convert inputs to MultiPoly objects */
|
|
2409
|
-
|
|
2410
|
-
var multipolys = [new MultiPolyIn(geom, true)];
|
|
2411
2374
|
|
|
2412
|
-
|
|
2375
|
+
/* Convert inputs to MultiPoly objects */
|
|
2376
|
+
const multipolys = [new MultiPolyIn(geom, true)];
|
|
2377
|
+
for (let i = 0, iMax = moreGeoms.length; i < iMax; i++) {
|
|
2413
2378
|
multipolys.push(new MultiPolyIn(moreGeoms[i], false));
|
|
2414
2379
|
}
|
|
2415
|
-
|
|
2416
2380
|
operation.numMultiPolys = multipolys.length;
|
|
2381
|
+
|
|
2417
2382
|
/* BBox optimization for difference operation
|
|
2418
2383
|
* If the bbox of a multipolygon that's part of the clipping doesn't
|
|
2419
2384
|
* intersect the bbox of the subject at all, we can just drop that
|
|
2420
2385
|
* multiploygon. */
|
|
2421
|
-
|
|
2422
|
-
if (operation.type === 'difference') {
|
|
2386
|
+
if (operation.type === "difference") {
|
|
2423
2387
|
// in place removal
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
if (getBboxOverlap(multipolys[_i].bbox, subject.bbox) !== null) _i++;else multipolys.splice(_i, 1);
|
|
2388
|
+
const subject = multipolys[0];
|
|
2389
|
+
let i = 1;
|
|
2390
|
+
while (i < multipolys.length) {
|
|
2391
|
+
if (getBboxOverlap(multipolys[i].bbox, subject.bbox) !== null) i++;else multipolys.splice(i, 1);
|
|
2429
2392
|
}
|
|
2430
2393
|
}
|
|
2394
|
+
|
|
2431
2395
|
/* BBox optimization for intersection operation
|
|
2432
2396
|
* If we can find any pair of multipolygons whose bbox does not overlap,
|
|
2433
2397
|
* then the result will be empty. */
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
if (operation.type === 'intersection') {
|
|
2398
|
+
if (operation.type === "intersection") {
|
|
2437
2399
|
// TODO: this is O(n^2) in number of polygons. By sorting the bboxes,
|
|
2438
2400
|
// it could be optimized to O(n * ln(n))
|
|
2439
|
-
for (
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
for (var j = _i2 + 1, jMax = multipolys.length; j < jMax; j++) {
|
|
2401
|
+
for (let i = 0, iMax = multipolys.length; i < iMax; i++) {
|
|
2402
|
+
const mpA = multipolys[i];
|
|
2403
|
+
for (let j = i + 1, jMax = multipolys.length; j < jMax; j++) {
|
|
2443
2404
|
if (getBboxOverlap(mpA.bbox, multipolys[j].bbox) === null) return [];
|
|
2444
2405
|
}
|
|
2445
2406
|
}
|
|
2446
2407
|
}
|
|
2447
|
-
/* Put segment endpoints in a priority queue */
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
var queue = new Tree(SweepEvent.compare);
|
|
2451
|
-
|
|
2452
|
-
for (var _i3 = 0, _iMax2 = multipolys.length; _i3 < _iMax2; _i3++) {
|
|
2453
|
-
var sweepEvents = multipolys[_i3].getSweepEvents();
|
|
2454
|
-
|
|
2455
|
-
for (var _j = 0, _jMax = sweepEvents.length; _j < _jMax; _j++) {
|
|
2456
|
-
queue.insert(sweepEvents[_j]);
|
|
2457
2408
|
|
|
2409
|
+
/* Put segment endpoints in a priority queue */
|
|
2410
|
+
const queue = new Tree(SweepEvent.compare);
|
|
2411
|
+
for (let i = 0, iMax = multipolys.length; i < iMax; i++) {
|
|
2412
|
+
const sweepEvents = multipolys[i].getSweepEvents();
|
|
2413
|
+
for (let j = 0, jMax = sweepEvents.length; j < jMax; j++) {
|
|
2414
|
+
queue.insert(sweepEvents[j]);
|
|
2458
2415
|
if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
|
|
2459
2416
|
// prevents an infinite loop, an otherwise common manifestation of bugs
|
|
2460
|
-
throw new Error(
|
|
2417
|
+
throw new Error("Infinite loop when putting segment endpoints in a priority queue " + "(queue size too big).");
|
|
2461
2418
|
}
|
|
2462
2419
|
}
|
|
2463
2420
|
}
|
|
2464
|
-
/* Pass the sweep line over those endpoints */
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
var sweepLine = new SweepLine(queue);
|
|
2468
|
-
var prevQueueSize = queue.size;
|
|
2469
|
-
var node = queue.pop();
|
|
2470
2421
|
|
|
2422
|
+
/* Pass the sweep line over those endpoints */
|
|
2423
|
+
const sweepLine = new SweepLine(queue);
|
|
2424
|
+
let prevQueueSize = queue.size;
|
|
2425
|
+
let node = queue.pop();
|
|
2471
2426
|
while (node) {
|
|
2472
|
-
|
|
2473
|
-
|
|
2427
|
+
const evt = node.key;
|
|
2474
2428
|
if (queue.size === prevQueueSize) {
|
|
2475
2429
|
// prevents an infinite loop, an otherwise common manifestation of bugs
|
|
2476
|
-
|
|
2477
|
-
throw new Error(
|
|
2430
|
+
const seg = evt.segment;
|
|
2431
|
+
throw new Error(`Unable to pop() ${evt.isLeft ? "left" : "right"} SweepEvent ` + `[${evt.point.x}, ${evt.point.y}] from segment #${seg.id} ` + `[${seg.leftSE.point.x}, ${seg.leftSE.point.y}] -> ` + `[${seg.rightSE.point.x}, ${seg.rightSE.point.y}] from queue.`);
|
|
2478
2432
|
}
|
|
2479
|
-
|
|
2480
2433
|
if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
|
|
2481
2434
|
// prevents an infinite loop, an otherwise common manifestation of bugs
|
|
2482
|
-
throw new Error(
|
|
2435
|
+
throw new Error("Infinite loop when passing sweep line over endpoints " + "(queue size too big).");
|
|
2483
2436
|
}
|
|
2484
|
-
|
|
2485
2437
|
if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
|
|
2486
2438
|
// prevents an infinite loop, an otherwise common manifestation of bugs
|
|
2487
|
-
throw new Error(
|
|
2439
|
+
throw new Error("Infinite loop when passing sweep line over endpoints " + "(too many sweep line segments).");
|
|
2488
2440
|
}
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
var _evt = newEvents[_i4];
|
|
2494
|
-
if (_evt.consumedBy === undefined) queue.insert(_evt);
|
|
2441
|
+
const newEvents = sweepLine.process(evt);
|
|
2442
|
+
for (let i = 0, iMax = newEvents.length; i < iMax; i++) {
|
|
2443
|
+
const evt = newEvents[i];
|
|
2444
|
+
if (evt.consumedBy === undefined) queue.insert(evt);
|
|
2495
2445
|
}
|
|
2496
|
-
|
|
2497
2446
|
prevQueueSize = queue.size;
|
|
2498
2447
|
node = queue.pop();
|
|
2499
|
-
}
|
|
2500
|
-
|
|
2448
|
+
}
|
|
2501
2449
|
|
|
2450
|
+
// free some memory we don't need anymore
|
|
2502
2451
|
rounder.reset();
|
|
2503
|
-
/* Collect and compile segments we're keeping into a multipolygon */
|
|
2504
2452
|
|
|
2505
|
-
|
|
2506
|
-
|
|
2453
|
+
/* Collect and compile segments we're keeping into a multipolygon */
|
|
2454
|
+
const ringsOut = RingOut.factory(sweepLine.segments);
|
|
2455
|
+
const result = new MultiPolyOut(ringsOut);
|
|
2507
2456
|
return result.getGeom();
|
|
2508
2457
|
}
|
|
2509
|
-
}]);
|
|
2510
|
-
|
|
2511
|
-
return Operation;
|
|
2512
|
-
}(); // singleton available by import
|
|
2513
|
-
|
|
2514
|
-
var operation = new Operation();
|
|
2515
|
-
|
|
2516
|
-
var union = function union(geom) {
|
|
2517
|
-
for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
2518
|
-
moreGeoms[_key - 1] = arguments[_key];
|
|
2519
|
-
}
|
|
2520
|
-
|
|
2521
|
-
return operation.run('union', geom, moreGeoms);
|
|
2522
|
-
};
|
|
2523
|
-
|
|
2524
|
-
var intersection$1 = function intersection(geom) {
|
|
2525
|
-
for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
|
|
2526
|
-
moreGeoms[_key2 - 1] = arguments[_key2];
|
|
2527
|
-
}
|
|
2528
|
-
|
|
2529
|
-
return operation.run('intersection', geom, moreGeoms);
|
|
2530
|
-
};
|
|
2531
|
-
|
|
2532
|
-
var xor = function xor(geom) {
|
|
2533
|
-
for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
|
|
2534
|
-
moreGeoms[_key3 - 1] = arguments[_key3];
|
|
2535
2458
|
}
|
|
2536
2459
|
|
|
2537
|
-
|
|
2538
|
-
|
|
2460
|
+
// singleton available by import
|
|
2461
|
+
const operation = new Operation();
|
|
2539
2462
|
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2463
|
+
const union = function (geom) {
|
|
2464
|
+
for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
2465
|
+
moreGeoms[_key - 1] = arguments[_key];
|
|
2466
|
+
}
|
|
2467
|
+
return operation.run("union", geom, moreGeoms);
|
|
2468
|
+
};
|
|
2469
|
+
const intersection = function (geom) {
|
|
2470
|
+
for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
|
|
2471
|
+
moreGeoms[_key2 - 1] = arguments[_key2];
|
|
2472
|
+
}
|
|
2473
|
+
return operation.run("intersection", geom, moreGeoms);
|
|
2474
|
+
};
|
|
2475
|
+
const xor = function (geom) {
|
|
2476
|
+
for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
|
|
2477
|
+
moreGeoms[_key3 - 1] = arguments[_key3];
|
|
2478
|
+
}
|
|
2479
|
+
return operation.run("xor", geom, moreGeoms);
|
|
2480
|
+
};
|
|
2481
|
+
const difference = function (subjectGeom) {
|
|
2482
|
+
for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
|
|
2483
|
+
clippingGeoms[_key4 - 1] = arguments[_key4];
|
|
2484
|
+
}
|
|
2485
|
+
return operation.run("difference", subjectGeom, clippingGeoms);
|
|
2486
|
+
};
|
|
2487
|
+
var index = {
|
|
2488
|
+
union: union,
|
|
2489
|
+
intersection: intersection,
|
|
2490
|
+
xor: xor,
|
|
2491
|
+
difference: difference
|
|
2492
|
+
};
|
|
2554
2493
|
|
|
2555
|
-
|
|
2494
|
+
return index;
|
|
2556
2495
|
|
|
2557
|
-
}))
|
|
2496
|
+
}));
|