@dra2020/baseclient 1.0.26 → 1.0.29

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.
@@ -14,3 +14,4 @@ export * from './topo';
14
14
  export * from './selfintersect';
15
15
  export * from './shamos';
16
16
  export * from './pointinpoly';
17
+ export * from './mapto';
@@ -12,6 +12,7 @@ export declare function clipLon(lon: number): number;
12
12
  export declare function boundboxExtend(bbox: BoundBox, x: number, y: number): void;
13
13
  export declare function boundbox(poly: any, bbox?: BoundBox): BoundBox;
14
14
  export declare function boundboxPoly(bb: BoundBox): any;
15
+ export declare function boundboxEmpty(bb: BoundBox): boolean;
15
16
  export declare function boundboxArea(poly: any): number;
16
17
  export declare function boundboxIntersects(bb1: BoundBox, bb2: BoundBox): boolean;
17
18
  export declare function boundboxContains(bb: BoundBox, x: number, y: number): boolean;
@@ -0,0 +1,2 @@
1
+ import * as G from '../geo/all';
2
+ export declare function polyMapTo(districts: G.GeoFeatureCollection, blocks: G.GeoFeatureCollection): any;
package/lib/geo/geo.ts CHANGED
@@ -113,6 +113,7 @@ export class GeoMultiCollection
113
113
 
114
114
  empty()
115
115
  {
116
+ this.all = { tag: 'all' };
116
117
  this.entries = {};
117
118
  this.hidden = {};
118
119
  this._onChange();
@@ -165,7 +166,8 @@ export class GeoMultiCollection
165
166
 
166
167
  _onChange(): void
167
168
  {
168
- this.all = { tag: 'all' };
169
+ if (this.all.topo || this.all.col || this.all.map)
170
+ this.all = { tag: 'all' };
169
171
  this.stamp++;
170
172
  }
171
173
 
@@ -278,12 +280,17 @@ export class GeoMultiCollection
278
280
  if (id)
279
281
  {
280
282
  if (typeof id === 'string')
281
- this.hidden[id] = true;
283
+ {
284
+ if (! this.hidden[id])
285
+ {
286
+ this.hidden[id] = true;
287
+ this._onChange();
288
+ }
289
+ }
282
290
  else if (Array.isArray(id))
283
- id.forEach((i: string) => { this.hidden[i] = true })
291
+ id.forEach((i: any) => this.hide(i));
284
292
  else if (typeof id === 'object')
285
- for (let p in id) if (id.hasOwnProperty(p)) this.hidden[p] = true;
286
- this._onChange();
293
+ for (let p in id) if (id.hasOwnProperty(p)) this.hide(p);
287
294
  }
288
295
  }
289
296
 
@@ -292,12 +299,17 @@ export class GeoMultiCollection
292
299
  if (id)
293
300
  {
294
301
  if (typeof id === 'string')
295
- delete this.hidden[id];
302
+ {
303
+ if (this.hidden[id])
304
+ {
305
+ delete this.hidden[id];
306
+ this._onChange();
307
+ }
308
+ }
296
309
  else if (Array.isArray(id))
297
- id.forEach((i: string) => { delete this.hidden[i] })
310
+ id.forEach((i: any) => this.show(i))
298
311
  else if (typeof id === 'object')
299
- for (let p in id) if (id.hasOwnProperty(p)) delete this.hidden[p];
300
- this._onChange();
312
+ for (let p in id) if (id.hasOwnProperty(p)) this.show(p);
301
313
  }
302
314
  }
303
315
 
package/lib/poly/all.ts CHANGED
@@ -14,3 +14,4 @@ export * from './topo';
14
14
  export * from './selfintersect';
15
15
  export * from './shamos';
16
16
  export * from './pointinpoly';
17
+ export * from './mapto';
@@ -79,7 +79,7 @@ export function boundbox(poly: any, bbox?: BoundBox): BoundBox
79
79
  }
80
80
 
81
81
  // single point
82
- else
82
+ else if (Array.isArray(poly) && poly.length >= 2)
83
83
  boundboxExtend(bbox, poly[0], poly[1]);
84
84
  }
85
85
 
