Разбор двоичных данных точек с помощью JavaScript
Эта проблема
Я получаю двоичные данные от API, который описывает группу цветных точек в трехмерном пространстве. Цель состоит в том, чтобы проанализировать точки и использовать их в буферной геометрии в Three.js.
Я немного над головой, когда дело доходит до работы с двоичными данными, поэтому мне нужна ваша помощь.
О двоичных данных, поступающих из API:
Двоичные данные начинаются с заголовка в следующем формате:
HTTP/1.1 200 OK
Content-Length: 13632 // varies depending on the query
Заголовок сопровождается пустой строкой, а затем эти точки в этом формате:
Каждые 32 байта:
- X: двойной (8 байт)
- Y: двойной (8 байт)
- Z: двойной (8 байт)
- R: беззнаковый символ (1 байт)
- G: беззнаковый символ (1 байт)
- B: беззнаковый символ (1 байт)
- 5 мусорных байт для заполнения оставшегося пространства
Где я сейчас нахожусь:
Предположим, что переменная binaryPoints содержит необработанные двоичные данные из API. Насколько я понимаю, я должен сначала добавить данные в arrayBuffer с размером байта 32 (размер каждой точки). Затем я добавляю этот буфер к объекту DataView, чтобы манипулировать им.
// create a 32-byte arrayBuffer (each point takes up 32 bytes)
const buffer = await binaryPoints.arrayBuffer(32);
// create a dataview of the buffer to read the points
const data = new DataView(buffer);
Так что у меня еще немногое. Я думаю, что мне нужно учесть пространство, занимаемое заголовком, путем реализации смещения, и я хотел бы получить количество точек из заголовка.
// temporary hard-set values
const numPoints = 1000;
const offsetFromHeader = 100; // bits
Из некоторых примеров и других вопросов SO, которые я видел, я полагаю, что я должен перебирать буфер по 32 байта за раз, считывая значения xyzrgb по ходу работы. Это может выглядеть примерно так:
// offset is in bits, increases by 256 each iteration (32*8)
for (var i=0, offset=offsetFromHeader; i<numPoints; i++, offset += 256) {
// Go through each xyz value, using Float64Array (double) to store that value
const xFloat64View = data.getFloat64Array(offset);
const yFloat64View = data.getFloat64Array(offset + 64);
const zFloat64View = data.getFloat64Array(offset + 128);
// Go through each rgb value, using Uint8Array (1 byte unsigned int) to store that value
const rUint8View = data.getUint8Array(offset + 192);
const gUint8View = data.getUint8Array(offset + 200);
const bUint8View = data.getUint8Array(offset + 208);
// just ignore the final bits
}
... но, по правде говоря, я не смог понять, что делать с информацией, когда дошел до этого момента. В некоторых примерах, которые я нашел, цикл проходит через двоичные данные только с одним типом информации (в моем случае это было бы так, как если бы у меня было только значение X).
Должен ли я создать новый простой массив точек javascript и добавить следующие значения:
// psuedo code
var points = [];
// in the loop
points[i].x = data.getFloat64Array(offset);
Вероятно, это не так, потому что на следующем шаге я планирую транскрибировать типизированные массивы непосредственно в bufferGeometries Three.js, а сохранение [большого] дополнительного простого массива JS добавляет накладные расходы.
Следующий шаг: получение баллов в Three.js bufferGeometry
Я буду использовать точки в bufferGeometry Three.js для рендеринга pointcloud. Я понимаю, что это сообщает вывод, который я хочу из предыдущей части.
Это может выглядеть примерно так:
const bufferGeometry = new THREE.BufferGeometry();
let vertices = new Float32Array(); // xyz
let colors = new Float32Array(); // rgb
bufferGeometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
bufferGeometry.addAttribute('color', new THREE.BufferAttribute(colors, 3));
const points = new THREE.Points(bufferGeometry, material);
scene.add(points);
Я знаю, что пока все это очень свободно, но я просто брожу в темноте, и все это помогает мне обдумать это.
1 ответ
Вы получили удвоенный gUint8View.. второй должен быть bUint8View..
Я думаю, что вы хотите API DataView... Тогда вы можете просто сделать, как...
var x= view.getFloat64(0);
var y= view.getFloat64(8);
var z= view.getFloat64(16);
var r = view.getUInt8(24);
var g = view.getUInt8(25);
var v = view.getUInt8(26);
Кроме того... вы уверены, что заголовок "100 бит" или вы имеете в виду байты? Кажется странным, что ваш источник данных будет начинаться со странной не 8-битной границы, что усложнит синтаксический анализ.
ТРЕТЬЯ сторона вашего кода выглядит примерно правильно.
Вы на правильном пути:) Я только что сделал подобное приложение, чтобы разобрать каталог звезд HYG и создать облако точек звезд....
Хорошая вещь!