@dra2020/baseclient 1.0.46 → 1.0.49

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.
@@ -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
@@ -313,6 +313,7 @@ export function topoSimplifyCollection(col: any, options?: SimplifyOptions): any
313
313
  if (! bDecided)
314
314
  {
315
315
  let pp = PP.polyPackTopoArcs(testtopo, arcs);
316
+ P.polyRewindRings(pp);
316
317
  if (selfIntersectFast(pp))
317
318
  {
318
319
  keepArcs(topo, oOld.arcs, keepweight);
@@ -321,11 +322,13 @@ export function topoSimplifyCollection(col: any, options?: SimplifyOptions): any
321
322
  else
322
323
  {
323
324
  let {x,y} = intpt(f);
324
- if (x && y && !polyContainsPoint(pp, x, y))
325
+ let d = PL.polyDistance(pp, x, y);
326
+ if (d < 0.00001) // d is negative if outside the polygon, so that qualifies here
325
327
  {
326
- keepArcs(topo, oOld.arcs, keepweight);
327
- nBad++;
328
- log(`topoSimplifyCollection: ${f.properties.id}: increasing feature fidelity because of intpt problem`);
328
+ keepTiny.set(f, f);
329
+ keepArcs(topo, oOld.arcs, 0); // keeps all points to avoid reprocessing these tiny shapes
330
+ nBad++, nTiny++;
331
+ log(`topoSimplifyCollection: ${f.properties.id}: increasing feature fidelity because intpt dist is ${d}`);
329
332
  }
330
333
  }
331
334
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dra2020/baseclient",
3
- "version": "1.0.46",
3
+ "version": "1.0.49",
4
4
  "description": "Utility functions for Javascript projects.",
5
5
  "main": "dist/baseclient.js",
6
6
  "types": "./dist/all/all.d.ts",