@dra2020/baseclient 1.0.171 → 1.0.172

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.
@@ -11204,6 +11204,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
11204
11204
  exports.FsmTopoUnion = void 0;
11205
11205
  exports.topoFromCollection = topoFromCollection;
11206
11206
  exports.topoContiguity = topoContiguity;
11207
+ exports.topoFeatureCacheStats = topoFeatureCacheStats;
11208
+ exports.topoFeatureCacheReset = topoFeatureCacheReset;
11207
11209
  exports.topoToFeature = topoToFeature;
11208
11210
  exports.topoSplice = topoSplice;
11209
11211
  exports.topoToCollection = topoToCollection;
@@ -11305,8 +11307,64 @@ function topoContiguity(topo) {
11305
11307
  });
11306
11308
  return result;
11307
11309
  }
11310
+ /**
11311
+ * Resolved polygon geometry, keyed on the TOPOLOGY OBJECT and held at module level.
11312
+ *
11313
+ * The two things a topology object stands for have opposite natures, and the split matters:
11314
+ *
11315
+ * ARCS are a property of the topology the object appears in. The same object shares different arcs
11316
+ * in different topologies - a precinct and a block do not break at the same places - which is why
11317
+ * arc offsets live in a per-topology WeakMap (topology.packed.objectArcs) rather than on the object.
11318
+ *
11319
+ * GEOMETRY is not. The points are the same wherever the object appears. It may end up PACKED into
11320
+ * different buffers depending on which collection packed it, but the coordinates are identical, and
11321
+ * a collection packed from several buffers is fine by construction (see packCollection).
11322
+ *
11323
+ * So geometry can be cached once, globally, for the life of the object. Module level rather than a
11324
+ * field on the object precisely to avoid the project-then-strip dance that packedarcs still needs
11325
+ * around JSON.stringify in topoToBuffer - a trick that has produced real bugs by leaving values
11326
+ * persisted where they should not be. A WeakMap is invisible to serialization and dies with the
11327
+ * object.
11328
+ *
11329
+ * THE RULE THAT KEEPS THIS CORRECT. Any operation that changes an object's resolved geometry must
11330
+ * produce a NEW object; operations that preserve geometry may share identity. Both hold today: splice
11331
+ * renumbers and subdivides arcs, neither of which moves a point, and it now shares objects
11332
+ * deliberately; simplification goes through topoFromCollection and so builds new objects. DRA
11333
+ * topologies are unquantized, so there is no transform that could decode the same arcs differently.
11334
+ */
11335
+ const builtGeometry = new WeakMap();
11336
+ let cacheHits = 0;
11337
+ let cacheMisses = 0;
11338
+ /** Hits are geometry that would otherwise have been rebuilt from arcs; misses are the rebuilds that
11339
+ * were actually necessary. That distinction is the point - a raw conversion count cannot tell them
11340
+ * apart. Call as Poly.topoFeatureCacheStats() from the console. */
11341
+ function topoFeatureCacheStats() {
11342
+ const total = cacheHits + cacheMisses;
11343
+ return { hits: cacheHits, misses: cacheMisses, pct: total ? Math.round((cacheHits / total) * 100) : 0 };
11344
+ }
11345
+ function topoFeatureCacheReset() { cacheHits = 0; cacheMisses = 0; }
11308
11346
  function topoToFeature(topo, geoid) {
11309
- return correctGeometry(TopoClient.feature(topo, topo.objects[geoid]));
11347
+ const o = topo.objects[geoid];
11348
+ const geometry = o == null ? undefined : builtGeometry.get(o);
11349
+ if (geometry !== undefined) {
11350
+ cacheHits++;
11351
+ // A fresh Feature wrapper each call, matching what TopoClient.feature returns - including sharing
11352
+ // the properties object with the topology object, which it already did. Only the geometry, the
11353
+ // expensive and immutable part, is reused.
11354
+ const f = { type: 'Feature', properties: o.properties == null ? {} : o.properties, geometry };
11355
+ if (o.id != null)
11356
+ f.id = o.id;
11357
+ if (o.bbox != null)
11358
+ f.bbox = o.bbox;
11359
+ return f;
11360
+ }
11361
+ cacheMisses++;
11362
+ const built = correctGeometry(TopoClient.feature(topo, o));
11363
+ // Cached AFTER correctGeometry, so every later reader gets the rewound rings rather than repeating
11364
+ // the correction.
11365
+ if (o != null && built && built.geometry)
11366
+ builtGeometry.set(o, built.geometry);
11367
+ return built;
11310
11368
  }
11311
11369
  function topoSplice(topoarray) {
11312
11370
  if (topoarray)