polymer-trace-mesh.ts 4.4 KB

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