Files
dougal-software/lib/www/server/lib/binary/bundle.js
2025-08-22 16:01:20 +02:00

387 lines
8.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const d3a = require('d3');
const { encode } = require('@dougal/binary');
function bundle (json, opts = {}) {
const { type, geometries, payload } = opts;
const deltas = [];
const values = [];
if (type == 0) {
/* Preplot information sail line points
*
* elem 0: Float32Array Longitude
* elem 1: Float32Array Latitude
* elem 2: Uint8Array Flags: 0x01 point ntba, 0x02 sailline ntba
*/
// Add preplot positions
values.push({
// longitude
key: el => el.geometry.coordinates?.[0],
type: Float32Array
});
values.push({
// latitude
key: el => el.geometry?.coordinates?.[1],
type: Float32Array
});
values.push({
// flags
key: el => (el.sailline_ntba ? 0x02 : 0) | (el.ntba ? 0x01 : 0),
type: Uint8Array
});
return encode.sequential(json, el => el.sailline, el => el.point, deltas, values, type)
} else if (type == 1) {
/* Preplot information source line points
*
* elem 0: Float32Array Longitude
* elem 1: Float32Array Latitude
* elem 2: Uint8Array Flags: 0x01 point ntba, 0x02 sailline ntba
* elem 3: Uint16Array Sailline
*/
// Add preplot positions
values.push({
// longitude
key: el => el.geometry.coordinates?.[0],
type: Float32Array
});
values.push({
// latitude
key: el => el.geometry?.coordinates?.[1],
type: Float32Array
});
values.push({
// flags
key: el => (el.sailline_ntba ? 0x02 : 0) | (el.ntba ? 0x01 : 0),
type: Uint8Array
});
values.push({
// sailline
key: el => el.sailline,
type: Uint16Array
});
return encode.sequential(json, el => el.line, el => el.point, deltas, values, type)
} else if (type == 2) {
/* Raw positions and gun information:
*
* - Δelem 0: BigUint64Array + Int16Array timestamps
* - elem 01: Float32Array, Float32Array Raw positions (x, y)
* - elem 23: Int16Array, Int16Array (×10) Raw position errors (i, j)
* - elem 46: Int8Array, Int8Array, Uint8Array Gun deltas (μ, σ, R)
* - elem 79: Uint16Array, Uint8Array, Uint16Array Gun pressures (μ, σ, R)
* - elem 1012: Gun depths (μ, σ, R)
* - elem 1315: Gun fill times (μ, σ, R)
* - elem 1618: Gun delay (μ, σ, R)
* - elem 19: No fire / autofire (in a single byte)
*/
// Add timestamps
deltas.push({
// Timestamp
key: el => el.tstamp.valueOf(),
baseType: BigUint64Array,
incrType: Int16Array
});
// Add raw positions
values.push({
// longitude
key: el => el.geometryraw?.coordinates?.[0] ?? el.geometry.preplot?.coordinates?.[0],
type: Float32Array
});
values.push({
// latitude
key: el => el.geometryraw?.coordinates?.[1] ?? el.geometry.preplot?.coordinates?.[1],
type: Float32Array
});
// Add raw inline, crossline errors
values.push({
// Crossline
key: el => el.errorraw?.coordinates?.[0] * 100,
type: Float32Array
});
values.push({
// Inline
key: el => el.errorraw?.coordinates?.[1] * 100,
type: Float32Array
});
// Include delta errors info
values.push({
// Average
key: el => (el.meta?.raw?.smsrc?.avg_delta ?? 0) * 10,
type: Int8Array
});
values.push({
// Standard deviation
key: el => (el.meta?.raw?.smsrc?.std_delta ?? 0) * 10,
type: Int8Array
});
values.push({
// Spread
key: el => (el.meta?.raw?.smsrc?.spread ?? 0), // Spread is already × 10
type: Uint8Array
});
// Include pressure info
const press = el => el.meta.raw?.smsrc?.guns?.map( i => i[11] ?? 0) ?? [];
values.push({
// Average
key: el => d3a.mean(press(el)) ?? 0,
type: Uint16Array
});
values.push({
// Standard deviation
key: el => d3a.deviation(press(el)) ?? 0,
type: Uint8Array
});
values.push({
// Spread
key: el => (d3a.max(press(el)) ?? 0) - (d3a.min(press(el)) ?? 0),
type: Uint16Array
});
// Include depth info (× 10)
const depths = el => el.meta.raw?.smsrc?.guns?.map( i => i[10] ?? 0).filter(i => i) ?? [];
values.push({
// Average
key: el => Math.min(d3a.mean(depths(el)) ?? 0, 25.5) * 10,
type: Uint8Array
});
values.push({
// Standard deviation
key: el => (d3a.deviation(depths(el)) ?? 0) * 10,
type: Uint8Array
});
values.push({
// Spread
key: el => ((d3a.max(depths(el)) ?? 0) - (d3a.min(depths(el)) ?? 0)) * 10,
type: Uint8Array
});
// Include fill times
const filltime = el => el.meta.raw?.smsrc?.guns?.map( i => i[13] ?? 0).filter(i => i) ?? [];
values.push({
// Average
key: el => d3a.mean(filltime(el)) ?? 0,
type: Uint16Array
});
values.push({
// Standard deviation
key: el => d3a.deviation(filltime(el)) ?? 0,
type: Uint16Array
});
values.push({
// Spread
key: el => ((d3a.max(filltime(el)) ?? 0) - (d3a.min(filltime(el)) ?? 0)),
type: Uint16Array
});
// Include fire delay
const delay = el => el.meta.raw?.smsrc?.guns?.map( i => i[9] ?? 0).filter(i => i) ?? [];
values.push({
// Average
key: el => (d3a.mean(delay(el)) ?? 0) * 10,
type: Uint16Array
});
values.push({
// Standard deviation
key: el => (d3a.deviation(delay(el)) ?? 0) * 10,
type: Uint16Array
});
values.push({
// Spread
key: el => ((d3a.max(delay(el)) ?? 0) - (d3a.min(delay(el)) ?? 0)) * 10,
type: Uint16Array
});
// Include no fire and autofire (same byte)
values.push({
key: el => (el.meta.raw?.smsrc?.no_fire ?? 0) << 4 | (el.meta.raw?.smsrc?.num_auto ?? 0),
type: Uint8Array
});
return encode.sequential(json, el => el.sequence, el => el.point, deltas, values, type)
} else if (type == 3) {
/* Final positions and raw vs final errors:
*
* - Δelem 0: BigUint64Array + Int16Array timestamps
* - elem 01: Float32Array, Float32Array Final positions (x, y)
* - elem 23: Int16Array, Int16Array (×10) Final - raw position errors (i, j)
*/
// Add timestamps
deltas.push({
// Timestamp
key: el => el.tstamp.valueOf(),
baseType: BigUint64Array,
incrType: Int16Array
});
// Add raw positions
values.push({
// longitude
key: el => el.geometryfinal?.coordinates?.[0],
type: Float32Array
});
values.push({
// latitude
key: el => el.geometryfinal?.coordinates?.[1],
type: Float32Array
});
// Add raw inline, crossline errors relative to preplot
values.push({
// Crossline
key: el => el.errorfinal?.coordinates?.[0] * 100,
type: Int16Array
});
values.push({
// Inline
key: el => el.errorfinal?.coordinates?.[1] * 100,
type: Int16Array
});
// Add raw inline, crossline errors relative to raw
values.push({
// Crossline
key: el => (el.errorfinal?.coordinates?.[0] - el.errorraw?.coordinates?.[0]) * 100,
type: Int16Array
});
values.push({
// Inline
key: el => (el.errorfinal?.coordinates?.[1] - el.errorraw?.coordinates?.[1]) * 100,
type: Int16Array
});
return encode.sequential(json, el => el.sequence, el => el.point, deltas, values, type)
} else if (type == 4) {
/* Bare final positions
*
* Δelem 0: Sequence no. (Uint16Array, Uint8Array)
* elem 01: Float32Array, Float32Array Final positions (x, y)
*
*/
deltas.push({
key: el => el[2],
baseType: Uint16Array,
incrType: Int8Array
});
values.push({
key: el => el[3],
type: Float32Array
});
values.push({
key: el => el[4],
type: Float32Array
});
return encode.sequential(json, el => el[0], el => el[1], deltas, values, type)
} else if (type == 0xa) {
/* 4D comparison data:
*
* elem0: i differences
* elem1: j differences
*
* Note that line/point may not be unique.
*
*/
/*
deltas.push({
key: el => el.baseTStamp,
baseType: BigUint64Array,
incrType: Int32Array
});
deltas.push({
key: el => el.monTStamp,
baseType: BigUint64Array,
incrType: Int32Array
})
*/
values.push({
key: el => el[2],
type: Float32Array
});
values.push({
key: el => el[3],
type: Float32Array
});
/*
values.push({
key: el => el.baseSeq,
type: Uint16Array
});
values.push({
key: el => el.monSeq,
type: Uint16Array
});
*/
return encode.sequential(json, el => el[0], el => el[1], deltas, values, type)
} else if (type == 0xc) {
/* 4D comparison data (reduced sample)
*
* Input is comparison records, i.e.:
* [ [ line, point, δi, δj ], … ]
*
* elem0: line
* elem1: point
* elem2: δi
* elem3: δj
*
* Note that the chunk's `i` and `j` values are not used
*/
values.push({
key: el => el[0],
type: Uint16Array
});
values.push({
key: el => el[1],
type: Uint16Array
});
values.push({
key: el => el[2],
type: Float32Array
});
values.push({
key: el => el[3],
type: Float32Array
});
return encode.sequential(json, el => 0, el => 0, deltas, values, type)
}
}
module.exports = { bundle };