lookup3d.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /**
  2. * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. import Structure from '../structure'
  8. import { Lookup3D, GridLookup3D, Box3D, Sphere3D, Result } from '../../../../mol-math/geometry';
  9. import { Vec3 } from '../../../../mol-math/linear-algebra';
  10. import { computeStructureBoundary } from './boundary';
  11. import { OrderedSet } from '../../../../mol-data/int';
  12. import { StructureUniqueSubsetBuilder } from './unique-subset-builder';
  13. import StructureElement from '../element';
  14. import Unit from '../unit';
  15. export interface StructureResult extends Result<StructureElement.UnitIndex> {
  16. units: Unit[]
  17. }
  18. export namespace StructureResult {
  19. export function add(result: StructureResult, unit: Unit, index: StructureElement.UnitIndex, distSq: number) {
  20. result.indices[result.count] = index;
  21. result.units[result.count] = unit;
  22. result.squaredDistances[result.count] = distSq;
  23. result.count++;
  24. }
  25. export function create(): StructureResult {
  26. return { count: 0, indices: [], units: [], squaredDistances: [] };
  27. }
  28. export function copy(out: StructureResult, result: StructureResult) {
  29. for (let i = 0; i < result.count; ++i) {
  30. out.indices[i] = result.indices[i];
  31. out.units[i] = result.units[i];
  32. out.squaredDistances[i] = result.squaredDistances[i];
  33. }
  34. out.count = result.count
  35. return out
  36. }
  37. }
  38. export class StructureLookup3D {
  39. private unitLookup: Lookup3D;
  40. private pivot = Vec3.zero();
  41. findUnitIndices(x: number, y: number, z: number, radius: number): Result<number> {
  42. return this.unitLookup.find(x, y, z, radius);
  43. }
  44. private result = StructureResult.create();
  45. find(x: number, y: number, z: number, radius: number): StructureResult {
  46. Result.reset(this.result);
  47. const { units } = this.structure;
  48. const closeUnits = this.unitLookup.find(x, y, z, radius);
  49. if (closeUnits.count === 0) return this.result;
  50. for (let t = 0, _t = closeUnits.count; t < _t; t++) {
  51. const unit = units[closeUnits.indices[t]];
  52. Vec3.set(this.pivot, x, y, z);
  53. if (!unit.conformation.operator.isIdentity) {
  54. Vec3.transformMat4(this.pivot, this.pivot, unit.conformation.operator.inverse);
  55. }
  56. const unitLookup = unit.lookup3d;
  57. const groupResult = unitLookup.find(this.pivot[0], this.pivot[1], this.pivot[2], radius);
  58. for (let j = 0, _j = groupResult.count; j < _j; j++) {
  59. StructureResult.add(this.result, unit, groupResult.indices[j], groupResult.squaredDistances[j]);
  60. }
  61. }
  62. return this.result;
  63. }
  64. findIntoBuilder(x: number, y: number, z: number, radius: number, builder: StructureUniqueSubsetBuilder) {
  65. const { units } = this.structure;
  66. const closeUnits = this.unitLookup.find(x, y, z, radius);
  67. if (closeUnits.count === 0) return;
  68. for (let t = 0, _t = closeUnits.count; t < _t; t++) {
  69. const unit = units[closeUnits.indices[t]];
  70. Vec3.set(this.pivot, x, y, z);
  71. if (!unit.conformation.operator.isIdentity) {
  72. Vec3.transformMat4(this.pivot, this.pivot, unit.conformation.operator.inverse);
  73. }
  74. const unitLookup = unit.lookup3d;
  75. const groupResult = unitLookup.find(this.pivot[0], this.pivot[1], this.pivot[2], radius);
  76. if (groupResult.count === 0) continue;
  77. const elements = unit.elements;
  78. builder.beginUnit(unit.id);
  79. for (let j = 0, _j = groupResult.count; j < _j; j++) {
  80. builder.addElement(elements[groupResult.indices[j]]);
  81. }
  82. builder.commitUnit();
  83. }
  84. }
  85. findIntoBuilderWithRadius(x: number, y: number, z: number, pivotR: number, maxRadius: number, radius: number, eRadius: StructureElement.Property<number>, builder: StructureUniqueSubsetBuilder) {
  86. const { units } = this.structure;
  87. const closeUnits = this.unitLookup.find(x, y, z, radius);
  88. if (closeUnits.count === 0) return;
  89. const se = StructureElement.Location.create();
  90. const queryRadius = pivotR + maxRadius + radius;
  91. for (let t = 0, _t = closeUnits.count; t < _t; t++) {
  92. const unit = units[closeUnits.indices[t]];
  93. Vec3.set(this.pivot, x, y, z);
  94. if (!unit.conformation.operator.isIdentity) {
  95. Vec3.transformMat4(this.pivot, this.pivot, unit.conformation.operator.inverse);
  96. }
  97. const unitLookup = unit.lookup3d;
  98. const groupResult = unitLookup.find(this.pivot[0], this.pivot[1], this.pivot[2], queryRadius);
  99. if (groupResult.count === 0) continue;
  100. const elements = unit.elements;
  101. se.unit = unit;
  102. builder.beginUnit(unit.id);
  103. for (let j = 0, _j = groupResult.count; j < _j; j++) {
  104. se.element = elements[groupResult.indices[j]];
  105. const rr = eRadius(se);
  106. if (Math.sqrt(groupResult.squaredDistances[j]) - pivotR - rr > radius) continue;
  107. builder.addElement(elements[groupResult.indices[j]]);
  108. }
  109. builder.commitUnit();
  110. }
  111. }
  112. check(x: number, y: number, z: number, radius: number): boolean {
  113. const { units } = this.structure;
  114. const closeUnits = this.unitLookup.find(x, y, z, radius);
  115. if (closeUnits.count === 0) return false;
  116. for (let t = 0, _t = closeUnits.count; t < _t; t++) {
  117. const unit = units[closeUnits.indices[t]];
  118. Vec3.set(this.pivot, x, y, z);
  119. if (!unit.conformation.operator.isIdentity) {
  120. Vec3.transformMat4(this.pivot, this.pivot, unit.conformation.operator.inverse);
  121. }
  122. const groupLookup = unit.lookup3d;
  123. if (groupLookup.check(this.pivot[0], this.pivot[1], this.pivot[2], radius)) return true;
  124. }
  125. return false;
  126. }
  127. _boundary: { box: Box3D; sphere: Sphere3D; } | undefined = void 0;
  128. get boundary() {
  129. if (this._boundary) return this._boundary!;
  130. this._boundary = computeStructureBoundary(this.structure);
  131. return this._boundary!;
  132. }
  133. constructor(private structure: Structure) {
  134. const { units } = structure;
  135. const unitCount = units.length;
  136. const xs = new Float32Array(unitCount);
  137. const ys = new Float32Array(unitCount);
  138. const zs = new Float32Array(unitCount);
  139. const radius = new Float32Array(unitCount);
  140. const center = Vec3.zero();
  141. for (let i = 0; i < unitCount; i++) {
  142. const unit = units[i];
  143. const lookup = unit.lookup3d;
  144. const s = lookup.boundary.sphere;
  145. Vec3.transformMat4(center, s.center, unit.conformation.operator.matrix);
  146. xs[i] = center[0];
  147. ys[i] = center[1];
  148. zs[i] = center[2];
  149. radius[i] = s.radius;
  150. }
  151. this.unitLookup = GridLookup3D({ x: xs, y: ys, z: zs, radius, indices: OrderedSet.ofBounds(0, unitCount) });
  152. }
  153. }