Ver código fonte

take parent structure into account for surface calculations

- new option `includeParent`
Alexander Rose 5 anos atrás
pai
commit
adbe8e1f67

+ 14 - 11
src/mol-geo/util/marching-cubes/algorithm.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -166,6 +166,19 @@ class MarchingCubesState {
         const v1 = sfg(sf, hi, hj, hk);
         const t = (this.isoLevel - v0) / (v0 - v1);
 
+        if (this.idField) {
+            const u = this.idFieldGet!(this.idField, li, lj, lk);
+            const v = this.idFieldGet!(this.idField, hi, hj, hk)
+            let a = t < 0.5 ? u : v;
+            // -1 means 'no id', check if the other cell has an id
+            if (a === -1) a = t < 0.5 ? v : u;
+            // -2 means 'ignore this cell'
+            if (a === -2) return -1
+            this.builder.addGroup(a);
+        } else {
+            this.builder.addGroup(0);
+        }
+
         const id = this.builder.addVertex(
             li + t * (li - hi),
             lj + t * (lj - hj),
@@ -189,16 +202,6 @@ class MarchingCubesState {
             n0z + t * (n0z - n1z)
         )
 
-        if (this.idField) {
-            const u = this.idFieldGet!(this.idField, li, lj, lk);
-            const v = this.idFieldGet!(this.idField, hi, hj, hk)
-            let a = t < 0.5 ? u : v;
-            if (a < 0) a = t < 0.5 ? v : u;
-            this.builder.addGroup(a);
-        } else {
-            this.builder.addGroup(0);
-        }
-
         return id;
     }
 

+ 23 - 13
src/mol-geo/util/marching-cubes/builder.ts

@@ -44,8 +44,13 @@ export function MarchinCubesMeshBuilder(vertexChunkSize: number, mesh?: Mesh): M
             ChunkedArray.add(groups, group);
         },
         addTriangle: (vertList: number[], a: number, b: number, c: number) => {
-            ++triangleCount
-            ChunkedArray.add3(indices, vertList[a], vertList[b], vertList[c]);
+            const i = vertList[a], j = vertList[b], k = vertList[c]
+            // vertex indices <0 mean that the vertex was ignored and is not available
+            // and hence we don't add a triangle when this occurs
+            if (i >= 0 && j >= 0 && k >= 0) {
+                ++triangleCount
+                ChunkedArray.add3(indices, i, j, k)
+            }
         },
         get: () => {
             const vb = ChunkedArray.compact(vertices, true) as Float32Array;
@@ -73,17 +78,22 @@ export function MarchinCubesLinesBuilder(vertexChunkSize: number, lines?: Lines)
             ChunkedArray.add(groups, group);
         },
         addTriangle: (vertList: number[], a: number, b: number, c: number, edgeFilter: number) => {
-            if (AllowedContours[a][b] & edgeFilter) {
-                ++linesCount
-                ChunkedArray.add2(indices, vertList[a], vertList[b])
-            }
-            if (AllowedContours[b][c] & edgeFilter) {
-                ++linesCount
-                ChunkedArray.add2(indices, vertList[b], vertList[c])
-            }
-            if (AllowedContours[a][c] & edgeFilter) {
-                ++linesCount
-                ChunkedArray.add2(indices, vertList[a], vertList[c])
+            const i = vertList[a], j = vertList[b], k = vertList[c]
+            // vertex indices <0 mean that the vertex was ignored and is not available
+            // and hence we don't add a triangle when this occurs
+            if (i >= 0 && j >= 0 && k >= 0) {
+                if (AllowedContours[a][b] & edgeFilter) {
+                    ++linesCount
+                    ChunkedArray.add2(indices, vertList[a], vertList[b])
+                }
+                if (AllowedContours[b][c] & edgeFilter) {
+                    ++linesCount
+                    ChunkedArray.add2(indices, vertList[b], vertList[c])
+                }
+                if (AllowedContours[a][c] & edgeFilter) {
+                    ++linesCount
+                    ChunkedArray.add2(indices, vertList[a], vertList[c])
+                }
             }
         },
         get: () => {

+ 8 - 7
src/mol-math/geometry/molecular-surface.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Fred Ludlow <fred.ludlow@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -53,7 +53,7 @@ export const DefaultMolecularSurfaceCalculationProps = PD.getDefaultValues(Molec
 export type MolecularSurfaceCalculationProps = typeof DefaultMolecularSurfaceCalculationProps
 
 
-export async function calcMolecularSurface(ctx: RuntimeContext, position: Required<PositionData>, maxRadius: number,  props: MolecularSurfaceCalculationProps) {
+export async function calcMolecularSurface(ctx: RuntimeContext, position: Required<PositionData>, maxRadius: number, box: Box3D | null, props: MolecularSurfaceCalculationProps) {
     // Field generation method adapted from AstexViewer (Mike Hartshorn) by Fred Ludlow.
     // Other parts based heavily on NGL (Alexander Rose) EDT Surface class
 
@@ -78,7 +78,7 @@ export async function calcMolecularSurface(ctx: RuntimeContext, position: Requir
         }
 
         for (let j = 0, jl = neighbours.count; j < jl; ++j) {
-            const ai = OrderedSet.getAt(position.indices, neighbours.indices[j])
+            const ai = OrderedSet.getAt(indices, neighbours.indices[j])
             if (ai !== a && ai !== b && singleAtomObscures(ai, x, y, z)) {
                 lastClip = ai
                 return ai
@@ -281,7 +281,7 @@ export async function calcMolecularSurface(ctx: RuntimeContext, position: Requir
                                 // Is this grid point closer to a or b?
                                 // Take dot product of atob and gridpoint->p (dx, dy, dz)
                                 const dp = dx * atob[0] + dy * atob[1] + dz * atob[2]
-                                idData[idx] = id[OrderedSet.indexOf(position.indices, dp < 0.0 ? b : a)]
+                                idData[idx] = id[OrderedSet.indexOf(indices, dp < 0.0 ? b : a)]
                             }
                         }
                     }
@@ -317,15 +317,16 @@ export async function calcMolecularSurface(ctx: RuntimeContext, position: Requir
     const scaleFactor = 1 / resolution
     const ngTorus = Math.max(5, 2 + Math.floor(probeRadius * scaleFactor))
 
-    const cellSize =  Vec3.create(maxRadius, maxRadius, maxRadius)
+    const cellSize = Vec3.create(maxRadius, maxRadius, maxRadius)
     Vec3.scale(cellSize, cellSize, 2)
     const lookup3d = GridLookup3D(position, cellSize)
     const neighbours = lookup3d.result
-    const box = lookup3d.boundary.box
+    if (box === null) box = lookup3d.boundary.box
+
     const { indices, x: px, y: py, z: pz, id, radius } = position
     const n = OrderedSet.size(indices)
 
-    const pad = maxRadius * 2 + resolution
+    const pad = maxRadius + resolution
     const expandedBox = Box3D.expand(Box3D(), box, Vec3.create(pad, pad, pad));
     const [ minX, minY, minZ ] = expandedBox.min
     const scaledBox = Box3D.scale(Box3D(), expandedBox, scaleFactor)

+ 1 - 0
src/mol-repr/structure/visual/gaussian-density-volume.ts

@@ -50,6 +50,7 @@ export function GaussianDensityVolumeVisual(materialId: number): ComplexVisual<G
                 newProps.isoValueNorm = Math.exp(-newProps.smoothness)
             }
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true
+            if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true
         }
     }, materialId)
 }

+ 3 - 0
src/mol-repr/structure/visual/gaussian-surface-mesh.ts

@@ -66,6 +66,7 @@ export function GaussianSurfaceMeshVisual(materialId: number): UnitsVisual<Gauss
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true
             if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true
+            if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true
         }
     }, materialId)
 }
