spacefill.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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 { ValueCell } from 'mol-util/value-cell'
  7. import { createRenderObject, RenderObject } from 'mol-gl/scene'
  8. // import { createColorTexture } from 'mol-gl/util';
  9. import { Vec3, Mat4 } from 'mol-math/linear-algebra'
  10. import { OrderedSet } from 'mol-data/int'
  11. import { Unit, ElementGroup } from 'mol-model/structure';
  12. import { RepresentationProps, UnitsRepresentation } from './index';
  13. import { Task } from 'mol-task'
  14. import { MeshBuilder } from '../../shape/mesh-builder';
  15. import { VdwRadius } from 'mol-model/structure/model/properties/atomic';
  16. import { ElementColor, colorToArray, normalizedColorToArray, ColorScale } from '../../color';
  17. import { Color } from 'mol-gl/renderable/mesh';
  18. import { createColorTexture } from 'mol-gl/util';
  19. export const DefaultSpacefillProps = {
  20. detail: 0
  21. }
  22. export type SpacefillProps = Partial<typeof DefaultSpacefillProps>
  23. // function buildColorBuffer() {
  24. // if (props && props.color) {
  25. // colors = new Float32Array(icosahedron.vertices.length)
  26. // for (let i = 0, il = colors.length; i < il; i += 3) {
  27. // hexColorToArray(props.color, colors, i)
  28. // }
  29. // }
  30. // }
  31. export default function Spacefill(): UnitsRepresentation<SpacefillProps> {
  32. const renderObjects: RenderObject[] = []
  33. return {
  34. renderObjects,
  35. create: (units: ReadonlyArray<Unit>, elementGroup: ElementGroup, props: SpacefillProps = {}) => Task.create('Spacefill', async ctx => {
  36. const { detail } = { ...DefaultSpacefillProps, ...props }
  37. const meshBuilder = MeshBuilder.create()
  38. const v = Vec3.zero()
  39. const m = Mat4.identity()
  40. const { x, y, z } = units[0].model.conformation
  41. const { type_symbol } = units[0].model.hierarchy.atoms
  42. const elementCount = OrderedSet.size(elementGroup.elements)
  43. for (let i = 0; i < elementCount; i++) {
  44. const e = OrderedSet.getAt(elementGroup.elements, i)
  45. v[0] = x[e]
  46. v[1] = y[e]
  47. v[2] = z[e]
  48. Mat4.setTranslation(m, v)
  49. meshBuilder.setId(i)
  50. meshBuilder.addIcosahedron(m, {
  51. radius: VdwRadius(type_symbol.value(e)),
  52. detail
  53. })
  54. if (i % 10 === 0 && ctx.shouldUpdate) {
  55. await ctx.update({ message: 'Spacefill', current: i, max: elementCount });
  56. }
  57. }
  58. const mesh = meshBuilder.getMesh()
  59. // console.log(mesh)
  60. if (!mesh.offsetBuffer.ref.value) return
  61. const unitsCount = units.length
  62. const transformArray = new Float32Array(unitsCount * 16)
  63. for (let i = 0; i < unitsCount; i++) {
  64. Mat4.toArray(units[i].operator.matrix, transformArray, i * 16)
  65. }
  66. // console.log({ unitsCount, elementCount })
  67. let colorType = 'element'
  68. let color: Color
  69. if (colorType === 'attribute') {
  70. const colors = new Float32Array(mesh.vertexCount * 3);
  71. const offsets = mesh.offsetBuffer.ref.value
  72. for (let i = 0, il = mesh.offsetCount - 1; i < il; ++i) {
  73. const start = offsets[i]
  74. const end = offsets[i + 1]
  75. const e = OrderedSet.getAt(elementGroup.elements, i)
  76. const hexColor = ElementColor(type_symbol.value(e))
  77. for (let i = start, il = end; i < il; ++i) {
  78. normalizedColorToArray(hexColor, colors, i * 3)
  79. }
  80. }
  81. color = { type: 'attribute', value: ValueCell.create(colors) }
  82. } else if (colorType === 'instance') {
  83. const colors = createColorTexture(unitsCount)
  84. const scale = ColorScale.create({ domain: [ 0, unitsCount - 1 ] })
  85. for (let i = 0; i < unitsCount; i++) {
  86. scale.colorToArray(i, colors, i * 3)
  87. }
  88. color = { type: 'instance', value: ValueCell.create(colors) }
  89. } else if (colorType === 'element') {
  90. const elementCount = mesh.offsetCount - 1
  91. const count = unitsCount * elementCount
  92. const colors = createColorTexture(count)
  93. const scale = ColorScale.create({ domain: [ 0, count - 1 ] })
  94. let colorOffset = 0
  95. for (let i = 0; i < unitsCount; i++) {
  96. for (let j = 0, jl = elementCount; j < jl; ++j) {
  97. const hexColor = scale.color(i * elementCount + j)
  98. colorToArray(hexColor, colors, colorOffset)
  99. colorOffset += 3
  100. }
  101. }
  102. color = { type: 'element', value: ValueCell.create(colors) }
  103. }
  104. const spheres = createRenderObject('mesh', {
  105. position: mesh.vertexBuffer,
  106. normal: mesh.normalBuffer,
  107. color: color!,
  108. id: mesh.idBuffer,
  109. transform: ValueCell.create(transformArray),
  110. index: mesh.indexBuffer,
  111. instanceCount: unitsCount,
  112. indexCount: mesh.triangleCount,
  113. elementCount: mesh.offsetCount - 1,
  114. positionCount: mesh.vertexCount
  115. }, {})
  116. renderObjects.push(spheres)
  117. }),
  118. update: (props: RepresentationProps) => false
  119. }
  120. }