Browse Source

added structure gaussian surface complex-visual

Alexander Rose 5 years ago
parent
commit
f2342c3273

+ 3 - 2
src/mol-repr/structure/representation/gaussian-surface.ts

@@ -4,17 +4,18 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { GaussianSurfaceMeshVisual, GaussianSurfaceTextureMeshVisual, GaussianSurfaceMeshParams } from '../visual/gaussian-surface-mesh';
+import { GaussianSurfaceMeshVisual, GaussianSurfaceTextureMeshVisual, GaussianSurfaceMeshParams, StructureGaussianSurfaceMeshParams, StructureGaussianSurfaceMeshVisual } from '../visual/gaussian-surface-mesh';
 import { UnitsRepresentation } from '../units-representation';
 import { GaussianWireframeVisual, GaussianWireframeParams } from '../visual/gaussian-surface-wireframe';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
-import { StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../representation';
+import { StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder, ComplexRepresentation } from '../representation';
 import { Representation, RepresentationParamsGetter, RepresentationContext } from '../../../mol-repr/representation';
 import { ThemeRegistryContext } from '../../../mol-theme/theme';
 import { Structure } from '../../../mol-model/structure';
 
 const GaussianSurfaceVisuals = {
     'gaussian-surface-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, GaussianSurfaceMeshParams>) => UnitsRepresentation('Gaussian surface', ctx, getParams, GaussianSurfaceMeshVisual),
+    'structure-gaussian-surface-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, StructureGaussianSurfaceMeshParams>) => ComplexRepresentation('Structure-Gaussian surface', ctx, getParams, StructureGaussianSurfaceMeshVisual),
     'gaussian-surface-texture-mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, GaussianSurfaceMeshParams>) => UnitsRepresentation('Gaussian surface', ctx, getParams, GaussianSurfaceTextureMeshVisual),
     'gaussian-wireframe': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, GaussianWireframeParams>) => UnitsRepresentation('Gaussian wireframe', ctx, getParams, GaussianWireframeVisual),
 }

+ 2 - 2
src/mol-repr/structure/visual/element-point.ts

@@ -12,7 +12,7 @@ import { Theme } from '../../../mol-theme/theme';
 import { Points } from '../../../mol-geo/geometry/points/points';
 import { PointsBuilder } from '../../../mol-geo/geometry/points/points-builder';
 import { Vec3 } from '../../../mol-math/linear-algebra';