@@ -91,6 +91,11 @@ export function boundboxPoly(bb: BoundBox): any
91
91
  return [ [ [bb.left, bb.top], [bb.left, bb.bottom], [bb.right, bb.bottom], [bb.right, bb.top], [bb.left, bb.top] ] ];
92
92
  }
93
93
 
94
+ export function boundboxEmpty(bb: BoundBox): boolean
95
+ {
96
+ return !bb || bb.left === undefined || P.polyArea(boundboxPoly(bb)) == 0;
97
+ }
98
+
94
99
  export function boundboxArea(poly: any): number
95
100
  {
96
101
  return P.polyArea(boundboxPoly(boundbox(poly)));
@@ -0,0 +1,64 @@
1
+ import * as G from '../geo/all';
2
+ import * as P from './poly';
3
+ import * as PP from './polypack';
4
+ import * as PL from './polylabel';
5
+ import * as BB from './boundbox';
6
+ import { polyContainsPoint } from './pointinpoly';
7
+
8
+ function setLabels(c: G.GeoFeatureCollection): void
9
+ {
10
+ c.features.forEach(f => {
11
+ if (f.properties.labelx === undefined)
12
+ {
13
+ let {x,y} = PL.polyLabel(f);
14
+ f.properties.labelx = x;
15
+ f.properties.labely = y;
16
+ }
17
+ });
18
+ }
19
+
20
+ // polyMapTo:
21
+ //
22
+ // Given a set of underlying blocks (or precincts), map them to the district (or any other feature)
23
+ // they are contained in.
24
+ //
25
+ // If a block maps to multiple districts or no district, it is left out of the result.
26
+ //
27
+ // Note that the algorithm is to see where the centroid of the block overlaps. So a block
28
+ // could potentially overlap multiple districts and this would return only the one containing
29
+ // the centroid.
30
+ //
31
+ // The thinking is that if you want fine granularity, use real blocks as the base collection.
32
+ // If you provide precincts, you will get a result on precinct granularity.
33
+ //
34
+ // The return value is an object that maps the block feature ids to the district feature id.
35
+ //
36
+
37
+ export function polyMapTo(districts: G.GeoFeatureCollection, blocks: G.GeoFeatureCollection): any
38
+ {
39
+ let map: any = {};
40
+
41
+ // Cache labelx, labely if necessary
42
+ setLabels(blocks);
43
+
44
+ // Cache district boundboxes for quick containment exclusion
45
+ let bbDistricts: BB.BoundBox[] = districts.features.map(f => BB.boundbox(f));
46
+
47
+ // Walk over blocks, mapping centroid to district
48
+ blocks.features.forEach(fBlock => {
49
+ let x = fBlock.properties.labelx;
50
+ let y = fBlock.properties.labely;
51
+
52
+ let fIn: G.GeoFeature[] = [];
53
+ districts.features.forEach((fDistrict: G.GeoFeature, i: number) => {
54
+ if (BB.boundboxContains(bbDistricts[i], x, y))
55
+ if (polyContainsPoint(fDistrict, x, y))
56
+ fIn.push(fDistrict);
57
+ });
58
+
59
+ if (fIn.length == 1)
60
+ map[fBlock.properties.id] = fIn[0].properties.id;
61
+ });
62
+
63
+ return map;
64
+ }
@@ -11,7 +11,7 @@ export function polyContainsPoint(poly: any, x: number, y: number): boolean
11
11
  if (bFound) return;
12
12
  let inside = false;
13
13
  let iEnd = iOffset + (nPoints - 1) * 2;
14
- for (let i = iOffset, j = iEnd; i < iEnd; j = i, i += 2)
14
+ for (let i = iOffset, j = iEnd; i <= iEnd; j = i, i += 2)
15
15
  {
16
16
  let xi = b[i], yi = b[i+1];
17
17
  let xj = b[j], yj = b[j+1];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dra2020/baseclient",
3
- "version": "1.0.26",
3
+ "version": "1.0.29",
4
4
  "description": "Utility functions for Javascript projects.",
5
5
  "main": "dist/baseclient.js",
6
6
  "types": "./dist/all/all.d.ts",