@dra2020/baseclient 1.0.14 → 1.0.17

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 (97) hide show
  1. package/README.md +5 -16
  2. package/dist/all/all.d.ts +2 -18
  3. package/dist/baseclient.js +1309 -173
  4. package/dist/baseclient.js.map +1 -1
  5. package/dist/filterexpr/filterexpr.d.ts +3 -0
  6. package/dist/fsm/fsm.d.ts +1 -0
  7. package/dist/geo/all.d.ts +2 -0
  8. package/dist/geo/geo.d.ts +67 -0
  9. package/dist/geo/vfeature.d.ts +4 -0
  10. package/dist/ot-js/otsession.d.ts +3 -0
  11. package/dist/poly/union.d.ts +1 -0
  12. package/docs/filterexpr.md +22 -0
  13. package/lib/all/all.ts +2 -22
  14. package/lib/filterexpr/filterexpr.ts +79 -5
  15. package/lib/fsm/fsm.ts +12 -2
  16. package/lib/geo/all.ts +2 -0
  17. package/lib/geo/geo.ts +452 -0
  18. package/lib/geo/vfeature.ts +34 -0
  19. package/lib/ot-js/otsession.ts +4 -1
  20. package/lib/poly/hash.ts +1 -1
  21. package/lib/poly/polybin.ts +5 -4
  22. package/lib/poly/polypack.ts +16 -4
  23. package/lib/poly/topo.ts +26 -41
  24. package/lib/poly/union.ts +17 -0
  25. package/package.json +9 -10
  26. package/dist/all/allclient.d.ts +0 -18
  27. package/dist/base.js +0 -33010
  28. package/dist/base.js.map +0 -1
  29. package/dist/dbabstract/all.d.ts +0 -1
  30. package/dist/dbabstract/db.d.ts +0 -83
  31. package/dist/dbdynamo/all.d.ts +0 -1
  32. package/dist/dbdynamo/dbdynamo.d.ts +0 -190
  33. package/dist/fsmfile/all.d.ts +0 -1
  34. package/dist/fsmfile/fsmfile.d.ts +0 -47
  35. package/dist/jsonstream/all.d.ts +0 -1
  36. package/dist/jsonstream/jsonstream.d.ts +0 -130
  37. package/dist/lambda/all.d.ts +0 -1
  38. package/dist/lambda/env.d.ts +0 -10
  39. package/dist/lambda/lambda.d.ts +0 -18
  40. package/dist/logserver/all.d.ts +0 -5
  41. package/dist/logserver/log.d.ts +0 -11
  42. package/dist/logserver/logaccum.d.ts +0 -154
  43. package/dist/logserver/logblob.d.ts +0 -24
  44. package/dist/logserver/logconcat.d.ts +0 -55
  45. package/dist/logserver/logkey.d.ts +0 -28
  46. package/dist/memsqs/all.d.ts +0 -4
  47. package/dist/memsqs/client.d.ts +0 -13
  48. package/dist/memsqs/loopback.d.ts +0 -11
  49. package/dist/memsqs/orderedlist.d.ts +0 -19
  50. package/dist/memsqs/queue.d.ts +0 -84
  51. package/dist/memsqs/server.d.ts +0 -37
  52. package/dist/storage/all.d.ts +0 -4
  53. package/dist/storage/datablob.d.ts +0 -9
  54. package/dist/storage/env.d.ts +0 -10
  55. package/dist/storage/splitsblob.d.ts +0 -13
  56. package/dist/storage/storage.d.ts +0 -166
  57. package/dist/storages3/all.d.ts +0 -1
  58. package/dist/storages3/s3.d.ts +0 -62
  59. package/docs/dbabstract.md +0 -2
  60. package/docs/dbdynamo.md +0 -2
  61. package/docs/fsmfile.md +0 -2
  62. package/docs/jsonstream.md +0 -44
  63. package/docs/lambda.md +0 -2
  64. package/docs/logserver.md +0 -2
  65. package/docs/storage.md +0 -2
  66. package/docs/storages3.md +0 -2
  67. package/lib/all/allclient.ts +0 -19
  68. package/lib/dbabstract/all.ts +0 -1
  69. package/lib/dbabstract/db.ts +0 -246
  70. package/lib/dbdynamo/all.ts +0 -1
  71. package/lib/dbdynamo/dbdynamo.ts +0 -1551
  72. package/lib/fsmfile/all.ts +0 -1
  73. package/lib/fsmfile/fsmfile.ts +0 -236
  74. package/lib/jsonstream/all.ts +0 -1
  75. package/lib/jsonstream/jsonstream.ts +0 -940
  76. package/lib/lambda/all.ts +0 -1
  77. package/lib/lambda/env.ts +0 -13
  78. package/lib/lambda/lambda.ts +0 -120
  79. package/lib/logserver/all.ts +0 -5
  80. package/lib/logserver/log.ts +0 -565
  81. package/lib/logserver/logaccum.ts +0 -1445
  82. package/lib/logserver/logblob.ts +0 -84
  83. package/lib/logserver/logconcat.ts +0 -313
  84. package/lib/logserver/logkey.ts +0 -125
  85. package/lib/memsqs/all.ts +0 -4
  86. package/lib/memsqs/client.ts +0 -268
  87. package/lib/memsqs/loopback.ts +0 -64
  88. package/lib/memsqs/orderedlist.ts +0 -74
  89. package/lib/memsqs/queue.ts +0 -395
  90. package/lib/memsqs/server.ts +0 -262
  91. package/lib/storage/all.ts +0 -4
  92. package/lib/storage/datablob.ts +0 -36
  93. package/lib/storage/env.ts +0 -14
  94. package/lib/storage/splitsblob.ts +0 -63
  95. package/lib/storage/storage.ts +0 -604
  96. package/lib/storages3/all.ts +0 -1
  97. package/lib/storages3/s3.ts +0 -576
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
+ }
@@ -23,7 +23,8 @@ export const FilterRecent: number = 3;
23
23
  export const FilterTrash: number = 4;
