Browse Source

Merge branch 'master' of https://github.com/molstar/molstar

David Sehnal 5 years ago
parent
commit
2e215440f7

+ 11 - 0
src/mol-repr/structure/visual/util/common.ts

@@ -15,6 +15,7 @@ import { fillSerial } from '../../../../mol-util/array';
 import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
 import { AssignableArrayLike } from '../../../../mol-util/type-helpers';
 import { getBoundary } from '../../../../mol-math/geometry/boundary';
+import { Box3D } from '../../../../mol-math/geometry';
 
 /** Return a Loci for the elements of a whole residue the elementIndex belongs to. */
 export function getResidueLoci(structure: Structure, unit: Unit.Atomic, elementIndex: ElementIndex): Loci {
@@ -99,6 +100,16 @@ export function includesUnitKind(unitKinds: UnitKind[], unit: Unit) {
 
 //
 
+const MaxCells = 500_000_000;
+
+/** guard against overly high resolution for the given box size */
+export function ensureReasonableResolution<T>(box: Box3D, props: { resolution: number } & T) {
+    const volume = Box3D.volume(box);
+    const approxCells = volume / props.resolution;
+    const resolution = approxCells > MaxCells ? volume / MaxCells : props.resolution;
+    return { ...props, resolution };
+}
+
 export function getConformation(unit: Unit) {
     switch (unit.kind) {
         case Unit.Kind.Atomic: return unit.model.atomicConformation;

+ 19 - 9
src/mol-repr/structure/visual/util/gaussian.ts

@@ -11,7 +11,7 @@ import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
 import { GaussianDensityTexture, GaussianDensityTexture2d } from '../../../../mol-math/geometry/gaussian-density/gpu';
 import { Texture } from '../../../../mol-gl/webgl/texture';
 import { WebGLContext } from '../../../../mol-gl/webgl/context';
-import { getUnitConformationAndRadius, getStructureConformationAndRadius, CommonSurfaceParams } from './common';
+import { getUnitConformationAndRadius, getStructureConformationAndRadius, CommonSurfaceParams, ensureReasonableResolution } from './common';
 import { BaseGeometry } from '../../../../mol-geo/geometry/base';
 
 const SharedGaussianDensityParams = {
@@ -37,38 +37,48 @@ export type GaussianDensityTextureProps = typeof DefaultGaussianDensityTexturePr
 //
 
 export function computeUnitGaussianDensity(structure: Structure, unit: Unit, props: GaussianDensityProps, webgl?: WebGLContext) {
-    const { position, radius } = getUnitConformationAndRadius(structure, unit, props);
+    const { box } = unit.lookup3d.boundary;
+    const p = ensureReasonableResolution(box, props);
+    const { position, radius } = getUnitConformationAndRadius(structure, unit, p);
     return Task.create('Gaussian Density', async ctx => {
-        return await GaussianDensity(ctx, position, unit.lookup3d.boundary.box, radius, props, webgl);
+        return await GaussianDensity(ctx, position, box, radius, p, webgl);
     });
 }
 
 export function computeUnitGaussianDensityTexture(structure: Structure, unit: Unit, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) {
-    const { position, radius } = getUnitConformationAndRadius(structure, unit, props);
+    const { box } = unit.lookup3d.boundary;
+    const p = ensureReasonableResolution(box, props);
+    const { position, radius } = getUnitConformationAndRadius(structure, unit, p);
     return Task.create('Gaussian Density', async ctx => {
-        return GaussianDensityTexture(webgl, position, unit.lookup3d.boundary.box, radius, props, texture);
+        return GaussianDensityTexture(webgl, position, box, radius, p, texture);
     });
 }
 
 export function computeUnitGaussianDensityTexture2d(structure: Structure, unit: Unit, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) {
-    const { position, radius } = getUnitConformationAndRadius(structure, unit, props);
+    const { box } = unit.lookup3d.boundary;
+    const p = ensureReasonableResolution(box, props);
+    const { position, radius } = getUnitConformationAndRadius(structure, unit, p);
     return Task.create('Gaussian Density', async ctx => {
-        return GaussianDensityTexture2d(webgl, position, unit.lookup3d.boundary.box, radius, props, texture);
+        return GaussianDensityTexture2d(webgl, position, box, radius, p, texture);
     });
 }
 
 //
 
 export function computeStructureGaussianDensity(structure: Structure, props: GaussianDensityProps, webgl?: WebGLContext) {
+    const { box } = structure.lookup3d.boundary;
+    const p = ensureReasonableResolution(box, props);
     const { position, radius } = getStructureConformationAndRadius(structure, props.ignoreHydrogens, props.traceOnly);
     return Task.create('Gaussian Density', async ctx => {
-        return await GaussianDensity(ctx, position, structure.lookup3d.boundary.box, radius, props, webgl);
+        return await GaussianDensity(ctx, position, box, radius, p, webgl);
     });
 }
 
 export function computeStructureGaussianDensityTexture(structure: Structure, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) {
+    const { box } = structure.lookup3d.boundary;
+    const p = ensureReasonableResolution(box, props);
     const { position, radius } = getStructureConformationAndRadius(structure, props.ignoreHydrogens, props.traceOnly);
     return Task.create('Gaussian Density', async ctx => {
-        return GaussianDensityTexture(webgl, position, structure.lookup3d.boundary.box, radius, props, texture);
+        return GaussianDensityTexture(webgl, position, box, radius, p, texture);
     });
 }

+ 4 - 3
src/mol-repr/structure/visual/util/molecular-surface.ts

@@ -6,7 +6,7 @@
 
 import { Unit, Structure } from '../../../../mol-model/structure';
 import { Task, RuntimeContext } from '../../../../mol-task';
-import { getUnitConformationAndRadius, CommonSurfaceProps } from './common';
+import { getUnitConformationAndRadius, CommonSurfaceProps, ensureReasonableResolution } from './common';
 import { PositionData, DensityData, Box3D } from '../../../../mol-math/geometry';
 import { MolecularSurfaceCalculationProps, calcMolecularSurface } from '../../../../mol-math/geometry/molecular-surface';
 import { OrderedSet } from '../../../../mol-data/int';
@@ -34,9 +34,10 @@ function getPositionDataAndMaxRadius(structure: Structure, unit: Unit, props: Mo
 
 export function computeUnitMolecularSurface(structure: Structure, unit: Unit, props: MolecularSurfaceProps) {
     const { box } = unit.lookup3d.boundary;
-    const { position, boundary, maxRadius } = getPositionDataAndMaxRadius(structure, unit, props);
+    const p = ensureReasonableResolution(box, props);
+    const { position, boundary, maxRadius } = getPositionDataAndMaxRadius(structure, unit, p);
     return Task.create('Molecular Surface', async ctx => {
-        return await MolecularSurface(ctx, position, boundary, maxRadius, box, props);
+        return await MolecularSurface(ctx, position, boundary, maxRadius, box, p);
     });
 }
 

+ 10 - 7
src/mol-repr/util.ts

@@ -7,6 +7,7 @@
 import { defaults } from '../mol-util';
 import { Structure } from '../mol-model/structure';
 import { VisualQuality } from '../mol-geo/geometry/base';
+import { Box3D } from '../mol-math/geometry';
 
 export interface VisualUpdateState {
     updateTransform: boolean
@@ -93,8 +94,10 @@ export function getQualityProps(props: Partial<QualityProps>, data?: any) {
     let resolution = defaults(props.resolution, 2);
     let doubleSided = defaults(props.doubleSided, true);
 
+    let volume = 0;
     if (quality === 'auto' && data instanceof Structure) {
         quality = getStructureQuality(data.root);
+        volume = Box3D.volume(data.boundary.box);
     }
 
     switch (quality) {
@@ -102,49 +105,49 @@ export function getQualityProps(props: Partial<QualityProps>, data?: any) {
             detail = 3;
             radialSegments = 36;
             linearSegments = 18;
-            resolution = 0.1;
+            resolution = Math.max(volume / 500_000_000, 0.1);
             doubleSided = true;
             break;
         case 'higher':
             detail = 3;
             radialSegments = 28;
             linearSegments = 14;
-            resolution = 0.3;
+            resolution = Math.max(volume / 400_000_000, 0.3);
             doubleSided = true;
             break;
         case 'high':
             detail = 2;
             radialSegments = 20;
             linearSegments = 10;
-            resolution = 0.5;
+            resolution = Math.max(volume / 300_000_000, 0.5);
             doubleSided = true;
             break;
         case 'medium':
             detail = 1;
             radialSegments = 12;
             linearSegments = 8;
-            resolution = 1;
+            resolution = Math.max(volume / 200_000_000, 1);
             doubleSided = true;
             break;
         case 'low':
             detail = 0;
             radialSegments = 8;
             linearSegments = 3;
-            resolution = 2;
+            resolution = Math.max(volume / 150_000_000, 2);
             doubleSided = false;
             break;
         case 'lower':
             detail = 0;
             radialSegments = 4;
             linearSegments = 2;
-            resolution = 4;
+            resolution = Math.max(volume / 100_000_000, 4);
             doubleSided = false;
             break;
         case 'lowest':
             detail = 0;
             radialSegments = 2;
             linearSegments = 1;
-            resolution = 8;
+            resolution = Math.max(volume / 75_000_000, 8);
             doubleSided = false;
             break;
         case 'custom':