inter-unit-link-cylinder.ts 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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 { Link, Structure, StructureElement } from 'mol-model/structure';
  7. import { ComplexVisual, VisualUpdateState } from '..';
  8. import { RuntimeContext } from 'mol-task'
  9. import { LinkCylinderProps, DefaultLinkCylinderProps, createLinkCylinderMesh, LinkIterator } from './util/link';
  10. import { Mesh } from '../../../geometry/mesh/mesh';
  11. import { PickingId } from '../../../util/picking';
  12. import { Vec3 } from 'mol-math/linear-algebra';
  13. import { Loci, EmptyLoci } from 'mol-model/loci';
  14. import { ComplexMeshVisual, DefaultComplexMeshProps } from '../complex-visual';
  15. import { Interval } from 'mol-data/int';
  16. import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size';
  17. import { BitFlags } from 'mol-util';
  18. async function createInterUnitLinkCylinderMesh(ctx: RuntimeContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) {
  19. const links = structure.links
  20. const { bondCount, bonds } = links
  21. if (!bondCount) return Mesh.createEmpty(mesh)
  22. const sizeTheme = SizeTheme(props.sizeTheme)
  23. const location = StructureElement.create()
  24. const builderProps = {
  25. linkCount: bondCount,
  26. referencePosition: (edgeIndex: number) => null, // TODO
  27. position: (posA: Vec3, posB: Vec3, edgeIndex: number) => {
  28. const b = bonds[edgeIndex]
  29. const uA = b.unitA, uB = b.unitB
  30. uA.conformation.position(uA.elements[b.indexA], posA)
  31. uB.conformation.position(uB.elements[b.indexB], posB)
  32. },
  33. order: (edgeIndex: number) => bonds[edgeIndex].order,
  34. flags: (edgeIndex: number) => BitFlags.create(bonds[edgeIndex].flag),
  35. radius: (edgeIndex: number) => {
  36. const b = bonds[edgeIndex]
  37. location.unit = b.unitA
  38. location.element = b.unitA.elements[b.indexA]
  39. return sizeTheme.size(location)
  40. }
  41. }
  42. return createLinkCylinderMesh(ctx, builderProps, props, mesh)
  43. }
  44. export const DefaultInterUnitLinkProps = {
  45. ...DefaultComplexMeshProps,
  46. ...DefaultLinkCylinderProps,
  47. sizeTheme: { name: 'physical', factor: 0.3 } as SizeThemeProps,
  48. }
  49. export type InterUnitLinkProps = typeof DefaultInterUnitLinkProps
  50. export function InterUnitLinkVisual(): ComplexVisual<InterUnitLinkProps> {
  51. return ComplexMeshVisual<InterUnitLinkProps>({
  52. defaultProps: DefaultInterUnitLinkProps,
  53. createMesh: createInterUnitLinkCylinderMesh,
  54. createLocationIterator: LinkIterator.fromStructure,
  55. getLoci: getLinkLoci,
  56. mark: markLink,
  57. setUpdateState: (state: VisualUpdateState, newProps: InterUnitLinkProps, currentProps: InterUnitLinkProps) => {
  58. state.createGeometry = newProps.radialSegments !== currentProps.radialSegments
  59. }
  60. })
  61. }
  62. function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
  63. const { objectId, groupId } = pickingId
  64. if (id === objectId) {
  65. const bond = structure.links.bonds[groupId]
  66. return Link.Loci([
  67. Link.Location(
  68. bond.unitA, bond.indexA as StructureElement.UnitIndex,
  69. bond.unitB, bond.indexB as StructureElement.UnitIndex
  70. )
  71. ])
  72. }
  73. return EmptyLoci
  74. }
  75. function markLink(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) {
  76. let changed = false
  77. if (Link.isLoci(loci)) {
  78. for (const b of loci.links) {
  79. const idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit)
  80. if (idx !== -1) {
  81. if (apply(Interval.ofSingleton(idx))) changed = true
  82. }
  83. }
  84. }
  85. return changed
  86. }