@dra2020/baseclient 1.0.47 → 1.0.50

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.
@@ -8,6 +8,7 @@ export declare function topoToFeature(topo: Topo, geoid: string): any;
8
8
  export declare function topoToCollection(topo: Topo): any;
9
9
  export interface SimplifyOptions {
10
10
  minArea?: number;
11
+ log?: boolean;
11
12
  }
12
13
  export declare function topoSimplifyCollection(col: any, options?: SimplifyOptions): any;
13
14
  export declare function topoMerge(topo: Topo, geoids: string[]): any;
@@ -21,16 +21,66 @@ export function polyDistance(poly: any, x: number, y: number): number
21
21
  let pp = P.polyNormalize(poly);
22
22
  if (pp == null) return 0;
23
23
 
24
- let forEachPointPair = (iter: any) => {
25
- PP.polyPackEachRing(pp, (b: Float64Array, iPoly, iRing: number, iOffset: number, nPoints: number) => {
26
- let iFirst = iOffset;
27
- let iLast = iOffset + nPoints * 2;
28
- let iSecond = iLast - 2;
29
- for (; iFirst < iLast; iSecond = iFirst, iFirst += 2)
30
- iter(iPoly, iRing, b[iFirst], b[iFirst+1], b[iSecond], b[iSecond+1]);
31
- });
32
- };
33
- return pointToPolygonDist(x, y, forEachPointPair);
24
+ // First find if it is contained in one of the outer polygons, or outside all outer polygons
25
+ let iContaining = -1;
26
+ let maxOutside = - Infinity;
27
+ let minInside = Infinity;
28
+ let noholes = true;
29
+ PP.polyPackEachRing(pp, (b: Float64Array, iPoly: number, iRing: number, iOffset: number, nPoints: number) => {
30
+ // If we have determined we are inside this polygon, keep track of whether it has holes
31
+ if (iContaining == iPoly && iRing > 0)
32
+ noholes = false;
33
+ // Don't process rings
34
+ if (iRing > 0) return;
35
+ // OK, get distance
36
+ let forEachPointPair = (iter: any) => {
37
+ PP.polyPackEachRing(pp, (b: Float64Array, iInteriorPoly: number, iRing: number, iOffset: number, nPoints: number) => {
38
+ if (iRing || iInteriorPoly != iPoly) return;
39
+ let iFirst = iOffset;
40
+ let iLast = iOffset + nPoints * 2;
41
+ let iSecond = iLast - 2;
42
+ for (; iFirst < iLast; iSecond = iFirst, iFirst += 2)
43
+ iter(b[iFirst], b[iFirst+1], b[iSecond], b[iSecond+1]);
44
+ });
45
+ };
46
+ let dist = pointToPolygonDist(x, y, forEachPointPair);
47
+ // If inside, is it closest inside (deal with multipolygons that self-contain - think filled donut)
48
+ if (dist > 0 && dist < minInside)
49
+ {
50
+ iContaining = iPoly;
51
+ minInside = dist;
52
+ noholes = true;
53
+ }
54
+ else if (dist < 0)
55
+ maxOutside = Math.max(maxOutside, dist);
56
+ });
57
+ if (iContaining < 0)
58
+ return maxOutside;
59
+ if (noholes)
60
+ return minInside;
61
+
62
+ // OK, now need to worry about holes in the polygon it is contained in
63
+ PP.polyPackEachRing(pp, (b: Float64Array, iPoly: number, iRing: number, iOffset: number, nPoints: number) => {
64
+ // Only want to look at the holes for the containing polygon
65
+ if (iPoly != iContaining || iRing == 0) return;
66
+ // Compute distance to those holes
67
+ let forEachPointPair = (iter: any) => {
68
+ PP.polyPackEachRing(pp, (b: Float64Array, iInteriorPoly: number, iRing: number, iOffset: number, nPoints: number) => {
69
+ if (iInteriorPoly != iContaining || iRing == 0) return;
70
+ let iFirst = iOffset;
71
+ let iLast = iOffset + nPoints * 2;
72
+ let iSecond = iLast - 2;
73
+ for (; iFirst < iLast; iSecond = iFirst, iFirst += 2)
74
+ iter(b[iFirst], b[iFirst+1], b[iSecond], b[iSecond+1]);
75
+ });
76
+ };
77
+ // Negate distance since dealing with holes
78
+ let dist = - pointToPolygonDist(x, y, forEachPointPair);
79
+ // We take the min to either get a negative value (inside hole) or a smaller positive value
80
+ // (outside hole but close to hole boundary).
81
+ minInside = Math.min(minInside, dist);
82
+ });
83
+ return minInside;
34
84
  }
