polymer-trace-mesh.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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 { createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object'
  8. import { Unit, StructureElement } from 'mol-model/structure';
  9. import { DefaultStructureProps, UnitsVisual } from '../index';
  10. import { RuntimeContext } from 'mol-task'
  11. import { createTransforms, createColors } from './util/common';
  12. import { markElement } from './util/element';
  13. import { deepEqual } from 'mol-util';
  14. import { MeshValues } from 'mol-gl/renderable';
  15. import { getMeshData } from '../../../util/mesh-data';
  16. import { Mesh } from '../../../shape/mesh';
  17. import { PickingId } from '../../../util/picking';
  18. import { OrderedSet } from 'mol-data/int';
  19. import { createMarkers, MarkerAction } from '../../../util/marker-data';
  20. import { Loci, EmptyLoci } from 'mol-model/loci';
  21. import { SizeTheme } from '../../../theme';
  22. import { createMeshValues, updateMeshValues, updateRenderableState, createRenderableState, DefaultMeshProps } from '../../util';
  23. import { MeshBuilder } from '../../../shape/mesh-builder';
  24. import { getPolymerElementCount, PolymerBackboneIterator } from './util/polymer';
  25. async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, mesh?: Mesh) {
  26. const polymerElementCount = getPolymerElementCount(unit)
  27. console.log('polymerElementCount', polymerElementCount)
  28. if (!polymerElementCount) return Mesh.createEmpty(mesh)
  29. // TODO better vertex count estimates
  30. const builder = MeshBuilder.create(polymerElementCount * 30, polymerElementCount * 30 / 2, mesh)
  31. let i = 0
  32. const polymerTraceIt = PolymerBackboneIterator(unit)
  33. while (polymerTraceIt.hasNext) {
  34. const v = polymerTraceIt.move()
  35. builder.setId(v.indexA)
  36. // TODO size theme
  37. builder.addCylinder(v.posA, v.posB, 0.5, { radiusTop: 0.2, radiusBottom: 0.2 })
  38. builder.setId(v.indexB)
  39. builder.addCylinder(v.posB, v.posA, 0.5, { radiusTop: 0.2, radiusBottom: 0.2 })
  40. if (i % 10000 === 0 && ctx.shouldUpdate) {
  41. await ctx.update({ message: 'Backbone mesh', current: i, max: polymerElementCount });
  42. }
  43. ++i
  44. }
  45. return builder.getMesh()
  46. }
  47. export const DefaultPolymerTraceProps = {
  48. ...DefaultMeshProps,
  49. ...DefaultStructureProps,
  50. sizeTheme: { name: 'physical', factor: 1 } as SizeTheme,
  51. detail: 0,
  52. unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[]
  53. }
  54. export type PolymerTraceProps = Partial<typeof DefaultPolymerTraceProps>
  55. export function PolymerTraceVisual(): UnitsVisual<PolymerTraceProps> {
  56. let renderObject: MeshRenderObject
  57. let currentProps: typeof DefaultPolymerTraceProps
  58. let mesh: Mesh
  59. let currentGroup: Unit.SymmetryGroup
  60. return {
  61. get renderObject () { return renderObject },
  62. async create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: PolymerTraceProps = {}) {
  63. currentProps = Object.assign({}, DefaultPolymerTraceProps, props)
  64. currentGroup = group
  65. const { colorTheme, unitKinds } = { ...DefaultPolymerTraceProps, ...props }
  66. const instanceCount = group.units.length
  67. const elementCount = group.elements.length
  68. const unit = group.units[0]
  69. mesh = unitKinds.includes(unit.kind)
  70. ? await createPolymerTraceMesh(ctx, unit, mesh)
  71. : Mesh.createEmpty(mesh)
  72. const transforms = createTransforms(group)
  73. const color = createColors(group, elementCount, colorTheme)
  74. const marker = createMarkers(instanceCount * elementCount)
  75. const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount }
  76. const values: MeshValues = {
  77. ...getMeshData(mesh),
  78. ...color,
  79. ...marker,
  80. aTransform: transforms,
  81. elements: mesh.indexBuffer,
  82. ...createMeshValues(currentProps, counts),
  83. }
  84. const state = createRenderableState(currentProps)
  85. renderObject = createMeshRenderObject(values, state)
  86. },
  87. async update(ctx: RuntimeContext, props: PolymerTraceProps) {
  88. const newProps = Object.assign({}, currentProps, props)
  89. if (!renderObject) return false
  90. let updateColor = false
  91. if (newProps.detail !== currentProps.detail) {
  92. const unit = currentGroup.units[0]
  93. mesh = await createPolymerTraceMesh(ctx, unit, mesh)
  94. ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3)
  95. updateColor = true
  96. }
  97. if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) {
  98. updateColor = true
  99. }
  100. if (updateColor) {
  101. const elementCount = currentGroup.elements.length
  102. if (ctx.shouldUpdate) await ctx.update('Computing trace colors');
  103. createColors(currentGroup, elementCount, newProps.colorTheme, renderObject.values)
  104. }
  105. updateMeshValues(renderObject.values, newProps)
  106. updateRenderableState(renderObject.state, newProps)
  107. currentProps = newProps
  108. return true
  109. },
  110. getLoci(pickingId: PickingId) {
  111. const { objectId, instanceId, elementId } = pickingId
  112. if (renderObject.id === objectId) {
  113. const unit = currentGroup.units[instanceId]
  114. const indices = OrderedSet.ofSingleton(elementId as StructureElement.UnitIndex);
  115. return StructureElement.Loci([{ unit, indices }])
  116. }
  117. return EmptyLoci
  118. },
  119. mark(loci: Loci, action: MarkerAction) {
  120. markElement(renderObject.values.tMarker, currentGroup, loci, action)
  121. },
  122. destroy() {
  123. // TODO
  124. }
  125. }
  126. }