@dra2020/baseclient 1.0.13 → 1.0.16
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/LICENSE +21 -0
- package/README.md +26 -0
- package/dist/all/all.d.ts +20 -0
- package/dist/baseclient.js +10121 -0
- package/dist/baseclient.js.map +1 -0
- package/dist/context/all.d.ts +1 -0
- package/dist/context/context.d.ts +13 -0
- package/dist/filterexpr/all.d.ts +1 -0
- package/dist/filterexpr/filterexpr.d.ts +67 -0
- package/dist/fsm/all.d.ts +1 -0
- package/dist/fsm/fsm.d.ts +119 -0
- package/dist/geo/all.d.ts +2 -0
- package/dist/geo/geo.d.ts +67 -0
- package/dist/geo/vfeature.d.ts +4 -0
- package/dist/logabstract/all.d.ts +1 -0
- package/dist/logabstract/log.d.ts +26 -0
- package/dist/logclient/all.d.ts +1 -0
- package/dist/logclient/log.d.ts +6 -0
- package/dist/ot-editutil/all.d.ts +2 -0
- package/dist/ot-editutil/oteditutil.d.ts +14 -0
- package/dist/ot-editutil/otmaputil.d.ts +21 -0
- package/dist/ot-js/all.d.ts +9 -0
- package/dist/ot-js/otarray.d.ts +111 -0
- package/dist/ot-js/otclientengine.d.ts +38 -0
- package/dist/ot-js/otcomposite.d.ts +37 -0
- package/dist/ot-js/otcounter.d.ts +17 -0
- package/dist/ot-js/otengine.d.ts +22 -0
- package/dist/ot-js/otmap.d.ts +19 -0
- package/dist/ot-js/otserverengine.d.ts +38 -0
- package/dist/ot-js/otsession.d.ts +114 -0
- package/dist/ot-js/ottypes.d.ts +29 -0
- package/dist/poly/all.d.ts +15 -0
- package/dist/poly/blend.d.ts +1 -0
- package/dist/poly/boundbox.d.ts +16 -0
- package/dist/poly/cartesian.d.ts +5 -0
- package/dist/poly/graham-scan.d.ts +8 -0
- package/dist/poly/hash.d.ts +1 -0
- package/dist/poly/matrix.d.ts +24 -0
- package/dist/poly/minbound.d.ts +1 -0
- package/dist/poly/poly.d.ts +52 -0
- package/dist/poly/polybin.d.ts +5 -0
- package/dist/poly/polylabel.d.ts +7 -0
- package/dist/poly/polypack.d.ts +30 -0
- package/dist/poly/polyround.d.ts +1 -0
- package/dist/poly/polysimplify.d.ts +1 -0
- package/dist/poly/quad.d.ts +48 -0
- package/dist/poly/selfintersect.d.ts +1 -0
- package/dist/poly/shamos.d.ts +1 -0
- package/dist/poly/simplify.d.ts +2 -0
- package/dist/poly/topo.d.ts +46 -0
- package/dist/poly/union.d.ts +49 -0
- package/dist/util/all.d.ts +5 -0
- package/dist/util/bintrie.d.ts +93 -0
- package/dist/util/countedhash.d.ts +19 -0
- package/dist/util/gradient.d.ts +15 -0
- package/dist/util/indexedarray.d.ts +15 -0
- package/dist/util/util.d.ts +68 -0
- package/docs/context.md +2 -0
- package/docs/filterexpr.md +22 -0
- package/docs/fsm.md +243 -0
- package/docs/logabstract.md +2 -0
- package/docs/logclient.md +2 -0
- package/docs/ot-editutil.md +2 -0
- package/docs/ot-js.md +95 -0
- package/docs/poly.md +103 -0
- package/docs/util.md +2 -0
- package/lib/all/all.ts +21 -0
- package/lib/context/all.ts +1 -0
- package/lib/context/context.ts +82 -0
- package/lib/filterexpr/all.ts +1 -0
- package/lib/filterexpr/filterexpr.ts +699 -0
- package/lib/fsm/all.ts +1 -0
- package/lib/fsm/fsm.ts +559 -0
- package/lib/geo/all.ts +2 -0
- package/lib/geo/geo.ts +452 -0
- package/lib/geo/vfeature.ts +34 -0
- package/lib/logabstract/all.ts +1 -0
- package/lib/logabstract/log.ts +55 -0
- package/lib/logclient/all.ts +1 -0
- package/lib/logclient/log.ts +105 -0
- package/lib/ot-editutil/all.ts +2 -0
- package/lib/ot-editutil/oteditutil.ts +180 -0
- package/lib/ot-editutil/otmaputil.ts +209 -0
- package/lib/ot-js/all.ts +9 -0
- package/lib/ot-js/otarray.ts +1168 -0
- package/lib/ot-js/otclientengine.ts +327 -0
- package/lib/ot-js/otcomposite.ts +247 -0
- package/lib/ot-js/otcounter.ts +145 -0
- package/lib/ot-js/otengine.ts +71 -0
- package/lib/ot-js/otmap.ts +144 -0
- package/lib/ot-js/otserverengine.ts +329 -0
- package/lib/ot-js/otsession.ts +202 -0
- package/lib/ot-js/ottypes.ts +98 -0
- package/lib/poly/all.ts +15 -0
- package/lib/poly/blend.ts +27 -0
- package/lib/poly/boundbox.ts +102 -0
- package/lib/poly/cartesian.ts +130 -0
- package/lib/poly/graham-scan.ts +401 -0
- package/lib/poly/hash.ts +15 -0
- package/lib/poly/matrix.ts +309 -0
- package/lib/poly/minbound.ts +211 -0
- package/lib/poly/poly.ts +767 -0
- package/lib/poly/polybin.ts +218 -0
- package/lib/poly/polylabel.ts +204 -0
- package/lib/poly/polypack.ts +468 -0
- package/lib/poly/polyround.ts +30 -0
- package/lib/poly/polysimplify.ts +24 -0
- package/lib/poly/quad.ts +272 -0
- package/lib/poly/selfintersect.ts +87 -0
- package/lib/poly/shamos.ts +297 -0
- package/lib/poly/simplify.ts +119 -0
- package/lib/poly/topo.ts +510 -0
- package/lib/poly/union.ts +388 -0
- package/lib/util/all.ts +5 -0
- package/lib/util/bintrie.ts +603 -0
- package/lib/util/countedhash.ts +83 -0
- package/lib/util/gradient.ts +108 -0
- package/lib/util/indexedarray.ts +80 -0
- package/lib/util/util.ts +695 -0
- package/package.json +15 -16
package/lib/geo/geo.ts
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
import * as geojson from 'geojson';
|
|
2
|
+
import * as Util from '../util/all'
|
|
3
|
+
import * as Poly from '../poly/all'
|
|
4
|
+
|
|
5
|
+
export type GeoProperties = geojson.GeoJsonProperties;
|
|
6
|
+
export type GeoFeature = geojson.Feature;
|
|
7
|
+
export type GeoFeatureArray = GeoFeature[];
|
|
8
|
+
export type GeoFeatureCollection = geojson.FeatureCollection;
|
|
9
|
+
|
|
10
|
+
export function geoCollectionToMap(col: GeoFeatureCollection): GeoFeatureMap
|
|
11
|
+
{
|
|
12
|
+
if (col == null) return null;
|
|
13
|
+
let map: GeoFeatureMap = {};
|
|
14
|
+
col.features.forEach((f: GeoFeature) => { map[String(f.properties.id)] = f; });
|
|
15
|
+
return map;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function geoMapToCollection(map: GeoFeatureMap): GeoFeatureCollection
|
|
19
|
+
{
|
|
20
|
+
if (map == null || Util.countKeys(map) == 0) return null;
|
|
21
|
+
let col: GeoFeatureCollection = { type: 'FeatureCollection', features: [] };
|
|
22
|
+
Object.keys(map).forEach((geoid: string) => { col.features.push(map[geoid]) });
|
|
23
|
+
return col;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function geoCollectionToTopo(col: GeoFeatureCollection): Poly.Topo
|
|
27
|
+
{
|
|
28
|
+
let topo = Poly.topoFromCollection(col);
|
|
29
|
+
Poly.topoPack(topo);
|
|
30
|
+
return topo;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function geoTopoToCollection(topo: Poly.Topo): GeoFeatureCollection
|
|
34
|
+
{
|
|
35
|
+
let col = Poly.topoToCollection(topo);
|
|
36
|
+
Poly.featurePack(col);
|
|
37
|
+
return col;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface GeoFeatureMap
|
|
41
|
+
{
|
|
42
|
+
[id: string]: GeoFeature; // Maps id to GeoFeature
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type FeatureFunc = (f: GeoFeature) => void;
|
|
46
|
+
|
|
47
|
+
interface GeoEntry
|
|
48
|
+
{
|
|
49
|
+
tag: string;
|
|
50
|
+
col?: GeoFeatureCollection;
|
|
51
|
+
map?: GeoFeatureMap;
|
|
52
|
+
topo?: Poly.Topo;
|
|
53
|
+
}
|
|
54
|
+
type GeoEntryMap = { [tag: string]: GeoEntry };
|
|
55
|
+
|
|
56
|
+
export function geoEqual(m1: GeoMultiCollection, m2: GeoMultiCollection): boolean
|
|
57
|
+
{
|
|
58
|
+
let n1 = m1 ? m1.length : 0;
|
|
59
|
+
let n2 = m2 ? m2.length : 0;
|
|
60
|
+
|
|
61
|
+
if (n1 != n2) return false;
|
|
62
|
+
if (n1 == 0) return true;
|
|
63
|
+
|
|
64
|
+
let n = 0;
|
|
65
|
+
let eq = true;
|
|
66
|
+
m1.forEach(f => { if (eq && !m2.find(f.properties.id)) eq = false });
|
|
67
|
+
return eq;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function geoMapEqual(m1: GeoFeatureMap, m2: GeoFeatureMap): boolean
|
|
71
|
+
{
|
|
72
|
+
if (m1 == null) return Util.isEmpty(m2);
|
|
73
|
+
if (m2 == null) return Util.isEmpty(m1);
|
|
74
|
+
let p: string;
|
|
75
|
+
for (p in m1) if (m1.hasOwnProperty(p))
|
|
76
|
+
if (m1[p] !== m2[p])
|
|
77
|
+
return false;
|
|
78
|
+
for (p in m2) if (m2.hasOwnProperty(p))
|
|
79
|
+
if (m1[p] === undefined)
|
|
80
|
+
return false;
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export class GeoMultiCollection
|
|
85
|
+
{
|
|
86
|
+
entries: GeoEntryMap;
|
|
87
|
+
all: GeoEntry;
|
|
88
|
+
hidden: any;
|
|
89
|
+
stamp: number;
|
|
90
|
+
|
|
91
|
+
constructor(tag?: string, topo?: Poly.Topo, col?: GeoFeatureCollection, map?: GeoFeatureMap)
|
|
92
|
+
{
|
|
93
|
+
this.stamp = Math.trunc(Math.random() * Number.MAX_SAFE_INTEGER / 2);
|
|
94
|
+
this.empty();
|
|
95
|
+
if (tag)
|
|
96
|
+
this.add(tag, topo, col, map);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
empty()
|
|
100
|
+
{
|
|
101
|
+
this.entries = {};
|
|
102
|
+
this.hidden = {};
|
|
103
|
+
this._onChange();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
get nEntries(): number { return Util.countKeys(this.entries) }
|
|
107
|
+
|
|
108
|
+
nthEntry(n: number): GeoEntry
|
|
109
|
+
{
|
|
110
|
+
return Util.nthProperty(this.entries, n) as GeoEntry;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
add(tag: string, topo: Poly.Topo, col: GeoFeatureCollection, map: GeoFeatureMap): void
|
|
114
|
+
{
|
|
115
|
+
let entry = this.entries[tag];
|
|
116
|
+
if (entry === undefined) entry = { tag: tag }, this.entries[tag] = entry;
|
|
117
|
+
if ((topo && entry.topo !== topo) || (col && entry.col !== col) || (map && entry.map !== map))
|
|
118
|
+
{
|
|
119
|
+
entry.topo = topo;
|
|
120
|
+
entry.col = col;
|
|
121
|
+
entry.map = map;
|
|
122
|
+
this._onChange();
|
|
123
|
+
}
|
|
124
|
+
else if (topo == null && col == null && map == null)
|
|
125
|
+
this.remove(tag);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
addMulti(multi: GeoMultiCollection): void
|
|
129
|
+
{
|
|
130
|
+
multi.forEachEntry(e => {
|
|
131
|
+
this.add(e.tag, e.topo, e.col, e.map);
|
|
132
|
+
});
|
|
133
|
+
for (let p in multi.hidden) if (multi.hidden.hasOwnProperty(p))
|
|
134
|
+
{
|
|
135
|
+
this.hidden[p] = true;
|
|
136
|
+
this._onChange();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
remove(tag: string): void
|
|
141
|
+
{
|
|
142
|
+
let entry = this.entries[tag];
|
|
143
|
+
if (entry)
|
|
144
|
+
{
|
|
145
|
+
if (entry.topo || entry.col || entry.map)
|
|
146
|
+
this._onChange();
|
|
147
|
+
delete this.entries[tag];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
_onChange(): void
|
|
152
|
+
{
|
|
153
|
+
this.all = { tag: 'all' };
|
|
154
|
+
this.stamp++;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
_col(e: GeoEntry): GeoFeatureCollection
|
|
158
|
+
{
|
|
159
|
+
if (e == null) return null;
|
|
160
|
+
if (! e.col)
|
|
161
|
+
{
|
|
162
|
+
if (e.map)
|
|
163
|
+
e.col = geoMapToCollection(e.map);
|
|
164
|
+
else if (e.topo)
|
|
165
|
+
e.col = geoTopoToCollection(e.topo);
|
|
166
|
+
}
|
|
167
|
+
return e.col;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
_map(e: GeoEntry): GeoFeatureMap
|
|
171
|
+
{
|
|
172
|
+
if (e == null) return null;
|
|
173
|
+
if (! e.map)
|
|
174
|
+
{
|
|
175
|
+
if (e.col)
|
|
176
|
+
e.map = geoCollectionToMap(e.col);
|
|
177
|
+
else if (e.topo)
|
|
178
|
+
{
|
|
179
|
+
e.col = geoTopoToCollection(e.topo);
|
|
180
|
+
e.map = geoCollectionToMap(e.col);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return e.map;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
_topo(e: GeoEntry): Poly.Topo
|
|
187
|
+
{
|
|
188
|
+
if (e == null) return null;
|
|
189
|
+
if (! e.topo)
|
|
190
|
+
{
|
|
191
|
+
if (e.col)
|
|
192
|
+
e.topo = geoCollectionToTopo(e.col);
|
|
193
|
+
else if (e.map)
|
|
194
|
+
{
|
|
195
|
+
e.col = geoMapToCollection(e.map);
|
|
196
|
+
e.topo = geoCollectionToTopo(e.col);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return e.topo;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
colOf(tag: string): GeoFeatureCollection { return this._col(this.entries[tag]); }
|
|
203
|
+
mapOf(tag: string): GeoFeatureMap { return this._map(this.entries[tag]); }
|
|
204
|
+
topoOf(tag: string): Poly.Topo { return this._topo(this.entries[tag]); }
|
|
205
|
+
|
|
206
|
+
forEachEntry(cb: (e: GeoEntry) => void): void
|
|
207
|
+
{
|
|
208
|
+
Object.values(this.entries).forEach(cb);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
allCol(): GeoFeatureCollection
|
|
212
|
+
{
|
|
213
|
+
if (this.nEntries == 0) return null;
|
|
214
|
+
if (! this.all.col)
|
|
215
|
+
{
|
|
216
|
+
// optimise case where one entry
|
|
217
|
+
let n = this.nEntries;
|
|
218
|
+
if (n == 1)
|
|
219
|
+
this.all.col = this._col(this.nthEntry(0));
|
|
220
|
+
else
|
|
221
|
+
// Going from map to collection guarantees that any duplicates are removed
|
|
222
|
+
this.all.col = geoMapToCollection(this.allMap());
|
|
223
|
+
}
|
|
224
|
+
return this.all.col;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
allMap(): GeoFeatureMap
|
|
228
|
+
{
|
|
229
|
+
if (this.nEntries == 0) return null;
|
|
230
|
+
if (! this.all.map)
|
|
231
|
+
{
|
|
232
|
+
// optimise case where one entry
|
|
233
|
+
let n = this.nEntries;
|
|
234
|
+
if (n == 1)
|
|
235
|
+
this.all.map = this._map(this.nthEntry(0));
|
|
236
|
+
else
|
|
237
|
+
{
|
|
238
|
+
let map: GeoFeatureMap = {};
|
|
239
|
+
this.all.map = map;
|
|
240
|
+
this.forEach(f => { map[String(f.properties.id)] = f });
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return this.all.map;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
allTopo(): Poly.Topo
|
|
247
|
+
{
|
|
248
|
+
if (this.nEntries == 0) return null;
|
|
249
|
+
if (! this.all.topo)
|
|
250
|
+
{
|
|
251
|
+
// optimise case where one entry
|
|
252
|
+
let n = this.nEntries;
|
|
253
|
+
if (n == 1)
|
|
254
|
+
this.all.topo = this._topo(this.nthEntry(0));
|
|
255
|
+
else
|
|
256
|
+
this.all.topo = geoCollectionToTopo(this.allCol());
|
|
257
|
+
}
|
|
258
|
+
return this.all.topo;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
hide(id: any): void
|
|
262
|
+
{
|
|
263
|
+
if (id)
|
|
264
|
+
{
|
|
265
|
+
if (typeof id === 'string')
|
|
266
|
+
this.hidden[id] = true;
|
|
267
|
+
else if (Array.isArray(id))
|
|
268
|
+
id.forEach((i: string) => { this.hidden[i] = true })
|
|
269
|
+
else if (typeof id === 'object')
|
|
270
|
+
for (let p in id) if (id.hasOwnProperty(p)) this.hidden[p] = true;
|
|
271
|
+
this._onChange();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
show(id: any): void
|
|
276
|
+
{
|
|
277
|
+
if (id)
|
|
278
|
+
{
|
|
279
|
+
if (typeof id === 'string')
|
|
280
|
+
delete this.hidden[id];
|
|
281
|
+
else if (Array.isArray(id))
|
|
282
|
+
id.forEach((i: string) => { delete this.hidden[i] })
|
|
283
|
+
else if (typeof id === 'object')
|
|
284
|
+
for (let p in id) if (id.hasOwnProperty(p)) delete this.hidden[p];
|
|
285
|
+
this._onChange();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
showAll(): void
|
|
290
|
+
{
|
|
291
|
+
if (! Util.isEmpty(this.hidden))
|
|
292
|
+
{
|
|
293
|
+
this.hidden = {};
|
|
294
|
+
this._onChange();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
get length(): number
|
|
299
|
+
{
|
|
300
|
+
let n = 0;
|
|
301
|
+
this.forEachEntry(e => {
|
|
302
|
+
if (e.col)
|
|
303
|
+
n += e.col.features.length;
|
|
304
|
+
else if (e.map)
|
|
305
|
+
n += Util.countKeys(e.map);
|
|
306
|
+
else if (e.topo)
|
|
307
|
+
n += Util.countKeys(e.topo.objects);
|
|
308
|
+
});
|
|
309
|
+
return n;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Use forEach in preference to iteration using this function
|
|
313
|
+
nthFeature(n: number): GeoFeature
|
|
314
|
+
{
|
|
315
|
+
let found: GeoFeature;
|
|
316
|
+
|
|
317
|
+
if (n >= 0)
|
|
318
|
+
this.forEachEntry(e => {
|
|
319
|
+
if (found) return;
|
|
320
|
+
let col = this._col(e);
|
|
321
|
+
if (col)
|
|
322
|
+
if (n > col.features.length)
|
|
323
|
+
n -= col.features.length;
|
|
324
|
+
else
|
|
325
|
+
found = col.features[n];
|
|
326
|
+
});
|
|
327
|
+
return found;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
nthFilteredFeature(n: number, cb: (f: GeoFeature) => boolean)
|
|
331
|
+
{
|
|
332
|
+
let found: GeoFeature;
|
|
333
|
+
|
|
334
|
+
this.forEachEntry(e => {
|
|
335
|
+
if (found) return;
|
|
336
|
+
let col = this._col(e);
|
|
337
|
+
if (col)
|
|
338
|
+
for (let i = 0; !found && i < col.features.length; i++)
|
|
339
|
+
{
|
|
340
|
+
let f = col.features[i];
|
|
341
|
+
if (this.hidden[f.properties.id] === undefined && cb(f))
|
|
342
|
+
{
|
|
343
|
+
if (n === 0)
|
|
344
|
+
{
|
|
345
|
+
found = f;
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
n--;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
return found;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
forEach(cb: FeatureFunc): void
|
|
356
|
+
{
|
|
357
|
+
this.forEachEntry(e => {
|
|
358
|
+
let col = this._col(e);
|
|
359
|
+
if (e.col)
|
|
360
|
+
e.col.features.forEach(f => { if (this.hidden[f.properties.id] === undefined) cb(f) })
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
map(cb: (f: GeoFeature) => GeoFeature): GeoFeature[]
|
|
365
|
+
{
|
|
366
|
+
let features: GeoFeature[] = [];
|
|
367
|
+
this.forEach((f: GeoFeature) => { features.push(cb(f)) });
|
|
368
|
+
return features;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
isHidden(id: string): boolean
|
|
372
|
+
{
|
|
373
|
+
return this.hidden[id] !== undefined;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
find(id: string): GeoFeature
|
|
377
|
+
{
|
|
378
|
+
if (this.hidden[id] !== undefined)
|
|
379
|
+
return undefined;
|
|
380
|
+
|
|
381
|
+
let entries = Object.values(this.entries);
|
|
382
|
+
for (let i = 0; i < entries.length; i++)
|
|
383
|
+
{
|
|
384
|
+
let map = this._map(entries[i]);
|
|
385
|
+
if (map[id])
|
|
386
|
+
return map[id];
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
filter(test: (f: GeoFeature) => boolean): GeoMultiCollection
|
|
393
|
+
{
|
|
394
|
+
let m = new GeoMultiCollection();
|
|
395
|
+
this.forEachEntry(e => {
|
|
396
|
+
let col = this._col(e);
|
|
397
|
+
let features = col ? col.features.filter(test) : null;
|
|
398
|
+
if (features && features.length)
|
|
399
|
+
m.add(e.tag, null, { type: 'FeatureCollection', features: features }, null);
|
|
400
|
+
});
|
|
401
|
+
return m;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export enum geoIntersectOptions { Intersects, Bounds, BoundsCenter };
|
|
406
|
+
|
|
407
|
+
function geoBoxIntersect(x1: Poly.BoundBox, x2: Poly.BoundBox, opt: geoIntersectOptions): boolean
|
|
408
|
+
{
|
|
409
|
+
if (x1.left === undefined || x2.left === undefined) return false;
|
|
410
|
+
|
|
411
|
+
let l1 = x1.left;
|
|
412
|
+
let l2 = x2.left;
|
|
413
|
+
let r1 = x1.right;
|
|
414
|
+
let r2 = x2.right;
|
|
415
|
+
let b1 = x1.top; // flip
|
|
416
|
+
let b2 = x2.top; // flip
|
|
417
|
+
let t1 = x1.bottom; // flip
|
|
418
|
+
let t2 = x2.bottom; // flip
|
|
419
|
+
let cx2 = l2 + (r2 - l2) / 2;
|
|
420
|
+
let cy2 = t2 + (b2 - t2) / 2;
|
|
421
|
+
|
|
422
|
+
// Note I flipped top and bottom above when extracting,
|
|
423
|
+
// in order to make below logic work for normal y axis alignment (0 at top).
|
|
424
|
+
switch (opt)
|
|
425
|
+
{
|
|
426
|
+
case geoIntersectOptions.Intersects:
|
|
427
|
+
return !(l2 > r1 || r2 < l1 || t2 > b1 || b2 < t1);
|
|
428
|
+
case geoIntersectOptions.Bounds:
|
|
429
|
+
return l1 <= l2 && t1 <= t2 && r1 >= r2 && b1 >= b2;
|
|
430
|
+
case geoIntersectOptions.BoundsCenter:
|
|
431
|
+
return l1 <= cx2 && t1 <= cy2 && r1 >= cx2 && b1 >= cy2;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export function geoIntersect(multi: GeoMultiCollection, bbox: Poly.BoundBox, opt: geoIntersectOptions): GeoMultiCollection
|
|
436
|
+
{
|
|
437
|
+
let m: GeoFeatureMap = {};
|
|
438
|
+
let bboxPoly = Poly.boundboxPoly(bbox);
|
|
439
|
+
|
|
440
|
+
multi.forEach((f: GeoFeature) => {
|
|
441
|
+
let box = Poly.boundbox(f);
|
|
442
|
+
if (geoBoxIntersect(bbox, box, opt))
|
|
443
|
+
{
|
|
444
|
+
if (opt !== geoIntersectOptions.Intersects || Poly.polyIntersects(bboxPoly, f))
|
|
445
|
+
m[f.properties.id] = f;
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
let result = new GeoMultiCollection();
|
|
450
|
+
result.add('result', null, null, m);
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as geojson from 'geojson';
|
|
2
|
+
import * as Util from '../util/all'
|
|
3
|
+
import * as Poly from '../poly/all'
|
|
4
|
+
import * as G from './geo';
|
|
5
|
+
|
|
6
|
+
// Given the topology for a precinct, the bintrie mapping and the list of blocks, construct the
|
|
7
|
+
// feature data for the virtual feature.
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
export function computeVFeature(topoPrecinct: Poly.Topo, bintrie: Util.BinTrie, blocks: string[]): G.GeoFeature
|
|
11
|
+
{
|
|
12
|
+
let contiguity = new Util.IndexedArray();
|
|
13
|
+
let block_contiguity = new Util.IndexedArray();
|
|
14
|
+
let f = Poly.topoMerge(topoPrecinct, blocks);
|
|
15
|
+
f.properties.datasets = {};
|
|
16
|
+
blocks.forEach(blockid => {
|
|
17
|
+
let b = topoPrecinct.objects[blockid];
|
|
18
|
+
if (b.properties.datasets)
|
|
19
|
+
Util.deepAccum(f.properties.datasets, b.properties.datasets);
|
|
20
|
+
if (b.properties.contiguity)
|
|
21
|
+
{
|
|
22
|
+
b.properties.contiguity.forEach((id: string) => {
|
|
23
|
+
contiguity.set(id === 'OUT_OF_STATE' ? id : bintrie.get(id));
|
|
24
|
+
});
|
|
25
|
+
b.properties.contiguity.forEach((id: string) => {
|
|
26
|
+
block_contiguity.set(id);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
f.properties.contiguity = contiguity.asArray();
|
|
31
|
+
f.properties.block_contiguity = block_contiguity.asArray();
|
|
32
|
+
f.properties.blocks = blocks;
|
|
33
|
+
return f;
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './log';
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as Util from '../util/all';
|
|
2
|
+
import * as FSM from '../fsm/all';
|
|
3
|
+
|
|
4
|
+
export interface ILog
|
|
5
|
+
{
|
|
6
|
+
dump: () => FSM.Fsm;
|
|
7
|
+
stamp: (o: any) => void;
|
|
8
|
+
log: (o: any, verbosity?: number) => void;
|
|
9
|
+
event: (o: any, verbosity?: number) => void;
|
|
10
|
+
error: (o: any) => void;
|
|
11
|
+
value: (o: any, verbosity?: number) => void;
|
|
12
|
+
chatter: (s: string) => void;
|
|
13
|
+
chatters: () => string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class Timer
|
|
17
|
+
{
|
|
18
|
+
ilog: ILog;
|
|
19
|
+
o: any;
|
|
20
|
+
verbosity: number;
|
|
21
|
+
elapsed: Util.Elapsed;
|
|
22
|
+
|
|
23
|
+
constructor(ilog: ILog, kind: string, o: any, verbosity: number = 0)
|
|
24
|
+
{
|
|
25
|
+
this.ilog = ilog;
|
|
26
|
+
if (typeof o === 'string') o = { event: o };
|
|
27
|
+
this.o = o;
|
|
28
|
+
this.o.kind = kind;
|
|
29
|
+
this.verbosity = verbosity;
|
|
30
|
+
this.elapsed = new Util.Elapsed();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
log(): void
|
|
34
|
+
{
|
|
35
|
+
this.elapsed.end();
|
|
36
|
+
this.o.ms = this.elapsed.ms();
|
|
37
|
+
this.ilog.log(this.o, this.verbosity);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class AsyncTimer extends Timer
|
|
42
|
+
{
|
|
43
|
+
constructor(ilog: ILog, o: any, verbosity: number = 0)
|
|
44
|
+
{
|
|
45
|
+
super(ilog, 'async', o, verbosity);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class SyncTimer extends Timer
|
|
50
|
+
{
|
|
51
|
+
constructor(ilog: ILog, o: any, verbosity: number = 0)
|
|
52
|
+
{
|
|
53
|
+
super(ilog, 'sync', o, verbosity);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './log';
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import * as Context from '../context/all';
|
|
2
|
+
import * as LogAbstract from '../logabstract/all';
|
|
3
|
+
import * as Util from '../util/all';
|
|
4
|
+
import * as FSM from '../fsm/all';
|
|
5
|
+
|
|
6
|
+
export interface LogEnvironment
|
|
7
|
+
{
|
|
8
|
+
context: Context.IContext;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
class LogManager implements LogAbstract.ILog
|
|
12
|
+
{
|
|
13
|
+
env: LogEnvironment;
|
|
14
|
+
count: number;
|
|
15
|
+
|
|
16
|
+
constructor(env: LogEnvironment)
|
|
17
|
+
{
|
|
18
|
+
this.env = env;
|
|
19
|
+
this.count = 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
dump(): FSM.Fsm { return null; }
|
|
23
|
+
|
|
24
|
+
print(o: any): void
|
|
25
|
+
{
|
|
26
|
+
let sa: string[] = [];
|
|
27
|
+
|
|
28
|
+
if (o._count !== undefined)
|
|
29
|
+
sa.push(String(o._count));
|
|
30
|
+
if (o.kind === 'error')
|
|
31
|
+
{
|
|
32
|
+
sa.push('error');
|
|
33
|
+
sa.push(o.event);
|
|
34
|
+
}
|
|
35
|
+
else if (o.kind !== 'value')
|
|
36
|
+
{
|
|
37
|
+
sa.push('info');
|
|
38
|
+
sa.push(o.event);
|
|
39
|
+
}
|
|
40
|
+
else
|
|
41
|
+
{
|
|
42
|
+
sa.push('value');
|
|
43
|
+
sa.push(o.event);
|
|
44
|
+
sa.push(String(o.value));
|
|
45
|
+
}
|
|
46
|
+
if (o.detail !== undefined)
|
|
47
|
+
sa.push(o.detail);
|
|
48
|
+
console.log(sa.join(': '));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
stamp(o: any): void
|
|
52
|
+
{
|
|
53
|
+
this.log(o);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
log(o: any, verbosity: number = 0): void
|
|
57
|
+
{
|
|
58
|
+
// Show some restraint
|
|
59
|
+
if (verbosity > this.env.context.xnumber('verbosity'))
|
|
60
|
+
return;
|
|
61
|
+
|
|
62
|
+
// Inject some standard properties
|
|
63
|
+
o._time = Util.Now();
|
|
64
|
+
o._count = this.count++;
|
|
65
|
+
if (o.kind === undefined)
|
|
66
|
+
o.kind = 'misc';
|
|
67
|
+
this.print(o);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
event(o: any, verbosity: number = 0): void
|
|
72
|
+
{
|
|
73
|
+
if (typeof o === 'string') o = { event: o };
|
|
74
|
+
o.kind = 'event';
|
|
75
|
+
this.log(o, verbosity);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
error(o: any): void
|
|
79
|
+
{
|
|
80
|
+
if (typeof o === 'string') o = { event: o };
|
|
81
|
+
o.kind = 'error';
|
|
82
|
+
this.log(o);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
value(o: any, verbosity: number = 0): void
|
|
86
|
+
{
|
|
87
|
+
o.kind = 'value';
|
|
88
|
+
this.log(o, verbosity);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
chatter(s: string): void
|
|
92
|
+
{
|
|
93
|
+
console.log(s);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
chatters(): string[]
|
|
97
|
+
{
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function create(env: LogEnvironment): LogAbstract.ILog
|
|
103
|
+
{
|
|
104
|
+
return new LogManager(env);
|
|
105
|
+
}
|