util.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Sphere3D } from 'mol-math/geometry'
  7. import { Vec3 } from 'mol-math/linear-algebra'
  8. import { BoundaryHelper } from 'mol-math/geometry/boundary-helper';
  9. export function calculateTextureInfo (n: number, itemSize: number) {
  10. const sqN = Math.sqrt(n)
  11. let width = Math.ceil(sqN)
  12. width = width + (itemSize - (width % itemSize)) % itemSize
  13. const height = width > 0 ? Math.ceil(n / width) : 0
  14. return { width, height, length: width * height * itemSize }
  15. }
  16. export interface TextureImage<T extends Uint8Array | Float32Array> {
  17. readonly array: T
  18. readonly width: number
  19. readonly height: number
  20. }
  21. export interface TextureVolume<T extends Uint8Array | Float32Array> {
  22. readonly array: T
  23. readonly width: number
  24. readonly height: number
  25. readonly depth: number
  26. }
  27. export function createTextureImage(n: number, itemSize: number, array?: Uint8Array): TextureImage<Uint8Array> {
  28. const { length, width, height } = calculateTextureInfo(n, itemSize)
  29. array = array && array.length >= length ? array : new Uint8Array(length)
  30. return { array, width, height }
  31. }
  32. export function printTextureImage(textureImage: TextureImage<any>, scale = 1) {
  33. const { array, width, height } = textureImage
  34. const itemSize = array.length / (width * height)
  35. const data = new Uint8ClampedArray(width * height * 4)
  36. if (itemSize === 1) {
  37. for (let y = 0; y < height; ++y) {
  38. for (let x = 0; x < width; ++x) {
  39. data[(y * width + x) * 4 + 3] = array[y * width + x]
  40. }
  41. }
  42. } else if (itemSize === 4) {
  43. data.set(array)
  44. } else {
  45. console.warn(`itemSize '${itemSize}' not supported`)
  46. }
  47. return printImageData(new ImageData(data, width, height), scale)
  48. }
  49. export function printImageData(imageData: ImageData, scale = 1) {
  50. const canvas = document.createElement('canvas')
  51. canvas.width = imageData.width
  52. canvas.height = imageData.height
  53. const ctx = canvas.getContext('2d')
  54. if (!ctx) throw new Error('Could not create canvas 2d context')
  55. ctx.putImageData(imageData, 0, 0)
  56. canvas.toBlob(imgBlob => {
  57. const objectURL = window.URL.createObjectURL(imgBlob)
  58. const img = document.createElement('img')
  59. img.src = objectURL
  60. img.style.width = imageData.width * scale + 'px'
  61. img.style.height = imageData.height * scale + 'px';
  62. (img.style as any).imageRendering = 'pixelated' // works in Chrome
  63. img.style.position = 'absolute'
  64. img.style.top = '0px'
  65. img.style.left = '0px'
  66. img.style.border = 'solid grey'
  67. document.body.appendChild(img)
  68. }, 'image/png')
  69. }
  70. //
  71. const v = Vec3.zero()
  72. const boundaryHelper = new BoundaryHelper()
  73. export function calculateInvariantBoundingSphere(position: Float32Array, positionCount: number): Sphere3D {
  74. boundaryHelper.reset(0)
  75. for (let i = 0, _i = positionCount * 3; i < _i; i += 3) {
  76. Vec3.fromArray(v, position, i)
  77. boundaryHelper.boundaryStep(v, 0)
  78. }
  79. boundaryHelper.finishBoundaryStep()
  80. for (let i = 0, _i = positionCount * 3; i < _i; i += 3) {
  81. Vec3.fromArray(v, position, i)
  82. boundaryHelper.extendStep(v, 0)
  83. }
  84. return boundaryHelper.getSphere()
  85. }
  86. export function calculateTransformBoundingSphere(invariantBoundingSphere: Sphere3D, transform: Float32Array, transformCount: number): Sphere3D {
  87. const { center, radius } = invariantBoundingSphere
  88. boundaryHelper.reset(0)
  89. for (let i = 0, _i = transformCount; i < _i; ++i) {
  90. Vec3.transformMat4Offset(v, center, transform, 0, 0, i * 16)
  91. boundaryHelper.boundaryStep(v, radius)
  92. }
  93. boundaryHelper.finishBoundaryStep()
  94. for (let i = 0, _i = transformCount; i < _i; ++i) {
  95. Vec3.transformMat4Offset(v, center, transform, 0, 0, i * 16)
  96. boundaryHelper.extendStep(v, radius)
  97. }
  98. return boundaryHelper.getSphere()
  99. }
  100. export function calculateBoundingSphere(position: Float32Array, positionCount: number, transform: Float32Array, transformCount: number, padding = 0): { boundingSphere: Sphere3D, invariantBoundingSphere: Sphere3D } {
  101. const invariantBoundingSphere = calculateInvariantBoundingSphere(position, positionCount)
  102. const boundingSphere = calculateTransformBoundingSphere(invariantBoundingSphere, transform, transformCount)
  103. Sphere3D.expand(boundingSphere, boundingSphere, padding)
  104. Sphere3D.expand(invariantBoundingSphere, invariantBoundingSphere, padding)
  105. return { boundingSphere, invariantBoundingSphere }
  106. }