@dra2020/baseclient 1.0.50 → 1.0.53

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/dist/geo/geo.d.ts CHANGED
@@ -10,7 +10,14 @@ export declare type GeoCentroidMap = {
10
10
  y: number;
11
11
  };
12
12
  };
13
- export declare function geoEnsureID(col: GeoFeatureCollection): void;
13
+ export interface NormalizeOptions {
14
+ joinPolygons?: boolean;
15
+ checkRewind?: boolean;
16
+ ensureID?: boolean;
17
+ }
18
+ export declare function geoEnsureID(col: GeoFeatureCollection, options?: NormalizeOptions): void;
19
+ export declare function geoNormalizeFeature(f: any, options?: NormalizeOptions): GeoFeature;
20
+ export declare function geoNormalizeCollection(col: GeoFeatureCollection, options?: NormalizeOptions): GeoFeatureCollection;
14
21
  export declare function geoCollectionToMap(col: GeoFeatureCollection): GeoFeatureMap;
15
22
  export declare function geoMapToCollection(map: GeoFeatureMap): GeoFeatureCollection;
16
23
  export declare function geoMapToCollectionNonNull(map: GeoFeatureMap): GeoFeatureCollection;
@@ -3,3 +3,4 @@ export * from './countedhash';
3
3
  export * from './indexedarray';
4
4
  export * from './gradient';
5
5
  export * from './bintrie';
6
+ export * from './bitset';
@@ -0,0 +1,10 @@
1
+ export declare class ListToBitset {
2
+ list: string[];
3
+ index: {
4
+ [s: string]: number;
5
+ };
6
+ size: number;
7
+ constructor(list: string[]);
8
+ toBits(l: string[]): Uint8Array;
9
+ toList(u8: Uint8Array): string[];
10
+ }
package/lib/geo/geo.ts CHANGED
@@ -8,16 +8,40 @@ export type GeoFeatureArray = GeoFeature[];
8
8
  export type GeoFeatureCollection = geojson.FeatureCollection;
9
9
  export type GeoCentroidMap = { [geoid: string]: { x: number, y: number } };
10
10
 
11
- export function geoEnsureID(col: GeoFeatureCollection): void
11
+ export interface NormalizeOptions
12
12
  {
13
+ joinPolygons?: boolean,
14
+ checkRewind?: boolean,
15
+ ensureID?: boolean,
16
+ }
17
+ const NormalizeAll: NormalizeOptions = { joinPolygons: true, checkRewind: true, ensureID: true };
18
+
19
+ // set the canonical 'id' property from the best property value.
20
+ // if joinPolygons is true, we do not enforce uniqueness.
21
+ //
22
+
23
+ export function geoEnsureID(col: GeoFeatureCollection, options?: NormalizeOptions): void
24
+ {
25
+ options = Util.shallowAssignImmutable({}, options);
26
+
13
27
  let prop: string;
14
- const props = ['id', 'GEOID', 'GEOID10', 'GEOID20', 'GEOID30' ];
28
+ const props = [ 'id', 'GEOID', 'GEOID10', 'GEOID20', 'GEOID30', 'DISTRICT', 'DISTRICTNO', 'DISTRICTNAME' ];
15
29
 
16
30
  if (col && col.features && col.features.length > 0)
17
31
  {
18
32
  let f = col.features[0];
19
- if (f.properties.id !== undefined) return;
20
- props.forEach(p => { if (prop === undefined && f.properties[p] !== undefined) prop = p; });
33
+ if (f.properties.id !== undefined) return; // short-cut - assume if 'id' is set, we're all good.
34
+ props.forEach(p => {
35
+ if (prop === undefined)
36
+ if (f.properties[p] !== undefined)
37
+ prop = p;
38
+ else
39
+ {
40
+ p = p.toLowerCase();
41
+ if (f.properties[p] !== undefined)
42
+ prop = p
43
+ }
44
+ });
21
45
  if (prop)
22
46
  col.features.forEach(f => { f.properties.id = f.properties[prop] });
23
47
  else
@@ -28,6 +52,94 @@ export function geoEnsureID(col: GeoFeatureCollection): void
28
52
  }
29
53
  }
30
54
 
