mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 10:27:09 +00:00
387 lines
8.7 KiB
JavaScript
387 lines
8.7 KiB
JavaScript
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 0‒1: Float32Array, Float32Array – Raw positions (x, y)
|
||
* - elem 2‒3: Int16Array, Int16Array – (×10) Raw position errors (i, j)
|
||
* - elem 4‒6: Int8Array, Int8Array, Uint8Array – Gun deltas (μ, σ, R)
|
||
* - elem 7‒9: Uint16Array, Uint8Array, Uint16Array – Gun pressures (μ, σ, R)
|
||
* - elem 10‒12: Gun depths (μ, σ, R)
|
||
* - elem 13‒15: Gun fill times (μ, σ, R)
|
||
* - elem 16‒18: 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 0‒1: Float32Array, Float32Array – Final positions (x, y)
|
||
* - elem 2‒3: 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 0‒1: 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 };
|