polymer-trace-mesh.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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 { Unit } from 'mol-model/structure';
  7. import { UnitsVisual, MeshUpdateState } from '..';
  8. import { RuntimeContext } from 'mol-task'
  9. import { markElement, getElementLoci } from './util/element';
  10. import { Mesh } from '../../../shape/mesh';
  11. import { MeshBuilder } from '../../../shape/mesh-builder';
  12. import { getPolymerElementCount, PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment } from './util/polymer';
  13. import { SecondaryStructureType, MoleculeType } from 'mol-model/structure/model/types';
  14. import { StructureElementIterator } from './util/location-iterator';
  15. import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual';
  16. import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size';
  17. export interface PolymerTraceMeshProps {
  18. sizeTheme: SizeThemeProps
  19. linearSegments: number
  20. radialSegments: number
  21. aspectRatio: number
  22. arrowFactor: number
  23. }
  24. // TODO handle polymer ends properly
  25. async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, props: PolymerTraceMeshProps, mesh?: Mesh) {
  26. const polymerElementCount = getPolymerElementCount(unit)
  27. if (!polymerElementCount) return Mesh.createEmpty(mesh)
  28. const sizeTheme = SizeTheme(props.sizeTheme)
  29. const { linearSegments, radialSegments, aspectRatio, arrowFactor } = props
  30. const vertexCount = linearSegments * radialSegments * polymerElementCount + (radialSegments + 1) * polymerElementCount * 2
  31. const builder = MeshBuilder.create(vertexCount, vertexCount / 10, mesh)
  32. const state = createCurveSegmentState(linearSegments)
  33. const { curvePoints, normalVectors, binormalVectors } = state
  34. let i = 0
  35. const polymerTraceIt = PolymerTraceIterator(unit)
  36. while (polymerTraceIt.hasNext) {
  37. const v = polymerTraceIt.move()
  38. builder.setId(v.center.element)
  39. const isNucleic = v.moleculeType === MoleculeType.DNA || v.moleculeType === MoleculeType.RNA
  40. const isSheet = SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Beta)
  41. const isHelix = SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Helix)
  42. const tension = (isNucleic || isSheet) ? 0.5 : 0.9
  43. interpolateCurveSegment(state, v, tension)
  44. let width = sizeTheme.size(v.center)
  45. if (isSheet) {
  46. const height = width * aspectRatio
  47. const arrowHeight = v.secStrucChange ? height * arrowFactor : 0
  48. builder.addSheet(curvePoints, normalVectors, binormalVectors, linearSegments, width, height, arrowHeight, true, true)
  49. } else {
  50. let height: number
  51. if (isHelix) {
  52. height = width * aspectRatio
  53. } else if (isNucleic) {
  54. height = width * aspectRatio;
  55. [width, height] = [height, width]
  56. } else {
  57. height = width
  58. }
  59. builder.addTube(curvePoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, 1, true, true)
  60. }
  61. if (i % 10000 === 0 && ctx.shouldUpdate) {
  62. await ctx.update({ message: 'Polymer trace mesh', current: i, max: polymerElementCount });
  63. }
  64. ++i
  65. }
  66. return builder.getMesh()
  67. }
  68. export const DefaultPolymerTraceProps = {
  69. ...DefaultUnitsMeshProps,
  70. linearSegments: 8,
  71. radialSegments: 12,
  72. aspectRatio: 5,
  73. arrowFactor: 1.5
  74. }
  75. export type PolymerTraceProps = typeof DefaultPolymerTraceProps
  76. export function PolymerTraceVisual(): UnitsVisual<PolymerTraceProps> {
  77. return UnitsMeshVisual<PolymerTraceProps>({
  78. defaultProps: DefaultPolymerTraceProps,
  79. createMesh: createPolymerTraceMesh,
  80. createLocationIterator: StructureElementIterator.fromGroup,
  81. getLoci: getElementLoci,
  82. mark: markElement,
  83. setUpdateState: (state: MeshUpdateState, newProps: PolymerTraceProps, currentProps: PolymerTraceProps) => {
  84. state.createMesh = (
  85. newProps.linearSegments !== currentProps.linearSegments ||
  86. newProps.radialSegments !== currentProps.radialSegments ||
  87. newProps.aspectRatio !== currentProps.aspectRatio ||
  88. newProps.arrowFactor !== currentProps.arrowFactor
  89. )
  90. }
  91. })
  92. }