-import { StructureElementIterator, getElementLoci, eachElement } from './util/element';
+import { ElementIterator, getElementLoci, eachElement } from './util/element';
 import { VisualUpdateState } from '../../util';
 
 export const ElementPointParams = {
@@ -46,7 +46,7 @@ export function ElementPointVisual(materialId: number): UnitsVisual<ElementPoint
     return UnitsPointsVisual<ElementPointParams>({
         defaultProps: PD.getDefaultValues(ElementPointParams),
         createGeometry: createElementPoint,
-        createLocationIterator: StructureElementIterator.fromGroup,
+        createLocationIterator: ElementIterator.fromGroup,
         getLoci: getElementLoci,
         eachLocation: eachElement,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementPointParams>, currentProps: PD.Values<ElementPointParams>) => {

+ 3 - 3
src/mol-repr/structure/visual/element-sphere.ts

@@ -8,7 +8,7 @@
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { UnitsMeshParams, UnitsSpheresParams, UnitsVisual, UnitsSpheresVisual, UnitsMeshVisual } from '../units-visual';
 import { WebGLContext } from '../../../mol-gl/webgl/context';
-import { createElementSphereImpostor, StructureElementIterator, getElementLoci, eachElement, createElementSphereMesh } from './util/element';
+import { createElementSphereImpostor, ElementIterator, getElementLoci, eachElement, createElementSphereMesh } from './util/element';
 import { VisualUpdateState } from '../../util';
 
 export const ElementSphereParams = {
@@ -28,7 +28,7 @@ export function ElementSphereImpostorVisual(materialId: number): UnitsVisual<Ele
     return UnitsSpheresVisual<ElementSphereParams>({
         defaultProps: PD.getDefaultValues(ElementSphereParams),
         createGeometry: createElementSphereImpostor,
-        createLocationIterator: StructureElementIterator.fromGroup,
+        createLocationIterator: ElementIterator.fromGroup,
         getLoci: getElementLoci,
         eachLocation: eachElement,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementSphereParams>, currentProps: PD.Values<ElementSphereParams>) => {
@@ -43,7 +43,7 @@ export function ElementSphereMeshVisual(materialId: number): UnitsVisual<Element
     return UnitsMeshVisual<ElementSphereParams>({
         defaultProps: PD.getDefaultValues(ElementSphereParams),
         createGeometry: createElementSphereMesh,
-        createLocationIterator: StructureElementIterator.fromGroup,
+        createLocationIterator: ElementIterator.fromGroup,
         getLoci: getElementLoci,
         eachLocation: eachElement,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<ElementSphereParams>, currentProps: PD.Values<ElementSphereParams>) => {

+ 48 - 4
src/mol-repr/structure/visual/gaussian-surface-mesh.ts

@@ -6,20 +6,21 @@
 
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
 import { UnitsMeshParams, UnitsTextureMeshParams, UnitsVisual, UnitsMeshVisual, UnitsTextureMeshVisual } from '../units-visual';
-import { GaussianDensityParams, computeUnitGaussianDensity, GaussianDensityTextureProps, computeUnitGaussianDensityTexture2d, GaussianDensityProps } from './util/gaussian';
+import { GaussianDensityParams, computeUnitGaussianDensity, GaussianDensityTextureProps, computeUnitGaussianDensityTexture2d, GaussianDensityProps, computeStructureGaussianDensity } from './util/gaussian';
 import { WebGLContext } from '../../../mol-gl/webgl/context';
 import { VisualContext } from '../../visual';
 import { Unit, Structure } from '../../../mol-model/structure';
 import { Theme } from '../../../mol-theme/theme';
 import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
 import { computeMarchingCubesMesh } from '../../../mol-geo/util/marching-cubes/algorithm';
-import { StructureElementIterator, getElementLoci, eachElement } from './util/element';
+import { ElementIterator, getElementLoci, eachElement, getSerialElementLoci, eachSerialElement } from './util/element';
 import { VisualUpdateState } from '../../util';
 import { TextureMesh } from '../../../mol-geo/geometry/texture-mesh/texture-mesh';
 import { calcActiveVoxels } from '../../../mol-gl/compute/marching-cubes/active-voxels';
 import { createHistogramPyramid } from '../../../mol-gl/compute/histogram-pyramid/reduction';
 import { createIsosurfaceBuffers } from '../../../mol-gl/compute/marching-cubes/isosurface';
 import { Sphere3D } from '../../../mol-math/geometry';
+import { ComplexVisual, ComplexMeshParams, ComplexMeshVisual } from '../complex-visual';
 
 export const GaussianSurfaceMeshParams = {
     ...UnitsMeshParams,
@@ -56,7 +57,7 @@ export function GaussianSurfaceMeshVisual(materialId: number): UnitsVisual<Gauss
     return UnitsMeshVisual<GaussianSurfaceMeshParams>({
         defaultProps: PD.getDefaultValues(GaussianSurfaceMeshParams),
         createGeometry: createGaussianSurfaceMesh,
-        createLocationIterator: StructureElementIterator.fromGroup,
+        createLocationIterator: ElementIterator.fromGroup,
         getLoci: getElementLoci,
         eachLocation: eachElement,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<GaussianSurfaceMeshParams>, currentProps: PD.Values<GaussianSurfaceMeshParams>) => {
@@ -71,6 +72,49 @@ export function GaussianSurfaceMeshVisual(materialId: number): UnitsVisual<Gauss
 
 //
 
+export const StructureGaussianSurfaceMeshParams = {
+    ...ComplexMeshParams,
+    ...GaussianDensityParams,
+    ignoreHydrogens: PD.Boolean(false),
+}
+export type StructureGaussianSurfaceMeshParams = typeof StructureGaussianSurfaceMeshParams
+
+async function createStructureGaussianSurfaceMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: GaussianDensityProps, mesh?: Mesh): Promise<Mesh> {
+    const { smoothness } = props
+    const { transform, field, idField } = await computeStructureGaussianDensity(structure, props, ctx.webgl).runInContext(ctx.runtime)
+
+    const params = {
+        isoLevel: Math.exp(-smoothness),
+        scalarField: field,
+        idField
+    }
+    const surface = await computeMarchingCubesMesh(params, mesh).runAsChild(ctx.runtime)
+
+    Mesh.transformImmediate(surface, transform)
+    Mesh.uniformTriangleGroup(surface)
+
+    return surface
+}
+
+export function StructureGaussianSurfaceMeshVisual(materialId: number): ComplexVisual<StructureGaussianSurfaceMeshParams> {
+    return ComplexMeshVisual<StructureGaussianSurfaceMeshParams>({
+        defaultProps: PD.getDefaultValues(StructureGaussianSurfaceMeshParams),
+        createGeometry: createStructureGaussianSurfaceMesh,
+        createLocationIterator: ElementIterator.fromStructure,
+        getLoci: getSerialElementLoci,
+        eachLocation: eachSerialElement,
+        setUpdateState: (state: VisualUpdateState, newProps: PD.Values<GaussianSurfaceMeshParams>, currentProps: PD.Values<GaussianSurfaceMeshParams>) => {
+            if (newProps.resolution !== currentProps.resolution) state.createGeometry = true
+            if (newProps.radiusOffset !== currentProps.radiusOffset) state.createGeometry = true
+            if (newProps.smoothness !== currentProps.smoothness) state.createGeometry = true
+            if (newProps.useGpu !== currentProps.useGpu) state.createGeometry = true
+            if (newProps.ignoreHydrogens !== currentProps.ignoreHydrogens) state.createGeometry = true
+        }
+    }, materialId)
+}
+
+//
+
 async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityTextureProps, textureMesh?: TextureMesh): Promise<TextureMesh> {
     if (!ctx.webgl) throw new Error('webgl context required to create gaussian surface texture-mesh')
     const isoLevel = Math.exp(-props.smoothness)
@@ -102,7 +146,7 @@ export function GaussianSurfaceTextureMeshVisual(materialId: number): UnitsVisua
     return UnitsTextureMeshVisual<GaussianSurfaceMeshParams>({
         defaultProps: PD.getDefaultValues(GaussianSurfaceMeshParams),
         createGeometry: createGaussianSurfaceTextureMesh,
-        createLocationIterator: StructureElementIterator.fromGroup,
+        createLocationIterator: ElementIterator.fromGroup,
         getLoci: getElementLoci,
         eachLocation: eachElement,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<GaussianSurfaceMeshParams>, currentProps: PD.Values<GaussianSurfaceMeshParams>) => {

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

@@ -12,7 +12,7 @@ import { Lines } from '../../../mol-geo/geometry/lines/lines';
 import { computeUnitGaussianDensity, GaussianDensityParams, GaussianDensityProps } from './util/gaussian';
 import { computeMarchingCubesLines } from '../../../mol-geo/util/marching-cubes/algorithm';
 import { UnitsLinesParams, UnitsVisual, UnitsLinesVisual } from '../units-visual';
-import { StructureElementIterator, getElementLoci, eachElement } from './util/element';
+import { ElementIterator, getElementLoci, eachElement } from './util/element';
 import { VisualUpdateState } from '../../util';
 
 async function createGaussianWireframe(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: GaussianDensityProps, lines?: Lines): Promise<Lines> {
@@ -43,7 +43,7 @@ export function GaussianWireframeVisual(materialId: number): UnitsVisual<Gaussia
     return UnitsLinesVisual<GaussianWireframeParams>({
         defaultProps: PD.getDefaultValues(GaussianWireframeParams),
         createGeometry: createGaussianWireframe,
-        createLocationIterator: StructureElementIterator.fromGroup,
+        createLocationIterator: ElementIterator.fromGroup,
         getLoci: getElementLoci,
         eachLocation: eachElement,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<GaussianWireframeParams>, currentProps: PD.Values<GaussianWireframeParams>) => {

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

@@ -13,7 +13,7 @@ import { Theme } from '../../../mol-theme/theme';
 import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
 import { computeUnitMolecularSurface, MolecularSurfaceProps } from './util/molecular-surface';
 import { computeMarchingCubesMesh } from '../../../mol-geo/util/marching-cubes/algorithm';
-import { StructureElementIterator, getElementLoci, eachElement } from './util/element';
+import { ElementIterator, getElementLoci, eachElement } from './util/element';
 import { VisualUpdateState } from '../../util';
 
 export const MolecularSurfaceMeshParams = {
@@ -46,7 +46,7 @@ export function MolecularSurfaceMeshVisual(materialId: number): UnitsVisual<Mole
     return UnitsMeshVisual<MolecularSurfaceMeshParams>({
         defaultProps: PD.getDefaultValues(MolecularSurfaceMeshParams),
         createGeometry: createMolecularSurfaceMesh,
-        createLocationIterator: StructureElementIterator.fromGroup,
+        createLocationIterator: ElementIterator.fromGroup,
         getLoci: getElementLoci,
         eachLocation: eachElement,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<MolecularSurfaceMeshParams>, currentProps: PD.Values<MolecularSurfaceMeshParams>) => {

+ 2 - 2
src/mol-repr/structure/visual/polymer-backbone-cylinder.ts

@@ -16,7 +16,7 @@ import { PolymerBackboneIterator } from './util/polymer';
 import { OrderedSet } from '../../../mol-data/int';
 import { addCylinder } from '../../../mol-geo/geometry/mesh/builder/cylinder';
 import { UnitsMeshParams, UnitsVisual, UnitsMeshVisual } from '../units-visual';
-import { StructureElementIterator, getElementLoci, eachElement } from './util/element';
+import { ElementIterator, getElementLoci, eachElement } from './util/element';
 import { VisualUpdateState } from '../../util';
 
 export const PolymerBackboneCylinderParams = {
@@ -71,7 +71,7 @@ export function PolymerBackboneVisual(materialId: number): UnitsVisual<PolymerBa
         defaultProps: PD.getDefaultValues(PolymerBackboneParams),
         createGeometry: createPolymerBackboneCylinderMesh,
         // TODO create a specialized location iterator
-        createLocationIterator: StructureElementIterator.fromGroup,
+        createLocationIterator: ElementIterator.fromGroup,
         getLoci: getElementLoci,
         eachLocation: eachElement,
         setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerBackboneParams>, currentProps: PD.Values<PolymerBackboneParams>) => {

+ 57 - 25
src/mol-repr/structure/visual/util/common.ts

@@ -138,37 +138,69 @@ export function getUnitConformationAndRadius(unit: Unit, ignoreHydrogens = false
 }
 
 export function getStructureConformationAndRadius(structure: Structure, ignoreHydrogens = false) {
-    const xs: number[] = []
-    const ys: number[] = []
-    const zs: number[] = []
-    const rs: number[] = []
-    const id: number[] = []
-
     const l = StructureElement.create()
     const sizeTheme = PhysicalSizeTheme({}, {})
 
-    let m = 0
-    for (let i = 0, il = structure.units.length; i < il; ++i) {
-        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
-
-            const mj = m + j
-            xs[mj] = x(eI)
-            ys[mj] = y(eI)
-            zs[mj] = z(eI)
-            l.element = eI
-            rs[mj] = sizeTheme.size(l)
-            id[mj] = mj
+    let xs: ArrayLike<number>
+    let ys: ArrayLike<number>
+    let zs: ArrayLike<number>
+    let rs: ArrayLike<number>
+    let id: ArrayLike<number>
+
+    if (ignoreHydrogens) {
+        const _xs: number[] = []
+        const _ys: number[] = []
+        const _zs: number[] = []
+        const _rs: number[] = []
+        const _id: number[] = []
+        for (let i = 0, m = 0, il = structure.units.length; i < il; ++i) {
+            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
+
+                _xs.push(x(eI))
+                _ys.push(y(eI))
+                _zs.push(z(eI))
+                l.element = eI
+                _rs.push(sizeTheme.size(l))
+                _id.push(m + j)
+            }
+            m += elements.length
+        }
+        xs = _xs, ys = _ys, zs = _zs, rs = _rs
+        id = _id
+    } else {
+        const { elementCount } = structure
+        const _xs = new Float32Array(elementCount)
+        const _ys = new Float32Array(elementCount)
+        const _zs = new Float32Array(elementCount)
+        const _rs = new Float32Array(elementCount)
+        for (let i = 0, m = 0, il = structure.units.length; i < il; ++i) {
+            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]
+
+                const mj = m + j
+                _xs[mj] = x(eI)
+                _ys[mj] = y(eI)
+                _zs[mj] = z(eI)
+                l.element = eI
+                _rs[mj] = sizeTheme.size(l)
+            }
+            m += elements.length
         }
-        m += elements.length
+        xs = _xs, ys = _ys, zs = _zs, rs = _rs
+        id = fillSerial(new Uint32Array(elementCount))
     }
 
-    const position = { indices: OrderedSet.ofRange(0, m), x: xs, y: ys, z: zs, id }
+    const position = { indices: OrderedSet.ofRange(0, id.length), x: xs, y: ys, z: zs, id }
     const radius = (index: number) => rs[index]
 
     return { position, radius }

+ 60 - 6
src/mol-repr/structure/visual/util/element.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -86,12 +86,12 @@ export function eachElement(loci: Loci, structureGroup: StructureGroup, apply: (
         const unitIdx = group.unitIndexMap.get(e.unit.id)
         if (unitIdx !== undefined) {
             if (Interval.is(e.indices)) {
-                const start = unitIdx * elementCount + Interval.start(e.indices);
-                const end = unitIdx * elementCount + Interval.end(e.indices);
+                const start = unitIdx * elementCount + Interval.start(e.indices)
+                const end = unitIdx * elementCount + Interval.end(e.indices)
                 if (apply(Interval.ofBounds(start, end))) changed = true
             } else {
                 for (let i = 0, _i = e.indices.length; i < _i; i++) {
-                    const idx = unitIdx * elementCount + e.indices[i];
+                    const idx = unitIdx * elementCount + e.indices[i]
                     if (apply(Interval.ofSingleton(idx))) changed = true
                 }
             }
@@ -105,13 +105,53 @@ export function getElementLoci(pickingId: PickingId, structureGroup: StructureGr
     if (id === objectId) {
         const { structure, group } = structureGroup
         const unit = group.units[instanceId]
-        const indices = OrderedSet.ofSingleton(groupId as StructureElement.UnitIndex);
+        const indices = OrderedSet.ofSingleton(groupId as StructureElement.UnitIndex)
         return StructureElement.Loci(structure, [{ unit, indices }])
     }
     return EmptyLoci
 }
 
-export namespace StructureElementIterator {
+//
+
+export function eachSerialElement(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) {
+    let changed = false
+    if (!StructureElement.isLoci(loci)) return false
+    if (!Structure.areEquivalent(loci.structure, structure)) return false
+    const { unitElementCount } = structure.serialMapping
+    for (const e of loci.elements) {
+        const unitIdx = structure.unitIndexMap.get(e.unit.id)
+        if (unitIdx !== undefined) {
+            if (Interval.is(e.indices)) {
+                const start = unitElementCount[unitIdx] + Interval.start(e.indices)
+                const end = unitElementCount[unitIdx] + Interval.end(e.indices)
+                if (apply(Interval.ofBounds(start, end))) changed = true
+            } else {
+                for (let i = 0, _i = e.indices.length; i < _i; i++) {
+                    const idx = unitElementCount[unitIdx] + e.indices[i]
+                    if (apply(Interval.ofSingleton(idx))) changed = true
+                }
+            }
+        }
+    }
+    return changed
+}
+
+export function getSerialElementLoci(pickingId: PickingId, structure: Structure, id: number) {
+    const { objectId, groupId } = pickingId
+    if (id === objectId) {
+        const { unitIndices, unitElementCount } = structure.serialMapping
+        const unitIdx = unitIndices[groupId]
+        const unit = structure.units[unitIdx]
+        const idx = groupId - unitElementCount[unitIdx]
+        const indices = OrderedSet.ofSingleton(idx as StructureElement.UnitIndex)
+        return StructureElement.Loci(structure, [{ unit, indices }])
+    }
+    return EmptyLoci
+}
+
+//
+
+export namespace ElementIterator {
     export function fromGroup(group: Unit.SymmetryGroup): LocationIterator {
         const groupCount = group.elements.length
         const instanceCount = group.units.length
@@ -124,4 +164,18 @@ export namespace StructureElementIterator {
         }
         return LocationIterator(groupCount, instanceCount, getLocation)
     }
+
+    export function fromStructure(structure: Structure): LocationIterator {
+        const { units, elementCount } = structure
+        const groupCount = elementCount
+        const instanceCount = 1
+        const { unitIndices, elementIndices } = structure.serialMapping
+        const location = StructureElement.create()
+        const getLocation = (groupIndex: number) => {
+            location.unit = units[unitIndices[groupIndex]]
+            location.element = elementIndices[groupIndex]
+            return location
+        }
+        return LocationIterator(groupCount, instanceCount, getLocation, true)
+    }
 }