@dra2020/baseclient 1.0.169 → 1.0.171
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/baseclient.js +184 -42
- package/dist/baseclient.js.map +1 -1
- package/dist/ot-js/otsession.d.ts +2 -0
- package/dist/poly/polybin.d.ts +21 -1
- package/dist/poly/polypack.d.ts +35 -1
- package/lib/ot-js/otsession.ts +2 -0
- package/lib/poly/polybin.ts +113 -17
- package/lib/poly/polypack.ts +80 -24
- package/lib/poly/topo.ts +22 -0
- package/package.json +1 -1
package/dist/baseclient.js
CHANGED
|
@@ -8994,19 +8994,79 @@ function unpackString(coder, buf8, buf32, offset) {
|
|
|
8994
8994
|
let s = Util.u82s(coder, buf8, offset + 4, size);
|
|
8995
8995
|
return s;
|
|
8996
8996
|
}
|
|
8997
|
-
function
|
|
8998
|
-
|
|
8999
|
-
|
|
9000
|
-
|
|
9001
|
-
|
|
9002
|
-
|
|
9003
|
-
|
|
9004
|
-
|
|
8997
|
+
function collectOmitted(col, omit) {
|
|
8998
|
+
let saved = [];
|
|
8999
|
+
if (!omit || omit.length === 0)
|
|
9000
|
+
return saved;
|
|
9001
|
+
const take = (o) => {
|
|
9002
|
+
if (!o)
|
|
9003
|
+
return;
|
|
9004
|
+
omit.forEach(name => {
|
|
9005
|
+
if (o[name] !== undefined) {
|
|
9006
|
+
saved.push({ o, name, value: o[name] });
|
|
9007
|
+
delete o[name];
|
|
9008
|
+
}
|
|
9009
|
+
});
|
|
9010
|
+
};
|
|
9011
|
+
take(col);
|
|
9012
|
+
if (col.features)
|
|
9013
|
+
col.features.forEach((f) => { take(f); take(f.properties); });
|
|
9014
|
+
return saved;
|
|
9015
|
+
}
|
|
9016
|
+
function restoreOmitted(saved) {
|
|
9017
|
+
saved.forEach(s => { s.o[s.name] = s.value; });
|
|
9018
|
+
}
|
|
9019
|
+
/**
|
|
9020
|
+
* Serialize a collection to the geopack format.
|
|
9021
|
+
*
|
|
9022
|
+
* The file wants one contiguous coordinate section with every feature's offset an index into it, and
|
|
9023
|
+
* that used to be arranged by requiring the whole collection to already sit in ONE buffer at exactly
|
|
9024
|
+
* those offsets - packCollection simply blitted that buffer across whole. Which held only as long as
|
|
9025
|
+
* nothing had touched the collection since: pack a collection, add a feature, pack again, and the
|
|
9026
|
+
* second pack either redid all the work or produced offsets into a buffer that no longer described it.
|
|
9027
|
+
*
|
|
9028
|
+
* So the coordinates are gathered feature by feature instead. Each one is given its place in the
|
|
9029
|
+
* output, and its floats are copied from wherever they happen to live now - one buffer or several. The
|
|
9030
|
+
* work is the same (every float is copied either way), the assumption is gone, and featurePack is free
|
|
9031
|
+
* to leave already-packed features alone.
|
|
9032
|
+
*
|
|
9033
|
+
* THE FORMAT IS UNCHANGED. Offsets are assigned in feature order from zero, which is exactly what a
|
|
9034
|
+
* single shared buffer produced, so files written before and after this are byte-identical and each
|
|
9035
|
+
* reads under the other.
|
|
9036
|
+
*
|
|
9037
|
+
* `omit` names properties to leave out of the serialized JSON - see the note on collectOmitted.
|
|
9038
|
+
*/
|
|
9039
|
+
function packCollection(coder, col, omit) {
|
|
9040
|
+
// Which features arrive unpacked, so they can be left that way. Packing is how the coordinates get
|
|
9041
|
+
// written; it is not something the caller asked for, and a caller that handed over an unpacked
|
|
9042
|
+
// collection and got a packed one back would find its own coordinates gone. Equally, a caller whose
|
|
9043
|
+
// collection was ALREADY packed must not have it unpacked - that rebuilds every coordinate array
|
|
9044
|
+
// for nothing, which on a large collection is the memory this change exists to stop spending.
|
|
9045
|
+
let wasUnpacked = [];
|
|
9046
|
+
if (col.features)
|
|
9047
|
+
col.features.forEach((f) => { if (!PP.featureIsPacked(f))
|
|
9048
|
+
wasUnpacked.push(f); });
|
|
9049
|
+
PP.featurePack(col);
|
|
9050
|
+
// Where every feature's coordinates are now, and where they will be in the file.
|
|
9051
|
+
let slots = [];
|
|
9052
|
+
let nFloats = 0;
|
|
9053
|
+
col.features.forEach((f) => {
|
|
9054
|
+
const packed = f.geometry ? f.geometry.packed : null;
|
|
9055
|
+
if (!packed)
|
|
9056
|
+
return;
|
|
9057
|
+
slots.push({ packed, buffer: packed.buffer, fromOffset: packed.offset, toOffset: nFloats,
|
|
9058
|
+
length: packed.length });
|
|
9059
|
+
nFloats += packed.length;
|
|
9060
|
+
});
|
|
9061
|
+
// The JSON carries each feature's offset, so the offsets have to be the file's before it is built.
|
|
9062
|
+
// Buffers come out because they are reconstructed on the way back in.
|
|
9063
|
+
slots.forEach(s => { s.packed.offset = s.toOffset; delete s.packed.buffer; });
|
|
9064
|
+
const omitted = collectOmitted(col, omit);
|
|
9065
|
+
let size = 16; // int endianness, offset to coordinates, float endianness
|
|
9005
9066
|
let j = JSON.stringify(col);
|
|
9006
9067
|
size += sizeOfString(coder, j);
|
|
9007
9068
|
size += pad(size, 8);
|
|
9008
|
-
let fullsize = size +
|
|
9009
|
-
// Now pack it
|
|
9069
|
+
let fullsize = size + nFloats * 8;
|
|
9010
9070
|
let ab = new ArrayBuffer(fullsize);
|
|
9011
9071
|
let buf8 = new Uint8Array(ab);
|
|
9012
9072
|
let buf32 = new Int32Array(ab);
|
|
@@ -9022,14 +9082,20 @@ function packCollection(coder, col) {
|
|
|
9022
9082
|
offset += pad(offset, 8);
|
|
9023
9083
|
if (offset != size)
|
|
9024
9084
|
throw 'Oops, packing error.';
|
|
9025
|
-
|
|
9026
|
-
|
|
9027
|
-
|
|
9028
|
-
|
|
9029
|
-
|
|
9030
|
-
|
|
9031
|
-
|
|
9032
|
-
|
|
9085
|
+
const foff = offset >> 3;
|
|
9086
|
+
slots.forEach(s => {
|
|
9087
|
+
const src = s.buffer;
|
|
9088
|
+
if (!src)
|
|
9089
|
+
return; // no coordinates: points, and features with no geometry
|
|
9090
|
+
let to = foff + s.toOffset;
|
|
9091
|
+
let from = s.fromOffset;
|
|
9092
|
+
for (let i = 0; i < s.length; i++)
|
|
9093
|
+
buf64[to++] = src[from++];
|
|
9094
|
+
});
|
|
9095
|
+
// Put the collection back exactly as it was found.
|
|
9096
|
+
slots.forEach(s => { s.packed.offset = s.fromOffset; s.packed.buffer = s.buffer; });
|
|
9097
|
+
restoreOmitted(omitted);
|
|
9098
|
+
wasUnpacked.forEach(f => PP.featureUnpack(f));
|
|
9033
9099
|
return ab;
|
|
9034
9100
|
}
|
|
9035
9101
|
function reverse(buf8, s, n) {
|
|
@@ -9749,7 +9815,9 @@ exports.polyPackTopoArcs = polyPackTopoArcs;
|
|
|
9749
9815
|
exports.polyPack = polyPack;
|
|
9750
9816
|
exports.polyPackCopy = polyPackCopy;
|
|
9751
9817
|
exports.polyUnpack = polyUnpack;
|
|
9818
|
+
exports.featureIsPacked = featureIsPacked;
|
|
9752
9819
|
exports.featurePackSize = featurePackSize;
|
|
9820
|
+
exports.repairPackedBuffers = repairPackedBuffers;
|
|
9753
9821
|
exports.featurePack = featurePack;
|
|
9754
9822
|
exports.featureUnpack = featureUnpack;
|
|
9755
9823
|
exports.featureUnpackTemporarily = featureUnpackTemporarily;
|
|
@@ -10038,12 +10106,55 @@ function polyUnpack(prepack) {
|
|
|
10038
10106
|
}
|
|
10039
10107
|
return coords.length > 1 ? coords : coords[0];
|
|
10040
10108
|
}
|
|
10109
|
+
/** Whether this feature's coordinates are already in packed form. */
|
|
10110
|
+
function featureIsPacked(f) {
|
|
10111
|
+
return !!(f && f.geometry && f.geometry.packed !== undefined);
|
|
10112
|
+
}
|
|
10113
|
+
/**
|
|
10114
|
+
* Floats this feature would ADD to a buffer if packed now: zero if it is already packed, and zero for
|
|
10115
|
+
* the shapes that carry no packed coordinates at all (points, and features with no geometry).
|
|
10116
|
+
*/
|
|
10041
10117
|
function featurePackSize(f) {
|
|
10118
|
+
if (featureIsPacked(f))
|
|
10119
|
+
return 0;
|
|
10042
10120
|
if (f && f.geometry && f.geometry.coordinates && f.geometry.type !== 'Point')
|
|
10043
10121
|
return polyPackSize(f.geometry.coordinates);
|
|
10044
10122
|
return 0;
|
|
10045
10123
|
}
|
|
10046
|
-
|
|
10124
|
+
/**
|
|
10125
|
+
* Repair packed buffers that have been through JSON and come back as plain objects.
|
|
10126
|
+
*
|
|
10127
|
+
* A Float64Array does not survive JSON.stringify/parse - it comes back as {"0":n,"1":n,...} - so a
|
|
10128
|
+
* collection that has been round-tripped through JSON while packed arrives with something that looks
|
|
10129
|
+
* packed but cannot be read. This puts the numbers back into a real Float64Array.
|
|
10130
|
+
*
|
|
10131
|
+
* Split out of featurePack, where it used to sit inline in the middle of the packing path, because it
|
|
10132
|
+
* is not packing: it is a repair for a specific way collections arrive damaged, it applies to
|
|
10133
|
+
* collections that are ALREADY packed, and burying it inside meant featurePack had to return early
|
|
10134
|
+
* with a different kind of value to signal it had happened. Returns whether anything was repaired.
|
|
10135
|
+
*/
|
|
10136
|
+
function repairPackedBuffers(col) {
|
|
10137
|
+
if (!col || !col.features || col.features.length === 0)
|
|
10138
|
+
return false;
|
|
10139
|
+
let ff = col.features[0];
|
|
10140
|
+
if (!featureIsPacked(ff) || ArrayBuffer.isView(ff.geometry.packed.buffer))
|
|
10141
|
+
return false;
|
|
10142
|
+
// One buffer is shared by every feature of a collection, so recovering the first recovers all.
|
|
10143
|
+
let o = ff.geometry.packed.buffer;
|
|
10144
|
+
let b = new Float64Array(Util.countKeys(o));
|
|
10145
|
+
for (const i in o)
|
|
10146
|
+
b[Number(i)] = o[i];
|
|
10147
|
+
col.features.forEach((f) => { if (featureIsPacked(f))
|
|
10148
|
+
f.geometry.packed.buffer = b; });
|
|
10149
|
+
return true;
|
|
10150
|
+
}
|
|
10151
|
+
/**
|
|
10152
|
+
* Pack ONE feature's coordinates, into `prepack`'s buffer when given one. Returns the PolyPack that
|
|
10153
|
+
* describes where they went, which is how the collection path below advances its offset.
|
|
10154
|
+
*
|
|
10155
|
+
* Internal: featurePack is the public entry and always answers with the object it was handed.
|
|
10156
|
+
*/
|
|
10157
|
+
function packOne(f, prepack) {
|
|
10047
10158
|
if (f && f.type === 'Feature') {
|
|
10048
10159
|
if (f.geometry && f.geometry.type === 'Point')
|
|
10049
10160
|
return prepack ? { offset: prepack.offset, length: 0, buffer: prepack.buffer } : { offset: 0, length: 0, buffer: null };
|
|
@@ -10057,41 +10168,52 @@ function featurePack(f, prepack) {
|
|
|
10057
10168
|
}
|
|
10058
10169
|
return f.geometry.packed;
|
|
10059
10170
|
}
|
|
10171
|
+
return null;
|
|
10172
|
+
}
|
|
10173
|
+
/**
|
|
10174
|
+
* Ensure a feature or collection is fully packed, and answer with the object handed in.
|
|
10175
|
+
*
|
|
10176
|
+
* ALWAYS the same object, whatever was passed and whatever it had to do. The previous signature
|
|
10177
|
+
* returned three different things - a PolyPack for a feature, a PolyPack for a collection it packed,
|
|
10178
|
+
* and the collection itself for one that was already packed - so a caller could not use the result
|
|
10179
|
+
* without knowing which case it had fallen into, and every caller but one ignored it. The one that
|
|
10180
|
+
* did not assigned a PolyPack to geometry.coordinates.
|
|
10181
|
+
*
|
|
10182
|
+
* A collection packs its UNPACKED features into one new buffer and leaves packed ones where they are.
|
|
10183
|
+
* That is what stops a second call re-packing work already done, which for a large collection means
|
|
10184
|
+
* allocating and copying the whole coordinate set again for nothing. Features already packed keep
|
|
10185
|
+
* whatever buffer they were in - the collection may end up spanning several - and packCollection no
|
|
10186
|
+
* longer minds, because it copies feature by feature rather than assuming one buffer holds them all.
|
|
10187
|
+
*/
|
|
10188
|
+
function featurePack(f) {
|
|
10189
|
+
if (f && f.type === 'Feature') {
|
|
10190
|
+
if (!featureIsPacked(f))
|
|
10191
|
+
packOne(f);
|
|
10192
|
+
return f;
|
|
10193
|
+
}
|
|
10060
10194
|
else if (f && f.type === 'FeatureCollection' && f.features) {
|
|
10061
|
-
|
|
10062
|
-
if (f.features.length == 0)
|
|
10195
|
+
if (f.features.length === 0)
|
|
10063
10196
|
return f;
|
|
10064
|
-
//
|
|
10065
|
-
|
|
10066
|
-
|
|
10067
|
-
// Already packed
|
|
10068
|
-
if (ArrayBuffer.isView(ff.geometry.packed.buffer))
|
|
10069
|
-
return f;
|
|
10070
|
-
// Improperly packed (buffer converted to object - convert back to buffer
|
|
10071
|
-
let o = ff.geometry.packed.buffer;
|
|
10072
|
-
let b = new Float64Array(Util.countKeys(o));
|
|
10073
|
-
for (const i in o)
|
|
10074
|
-
b[Number(i)] = o[i];
|
|
10075
|
-
f.features.forEach((ff) => ff.geometry.packed.buffer = b);
|
|
10076
|
-
return f;
|
|
10077
|
-
}
|
|
10078
|
-
// Allocate one large buffer
|
|
10197
|
+
// Before measuring anything: a collection in this state looks packed but is not readable.
|
|
10198
|
+
repairPackedBuffers(f);
|
|
10199
|
+
// One buffer for everything still unpacked. Sized first so it is allocated exactly once.
|
|
10079
10200
|
let nFloats = 0;
|
|
10080
10201
|
let i;
|
|
10081
10202
|
for (i = 0; i < f.features.length; i++)
|
|
10082
10203
|
nFloats += featurePackSize(f.features[i]);
|
|
10083
|
-
let
|
|
10084
|
-
|
|
10085
|
-
// Now pack
|
|
10204
|
+
let prepack = { offset: 0, length: nFloats,
|
|
10205
|
+
buffer: new Float64Array(new ArrayBuffer(nFloats * 8)) };
|
|
10086
10206
|
for (i = 0; i < f.features.length; i++) {
|
|
10087
|
-
|
|
10207
|
+
if (featureIsPacked(f.features[i]))
|
|
10208
|
+
continue;
|
|
10209
|
+
let postpack = packOne(f.features[i], prepack);
|
|
10088
10210
|
prepack.offset += postpack ? postpack.length : 0;
|
|
10089
10211
|
}
|
|
10090
10212
|
if (prepack.offset != nFloats)
|
|
10091
10213
|
throw 'oops, packing bug';
|
|
10092
|
-
return
|
|
10214
|
+
return f;
|
|
10093
10215
|
}
|
|
10094
|
-
return
|
|
10216
|
+
return f;
|
|
10095
10217
|
}
|
|
10096
10218
|
function featureUnpack(f) {
|
|
10097
10219
|
if (f && f.geometry && f.geometry.packed !== undefined) {
|
|
@@ -11099,6 +11221,7 @@ const TopoServer = __importStar(__webpack_require__(/*! @dra2020/topojson-server
|
|
|
11099
11221
|
const TopoSimplify = __importStar(__webpack_require__(/*! @dra2020/topojson-simplify */ "@dra2020/topojson-simplify"));
|
|
11100
11222
|
const Util = __importStar(__webpack_require__(/*! ../util/all */ "./lib/util/all.ts"));
|
|
11101
11223
|
const FSM = __importStar(__webpack_require__(/*! ../fsm/all */ "./lib/fsm/all.ts"));
|
|
11224
|
+
const G = __importStar(__webpack_require__(/*! ../geo/all */ "./lib/geo/all.ts"));
|
|
11102
11225
|
const P = __importStar(__webpack_require__(/*! ./poly */ "./lib/poly/poly.ts"));
|
|
11103
11226
|
const PP = __importStar(__webpack_require__(/*! ./polypack */ "./lib/poly/polypack.ts"));
|
|
11104
11227
|
const PL = __importStar(__webpack_require__(/*! ./polylabel */ "./lib/poly/polylabel.ts"));
|
|
@@ -11121,6 +11244,18 @@ function getGEOID(f) {
|
|
|
11121
11244
|
function topoFromCollection(col) {
|
|
11122
11245
|
if (col == null)
|
|
11123
11246
|
return null;
|
|
11247
|
+
// The objects map below is keyed per feature, so every feature needs an id that is present, unique
|
|
11248
|
+
// and a string - and the topology is meaningless without one. A collection that has no usable id
|
|
11249
|
+
// would otherwise key EVERY feature to undefined and collapse the whole thing onto a single object,
|
|
11250
|
+
// silently: the topology comes back with one object in it and nothing anywhere reports a problem.
|
|
11251
|
+
// An imported GeoJSON file is the ordinary way to arrive here in that state, because GeoJSON puts a
|
|
11252
|
+
// feature's id at the TOP level and most exporters write it there rather than in properties.
|
|
11253
|
+
//
|
|
11254
|
+
// geoEnsureID also NORMALIZES, which matters as much: it copies GEOID/GEOID10 into properties.id,
|
|
11255
|
+
// so the key used here is properties.id whatever the collection called it. Callers that read the
|
|
11256
|
+
// objects map back - topoSimplifyCollection does, by properties.id - would otherwise be looking up
|
|
11257
|
+
// a key this function never used.
|
|
11258
|
+
G.geoEnsureID(col);
|
|
11124
11259
|
let save = PP.featureUnpackTemporarily(col);
|
|
11125
11260
|
let prop = getGEOID(col);
|
|
11126
11261
|
let objects = {};
|
|
@@ -11305,6 +11440,13 @@ function topoSimplifyCollection(col, options) {
|
|
|
11305
11440
|
col.features.forEach((f) => {
|
|
11306
11441
|
let oOld = topo.objects[f.properties.id];
|
|
11307
11442
|
let oNew = testtopo.objects[f.properties.id];
|
|
11443
|
+
// Every feature must have found its own object. topoFromCollection guarantees it, so reaching
|
|
11444
|
+
// here means the keying has diverged - and the two ways that goes wrong are both silent or
|
|
11445
|
+
// worse: a collection with no ids used to put every feature on ONE object and come back
|
|
11446
|
+
// simplified to a single feature, and a mismatched key dereferences undefined a few lines
|
|
11447
|
+
// below. Neither is worth guessing through, so stop and leave the collection alone.
|
|
11448
|
+
if (oOld === undefined || oNew === undefined)
|
|
11449
|
+
throw `topoSimplifyCollection: feature id ${f.properties.id} has no topology object`;
|
|
11308
11450
|
// Ignore points
|
|
11309
11451
|
if (f.geometry && f.geometry.type === 'Point')
|
|
11310
11452
|
keepTiny.set(f, f);
|