@@ -109,6 +110,7 @@ export function StructureGaussianSurfaceMeshVisual(materialId: number): ComplexV
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true
             if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true
+            if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true
         }
     }, materialId)
 }
@@ -154,6 +156,7 @@ export function GaussianSurfaceTextureMeshVisual(materialId: number): UnitsVisua
             if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true
+            if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true
         }
     }, materialId)
 }

+ 1 - 0
src/mol-repr/structure/visual/gaussian-surface-wireframe.ts

@@ -53,6 +53,7 @@ export function GaussianWireframeVisual(materialId: number): UnitsVisual<Gaussia
             if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true
             if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true
+            if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true
         }
     }, materialId)
 }

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

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -15,18 +15,18 @@ import { computeUnitMolecularSurface, MolecularSurfaceProps } from './util/molec
 import { computeMarchingCubesMesh } from '../../../mol-geo/util/marching-cubes/algorithm';
 import { ElementIterator, getElementLoci, eachElement } from './util/element';
 import { VisualUpdateState } from '../../util';
+import { CommonSurfaceParams } from './util/common';
 
 export const MolecularSurfaceMeshParams = {
     ...UnitsMeshParams,
     ...MolecularSurfaceCalculationParams,
-    ignoreHydrogens: PD.Boolean(false),
+    ...CommonSurfaceParams
 }
 export type MolecularSurfaceMeshParams = typeof MolecularSurfaceMeshParams
 
 //
 
 async function createMolecularSurfaceMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: MolecularSurfaceProps, mesh?: Mesh): Promise<Mesh> {
-
     const { transform, field, idField } = await computeUnitMolecularSurface(structure, unit, props).runInContext(ctx.runtime)
     const params = {
         isoLevel: props.probeRadius,
@@ -53,6 +53,7 @@ export function MolecularSurfaceMeshVisual(materialId: number): UnitsVisual<Mole
             if (newProps.probeRadius !== currentProps.probeRadius) state.createGeometry = true
             if (newProps.probePositions !== currentProps.probePositions) state.createGeometry = true
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true
+            if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true
         }
     }, materialId)
 }

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

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -15,19 +15,19 @@ import { computeUnitMolecularSurface, MolecularSurfaceProps } from './util/molec
 import { computeMarchingCubesLines } from '../../../mol-geo/util/marching-cubes/algorithm';
 import { ElementIterator, getElementLoci, eachElement } from './util/element';
 import { VisualUpdateState } from '../../util';
