compose.ts 4.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * Taken/adapted from DensityServer (https://github.com/dsehnal/DensityServer)
  5. *
  6. * @author David Sehnal <david.sehnal@gmail.com>
  7. */
  8. import * as Data from './data-model';
  9. import * as Box from '../algebra/box';
  10. import * as Coords from '../algebra/coordinate';
  11. import { createTypedArrayBufferContext, getElementByteSize, readTypedArray } from '../../../../mol-io/common/typed-array';
  12. export async function compose(query: Data.QueryContext.Data) {
  13. for (const block of query.samplingInfo.blocks) {
  14. await fillBlock(query, block);
  15. }
  16. }
  17. async function readBlock(query: Data.QueryContext.Data, coord: Coords.Grid<'Block'>, blockBox: Box.Fractional): Promise<Data.BlockData> {
  18. const { valueType, blockSize } = query.data.header;
  19. const elementByteSize = getElementByteSize(valueType);
  20. const numChannels = query.data.header.channels.length;
  21. const blockSampleCount = Box.dimensions(Box.fractionalToGrid(blockBox, query.samplingInfo.sampling.dataDomain));
  22. const size = numChannels * blockSampleCount[0] * blockSampleCount[1] * blockSampleCount[2];
  23. const byteSize = elementByteSize * size;
  24. const dataSampleCount = query.data.header.sampling[query.samplingInfo.sampling.index].sampleCount;
  25. const buffer = createTypedArrayBufferContext(size, valueType);
  26. const byteOffset = query.samplingInfo.sampling.byteOffset
  27. + elementByteSize * numChannels * blockSize
  28. * (blockSampleCount[1] * blockSampleCount[2] * coord[0]
  29. + dataSampleCount[0] * blockSampleCount[2] * coord[1]
  30. + dataSampleCount[0] * dataSampleCount[1] * coord[2]);
  31. const values = await readTypedArray(buffer, query.data.file, byteOffset, byteSize, 0);
  32. return {
  33. sampleCount: blockSampleCount,
  34. values
  35. };
  36. }
  37. function fillData(query: Data.QueryContext.Data, blockData: Data.BlockData, blockGridBox: Box.Grid<'BlockGrid'>, queryGridBox: Box.Grid<'Query'>) {
  38. const source = blockData.values;
  39. const { sizeX: tSizeH, sizeXY: tSizeHK } = Coords.gridMetrics(query.samplingInfo.gridDomain.sampleCount);
  40. const { sizeX: sSizeH, sizeXY: sSizeHK } = Coords.gridMetrics(blockData.sampleCount);
  41. const offsetTarget = queryGridBox.a[0] + queryGridBox.a[1] * tSizeH + queryGridBox.a[2] * tSizeHK;
  42. const [maxH, maxK, maxL] = Box.dimensions(blockGridBox);
  43. for (let channelIndex = 0, _ii = query.data.header.channels.length; channelIndex < _ii; channelIndex++) {
  44. const target = query.values[channelIndex];
  45. const offsetSource = channelIndex * blockGridBox.a.domain.sampleVolume
  46. + blockGridBox.a[0] + blockGridBox.a[1] * sSizeH + blockGridBox.a[2] * sSizeHK;
  47. for (let l = 0; l < maxL; l++) {
  48. for (let k = 0; k < maxK; k++) {
  49. for (let h = 0; h < maxH; h++) {
  50. target[offsetTarget + h + k * tSizeH + l * tSizeHK]
  51. = source[offsetSource + h + k * sSizeH + l * sSizeHK];
  52. }
  53. }
  54. }
  55. }
  56. }
  57. function createBlockGridDomain(block: Coords.Grid<'Block'>, grid: Coords.GridDomain<'Data'>): Coords.GridDomain<'BlockGrid'> {
  58. const blockBox = Box.fractionalFromBlock(block);
  59. const origin = blockBox.a;
  60. const dimensions = Coords.sub(blockBox.b, blockBox.a);
  61. const sampleCount = Coords.sampleCounts(dimensions, grid.delta);
  62. return Coords.domain<'BlockGrid'>('BlockGrid', { origin, dimensions, delta: grid.delta, sampleCount });
  63. }
  64. /** Read the block data and fill all the overlaps with the query region. */
  65. async function fillBlock(query: Data.QueryContext.Data, block: Data.QueryBlock) {
  66. const baseBox = Box.fractionalFromBlock(block.coord);
  67. const blockGridDomain = createBlockGridDomain(block.coord, query.samplingInfo.sampling.dataDomain);
  68. const blockData: Data.BlockData = await readBlock(query, block.coord, baseBox);
  69. for (const offset of block.offsets) {
  70. const offsetQueryBox = Box.shift(query.samplingInfo.fractionalBox, offset);
  71. const dataBox = Box.intersect(baseBox, offsetQueryBox);
  72. if (!dataBox) continue;
  73. const offsetDataBox = Box.shift(dataBox, Coords.invert(offset));
  74. const blockGridBox = Box.clampGridToSamples(Box.fractionalToGrid(dataBox, blockGridDomain));
  75. const queryGridBox = Box.clampGridToSamples(Box.fractionalToGrid(offsetDataBox, query.samplingInfo.gridDomain));
  76. fillData(query, blockData, blockGridBox, queryGridBox);
  77. }
  78. }