@dra2020/baseclient 1.0.13 → 1.0.14

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.
Files changed (185) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/all/all.d.ts +36 -0
  4. package/dist/all/allclient.d.ts +18 -0
  5. package/dist/base.js +33010 -0
  6. package/dist/base.js.map +1 -0
  7. package/dist/baseclient.js +8991 -0
  8. package/dist/baseclient.js.map +1 -0
  9. package/dist/context/all.d.ts +1 -0
  10. package/dist/context/context.d.ts +13 -0
  11. package/dist/dbabstract/all.d.ts +1 -0
  12. package/dist/dbabstract/db.d.ts +83 -0
  13. package/dist/dbdynamo/all.d.ts +1 -0
  14. package/dist/dbdynamo/dbdynamo.d.ts +190 -0
  15. package/dist/filterexpr/all.d.ts +1 -0
  16. package/dist/filterexpr/filterexpr.d.ts +64 -0
  17. package/dist/fsm/all.d.ts +1 -0
  18. package/dist/fsm/fsm.d.ts +118 -0
  19. package/dist/fsmfile/all.d.ts +1 -0
  20. package/dist/fsmfile/fsmfile.d.ts +47 -0
  21. package/dist/jsonstream/all.d.ts +1 -0
  22. package/dist/jsonstream/jsonstream.d.ts +130 -0
  23. package/dist/lambda/all.d.ts +1 -0
  24. package/dist/lambda/env.d.ts +10 -0
  25. package/dist/lambda/lambda.d.ts +18 -0
  26. package/dist/logabstract/all.d.ts +1 -0
  27. package/dist/logabstract/log.d.ts +26 -0
  28. package/dist/logclient/all.d.ts +1 -0
  29. package/dist/logclient/log.d.ts +6 -0
  30. package/dist/logserver/all.d.ts +5 -0
  31. package/dist/logserver/log.d.ts +11 -0
  32. package/dist/logserver/logaccum.d.ts +154 -0
  33. package/dist/logserver/logblob.d.ts +24 -0
  34. package/dist/logserver/logconcat.d.ts +55 -0
  35. package/dist/logserver/logkey.d.ts +28 -0
  36. package/dist/memsqs/all.d.ts +4 -0
  37. package/dist/memsqs/client.d.ts +13 -0
  38. package/dist/memsqs/loopback.d.ts +11 -0
  39. package/dist/memsqs/orderedlist.d.ts +19 -0
  40. package/dist/memsqs/queue.d.ts +84 -0
  41. package/dist/memsqs/server.d.ts +37 -0
  42. package/dist/ot-editutil/all.d.ts +2 -0
  43. package/dist/ot-editutil/oteditutil.d.ts +14 -0
  44. package/dist/ot-editutil/otmaputil.d.ts +21 -0
  45. package/dist/ot-js/all.d.ts +9 -0
  46. package/dist/ot-js/otarray.d.ts +111 -0
  47. package/dist/ot-js/otclientengine.d.ts +38 -0
  48. package/dist/ot-js/otcomposite.d.ts +37 -0
  49. package/dist/ot-js/otcounter.d.ts +17 -0
  50. package/dist/ot-js/otengine.d.ts +22 -0
  51. package/dist/ot-js/otmap.d.ts +19 -0
  52. package/dist/ot-js/otserverengine.d.ts +38 -0
  53. package/dist/ot-js/otsession.d.ts +111 -0
  54. package/dist/ot-js/ottypes.d.ts +29 -0
  55. package/dist/poly/all.d.ts +15 -0
  56. package/dist/poly/blend.d.ts +1 -0
  57. package/dist/poly/boundbox.d.ts +16 -0
  58. package/dist/poly/cartesian.d.ts +5 -0
  59. package/dist/poly/graham-scan.d.ts +8 -0
  60. package/dist/poly/hash.d.ts +1 -0
  61. package/dist/poly/matrix.d.ts +24 -0
  62. package/dist/poly/minbound.d.ts +1 -0
  63. package/dist/poly/poly.d.ts +52 -0
  64. package/dist/poly/polybin.d.ts +5 -0
  65. package/dist/poly/polylabel.d.ts +7 -0
  66. package/dist/poly/polypack.d.ts +30 -0
  67. package/dist/poly/polyround.d.ts +1 -0
  68. package/dist/poly/polysimplify.d.ts +1 -0
  69. package/dist/poly/quad.d.ts +48 -0
  70. package/dist/poly/selfintersect.d.ts +1 -0
  71. package/dist/poly/shamos.d.ts +1 -0
  72. package/dist/poly/simplify.d.ts +2 -0
  73. package/dist/poly/topo.d.ts +46 -0
  74. package/dist/poly/union.d.ts +48 -0
  75. package/dist/storage/all.d.ts +4 -0
  76. package/dist/storage/datablob.d.ts +9 -0
  77. package/dist/storage/env.d.ts +10 -0
  78. package/dist/storage/splitsblob.d.ts +13 -0
  79. package/dist/storage/storage.d.ts +166 -0
  80. package/dist/storages3/all.d.ts +1 -0
  81. package/dist/storages3/s3.d.ts +62 -0
  82. package/dist/util/all.d.ts +5 -0
  83. package/dist/util/bintrie.d.ts +93 -0
  84. package/dist/util/countedhash.d.ts +19 -0
  85. package/dist/util/gradient.d.ts +15 -0
  86. package/dist/util/indexedarray.d.ts +15 -0
  87. package/dist/util/util.d.ts +68 -0
  88. package/docs/context.md +2 -0
  89. package/docs/dbabstract.md +2 -0
  90. package/docs/dbdynamo.md +2 -0
  91. package/docs/fsm.md +243 -0
  92. package/docs/fsmfile.md +2 -0
  93. package/docs/jsonstream.md +44 -0
  94. package/docs/lambda.md +2 -0
  95. package/docs/logabstract.md +2 -0
  96. package/docs/logclient.md +2 -0
  97. package/docs/logserver.md +2 -0
  98. package/docs/ot-editutil.md +2 -0
  99. package/docs/ot-js.md +95 -0
  100. package/docs/poly.md +103 -0
  101. package/docs/storage.md +2 -0
  102. package/docs/storages3.md +2 -0
  103. package/docs/util.md +2 -0
  104. package/lib/all/all.ts +41 -0
  105. package/lib/all/allclient.ts +19 -0
  106. package/lib/context/all.ts +1 -0
  107. package/lib/context/context.ts +82 -0
  108. package/lib/dbabstract/all.ts +1 -0
  109. package/lib/dbabstract/db.ts +246 -0
  110. package/lib/dbdynamo/all.ts +1 -0
  111. package/lib/dbdynamo/dbdynamo.ts +1551 -0
  112. package/lib/filterexpr/all.ts +1 -0
  113. package/lib/filterexpr/filterexpr.ts +625 -0
  114. package/lib/fsm/all.ts +1 -0
  115. package/lib/fsm/fsm.ts +549 -0
  116. package/lib/fsmfile/all.ts +1 -0
  117. package/lib/fsmfile/fsmfile.ts +236 -0
  118. package/lib/jsonstream/all.ts +1 -0
  119. package/lib/jsonstream/jsonstream.ts +940 -0
  120. package/lib/lambda/all.ts +1 -0
  121. package/lib/lambda/env.ts +13 -0
  122. package/lib/lambda/lambda.ts +120 -0
  123. package/lib/logabstract/all.ts +1 -0
  124. package/lib/logabstract/log.ts +55 -0
  125. package/lib/logclient/all.ts +1 -0
  126. package/lib/logclient/log.ts +105 -0
  127. package/lib/logserver/all.ts +5 -0
  128. package/lib/logserver/log.ts +565 -0
  129. package/lib/logserver/logaccum.ts +1445 -0
  130. package/lib/logserver/logblob.ts +84 -0
  131. package/lib/logserver/logconcat.ts +313 -0
  132. package/lib/logserver/logkey.ts +125 -0
  133. package/lib/memsqs/all.ts +4 -0
  134. package/lib/memsqs/client.ts +268 -0
  135. package/lib/memsqs/loopback.ts +64 -0
  136. package/lib/memsqs/orderedlist.ts +74 -0
  137. package/lib/memsqs/queue.ts +395 -0
  138. package/lib/memsqs/server.ts +262 -0
  139. package/lib/ot-editutil/all.ts +2 -0
  140. package/lib/ot-editutil/oteditutil.ts +180 -0
  141. package/lib/ot-editutil/otmaputil.ts +209 -0
  142. package/lib/ot-js/all.ts +9 -0
  143. package/lib/ot-js/otarray.ts +1168 -0
  144. package/lib/ot-js/otclientengine.ts +327 -0
  145. package/lib/ot-js/otcomposite.ts +247 -0
  146. package/lib/ot-js/otcounter.ts +145 -0
  147. package/lib/ot-js/otengine.ts +71 -0
  148. package/lib/ot-js/otmap.ts +144 -0
  149. package/lib/ot-js/otserverengine.ts +329 -0
  150. package/lib/ot-js/otsession.ts +199 -0
  151. package/lib/ot-js/ottypes.ts +98 -0
  152. package/lib/poly/all.ts +15 -0
  153. package/lib/poly/blend.ts +27 -0
  154. package/lib/poly/boundbox.ts +102 -0
  155. package/lib/poly/cartesian.ts +130 -0
  156. package/lib/poly/graham-scan.ts +401 -0
  157. package/lib/poly/hash.ts +15 -0
  158. package/lib/poly/matrix.ts +309 -0
  159. package/lib/poly/minbound.ts +211 -0
  160. package/lib/poly/poly.ts +767 -0
  161. package/lib/poly/polybin.ts +218 -0
  162. package/lib/poly/polylabel.ts +204 -0
  163. package/lib/poly/polypack.ts +458 -0
  164. package/lib/poly/polyround.ts +30 -0
  165. package/lib/poly/polysimplify.ts +24 -0
  166. package/lib/poly/quad.ts +272 -0
  167. package/lib/poly/selfintersect.ts +87 -0
  168. package/lib/poly/shamos.ts +297 -0
  169. package/lib/poly/simplify.ts +119 -0
  170. package/lib/poly/topo.ts +525 -0
  171. package/lib/poly/union.ts +371 -0
  172. package/lib/storage/all.ts +4 -0
  173. package/lib/storage/datablob.ts +36 -0
  174. package/lib/storage/env.ts +14 -0
  175. package/lib/storage/splitsblob.ts +63 -0
  176. package/lib/storage/storage.ts +604 -0
  177. package/lib/storages3/all.ts +1 -0
  178. package/lib/storages3/s3.ts +576 -0
  179. package/lib/util/all.ts +5 -0
  180. package/lib/util/bintrie.ts +603 -0
  181. package/lib/util/countedhash.ts +83 -0
  182. package/lib/util/gradient.ts +108 -0
  183. package/lib/util/indexedarray.ts +80 -0
  184. package/lib/util/util.ts +695 -0
  185. package/package.json +8 -8