+import { CommonSurfaceParams } from './util/common';
 
 export const MolecularSurfaceWireframeParams = {
     ...UnitsLinesParams,
     ...MolecularSurfaceCalculationParams,
+    ...CommonSurfaceParams,
     sizeFactor: PD.Numeric(1.5, { min: 0, max: 10, step: 0.1 }),
-    ignoreHydrogens: PD.Boolean(false),
 }
 export type MolecularSurfaceWireframeParams = typeof MolecularSurfaceWireframeParams
 
 //
 
 async function createMolecularSurfaceWireframe(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: MolecularSurfaceProps, lines?: Lines): Promise<Lines> {
-
     const { transform, field, idField } = await computeUnitMolecularSurface(structure, unit, props).runInContext(ctx.runtime)
     const params = {
         isoLevel: props.probeRadius,
@@ -53,6 +53,7 @@ export function MolecularSurfaceWireframeVisual(materialId: number): UnitsVisual
             if (newProps.probeRadius !== currentProps.probeRadius) state.createGeometry = true
             if (newProps.probePositions !== currentProps.probePositions) state.createGeometry = true
             if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true
+            if (newProps.includeParent !== currentProps.includeParent) state.createGeometry = true
         }
     }, materialId)
 }

+ 56 - 19
src/mol-repr/structure/visual/util/common.ts

@@ -1,17 +1,19 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
 import { Unit, Structure, ElementIndex, StructureElement, ResidueIndex } from '../../../../mol-model/structure';
-import { Mat4 } from '../../../../mol-math/linear-algebra';
+import { Mat4, Vec3 } from '../../../../mol-math/linear-algebra';
 import { TransformData, createTransform } from '../../../../mol-geo/geometry/transform-data';
 import { OrderedSet, SortedArray } from '../../../../mol-data/int';
 import { EmptyLoci, Loci } from '../../../../mol-model/loci';
 import { PhysicalSizeTheme } from '../../../../mol-theme/size/physical';
 import { AtomicNumbers, AtomNumber } from '../../../../mol-model/structure/model/properties/atomic';
 import { fillSerial } from '../../../../mol-util/array';