35
85
 
36
86
  //
@@ -69,7 +119,7 @@ export function polyLabel(poly: any, precision?: number, debug?: boolean): PolyL
69
119
  let iLast = iOffset + nPoints * 2;
70
120
  let iSecond = iLast - 2;
71
121
  for (; iFirst < iLast; iSecond = iFirst, iFirst += 2)
72
- iter(iPoly, iRing, b[iFirst], b[iFirst+1], b[iSecond], b[iSecond+1]);
122
+ iter(b[iFirst], b[iFirst+1], b[iSecond], b[iSecond+1]);
73
123
  });
74
124
  };
75
125
 
@@ -164,38 +214,15 @@ class Cell
164
214
  // signed distance from point to polygon outline (negative if point is outside)
165
215
  function pointToPolygonDist(x: number, y: number, forEachPointPair: any): number
166
216
  {
167
- let iPolyLast = -1;
168
- let iRingLast = -1;
169
217
  let inside = false;
170
- let thisInside = false;
171
- let useInside = false;
172
- let isHole = false;
173
- let minDistSq: number = Infinity;
218
+ let minDistSq = Infinity;
174
219
 
175
- forEachPointPair((iPoly: number, iRing: number, ax: number, ay: number, bx: number, by: number) => {
176
- if (iPoly != iPolyLast || iRing != iRingLast)
177
- {
178
- if (useInside)
179
- inside = isHole ? ! thisInside : thisInside;
180
- iPolyLast = iPoly;
181
- iRingLast = iRing;
182
- thisInside = false;
183
- useInside = false;
184
- isHole = false;
185
- }
220
+ forEachPointPair((ax: number, ay: number, bx: number, by: number) => {
186
221
  if ((ay > y !== by > y) && (x < (bx - ax) * (y - ay) / (by - ay) + ax))
187
- thisInside = !thisInside;
222
+ inside = !inside;
188
223
 
189
- let thisDistSq = getSegDistSq(x, y, ax, ay, bx, by);
190
- if (thisDistSq < minDistSq)
191
- {
192
- minDistSq = thisDistSq;
193
- useInside = true;
194
- isHole = iRing != 0;
195
- }
224
+ minDistSq = Math.min(minDistSq, getSegDistSq(x, y, ax, ay, bx, by));
196
225
  });
197
- if (useInside)
198
- inside = isHole ? ! thisInside : thisInside;
199
226
 
200
227
  return (inside ? 1 : -1) * Math.sqrt(minDistSq);
201
228
  }
@@ -209,7 +236,7 @@ function getCentroidCell(forEachPointPair: any): Cell
209
236
  let fx: number;
210
237
  let fy: number;
211
238
 
212
- forEachPointPair((iPoly: number, iRing: number, ax: number, ay: number, bx: number, by: number) => {
239
+ forEachPointPair((ax: number, ay: number, bx: number, by: number) => {
213
240
  if (fx === undefined) fx = ax, fy = ay;
214
241
  let f: number = ax * by - bx * ay;
215
242
  x += (ax + bx) * f;
package/lib/poly/topo.ts CHANGED
@@ -215,13 +215,14 @@ function intpt(f: any): { x: number, y: number }
215
215
  export interface SimplifyOptions
216
216
  {
217
217
  minArea?: number,
218
+ log?: boolean,
218
219
  }
219
220
 
220
221
  const DefaultSimplifyOptions: SimplifyOptions = { minArea: 500 };
221
222
 
222
- function log(s: string): void
223
+ function log(emitlog: boolean, s: string): void
223
224
  {
224
- console.log(s);
225
+ if (emitlog) console.log(s);
225
226
  }
226
227
 
227
228
  //
@@ -248,10 +249,10 @@ export function topoSimplifyCollection(col: any, options?: SimplifyOptions): any
248
249
  let elapsedTotal = new Util.Elapsed();
249
250
  let elapsed = new Util.Elapsed();
250
251
  let topo = topoFromCollection(col);
251
- log(`topoSimplifyCollection: fromCollection: ${Math.round(elapsed.ms())}ms`);
252
+ log(options.log, `topoSimplifyCollection: fromCollection: ${Math.round(elapsed.ms())}ms`);
252
253
  elapsed.start();
253
254
  topo = TopoSimplify.presimplify(topo, TopoSimplify['sphericalTriangleArea']);
254
- log(`topoSimplifyCollection: presimplify: ${Math.round(elapsed.ms())}ms`);
255
+ log(options.log, `topoSimplifyCollection: presimplify: ${Math.round(elapsed.ms())}ms`);
255
256
  elapsed.start();
256
257
 
257
258
  // Keep iterating on removing simplification from degenerate shapes
@@ -313,6 +314,7 @@ export function topoSimplifyCollection(col: any, options?: SimplifyOptions): any
313
314
  if (! bDecided)
314
315
  {
315
316
  let pp = PP.polyPackTopoArcs(testtopo, arcs);
317
+ P.polyRewindRings(pp);
316
318
  if (selfIntersectFast(pp))
317
319
  {
318
320
  keepArcs(topo, oOld.arcs, keepweight);
@@ -321,24 +323,25 @@ export function topoSimplifyCollection(col: any, options?: SimplifyOptions): any
321
323
  else
322
324
  {
323
325
  let {x,y} = intpt(f);
324
- if (x && y && !polyContainsPoint(pp, x, y))
326
+ let d = PL.polyDistance(pp, x, y);
327
+ if (d < 0.00001) // d is negative if outside the polygon, so that qualifies here
325
328
  {
326
329
  keepTiny.set(f, f);
327
330
  keepArcs(topo, oOld.arcs, 0); // keeps all points to avoid reprocessing these tiny shapes
328
331
  nBad++, nTiny++;
329
- log(`topoSimplifyCollection: ${f.properties.id}: increasing feature fidelity because of intpt problem`);
332
+ log(options.log, `topoSimplifyCollection: ${f.properties.id}: increasing feature fidelity because intpt dist is ${d}`);
330
333
  }
331
334
  }
332
335
  }
333
336
  }
334
337
  });
335
- log(`topoSimplifyCollection: pass ${nTries}: ${nBad} (${nTiny} tiny) of ${col.features.length} features are degenerate`);
338
+ log(options.log, `topoSimplifyCollection: pass ${nTries}: ${nBad} (${nTiny} tiny) of ${col.features.length} features are degenerate`);
336
339
 
337
340
  // If not making progress, keep more points
338
341
  if (nBad >= nBadLast)
339
342
  {
340
343
  keepweight /= 10;
341
- log(`topoSimplifyCollection: pass ${nTries}: reducing weight limit to ${keepweight}`);
344
+ log(options.log, `topoSimplifyCollection: pass ${nTries}: reducing weight limit to ${keepweight}`);
342
345
  }
343
346
  nBadLast = nBad;
344
347
 
@@ -354,7 +357,7 @@ export function topoSimplifyCollection(col: any, options?: SimplifyOptions): any
354
357
  nTries++;
355
358
  }
356
359
 
357
- log(`topoSimplifyCollection: total elapsed time: ${bigTimeString(elapsedTotal.ms())}`);
360
+ log(options.log, `topoSimplifyCollection: total elapsed time: ${bigTimeString(elapsedTotal.ms())}`);
358
361
 
359
362
  return col;
360
363
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dra2020/baseclient",
3
- "version": "1.0.47",
3
+ "version": "1.0.50",
4
4
  "description": "Utility functions for Javascript projects.",
5
5
  "main": "dist/baseclient.js",
6
6
  "types": "./dist/all/all.d.ts",