Разбор данных двоичной точки с помощью 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);

Вероятно, это не тот случай, потому что я планирую транскрибировать типизированные массивы непосредственно в буферную геометрию Three.js на следующем шаге, а сохранение [большого] дополнительного простого массива JS добавляет накладные расходы.


Следующий шаг: Получение точек в Three.js bufferGeometry

Я буду использовать точки в буферной геометрии Three.js для рендеринга облака точек. Я понимаю, что это информирует о выводе, который я хочу получить из предыдущей части.

Это может выглядеть примерно так:

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);

Я знаю, что пока все это очень расплывчато, но я просто блуждаю в темноте, и запись всего этого помогает мне все обдумать.


person Justin J Medina    schedule 18.05.2018    source источник
comment
Похоже, вы указываете свои смещения в битах, а не в байтах... это правильно?   -  person manthrax    schedule 18.05.2018


Ответы (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 и создания облака точек звезд....

Хорошая вещь!

person manthrax    schedule 18.05.2018
comment
Спасибо, @manthrax! Исправил мою опечатку - следствие скопированного псевдокода. Мне было любопытно узнать о битах и ​​байтах для смещения; Я переключился на байты, и это помогло. Что касается headerOffset, то это просто фиксированное значение. У меня возникли проблемы с выяснением того, как различить начальное смещение. Должен ли я искать в буфере первый экземпляр символа новой строки? Я собираюсь разделить этот вопрос на несколько более мелких вопросов. - person Justin J Medina; 18.05.2018