+import { ParamDefinition as PD } from '../../../../mol-util/param-definition';
+import { AssignableArrayLike } from '../../../../mol-util/type-helpers';
 
 /** 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 {
@@ -105,37 +107,71 @@ export function getConformation(unit: Unit) {
     }
 }
 
-export function getUnitConformationAndRadius(structure: Structure, unit: Unit, ignoreHydrogens = false) {
-    const conformation = getConformation(unit)
-    const { elements } = unit
+export const CommonSurfaceParams = {
+    ignoreHydrogens: PD.Boolean(false),
+    includeParent: PD.Boolean(true, { description: 'Include elements of the parent structure in surface calculation to get a surface patch of the current structure.' }),
+}
+export const DefaultCommonSurfaceProps = PD.getDefaultValues(CommonSurfaceParams)
+export type CommonSurfaceProps = typeof DefaultCommonSurfaceProps
+
+const v = Vec3()
+function squaredDistance(x: number, y: number, z: number, center: Vec3) {
+    return Vec3.squaredDistance(Vec3.set(v, x, y, z), center)
+}
+
+/** marks `indices` for filtering/ignoring in `id` when not in `elements` */
+function filterId(id: AssignableArrayLike<number>, elements: SortedArray, indices: SortedArray) {
+    let start = 0
+    const end = elements.length
+    for (let i = 0, il = indices.length; i < il; ++i) {
+        const idx = SortedArray.indexOfInRange(elements, indices[i], start, end)
+        if (idx === -1) {
+            id[i] = -2
+        } else {
+            id[i] = idx
+            start = idx
+        }
+    }
+}
+
+export function getUnitConformationAndRadius(structure: Structure, unit: Unit, props: CommonSurfaceProps) {
+    const { ignoreHydrogens, includeParent } = props
+    const rootUnit = includeParent ? structure.root.unitMap.get(unit.id) : unit
+
+    const { x, y, z } = getConformation(rootUnit)
+    const { elements } = rootUnit
+    const { center, radius: sphereRadius } = unit.lookup3d.boundary.sphere
+    const extraRadius = (2 + 1.5) * 2 // TODO should be twice (the max vdW/sphere radius plus the probe radius)
+    const radiusSq = (sphereRadius + extraRadius) * (sphereRadius + extraRadius)
 
     let indices: SortedArray<ElementIndex>
-    let id: ArrayLike<number>
+    let id: AssignableArrayLike<number>
 
-    if (ignoreHydrogens) {
+    if (ignoreHydrogens || (includeParent && rootUnit !== unit)) {
         const _indices = []
         const _id = []
         for (let i = 0, il = elements.length; i < il; ++i) {
-            if (isHydrogen(unit, elements[i])) continue
-            _indices.push(elements[i])
+            const eI = elements[i]
+            if (ignoreHydrogens && isHydrogen(rootUnit, eI)) continue
+            if (includeParent && squaredDistance(x[eI], y[eI], z[eI], center) > radiusSq) continue
+
+            _indices.push(eI)
             _id.push(i)
         }
         indices = SortedArray.ofSortedArray(_indices)
         id = _id
     } else {
         indices = elements
-        id = fillSerial(new Uint32Array(indices.length))
+        id = fillSerial(new Int32Array(indices.length))
     }
 
-    const position = {
-        indices,
-        x: conformation.x,
-        y: conformation.y,
-        z: conformation.z,
-        id
+    if (includeParent && rootUnit !== unit) {
+        filterId(id, unit.elements, indices)
     }
 
-    const l = StructureElement.Location.create(structure, unit)
+    const position = { indices, x, y, z, id }
+
+    const l = StructureElement.Location.create(structure, rootUnit)
     const sizeTheme = PhysicalSizeTheme({}, {})
     const radius = (index: number) => {
         l.element = index as ElementIndex
@@ -145,7 +181,7 @@ export function getUnitConformationAndRadius(structure: Structure, unit: Unit, i
     return { position, radius }
 }
 
-export function getStructureConformationAndRadius(structure: Structure, ignoreHydrogens = false) {
+export function getStructureConformationAndRadius(structure: Structure, ignoreHydrogens: boolean) {
     const l = StructureElement.Location.create(structure)
     const sizeTheme = PhysicalSizeTheme({}, {})
 
@@ -165,10 +201,11 @@ export function getStructureConformationAndRadius(structure: Structure, ignoreHy
             const unit = structure.units[i]
             const { elements } = unit
             const { x, y, z } = unit.conformation
+
             l.unit = unit
             for (let j = 0, jl = elements.length; j < jl; ++j) {
                 const eI = elements[j]
-                if (ignoreHydrogens && isHydrogen(unit, eI)) continue
+                if (isHydrogen(unit, eI)) continue
 
                 _xs.push(x(eI))
                 _ys.push(y(eI))

+ 12 - 11
src/mol-repr/structure/visual/util/gaussian.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -11,23 +11,24 @@ 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 } from './common';
+import { getUnitConformationAndRadius, getStructureConformationAndRadius, CommonSurfaceParams } from './common';
 
-export const GaussianDensityParams = {
+const SharedGaussianDensityParams = {
     resolution: PD.Numeric(1, { min: 0.1, max: 20, step: 0.1 }),
     radiusOffset: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }),
     smoothness: PD.Numeric(1.5, { min: 0.5, max: 2.5, step: 0.1 }),
+    ...CommonSurfaceParams
+}
+
+export const GaussianDensityParams = {
+    ...SharedGaussianDensityParams,
     useGpu: PD.Boolean(false),
-    ignoreHydrogens: PD.Boolean(false),
 }
 export const DefaultGaussianDensityProps = PD.getDefaultValues(GaussianDensityParams)
 export type GaussianDensityProps = typeof DefaultGaussianDensityProps
 
 export const GaussianDensityTextureParams = {
-    resolution: PD.Numeric(1, { min: 0.1, max: 20, step: 0.1 }),
-    radiusOffset: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }),
-    smoothness: PD.Numeric(1.5, { min: 0.5, max: 2.5, step: 0.1 }),
-    ignoreHydrogens: PD.Boolean(false),
+    ...SharedGaussianDensityParams
 }
 export const DefaultGaussianDensityTextureProps = PD.getDefaultValues(GaussianDensityTextureParams)
 export type GaussianDensityTextureProps = typeof DefaultGaussianDensityTextureProps
@@ -35,21 +36,21 @@ export type GaussianDensityTextureProps = typeof DefaultGaussianDensityTexturePr
 //
 
 export function computeUnitGaussianDensity(structure: Structure, unit: Unit, props: GaussianDensityProps, webgl?: WebGLContext) {
-    const { position, radius } = getUnitConformationAndRadius(structure, unit, props.ignoreHydrogens)
+    const { position, radius } = getUnitConformationAndRadius(structure, unit, props)
     return Task.create('Gaussian Density', async ctx => {
         return await GaussianDensity(ctx, position, unit.lookup3d.boundary.box, radius, props, webgl);
     });
 }
 
 export function computeUnitGaussianDensityTexture(structure: Structure, unit: Unit, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) {
-    const { position, radius } = getUnitConformationAndRadius(structure, unit, props.ignoreHydrogens)
+    const { position, radius } = getUnitConformationAndRadius(structure, unit, props)
     return Task.create('Gaussian Density', async ctx => {
         return GaussianDensityTexture(webgl, position, unit.lookup3d.boundary.box, radius, props, texture);
     });
 }
 
 export function computeUnitGaussianDensityTexture2d(structure: Structure, unit: Unit, props: GaussianDensityTextureProps, webgl: WebGLContext, texture?: Texture) {
-    const { position, radius } = getUnitConformationAndRadius(structure, unit, props.ignoreHydrogens)
+    const { position, radius } = getUnitConformationAndRadius(structure, unit, props)
     return Task.create('Gaussian Density', async ctx => {
         return GaussianDensityTexture2d(webgl, position, unit.lookup3d.boundary.box, radius, props, texture);
     });

+ 10 - 11
src/mol-repr/structure/visual/util/molecular-surface.ts

@@ -1,23 +1,21 @@
 /**
- * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
 import { Unit, Structure } from '../../../../mol-model/structure';
 import { Task, RuntimeContext } from '../../../../mol-task';
-import { getUnitConformationAndRadius } from './common';
-import { PositionData, DensityData } from '../../../../mol-math/geometry';
+import { getUnitConformationAndRadius, CommonSurfaceProps } 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';
 
-export type MolecularSurfaceProps = MolecularSurfaceCalculationProps & {
-    ignoreHydrogens: boolean
-}
+export type MolecularSurfaceProps = MolecularSurfaceCalculationProps & CommonSurfaceProps
 
 function getPositionDataAndMaxRadius(structure: Structure, unit: Unit, props: MolecularSurfaceProps) {
-    const { probeRadius, ignoreHydrogens } = props
-    const { position, radius } = getUnitConformationAndRadius(structure, unit, ignoreHydrogens)
+    const { probeRadius } = props
+    const { position, radius } = getUnitConformationAndRadius(structure, unit, props)
     const { indices } = position
     const n = OrderedSet.size(indices)
     const radii = new Float32Array(OrderedSet.end(indices))
@@ -34,14 +32,15 @@ function getPositionDataAndMaxRadius(structure: Structure, unit: Unit, props: Mo
 }
 
 export function computeUnitMolecularSurface(structure: Structure, unit: Unit, props: MolecularSurfaceProps) {
+    const { box } = unit.lookup3d.boundary
     const { position, maxRadius } = getPositionDataAndMaxRadius(structure, unit, props)
     return Task.create('Molecular Surface', async ctx => {
-        return await MolecularSurface(ctx, position, maxRadius, props);
+        return await MolecularSurface(ctx, position, maxRadius, box, props);
     });
 }
 
 //
 
-async function MolecularSurface(ctx: RuntimeContext, position: Required<PositionData>, maxRadius: number,  props: MolecularSurfaceCalculationProps): Promise<DensityData> {
-    return calcMolecularSurface(ctx, position, maxRadius, props)
+async function MolecularSurface(ctx: RuntimeContext, position: Required<PositionData>, maxRadius: number, box: Box3D | null, props: MolecularSurfaceCalculationProps): Promise<DensityData> {
+    return calcMolecularSurface(ctx, position, maxRadius, box, props)
 }