volume.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { VolumeData, VolumeIsoValue } from './data';
  7. import { OrderedSet } from '../../mol-data/int';
  8. import { Sphere3D } from '../../mol-math/geometry';
  9. import { Vec3, Mat4 } from '../../mol-math/linear-algebra';
  10. import { BoundaryHelper } from '../../mol-math/geometry/boundary-helper';
  11. import { CubeFormat } from '../../mol-model-formats/volume/cube';
  12. export namespace Volume {
  13. export type CellIndex = { readonly '@type': 'cell-index' } & number
  14. export function isOrbitals(volume: VolumeData) {
  15. if (!CubeFormat.is(volume.sourceData)) return false;
  16. return volume.sourceData.data.header.orbitals;
  17. }
  18. export interface Loci { readonly kind: 'volume-loci', readonly volume: VolumeData }
  19. export function Loci(volume: VolumeData): Loci { return { kind: 'volume-loci', volume }; }
  20. export function isLoci(x: any): x is Loci { return !!x && x.kind === 'volume-loci'; }
  21. export function areLociEqual(a: Loci, b: Loci) { return a.volume === b.volume; }
  22. export function isLociEmpty(loci: Loci) { return loci.volume.data.data.length === 0; }
  23. export function getBoundingSphere(volume: VolumeData, boundingSphere?: Sphere3D) {
  24. if (!boundingSphere) boundingSphere = Sphere3D();
  25. const transform = VolumeData.getGridToCartesianTransform(volume);
  26. const [x, y, z] = volume.data.space.dimensions;
  27. const cpA = Vec3.create(0, 0, 0); Vec3.transformMat4(cpA, cpA, transform);
  28. const cpB = Vec3.create(x, y, z); Vec3.transformMat4(cpB, cpB, transform);
  29. const cpC = Vec3.create(x, 0, 0); Vec3.transformMat4(cpC, cpC, transform);
  30. const cpD = Vec3.create(0, y, z); Vec3.transformMat4(cpD, cpC, transform);
  31. const cpE = Vec3.create(0, 0, z); Vec3.transformMat4(cpE, cpE, transform);
  32. const cpF = Vec3.create(x, 0, z); Vec3.transformMat4(cpF, cpF, transform);
  33. const cpG = Vec3.create(x, y, 0); Vec3.transformMat4(cpG, cpG, transform);
  34. const cpH = Vec3.create(0, y, 0); Vec3.transformMat4(cpH, cpH, transform);
  35. const center = Vec3();
  36. Vec3.add(center, cpA, cpB);
  37. Vec3.scale(center, center, 0.5);
  38. const d = Math.max(Vec3.distance(cpA, cpB), Vec3.distance(cpC, cpD));
  39. Sphere3D.set(boundingSphere, center, d / 2);
  40. Sphere3D.setExtrema(boundingSphere, [cpA, cpB, cpC, cpD, cpE, cpF, cpG, cpH]);
  41. return boundingSphere;
  42. }
  43. export namespace Isosurface {
  44. export interface Loci { readonly kind: 'isosurface-loci', readonly volume: VolumeData, readonly isoValue: VolumeIsoValue }
  45. export function Loci(volume: VolumeData, isoValue: VolumeIsoValue): Loci { return { kind: 'isosurface-loci', volume, isoValue }; }
  46. export function isLoci(x: any): x is Loci { return !!x && x.kind === 'isosurface-loci'; }
  47. export function areLociEqual(a: Loci, b: Loci) { return a.volume === b.volume && VolumeIsoValue.areSame(a.isoValue, b.isoValue, a.volume.dataStats); }
  48. export function isLociEmpty(loci: Loci) { return loci.volume.data.data.length === 0; }
  49. export function getBoundingSphere(volume: VolumeData, isoValue: VolumeIsoValue, boundingSphere?: Sphere3D) {
  50. // TODO get bounding sphere for subgrid with values >= isoValue
  51. return Volume.getBoundingSphere(volume, boundingSphere);
  52. }
  53. }
  54. export namespace Cell {
  55. export interface Loci { readonly kind: 'cell-loci', readonly volume: VolumeData, readonly indices: OrderedSet<CellIndex> }
  56. export function Loci(volume: VolumeData, indices: OrderedSet<CellIndex>): Loci { return { kind: 'cell-loci', volume, indices }; }
  57. export function isLoci(x: any): x is Loci { return !!x && x.kind === 'cell-loci'; }
  58. export function areLociEqual(a: Loci, b: Loci) { return a.volume === b.volume && OrderedSet.areEqual(a.indices, b.indices); }
  59. export function isLociEmpty(loci: Loci) { return OrderedSet.size(loci.indices) === 0; }
  60. const boundaryHelper = new BoundaryHelper('98');
  61. const tmpBoundaryPos = Vec3();
  62. export function getBoundingSphere(volume: VolumeData, indices: OrderedSet<CellIndex>, boundingSphere?: Sphere3D) {
  63. boundaryHelper.reset();
  64. const transform = VolumeData.getGridToCartesianTransform(volume);
  65. const { getCoords } = volume.data.space;
  66. for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
  67. const o = OrderedSet.getAt(indices, i);
  68. getCoords(o, tmpBoundaryPos);
  69. Vec3.transformMat4(tmpBoundaryPos, tmpBoundaryPos, transform);
  70. boundaryHelper.includePosition(tmpBoundaryPos);
  71. }
  72. boundaryHelper.finishedIncludeStep();
  73. for (let i = 0, _i = OrderedSet.size(indices); i < _i; i++) {
  74. const o = OrderedSet.getAt(indices, i);
  75. getCoords(o, tmpBoundaryPos);
  76. Vec3.transformMat4(tmpBoundaryPos, tmpBoundaryPos, transform);
  77. boundaryHelper.radiusPosition(tmpBoundaryPos);
  78. }
  79. const bs = boundaryHelper.getSphere(boundingSphere);
  80. return Sphere3D.expand(bs, bs, Mat4.getMaxScaleOnAxis(transform) * 10);
  81. }
  82. }
  83. }