loci.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /**
  2. * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { StructureElement } from './structure'
  7. import { Link } from './structure/structure/unit/links'
  8. import { Shape, ShapeGroup } from './shape';
  9. import { Sphere3D } from 'mol-math/geometry';
  10. import { CentroidHelper } from 'mol-math/geometry/centroid-helper';
  11. import { Vec3 } from 'mol-math/linear-algebra';
  12. import { OrderedSet } from 'mol-data/int';
  13. import { Structure } from './structure/structure';
  14. /** A Loci that includes every loci */
  15. export const EveryLoci = { kind: 'every-loci' as 'every-loci' }
  16. export type EveryLoci = typeof EveryLoci
  17. export function isEveryLoci(x: any): x is EveryLoci {
  18. return !!x && x.kind === 'every-loci';
  19. }
  20. /** A Loci that is empty */
  21. export const EmptyLoci = { kind: 'empty-loci' as 'empty-loci' }
  22. export type EmptyLoci = typeof EmptyLoci
  23. export function isEmptyLoci(x: any): x is EmptyLoci {
  24. return !!x && x.kind === 'empty-loci';
  25. }
  26. /** A generic data loci */
  27. export interface DataLoci {
  28. readonly kind: 'data-loci',
  29. readonly data: any,
  30. readonly tag: string
  31. readonly indices: OrderedSet<number>
  32. }
  33. export function isDataLoci(x: any): x is DataLoci {
  34. return !!x && x.kind === 'data-loci';
  35. }
  36. export function areDataLociEqual(a: DataLoci, b: DataLoci) {
  37. return a.data === b.data && a.tag === b.tag && OrderedSet.areEqual(a.indices, b.indices)
  38. }
  39. export function createDataLoci(data: any, tag: string, indices: OrderedSet<number>): DataLoci {
  40. return { kind: 'data-loci', data, tag, indices }
  41. }
  42. export { Loci }
  43. type Loci = StructureElement.Loci | Structure.Loci | Link.Loci | EveryLoci | EmptyLoci | DataLoci | Shape.Loci | ShapeGroup.Loci
  44. namespace Loci {
  45. export function areEqual(lociA: Loci, lociB: Loci) {
  46. if (isEveryLoci(lociA) && isEveryLoci(lociB)) return true
  47. if (isEmptyLoci(lociA) && isEmptyLoci(lociB)) return true
  48. if (isDataLoci(lociA) && isDataLoci(lociB)) {
  49. return areDataLociEqual(lociA, lociB)
  50. }
  51. if (Structure.isLoci(lociA) && Structure.isLoci(lociB)) {
  52. return Structure.areLociEqual(lociA, lociB)
  53. }
  54. if (StructureElement.isLoci(lociA) && StructureElement.isLoci(lociB)) {
  55. return StructureElement.areLociEqual(lociA, lociB)
  56. }
  57. if (Link.isLoci(lociA) && Link.isLoci(lociB)) {
  58. return Link.areLociEqual(lociA, lociB)
  59. }
  60. if (Shape.isLoci(lociA) && Shape.isLoci(lociB)) {
  61. return Shape.areLociEqual(lociA, lociB)
  62. }
  63. if (ShapeGroup.isLoci(lociA) && ShapeGroup.isLoci(lociB)) {
  64. return ShapeGroup.areLociEqual(lociA, lociB)
  65. }
  66. return false
  67. }
  68. const sphereHelper = new CentroidHelper(), tempPos = Vec3.zero();
  69. export function getBoundingSphere(loci: Loci, boundingSphere?: Sphere3D): Sphere3D | undefined {
  70. if (loci.kind === 'every-loci' || loci.kind === 'empty-loci') return void 0;
  71. if (!boundingSphere) boundingSphere = Sphere3D.zero()
  72. sphereHelper.reset();
  73. if (loci.kind === 'structure-loci') {
  74. return Sphere3D.copy(boundingSphere, loci.structure.boundary.sphere)
  75. } else if (loci.kind === 'element-loci') {
  76. return StructureElement.Loci.getBoundary(loci).sphere;
  77. } else if (loci.kind === 'link-loci') {
  78. for (const e of loci.links) {
  79. e.aUnit.conformation.position(e.aUnit.elements[e.aIndex], tempPos);
  80. sphereHelper.includeStep(tempPos);
  81. e.bUnit.conformation.position(e.bUnit.elements[e.bIndex], tempPos);
  82. sphereHelper.includeStep(tempPos);
  83. }
  84. sphereHelper.finishedIncludeStep();
  85. for (const e of loci.links) {
  86. e.aUnit.conformation.position(e.aUnit.elements[e.aIndex], tempPos);
  87. sphereHelper.radiusStep(tempPos);
  88. e.aUnit.conformation.position(e.bUnit.elements[e.bIndex], tempPos);
  89. sphereHelper.radiusStep(tempPos);
  90. }
  91. } else if (loci.kind === 'shape-loci') {
  92. // TODO
  93. return void 0;
  94. } else if (loci.kind === 'group-loci') {
  95. // TODO
  96. return void 0;
  97. } else if (loci.kind === 'data-loci') {
  98. // TODO maybe add loci.getBoundingSphere()???
  99. return void 0;
  100. }
  101. Vec3.copy(boundingSphere.center, sphereHelper.center)
  102. boundingSphere.radius = Math.sqrt(sphereHelper.radiusSq)
  103. return boundingSphere
  104. }
  105. const tmpSphere3D = Sphere3D.zero()
  106. export function getCenter(loci: Loci, center?: Vec3): Vec3 | undefined {
  107. const boundingSphere = getBoundingSphere(loci, tmpSphere3D)
  108. return boundingSphere ? Vec3.copy(center || Vec3.zero(), boundingSphere.center) : undefined
  109. }
  110. }