location-iterator.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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 { Iterator } from 'mol-data';
  7. import { Unit, StructureElement, Structure, Link } from 'mol-model/structure';
  8. import { NullLocation, Location } from 'mol-model/location';
  9. export interface LocationValue {
  10. location: Location
  11. index: number
  12. elementIndex: number
  13. instanceIndex: number
  14. }
  15. export const NullLocationValue = {
  16. location: NullLocation,
  17. index: 0,
  18. elementIndex: 0,
  19. instanceIndex: 0
  20. }
  21. export interface LocationIterator extends Iterator<LocationValue> {
  22. readonly hasNext: boolean
  23. readonly isNextNewInstance: boolean
  24. readonly elementCount: number
  25. readonly instanceCount: number
  26. move(): LocationValue
  27. skipInstance(): void
  28. }
  29. type LocationGetter = (elementIndex: number, instanceIndex: number) => Location
  30. export function LocationIterator(elementCount: number, instanceCount: number, getLocation: LocationGetter): LocationIterator {
  31. const value = {
  32. location: NullLocation as Location,
  33. index: 0,
  34. elementIndex: 0,
  35. instanceIndex: 0
  36. }
  37. let hasNext = value.elementIndex < elementCount
  38. let isNextNewInstance = false
  39. let elementIndex = 0
  40. let instanceIndex = 0
  41. return {
  42. get hasNext () { return hasNext },
  43. get isNextNewInstance () { return isNextNewInstance },
  44. get elementCount () { return elementCount },
  45. get instanceCount () { return instanceCount },
  46. move() {
  47. if (hasNext) {
  48. value.elementIndex = elementIndex
  49. value.instanceIndex = instanceIndex
  50. value.index = instanceIndex * elementCount + elementIndex
  51. value.location = getLocation(elementIndex, instanceIndex)
  52. ++elementIndex
  53. if (elementIndex === elementCount) {
  54. ++instanceIndex
  55. isNextNewInstance = true
  56. if (instanceIndex < instanceCount) elementIndex = 0
  57. } else {
  58. isNextNewInstance = false
  59. }
  60. hasNext = elementIndex < elementCount
  61. }
  62. return value
  63. },
  64. skipInstance() {
  65. if (hasNext && value.instanceIndex === instanceIndex) {
  66. ++instanceIndex
  67. elementIndex = 0
  68. hasNext = instanceIndex < instanceCount
  69. }
  70. }
  71. }
  72. }
  73. export namespace StructureElementIterator {
  74. export function fromGroup(group: Unit.SymmetryGroup): LocationIterator {
  75. const unit = group.units[0]
  76. const elementCount = group.elements.length
  77. const instanceCount = group.units.length
  78. const location = StructureElement.create(unit)
  79. const getLocation = (elementIndex: number, instanceIndex: number) => {
  80. location.element = unit.elements[elementIndex]
  81. return location
  82. }
  83. return LocationIterator(elementCount, instanceCount, getLocation)
  84. }
  85. }
  86. export namespace LinkIterator {
  87. export function fromGroup(group: Unit.SymmetryGroup): LocationIterator {
  88. const unit = group.units[0]
  89. const elementCount = Unit.isAtomic(unit) ? unit.links.edgeCount * 2 : 0
  90. const instanceCount = group.units.length
  91. const location = StructureElement.create(unit)
  92. const getLocation = (elementIndex: number, instanceIndex: number) => {
  93. location.element = unit.elements[(unit as Unit.Atomic).links.a[elementIndex]]
  94. return location
  95. }
  96. return LocationIterator(elementCount, instanceCount, getLocation)
  97. }
  98. export function fromStructure(structure: Structure): LocationIterator {
  99. const elementCount = structure.links.bondCount
  100. const instanceCount = 1
  101. const location = Link.Location()
  102. const getLocation = (elementIndex: number, instanceIndex: number) => {
  103. const bond = structure.links.bonds[elementIndex]
  104. location.aUnit = bond.unitA
  105. location.aIndex = bond.indexA as StructureElement.UnitIndex
  106. location.bUnit = bond.unitB
  107. location.bIndex = bond.indexB as StructureElement.UnitIndex
  108. return location
  109. }
  110. return LocationIterator(elementCount, instanceCount, getLocation)
  111. }
  112. }