representation.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /**
  2. * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Representation, RepresentationContext, RepresentationParamsGetter } from '../../../mol-repr/representation';
  7. import { ThemeRegistryContext } from '../../../mol-theme/theme';
  8. import { Theme } from '../../../mol-theme/theme';
  9. import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
  10. import { Vec3 } from '../../../mol-math/linear-algebra';
  11. import { LocationIterator } from '../../../mol-geo/util/location-iterator';
  12. import { PickingId } from '../../../mol-geo/geometry/picking';
  13. import { EmptyLoci, Loci } from '../../../mol-model/loci';
  14. import { Interval } from '../../../mol-data/int';
  15. import { ParamDefinition as PD } from '../../../mol-util/param-definition';
  16. import { Structure, StructureElement } from '../../../mol-model/structure';
  17. import { VisualContext } from '../../../mol-repr/visual';
  18. import { createLinkCylinderMesh, LinkCylinderParams } from '../../../mol-repr/structure/visual/util/link';
  19. import { ComplexMeshParams, ComplexVisual, ComplexMeshVisual } from '../../../mol-repr/structure/complex-visual';
  20. import { VisualUpdateState } from '../../../mol-repr/util';
  21. import { ComplexRepresentation, StructureRepresentation, StructureRepresentationStateBuilder, StructureRepresentationProvider } from '../../../mol-repr/structure/representation';
  22. import { UnitKind, UnitKindOptions } from '../../../mol-repr/structure/visual/util/common';
  23. import { CustomProperty } from '../../common/custom-property';
  24. import { CrossLinkRestraintProvider, CrossLinkRestraint } from './property';
  25. function createCrossLinkRestraintCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<CrossLinkRestraintCylinderParams>, mesh?: Mesh) {
  26. const crossLinks = CrossLinkRestraintProvider.get(structure).value!
  27. if (!crossLinks.count) return Mesh.createEmpty(mesh)
  28. const { sizeFactor } = props
  29. const location = StructureElement.Location.create(structure)
  30. const builderProps = {
  31. linkCount: crossLinks.count,
  32. position: (posA: Vec3, posB: Vec3, edgeIndex: number) => {
  33. const b = crossLinks.pairs[edgeIndex]
  34. const uA = b.unitA, uB = b.unitB
  35. uA.conformation.position(uA.elements[b.indexA], posA)
  36. uB.conformation.position(uB.elements[b.indexB], posB)
  37. },
  38. radius: (edgeIndex: number) => {
  39. const b = crossLinks.pairs[edgeIndex]
  40. location.unit = b.unitA
  41. location.element = b.unitA.elements[b.indexA]
  42. return theme.size.size(location) * sizeFactor
  43. },
  44. }
  45. return createLinkCylinderMesh(ctx, builderProps, props, mesh)
  46. }
  47. export const CrossLinkRestraintCylinderParams = {
  48. ...ComplexMeshParams,
  49. ...LinkCylinderParams,
  50. sizeFactor: PD.Numeric(0.5, { min: 0, max: 10, step: 0.1 }),
  51. }
  52. export type CrossLinkRestraintCylinderParams = typeof CrossLinkRestraintCylinderParams
  53. export function CrossLinkRestraintVisual(materialId: number): ComplexVisual<CrossLinkRestraintCylinderParams> {
  54. return ComplexMeshVisual<CrossLinkRestraintCylinderParams>({
  55. defaultProps: PD.getDefaultValues(CrossLinkRestraintCylinderParams),
  56. createGeometry: createCrossLinkRestraintCylinderMesh,
  57. createLocationIterator: createCrossLinkRestraintIterator,
  58. getLoci: getLinkLoci,
  59. eachLocation: eachCrossLink,
  60. setUpdateState: (state: VisualUpdateState, newProps: PD.Values<CrossLinkRestraintCylinderParams>, currentProps: PD.Values<CrossLinkRestraintCylinderParams>) => {
  61. state.createGeometry = (
  62. newProps.sizeFactor !== currentProps.sizeFactor ||
  63. newProps.radialSegments !== currentProps.radialSegments ||
  64. newProps.linkCap !== currentProps.linkCap
  65. )
  66. }
  67. }, materialId)
  68. }
  69. function createCrossLinkRestraintIterator(structure: Structure): LocationIterator {
  70. const crossLinkRestraints = CrossLinkRestraintProvider.get(structure).value!
  71. const { pairs } = crossLinkRestraints
  72. const groupCount = pairs.length
  73. const instanceCount = 1
  74. const location = CrossLinkRestraint.Location(crossLinkRestraints, structure)
  75. const getLocation = (groupIndex: number) => {
  76. location.element = groupIndex
  77. return location
  78. }
  79. return LocationIterator(groupCount, instanceCount, getLocation, true)
  80. }
  81. function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
  82. const { objectId, groupId } = pickingId
  83. if (id === objectId) {
  84. const crossLinkRestraints = CrossLinkRestraintProvider.get(structure).value!
  85. const pair = crossLinkRestraints.pairs[groupId]
  86. if (pair) {
  87. return CrossLinkRestraint.Loci(structure, crossLinkRestraints, [groupId])
  88. }
  89. }
  90. return EmptyLoci
  91. }
  92. function eachCrossLink(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) {
  93. let changed = false
  94. if (CrossLinkRestraint.isLoci(loci)) {
  95. if (!Structure.areEquivalent(loci.data.structure, structure)) return false
  96. const crossLinkRestraints = CrossLinkRestraintProvider.get(structure).value!
  97. if (loci.data.crossLinkRestraints !== crossLinkRestraints) return false
  98. for (const e of loci.elements) {
  99. if (apply(Interval.ofSingleton(e))) changed = true
  100. }
  101. }
  102. return changed
  103. }
  104. //
  105. const CrossLinkRestraintVisuals = {
  106. 'cross-link-restraint': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, CrossLinkRestraintCylinderParams>) => ComplexRepresentation('Cross-link restraint', ctx, getParams, CrossLinkRestraintVisual),
  107. }
  108. export const CrossLinkRestraintParams = {
  109. ...CrossLinkRestraintCylinderParams,
  110. unitKinds: PD.MultiSelect<UnitKind>(['atomic', 'spheres'], UnitKindOptions),
  111. }
  112. export type CrossLinkRestraintParams = typeof CrossLinkRestraintParams
  113. export function getCrossLinkRestraintParams(ctx: ThemeRegistryContext, structure: Structure) {
  114. return PD.clone(CrossLinkRestraintParams)
  115. }
  116. export type CrossLinkRestraintRepresentation = StructureRepresentation<CrossLinkRestraintParams>
  117. export function CrossLinkRestraintRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, CrossLinkRestraintParams>): CrossLinkRestraintRepresentation {
  118. return Representation.createMulti('CrossLinkRestraint', ctx, getParams, StructureRepresentationStateBuilder, CrossLinkRestraintVisuals as unknown as Representation.Def<Structure, CrossLinkRestraintParams>)
  119. }
  120. export const CrossLinkRestraintRepresentationProvider = StructureRepresentationProvider({
  121. name: CrossLinkRestraint.Tag.CrossLinkRestraint,
  122. label: 'Cross Link Restraint',
  123. description: 'Displays cross-link restraints.',
  124. factory: CrossLinkRestraintRepresentation,
  125. getParams: getCrossLinkRestraintParams,
  126. defaultValues: PD.getDefaultValues(CrossLinkRestraintParams),
  127. defaultColorTheme: { name: CrossLinkRestraint.Tag.CrossLinkRestraint },
  128. defaultSizeTheme: { name: 'uniform' },
  129. isApplicable: (structure: Structure) => CrossLinkRestraint.isApplicable(structure),
  130. ensureCustomProperties: {
  131. attach: (ctx: CustomProperty.Context, structure: Structure) => CrossLinkRestraintProvider.attach(ctx, structure, void 0, true),
  132. detach: (_, data) => CrossLinkRestraintProvider.ref(data, false)
  133. }
  134. })