polymer-backbone-cylinder.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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, Structure } from 'mol-model/structure';
  7. import { UnitsVisual } from '../index';
  8. import { VisualUpdateState } from '../../util';
  9. import { RuntimeContext } from 'mol-task'
  10. import { PolymerBackboneIterator } from './util/polymer';
  11. import { getElementLoci, markElement, StructureElementIterator } from './util/element';
  12. import { Vec3 } from 'mol-math/linear-algebra';
  13. import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
  14. import { SizeTheme, SizeThemeOptions, SizeThemeName } from 'mol-theme/size';
  15. import { OrderedSet } from 'mol-data/int';
  16. import { paramDefaultValues, NumberParam, SelectParam } from 'mol-util/parameter';
  17. import { Mesh } from 'mol-geo/geometry/mesh/mesh';
  18. import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
  19. import { CylinderProps } from 'mol-geo/primitive/cylinder';
  20. import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder';
  21. export const PolymerBackboneCylinderParams = {
  22. sizeTheme: SelectParam<SizeThemeName>('Size Theme', '', 'uniform', SizeThemeOptions),
  23. sizeValue: NumberParam('Size Value', '', 1, 0, 10, 0.1),
  24. radialSegments: NumberParam('Radial Segments', '', 16, 3, 56, 1),
  25. }
  26. export const DefaultPolymerBackboneCylinderProps = paramDefaultValues(PolymerBackboneCylinderParams)
  27. export type PolymerBackboneCylinderProps = typeof DefaultPolymerBackboneCylinderProps
  28. async function createPolymerBackboneCylinderMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: PolymerBackboneCylinderProps, mesh?: Mesh) {
  29. const polymerElementCount = unit.polymerElements.length
  30. if (!polymerElementCount) return Mesh.createEmpty(mesh)
  31. const sizeTheme = SizeTheme({ name: props.sizeTheme, value: props.sizeValue })
  32. const { radialSegments } = props
  33. const vertexCountEstimate = radialSegments * 2 * polymerElementCount * 2
  34. const builder = MeshBuilder.create(vertexCountEstimate, vertexCountEstimate / 10, mesh)
  35. const { elements } = unit
  36. const pos = unit.conformation.invariantPosition
  37. const pA = Vec3.zero()
  38. const pB = Vec3.zero()
  39. const cylinderProps: CylinderProps = { radiusTop: 1, radiusBottom: 1, radialSegments }
  40. let i = 0
  41. const polymerBackboneIt = PolymerBackboneIterator(unit)
  42. while (polymerBackboneIt.hasNext) {
  43. const { centerA, centerB } = polymerBackboneIt.move()
  44. pos(centerA.element, pA)
  45. pos(centerB.element, pB)
  46. cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(centerA)
  47. builder.setGroup(OrderedSet.indexOf(elements, centerA.element))
  48. addCylinder(builder, pA, pB, 0.5, cylinderProps)
  49. cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(centerB)
  50. builder.setGroup(OrderedSet.indexOf(elements, centerB.element))
  51. addCylinder(builder, pB, pA, 0.5, cylinderProps)
  52. if (i % 10000 === 0 && ctx.shouldUpdate) {
  53. await ctx.update({ message: 'Backbone mesh', current: i, max: polymerElementCount });
  54. }
  55. ++i
  56. }
  57. return builder.getMesh()
  58. }
  59. export const PolymerBackboneParams = {
  60. ...UnitsMeshParams,
  61. ...PolymerBackboneCylinderParams,
  62. }
  63. export const DefaultPolymerBackboneProps = paramDefaultValues(PolymerBackboneParams)
  64. export type PolymerBackboneProps = typeof DefaultPolymerBackboneProps
  65. export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneProps> {
  66. return UnitsMeshVisual<PolymerBackboneProps>({
  67. defaultProps: DefaultPolymerBackboneProps,
  68. createGeometry: createPolymerBackboneCylinderMesh,
  69. // TODO create a specialized location iterator
  70. createLocationIterator: StructureElementIterator.fromGroup,
  71. getLoci: getElementLoci,
  72. mark: markElement,
  73. setUpdateState: (state: VisualUpdateState, newProps: PolymerBackboneProps, currentProps: PolymerBackboneProps) => {
  74. state.createGeometry = newProps.radialSegments !== currentProps.radialSegments
  75. }
  76. })
  77. }