55
+ export function geoNormalizeFeature(f: any, options?: NormalizeOptions): GeoFeature
56
+ {
57
+ options = Util.shallowAssignImmutable({}, options);
58
+
59
+ if (f && f.geometry && f.geometry.type === 'MultiPolygon' && f.geometry.coordinates)
60
+ {
61
+ let multiPoly = f.geometry.coordinates;
62
+
63
+ // Convert degenerate MultiPolygon to Polygon
64
+ if (multiPoly.length == 1)
65
+ {
66
+ f.geometry.type = 'Polygon';
67
+ f.geometry.coordinates = multiPoly[0];
68
+ }
69
+ }
70
+ else if (f && f.geometry && f.geometry.type === 'Point' && f.geometry.coordinates)
71
+ {
72
+ while (Array.isArray(f.geometry.coordinates[0]))
73
+ f.geometry.coordinates = f.geometry.coordinates[0];
74
+ }
75
+ else if (options.checkRewind)
76
+ // Various tools do not guarantee valid GeoJSON winding rules. Verify it since internal processing
77
+ // assumes it is correct.
78
+ Poly.featureRewind(f);
79
+
80
+ return f;
81
+ }
82
+
83
+ function onlyPolygons(col: GeoFeatureCollection): boolean
84
+ {
85
+ if (col && Array.isArray(col.features))
86
+ for (let i = 0; i < col.features.length; i++)
87
+ {
88
+ let f = col.features[i];
89
+ if (f.geometry && f.geometry.type === 'MultiPolygon')
90
+ return false;
91
+ }
92
+
93
+ return true;
94
+ }
95
+
96
+ function mergePolygon(f1: any, f2: any): any
97
+ {
98
+ if (!f1) return f2;
99
+ if (!f2) return f1;
100
+ if (f1.geometry.type !== 'Polygon' && f1.geometry.type !== 'MultiPolygon')
101
+ return f1;
102
+ if (f2.geometry.type !== 'Polygon' && f2.geometry.type !== 'MultiPolygon')
103
+ return f2;
104
+ if (f1.geometry.type === 'Polygon')
105
+ {
106
+ f1.geometry.type = 'MultiPolygon';
107
+ if (f2.geometry.type === 'Polygon')
108
+ f1.geometry.coordinates = [ f1.geometry.coordinates, f2.geometry.coordinates ];
109
+ else
110
+ f1.geometry.coordinates = [ f1.geometry.coordinates, ...f2.geometry.coordinates ];
111
+ }
112
+ else
113
+ {
114
+ if (f2.geometry.type === 'Polygon')
115
+ f1.geometry.coordinates.push(f2.geometry.coordinates);
116
+ else
117
+ f1.geometry.coordinates = [...f1.geometry.coordinates, ...f2.geometry.coordinates];
118
+ }
119
+ return f1;
120
+ }
121
+
122
+ export function geoNormalizeCollection(col: GeoFeatureCollection, options?: NormalizeOptions): GeoFeatureCollection
123
+ {
124
+ options = Util.shallowAssignImmutable(NormalizeAll, options);
125
+
126
+ // Normalize individual features
127
+ if (col && Array.isArray(col.features)) col.features.forEach((f: GeoFeature) => geoNormalizeFeature(f, options));
128
+
129
+ // Ensure ID
130
+ if (options.ensureID)
131
+ geoEnsureID(col, options);
132
+
133
+ // Merge polygons into multi-polygons based on id?
134
+ if (options.ensureID && options.joinPolygons && onlyPolygons(col))
135
+ {
136
+ let map: GeoFeatureMap = {};
137
+ col.features.forEach(f => { let id = f.properties.id; map[id] = mergePolygon(map[id], f) });
138
+ col.features = Object.values(map);
139
+ }
140
+ return col;
141
+ }
142
+
31
143
  export function geoCollectionToMap(col: GeoFeatureCollection): GeoFeatureMap
32
144
  {
33
145
  if (col == null) return null;
package/lib/util/all.ts CHANGED
@@ -3,3 +3,4 @@ export * from './countedhash';
3
3
  export * from './indexedarray';
4
4
  export * from './gradient';
5
5
  export * from './bintrie';
6
+ export * from './bitset';
@@ -0,0 +1,52 @@
1
+ const BitLookup = [ 1, 2, 4, 8, 16, 32, 64, 128 ];
2
+
3
+ export class ListToBitset
4
+ {
5
+ list: string[];
6
+ index: { [s: string]: number };
7
+ size: number;
8
+
9
+ constructor(list: string[])
10
+ {
11
+ this.list = list;
12
+ }
13
+
14
+ toBits(l: string[]): Uint8Array
15
+ {
16
+ if (! this.index)
17
+ {
18
+ this.size = Math.floor((this.list.length+7)/8);
19
+ this.index = {};
20
+ this.list.forEach((s: string, i: number) => { this.index[s] = i });
21
+ }
22
+ let ab = new ArrayBuffer(this.size);
23
+ let u8 = new Uint8Array(ab);
24
+ if (l) l.forEach(s => {
25
+ let n = this.index[s];
26
+ let i = Math.floor(n/8);
27
+ u8[i] |= BitLookup[n % 8];
28
+ });
29
+ return u8;
30
+ }
31
+
32
+ toList(u8: Uint8Array): string[]
33
+ {
34
+ let list: string[] = [];
35
+ for (let i = 0; i < u8.length; i++)
36
+ {
37
+ let u = u8[i];
38
+ if (u)
39
+ {
40
+ if (u & 1) list.push(this.list[i*8+0]);
41
+ if (u & 2) list.push(this.list[i*8+1]);
42
+ if (u & 4) list.push(this.list[i*8+2]);
43
+ if (u & 8) list.push(this.list[i*8+3]);
44
+ if (u & 16) list.push(this.list[i*8+4]);
45
+ if (u & 32) list.push(this.list[i*8+5]);
46
+ if (u & 64) list.push(this.list[i*8+6]);
47
+ if (u & 128) list.push(this.list[i*8+7]);
48
+ }
49
+ }
50
+ return list;
51
+ }
52
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dra2020/baseclient",
3
- "version": "1.0.50",
3
+ "version": "1.0.53",
4
4
  "description": "Utility functions for Javascript projects.",
5
5
  "main": "dist/baseclient.js",
6
6
  "types": "./dist/all/all.d.ts",