element.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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 { Vec3 } from 'mol-math/linear-algebra';
  7. import { Unit, StructureElement, Structure } from 'mol-model/structure';
  8. import { Loci, EmptyLoci } from 'mol-model/loci';
  9. import { Interval, OrderedSet } from 'mol-data/int';
  10. import { Mesh } from 'mol-geo/geometry/mesh/mesh';
  11. import { sphereVertexCount } from 'mol-geo/primitive/sphere';
  12. import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
  13. import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere';
  14. import { PickingId } from 'mol-geo/geometry/picking';
  15. import { LocationIterator } from 'mol-geo/util/location-iterator';
  16. import { VisualContext } from 'mol-repr/visual';
  17. import { Theme } from 'mol-theme/theme';
  18. import { StructureGroup } from 'mol-repr/structure/units-visual';
  19. import { Spheres } from 'mol-geo/geometry/spheres/spheres';
  20. import { SpheresBuilder } from 'mol-geo/geometry/spheres/spheres-builder';
  21. export interface ElementSphereMeshProps {
  22. detail: number,
  23. sizeFactor: number
  24. }
  25. export function createElementSphereMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: ElementSphereMeshProps, mesh?: Mesh): Mesh {
  26. const { detail, sizeFactor } = props
  27. const { elements } = unit;
  28. const elementCount = elements.length;
  29. const vertexCount = elementCount * sphereVertexCount(detail)
  30. const builderState = MeshBuilder.createState(vertexCount, vertexCount / 2, mesh)
  31. const v = Vec3.zero()
  32. const pos = unit.conformation.invariantPosition
  33. const l = StructureElement.create()
  34. l.unit = unit
  35. for (let i = 0; i < elementCount; i++) {
  36. l.element = elements[i]
  37. pos(elements[i], v)
  38. builderState.currentGroup = i
  39. addSphere(builderState, v, theme.size.size(l) * sizeFactor, detail)
  40. }
  41. return MeshBuilder.getMesh(builderState)
  42. }
  43. export interface ElementSphereImpostorProps { }
  44. export function createElementSphereImpostor(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: ElementSphereImpostorProps, spheres?: Spheres): Spheres {
  45. const { elements } = unit;
  46. const elementCount = elements.length;
  47. const builder = SpheresBuilder.create(elementCount, elementCount / 2, spheres)
  48. const v = Vec3.zero()
  49. const pos = unit.conformation.invariantPosition
  50. for (let i = 0; i < elementCount; i++) {
  51. pos(elements[i], v)
  52. builder.add(v[0], v[1], v[2], i)
  53. }
  54. return builder.getSpheres()
  55. }
  56. export function eachElement(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {
  57. let changed = false
  58. if (!StructureElement.isLoci(loci)) return false
  59. const { structure, group } = structureGroup
  60. if (!Structure.areEquivalent(loci.structure, structure)) return false
  61. const elementCount = group.elements.length
  62. for (const e of loci.elements) {
  63. const unitIdx = group.unitIndexMap.get(e.unit.id)
  64. if (unitIdx !== undefined) {
  65. if (Interval.is(e.indices)) {
  66. const start = unitIdx * elementCount + Interval.start(e.indices);
  67. const end = unitIdx * elementCount + Interval.end(e.indices);
  68. if (apply(Interval.ofBounds(start, end))) changed = true
  69. } else {
  70. for (let i = 0, _i = e.indices.length; i < _i; i++) {
  71. const idx = unitIdx * elementCount + e.indices[i];
  72. if (apply(Interval.ofSingleton(idx))) changed = true
  73. }
  74. }
  75. }
  76. }
  77. return changed
  78. }
  79. export function getElementLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number) {
  80. const { objectId, instanceId, groupId } = pickingId
  81. if (id === objectId) {
  82. const { structure, group } = structureGroup
  83. const unit = group.units[instanceId]
  84. const indices = OrderedSet.ofSingleton(groupId as StructureElement.UnitIndex);
  85. return StructureElement.Loci(structure, [{ unit, indices }])
  86. }
  87. return EmptyLoci
  88. }
  89. export namespace StructureElementIterator {
  90. export function fromGroup(group: Unit.SymmetryGroup): LocationIterator {
  91. const groupCount = group.elements.length
  92. const instanceCount = group.units.length
  93. const location = StructureElement.create()
  94. const getLocation = (groupIndex: number, instanceIndex: number) => {
  95. const unit = group.units[instanceIndex]
  96. location.unit = unit
  97. location.element = unit.elements[groupIndex]
  98. return location
  99. }
  100. return LocationIterator(groupCount, instanceCount, getLocation)
  101. }
  102. }