@@ -0,0 +1,272 @@
1
+ // Public libraries
2
+ import * as PC from 'polygon-clipping';
3
+
4
+ // Shared libraries
5
+ import * as Util from '../util/all';
6
+ import * as FSM from '../fsm/all';
7
+
8
+ // Local libraries
9
+ import * as Poly from './poly';
10
+ import * as PP from './polypack';
11
+ import * as BB from './boundbox';
12
+ import * as PR from './polyround';
13
+
14
+ let _union: any = undefined;
15
+ let anyPC: any = PC;
16
+ if (anyPC.union) _union = anyPC.union;
17
+ if (anyPC.default && anyPC.default.union) _union = anyPC.default.union;
18
+ if (_union === undefined) throw 'Unable to load union function from polygon-clipping';
19
+
20
+ export interface WrappedPoly { box: BB.BoundBox, p: any };
21
+
22
+ export interface WorkDone
23
+ {
24
+ nUnion: number,
25
+ nDifference: number,
26
+ ms: number,
27
+ }
28
+
29
+ function featureCoords(feature: any): any
30
+ {
31
+ /*
32
+ if (feature.geometry !== undefined)
33
+ {
34
+ if (feature.geometry.packed !== undefined)
35
+ return PP.polyUnpack(feature.geometry.packed);
36
+ else
37
+ return feature.geometry.coordinates;
38
+ }
39
+ else if (feature.offset !== undefined)
40
+ return PP.polyUnpack(feature);
41
+ else
42
+ return feature;
43
+ */
44
+ if (feature.geometry !== undefined)
45
+ {
46
+ if (feature.geometry.packed !== undefined)
47
+ return feature.geometry.packed;
48
+ else
49
+ return feature.geometry.coordinates;
50
+ }
51
+ else
52
+ return feature;
53
+ }
54
+
55
+ // This function takes an array of packed or unpacked polygon/multipolygons and
56
+ // returns an unpacked polygon/multipolygon coordinate array. Returns null if
57
+ // handed an empty array.
58
+
59
+ export function unionPolys(polys: any[]): any
60
+ {
61
+ if (polys == null) return null;
62
+
63
+ let cleanPolys: any[] = polys.filter((f: any) => f != null);
64
+ if (cleanPolys.length == 0) return null;
65
+ if (cleanPolys.length == 1) return PP.polyUnpack(cleanPolys[0]);
66
+ cleanPolys = cleanPolys.map( (f: any) => PP.polyUnpack(f) );
67
+
68
+ let poly: any = cleanPolys.pop();
69
+ return PR.polyRound(_union(poly, ...cleanPolys));
70
+ }
71
+
72
+ export interface QuadOptions
73
+ {
74
+ maxLeafCount?: number;
75
+ maxDepth?: number;
76
+ tickStep?: number;
77
+ }
78
+ export const DefaultQuadOptions: QuadOptions = { maxLeafCount: 20, maxDepth: 20, tickStep: 1 };
79
+
80
+ export interface TickCounter { ticks: number };
81
+
82
+ // Use geo orientation for t/b (that is, t > b)
83
+ class QuadLevel
84
+ {
85
+ options: QuadOptions;
86
+ level: number;
87
+ children: QuadLevel[];
88
+ features: any[];
89
+ box: BB.BoundBox;
90
+ asyncUnion: any;
91
+
92
+ constructor(options: QuadOptions, level: number, box: BB.BoundBox, features: WrappedPoly[])
93
+ {
94
+ this.options = options;
95
+ this.level = level;
96
+ this.box = box;
97
+ if (features.length <= options.maxLeafCount || this.level >= options.maxDepth)
98
+ {
99
+ if (this.level >= options.maxDepth)
100
+ throw `QuadTree: maximum depth of ${options.maxDepth} exceeded`;
101
+ this.features = features.map((wp: WrappedPoly) => wp.p);
102
+ this.children = null;
103
+ }
104
+ else
105
+ {
106
+ this.features = null;
107
+ let cx = BB.boundboxCX(box);
108
+ let cy = BB.boundboxCY(box);
109
+
110
+ let tl: BB.BoundBox = { left: box.left, top: box.top, right: cx, bottom: cy };
111
+ let tr: BB.BoundBox = { left: cx, top: box.top, right: box.right, bottom: cy };
112
+ let bl: BB.BoundBox = { left: box.left, top: cy, right: cx, bottom: box.bottom };
113
+ let br: BB.BoundBox = { left: cx, top: cy, right: box.right, bottom: box.bottom };
114
+ let tlFeatures = [];
115
+ let trFeatures = [];
116
+ let blFeatures = [];
117
+ let brFeatures = [];
118
+
119
+ for (let i: number = 0; i < features.length; i++)
120
+ {
121
+ let f = features[i];
122
+
123
+ if (this.featureInBox(tl, f))
124
+ tlFeatures.push(f);
125
+ else if (this.featureInBox(tr, f))
126
+ trFeatures.push(f);
127
+ else if (this.featureInBox(bl, f))
128
+ blFeatures.push(f);
129
+ else if (this.featureInBox(br, f))
130
+ brFeatures.push(f);
131
+ }
132
+ this.children = [];
133
+ this.children.push(new QuadLevel(options, level+1, tl, tlFeatures));
134
+ this.children.push(new QuadLevel(options, level+1, tr, trFeatures));
135
+ this.children.push(new QuadLevel(options, level+1, bl, blFeatures));
136
+ this.children.push(new QuadLevel(options, level+1, br, brFeatures));
137
+ this.asyncUnion = null;
138
+ }
139
+ }
140
+
141
+ private featureInBox(box: BB.BoundBox, f: WrappedPoly): boolean
142
+ {
143
+ return BB.boundboxIntersects(box, f.box);
144
+ }
145
+
146
+ union(): any
147
+ {
148
+ if (this.asyncUnion == null)
149
+ {
150
+ if (this.children == null)
151
+ this.asyncUnion = unionPolys(this.features);
152
+ else
153
+ this.asyncUnion = unionPolys(this.children.map((q: QuadLevel) => q.union()));
154
+ }
155
+ return this.asyncUnion;
156
+ }
157
+
158
+ get isempty(): boolean
159
+ {
160
+ return this.children == null && this.features.length == 0;
161
+ }
162
+
163
+ tickUnion(tickCounter: TickCounter): void
164
+ {
165
+ if (!this.isempty && this.asyncUnion == null)
166
+ {
167
+ if (this.children == null)
168
+ {
169
+ if (tickCounter.ticks != 0)
170
+ {
171
+ this.union();
172
+ tickCounter.ticks--;
173
+ }
174
+ }
175
+ else
176
+ {
177
+ for (let i: number = 0; i < this.children.length && tickCounter.ticks != 0; i++)
178
+ this.children[i].tickUnion(tickCounter);
179
+
180
+ // If tickCounter hasn't gone to zero, we fully computed children, go ahead and compute union here.
181
+ if (tickCounter.ticks != 0)
182
+ {
183
+ this.union();
184
+ tickCounter.ticks--;
185
+ }
186
+ }
187
+ }
188
+ }
189
+ }
190
+
191
+ export class FsmQuadTree extends FSM.Fsm
192
+ {
193
+ quad: QuadLevel;
194
+ asyncUnion: any;
195
+ isempty: boolean;
196
+ options: Poly.TickOptions;
197
+ work: WorkDone;
198
+
199
+ constructor(env: FSM.FsmEnvironment, options?: Poly.TickOptions, col?: any)
200
+ {
201
+ super(env);
202
+ this.options = Util.shallowAssignImmutable(Poly.DefaultTickOptions, options);
203
+ this.work = { nUnion: 0, nDifference: 0, ms: 0 };
204
+ this.initialize(col);
205
+ }
206
+
207
+ initialize(col: any): void
208
+ {
209
+ this.quad = null;
210
+ this.asyncUnion = undefined;
211
+ this.isempty = true;
212
+
213
+ if (col != null)
214
+ {
215
+ let features: any = col.features ? col.features : col;
216
+ this.work.nUnion = features.length;
217
+ this.isempty = features.length == 0;
218
+
219
+ // Compute BoundBox for each feature
220
+ let wrapped: WrappedPoly[] = features.map((f: any) => { return { box: BB.boundbox(f), p: featureCoords(f) } });
221
+
222
+ let box = BB.boundbox(col);
223
+ this.quad = new QuadLevel(this.options, 0, box, wrapped);
224
+ }
225
+
226
+ this.setState(this.isempty ? FSM.FSM_DONE : FSM.FSM_STARTING);
227
+ }
228
+
229
+ cancel(): any
230
+ {
231
+ this.quad = null;
232
+ this.asyncUnion = undefined;
233
+ this.isempty = true;
234
+ this.setState(FSM.FSM_DONE);
235
+ }
236
+
237
+ get result(): any
238
+ {
239
+ if (this.asyncUnion === undefined && this.quad)
240
+ this.asyncUnion = this.quad.union();
241
+ return this.asyncUnion;
242
+ }
243
+
244
+ tick(): void
245
+ {
246
+ if (this.ready)
247
+ {
248
+ switch (this.state)
249
+ {
250
+ case FSM.FSM_STARTING:
251
+ this.setState(FSM.FSM_PENDING);
252
+ break;
253
+
254
+ case FSM.FSM_PENDING:
255
+ let tickCounter: TickCounter = { ticks: this.options.tickStep }
256
+ let elapsed = new Util.Elapsed();
257
+ if (!this.isempty && this.asyncUnion === undefined)
258
+ {
259
+ this.quad.tickUnion(tickCounter);
260
+ if (tickCounter.ticks != 0)
261
+ this.result;
262
+ }
263
+ this.work.ms += elapsed.ms();
264
+ if (this.asyncUnion !== undefined)
265
+ this.setState(FSM.FSM_DONE);
266
+ else
267
+ this.setState(FSM.FSM_PENDING);
268
+ break;
269
+ }
270
+ }
271
+ }
272
+ }
@@ -0,0 +1,87 @@
1
+ import * as Util from '../util/all';
2
+
3
+ import * as P from './poly';
4
+ import * as PP from './polypack';
5
+
6
+ // Given three colinear points p, q, r, the function checks if
7
+ // point q lies on line segment 'pr'
8
+ function onSegment(px: number, py: number, qx: number, qy: number, rx: number, ry: number): boolean
9
+ {
10
+ if (qx <= Math.max(px, rx) && qx >= Math.min(px, rx) &&
11
+ qy <= Math.max(py, ry) && qy >= Math.min(py, ry))
12
+ return true;
13
+
14
+ return false;
15
+ }
16
+
17
+ // To find orientation of ordered triplet (p, q, r).
18
+ // The function returns following values
19
+ // 0 --> p, q and r are colinear
20
+ // 1 --> Clockwise
21
+ // 2 --> Counterclockwise
22
+ function orientation(px: number, py: number, qx: number, qy: number, rx: number, ry: number): number
23
+ {
24
+ // See https://www.geeksforgeeks.org/orientation-3-ordered-points/
25
+ // for details of below formula.
26
+ let val: number = (qy - py) * (rx - qx) -
27
+ (qx - px) * (ry - qy);
28
+
29
+ if (val == 0) return 0; // colinear
30
+
31
+ return (val > 0)? 1: 2; // clock or counterclock wise
32
+ }
33
+
34
+ // The main function that returns true if line segment 'p1q1'
35
+ // and 'p2q2' intersect.
36
+ function doIntersect(p1x: number, p1y: number, q1x: number, q1y: number, p2x: number, p2y: number, q2x: number, q2y: number): boolean
37
+ {
38
+ // closing segment is not intersection
39
+ if (p1x - q2x + p1y - q2y === 0) return false;
40
+
41
+ // Find the four orientations needed for general and
42
+ // special cases
43
+ let o1 = orientation(p1x, p1y, q1x, q1y, p2x, p2y);
44
+ let o2 = orientation(p1x, p1y, q1x, q1y, q2x, q2y);
45
+ let o3 = orientation(p2x, p2y, q2x, q2y, p1x, p1y);
46
+ let o4 = orientation(p2x, p2y, q2x, q2y, q1x, q1y);
47
+
48
+ // General case
49
+ if (o1 != o2 && o3 != o4)
50
+ return true;
51
+
52
+ // Special Cases
53
+ // p1, q1 and p2 are colinear and p2 lies on segment p1q1
54
+ if (o1 == 0 && onSegment(p1x, p1y, p2x, p2y, q1x, q1y)) return true;
55
+
56
+ // p1, q1 and q2 are colinear and q2 lies on segment p1q1
57
+ if (o2 == 0 && onSegment(p1x, p1y, q2x, q2y, q1x, q1y)) return true;
58
+
59
+ // p2, q2 and p1 are colinear and p1 lies on segment p2q2
60
+ if (o3 == 0 && onSegment(p2x, p2y, p1x, p1y, q2x, q2y)) return true;
61
+
62
+ // p2, q2 and q1 are colinear and q1 lies on segment p2q2
63
+ if (o4 == 0 && onSegment(p2x, p2y, q1x, q1y, q2x, q2y)) return true;
64
+
65
+ return false; // Doesn't fall in any of the above cases
66
+ }
67
+
68
+ // no extra storage, but brute-force O(N^2) in number of segments. See selfIntersectFast for better approach.
69
+ export function selfIntersect(poly: any): boolean
70
+ {
71
+ let pp = P.polyNormalize(poly);
72
+ if (pp == null) return false;
73
+ let bIntersect = false;
74
+ PP.polyPackEachRing(pp, (b: Float64Array, iPoly: number, iRing: number, iOffset: number, nPoints: number) => {
75
+ if (bIntersect) return;
76
+ let iEnd = iOffset + ((nPoints-2) * 2);
77
+ let jEnd = iOffset + ((nPoints-1) * 2);
78
+ for (let i = iOffset; i < iEnd; i += 2)
79
+ for (let j = i + 4; j < jEnd; j += 2)
80
+ if (doIntersect(b[i], b[i+1], b[i+2], b[i+3], b[j], b[j+1], b[j+2], b[j+3]))
81
+ {
82
+ bIntersect = true;
83
+ return;
84
+ }
85
+ });
86
+ return bIntersect;
87
+ }
@@ -0,0 +1,297 @@
1
+ import * as Util from '../util/all';
2
+
3
+ import * as P from './poly';
4
+ import * as PP from './polypack';
5
+
6
+ // Adapted from rowanwins/shamos-hoey
7
+ /*
8
+ MIT License
9
+
10
+ Copyright (c) 2019 Rowan Winsemius
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+ */
30
+
31
+ // External libraries
32
+ import TinyQueue from 'tinyqueue'
33
+ import SplayTree from 'splaytree'
34
+
35
+ class Event
36
+ {
37
+ x: number;
38
+ y: number;
39
+ otherEvent: Event;
40
+ isLeftEndpoint: boolean | null;
41
+ segment: Segment;
42
+
43
+ constructor(x: number, y: number)
44
+ {
45
+ this.x = x
46
+ this.y = y
47
+
48
+ this.otherEvent = null
49
+ this.isLeftEndpoint = null
50
+ this.segment = null
51
+ }
52
+
53
+ isOtherEndOfSegment(eventToCheck: Event): boolean
54
+ {
55
+ return this === eventToCheck.otherEvent
56
+ }
57
+
58
+ isSamePoint(eventToCheck: Event): boolean
59
+ {
60
+ return this.x === eventToCheck.x && this.y === eventToCheck.y
61
+ }
62
+
63
+ isBelow(p: Event): boolean
64
+ {
65
+ return this.isLeftEndpoint ?
66
+ signedArea(this, this.otherEvent, p) > 0 :
67
+ signedArea(this.otherEvent, p, this) > 0
68
+ }
69
+
70
+ isAbove(p: Event): boolean
71
+ {
72
+ return !this.isBelow(p)
73
+ }
74
+ }
75
+
76
+ class EventQueue
77
+ {
78
+ tiny: TinyQueue<Event>;
79
+
80
+ constructor()
81
+ {
82
+ this.tiny = new TinyQueue<Event>([], checkWhichEventIsLeft)
83
+ }
84
+
85
+ push(event: Event): void { this.tiny.push(event) }
86
+ pop(): Event { return this.tiny.pop() as Event }
87
+ get length(): number { return this.tiny.length }
88
+ }
89
+
90
+ class Segment
91
+ {
92
+ leftSweepEvent: Event;
93
+ rightSweepEvent: Event;
94
+ segmentAbove: Segment;
95
+ segmentBelow: Segment;
96
+
97
+ constructor(event: Event)
98
+ {
99
+ this.leftSweepEvent = event
100
+ this.rightSweepEvent = event.otherEvent
101
+ this.segmentAbove = null
102
+ this.segmentBelow = null
103
+
104
+ event.segment = this
105
+ event.otherEvent.segment = this
106
+ }
107
+ }
108
+
109
+ class SweepLine
110
+ {
111
+ tree: SplayTree<Segment>;
112
+
113
+ constructor()
114
+ {
115
+ this.tree = new SplayTree<Segment>(compareSegments)
116
+ }
117
+
118
+ addSegment(event: Event): Segment
119
+ {
120
+ const seg = new Segment(event)
121
+ const node: any = this.tree.insert(seg)
122
+ const nextNode: any = this.tree.next(node)
123
+ const prevNode: any = this.tree.prev(node)
124
+ if (nextNode !== null)
125
+ {
126
+ seg.segmentAbove = nextNode.key
127
+ seg.segmentAbove.segmentBelow = seg
128
+ }
129
+ if (prevNode !== null)
130
+ {
131
+ seg.segmentBelow = prevNode.key
132
+ seg.segmentBelow.segmentAbove = seg
133
+ }
134
+ return node.key
135
+ }
136
+
137
+ findSegment(seg: Segment): Segment
138
+ {
139
+ const node: any = this.tree.find(seg)
140
+ if (node === null) return null
141
+ return node.key
142
+ }
143
+
144
+ removeSegmentFromSweepline(seg: Segment): void
145
+ {
146
+ const node: any = this.tree.find(seg)
147
+ if (node === null) return
148
+ const nextNode: any = this.tree.next(node)
149
+ const prevNode: any = this.tree.prev(node)
150
+
151
+ if (nextNode !== null)
152
+ {
153
+ const nextSeg = nextNode.key
154
+ nextSeg.segmentBelow = seg.segmentBelow
155
+ }
156
+ if (prevNode !== null)
157
+ {
158
+ const prevSeg = prevNode.key
159
+ prevSeg.segmentAbove = seg.segmentAbove
160
+ }
161
+ this.tree.remove(seg)
162
+ }
163
+
164
+ testIntersect(seg1: Segment, seg2: Segment): boolean
165
+ {
166
+ if (seg1 === null || seg2 === null) return false
167
+
168
+ if (seg1.rightSweepEvent.isSamePoint(seg2.leftSweepEvent) ||
169
+ seg1.rightSweepEvent.isSamePoint(seg2.rightSweepEvent) ||
170
+ seg1.leftSweepEvent.isSamePoint(seg2.leftSweepEvent) ||
171
+ seg1.leftSweepEvent.isSamePoint(seg2.rightSweepEvent)) return false
172
+
173
+ const x1 = seg1.leftSweepEvent.x
174
+ const y1 = seg1.leftSweepEvent.y
175
+ const x2 = seg1.rightSweepEvent.x
176
+ const y2 = seg1.rightSweepEvent.y
177
+ const x3 = seg2.leftSweepEvent.x
178
+ const y3 = seg2.leftSweepEvent.y
179
+ const x4 = seg2.rightSweepEvent.x
180
+ const y4 = seg2.rightSweepEvent.y
181
+
182
+ const denom = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1))
183
+ const numeA = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3))
184
+ const numeB = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3))
185
+
186
+ if (denom === 0)
187
+ {
188
+ if (numeA === 0 && numeB === 0) return false
189
+ return false
190
+ }
191
+
192
+ const uA = numeA / denom
193
+ const uB = numeB / denom
194
+
195
+ return (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1)
196
+ }
197
+ }
198
+
199
+ function checkWhichEventIsLeft(e1: Event, e2: Event): number
200
+ {
201
+ if (e1.x > e2.x) return 1
202
+ if (e1.x < e2.x) return -1
203
+
204
+ if (e1.y !== e2.y) return e1.y > e2.y ? 1 : -1
205
+ return 1
206
+ }
207
+
208
+ function compareSegments(seg1: Segment, seg2: Segment): number
209
+ {
210
+ if (seg1 === seg2) return 0
211
+
212
+ if (signedArea(seg1.leftSweepEvent, seg1.rightSweepEvent, seg2.leftSweepEvent) !== 0 ||
213
+ signedArea(seg1.leftSweepEvent, seg1.rightSweepEvent, seg2.rightSweepEvent) !== 0)
214
+ {
215
+ // If the segments share their left endpoints
216
+ // use the right endpoint to sort
217
+ if (seg1.leftSweepEvent.isSamePoint(seg2.leftSweepEvent)) return seg1.leftSweepEvent.isBelow(seg2.rightSweepEvent) ? -1 : 1
218
+
219
+ // If the segments have different left endpoints
220
+ // use the left endpoint to sort
221
+ if (seg1.leftSweepEvent.x === seg2.leftSweepEvent.x) return seg1.leftSweepEvent.y < seg2.leftSweepEvent.y ? -1 : 1
222
+
223
+ // If the line segment associated to e1 been inserted
224
+ // into S after the line segment associated to e2 ?
225
+ if (checkWhichEventIsLeft(seg1.leftSweepEvent, seg2.leftSweepEvent) === 1) return seg2.leftSweepEvent.isAbove(seg1.leftSweepEvent) ? -1 : 1
226
+
227
+ // The line segment associated to e2 has been inserted
228
+ // into S after the line segment associated to e1
229
+ return seg1.leftSweepEvent.isBelow(seg2.leftSweepEvent) ? -1 : 1
230
+ }
231
+
232
+ return checkWhichEventIsLeft(seg1.leftSweepEvent, seg2.leftSweepEvent) === 1 ? 1 : -1
233
+ }
234
+
235
+ function runCheck(eventQueue: EventQueue): boolean
236
+ {
237
+ const sweepLine = new SweepLine()
238
+ let currentSegment = null
239
+ while (eventQueue.length)
240
+ {
241
+ const event = eventQueue.pop()
242
+
243
+ if (event.isLeftEndpoint)
244
+ {
245
+ currentSegment = sweepLine.addSegment(event)
246
+ if (sweepLine.testIntersect(currentSegment, currentSegment.segmentAbove)) return true
247
+ if (sweepLine.testIntersect(currentSegment, currentSegment.segmentBelow)) return true
248
+ }
249
+ else
250
+ {
251
+ if (!event.segment) continue
252
+ if (sweepLine.testIntersect(event.segment.segmentAbove, event.segment.segmentBelow)) return true
253
+ sweepLine.removeSegmentFromSweepline(event.segment)
254
+ }
255
+ }
256
+ return false
257
+ }
258
+
259
+ function signedArea(p0: any, p1: any, p2: any): number
260
+ {
261
+ return (p0.x - p2.x) * (p1.y - p2.y) - (p1.x - p2.x) * (p0.y - p2.y)
262
+ }
263
+
264
+ export function selfIntersectFast(poly: any): boolean
265
+ {
266
+ let pp = P.polyNormalize(poly);
267
+ if (pp == null) return false;
268
+
269
+ // Fill queue
270
+ let eventQueue = new EventQueue();
271
+ PP.polyPackEachRing(pp, (b: Float64Array, iPoly: number, iRing: number, iOffset: number, nPoints: number) => {
272
+ let iEnd = iOffset + (nPoints - 1) * 2; // iterating over segments so right before last point
273
+ for (; iOffset < iEnd; iOffset += 2)
274
+ {
275
+ const e1 = new Event(b[iOffset], b[iOffset+1]);
276
+ const e2 = new Event(b[iOffset+2], b[iOffset+3]);
277
+
278
+ e1.otherEvent = e2
279
+ e2.otherEvent = e1
280
+
281
+ if (checkWhichEventIsLeft(e1, e2) > 0)
282
+ {
283
+ e2.isLeftEndpoint = true
284
+ e1.isLeftEndpoint = false
285
+ }
286
+ else
287
+ {
288
+ e1.isLeftEndpoint = true
289
+ e2.isLeftEndpoint = false
290
+ }
291
+ eventQueue.push(e1)
292
+ eventQueue.push(e2)
293
+ }
294
+ });
295
+
296
+ return runCheck(eventQueue)
297
+ }