24
24
  export const FilterPublic: number = 5;
25
25
  export const FilterOfficial: number = 6;
26
- export const FilterCount: number = 7;
26
+ export const FilterCOI: number = 7;
27
+ export const FilterCount: number = 8;
27
28
  export type Filter = number;
28
29
 
29
30
  // Permissions
@@ -111,6 +112,8 @@ export interface SessionProps
111
112
  loadFailed: boolean;
112
113
  accessMap: AccessMap;
113
114
  revisions: RevisionList;
115
+ expunged?: boolean;
116
+ expungeDate?: string;
114
117
  xprops?: { [prop: string]: string };
115
118
  }
116
119
 
package/lib/poly/hash.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as objectHash from 'object-hash';
1
+ import objectHash from 'object-hash';
2
2
 
3
3
  export function qhash(o: any, keys?: any): any
4
4
  {
@@ -54,9 +54,10 @@ export function packCollection(coder: Util.Coder, col: any): ArrayBuffer
54
54
  {
55
55
  // Compute size
56
56
  let pp = PP.featurePack(col) as PP.PolyPack;
57
- let buffer: any = col.features.length ? col.features[0].geometry.packed.buffer : null; // to restore, below
57
+ let f: any = col.features.find((f: any) => { return f.geometry.packed ? f.geometry.packed.buffer : null });
58
+ let buffer: any = f ? f.geometry.packed.buffer : null;
58
59
  let size = 16; // int endiness, offset to coordinates, float endiness
59
- col.features.forEach((f: any) => { delete f.geometry.packed.buffer; }); // reconstructed when unpacking
60
+ col.features.forEach((f: any) => { if (f.geometry.packed) delete f.geometry.packed.buffer; }); // reconstructed when unpacking
60
61
  let j = JSON.stringify(col);
61
62
  size += sizeOfString(coder, j);
62
63
  size += pad(size, 8);
@@ -84,7 +85,7 @@ export function packCollection(coder: Util.Coder, col: any): ArrayBuffer
84
85
  buf64[foff++] = buf[i];
85
86
 
86
87
  // Now restore
87
- col.features.forEach((f: any) => { f.geometry.packed.buffer = buffer; });
88
+ col.features.forEach((f: any) => { if (f.geometry.packed) f.geometry.packed.buffer = buffer; });
88
89
  PP.featureUnpack(col);
89
90
 
90
91
  return ab;
@@ -144,7 +145,7 @@ export function unpackCollection(coder: Util.Coder, ab: ArrayBuffer): any
144
145
  let offset = 16;
145
146
  let j = unpackString(coder, buf8, buf32, offset);
146
147
  col = JSON.parse(j);
147
- col.features.forEach((f: any) => { f.geometry.packed.buffer = buf64 });
148
+ col.features.forEach((f: any) => { if (f.geometry.packed) f.geometry.packed.buffer = buf64 });
148
149
  return col;
149
150
  }
150
151
 
@@ -221,7 +221,8 @@ export function polyPack(coords: any, prepack?: PolyPack): PolyPack
221
221
 
222
222
  // Transparently handle polygon or multi-polygon
223
223
  let depth = Util.depthof(coords);
224
- if (depth == 3) coords = [ [ coords ] ];
224
+ if (depth == 2) coords = [ [ [ coords ] ] ];
225
+ else if (depth == 3) coords = [ [ coords ] ];
225
226
  else if (depth == 4) coords = [ coords ];
226
227
 
227
228
  let nFloats = polyPackSize(coords);
@@ -325,7 +326,7 @@ export function polyUnpack(prepack: any): any
325
326
 
326
327
  export function featurePackSize(f: any): number
327
328
  {
328
- if (f && f.geometry && f.geometry.coordinates)
329
+ if (f && f.geometry && f.geometry.coordinates && f.geometry.type !== 'Point')
329
330
  return polyPackSize(f.geometry.coordinates);
330
331
  return 0;
331
332
  }
@@ -334,7 +335,9 @@ export function featurePack(f: any, prepack?: PolyPack): any
334
335
  {
335
336
  if (f && f.type === 'Feature')
336
337
  {
337
- if (f.geometry && f.geometry.coordinates)
338
+ if (f.geometry && f.geometry.type === 'Point')
339
+ return prepack ? { offset: prepack.offset, length: 0, buffer: prepack.buffer } : { offset: 0, length: 0, buffer: null };
340
+ else if (f.geometry && f.geometry.coordinates)
338
341
  {
339
342
  f.geometry.packed = polyPack(f.geometry.coordinates, prepack);
340
343
  delete f.geometry.coordinates;
@@ -374,9 +377,18 @@ export function featureUnpack(f: any): any
374
377
  if (f && f.geometry && f.geometry.packed !== undefined)
375
378
  {
376
379
  f.geometry.coordinates = polyUnpack(f.geometry.packed);
380
+ let depth = Util.depthof(f.geometry.coordinates);
377
381
  // Check for oops, optimized away the multipolygon in polyUnpack
378
- if (f.geometry.type === 'MultiPolygon' && Util.depthof(f.geometry.coordinates) === 4)
382
+ if (f.geometry.type === 'MultiPolygon' && depth === 4)
379
383
  f.geometry.coordinates = [ f.geometry.coordinates ];
384
+ else if (f.geometry.type === 'Point' && depth != 2)
385
+ {
386
+ while (depth > 2)
387
+ {
388
+ f.geometry.coordinates = f.geometry.coordinates[0];
389
+ depth = Util.depthof(f.geometry.coordinates);
390
+ }
391
+ }
380
392
  delete f.geometry.packed;
381
393
  }
382
394
  else if (f.type && f.type === 'FeatureCollection' && f.features)