Browse Source

wip, gaussian surface

Alexander Rose 6 years ago
parent
commit
9ea8d6e5b1

+ 67 - 2
src/apps/canvas/component/structure-representation.tsx

@@ -10,6 +10,7 @@ import Viewer from 'mol-view/viewer';
 import { VisualQuality, VisualQualityNames } from 'mol-geo/representation/util';
 import { ColorThemeProps, ColorThemeName, ColorThemeNames, ColorTheme } from 'mol-view/theme/color';
 import { Color } from 'mol-util/color';
+import { Progress } from 'mol-task';
 
 export interface StructureRepresentationComponentProps {
     viewer: Viewer
@@ -22,6 +23,10 @@ export interface StructureRepresentationComponentState {
     alpha: number
     quality: VisualQuality
     colorTheme: ColorThemeProps
+
+    resolutionFactor?: number
+    probeRadius?: number
+    isoValue?: number
 }
 
 export class StructureRepresentationComponent extends React.Component<StructureRepresentationComponentProps, StructureRepresentationComponentState> {
@@ -31,6 +36,10 @@ export class StructureRepresentationComponent extends React.Component<StructureR
         alpha: this.props.representation.props.alpha,
         quality: this.props.representation.props.quality,
         colorTheme: this.props.representation.props.colorTheme,
+
+        resolutionFactor: (this.props.representation.props as any).resolutionFactor,
+        probeRadius: (this.props.representation.props as any).probeRadius,
+        isoValue: (this.props.representation.props as any).isoValue,
     }
 
     componentWillMount() {
@@ -43,6 +52,10 @@ export class StructureRepresentationComponent extends React.Component<StructureR
             alpha: repr.props.alpha,
             quality: repr.props.quality,
             colorTheme: repr.props.colorTheme,
+
+            resolutionFactor: (repr.props as any).resolutionFactor,
+            probeRadius: (repr.props as any).probeRadius,
+            isoValue: (repr.props as any).isoValue,
         })
     }
 
@@ -55,17 +68,36 @@ export class StructureRepresentationComponent extends React.Component<StructureR
         if (state.alpha !== undefined) props.alpha = state.alpha
         if (state.colorTheme !== undefined) props.colorTheme = state.colorTheme
 
-        await repr.createOrUpdate(props).run()
+        if (state.resolutionFactor !== undefined) (props as any).resolutionFactor = state.resolutionFactor
+        if (state.probeRadius !== undefined) (props as any).probeRadius = state.probeRadius
+        if (state.isoValue !== undefined) (props as any).isoValue = state.isoValue
+
+        await repr.createOrUpdate(props).run(
+            progress => console.log(Progress.format(progress)), 100
+        )
         this.props.viewer.add(repr)
-        this.props.viewer.requestDraw(true)
+        this.props.viewer.draw(true)
         console.log(this.props.viewer.stats)
 
+        console.log(
+            'drawCount',
+            repr.renderObjects[0].values.drawCount.ref.version,
+            repr.renderObjects[0].values.drawCount.ref.value,
+            'dColorType',
+            repr.renderObjects[0].values.dColorType.ref.version,
+            repr.renderObjects[0].values.dColorType.ref.value
+        )
+
         const newState = {
             ...this.state,
             visible: repr.props.visible,
             quality: repr.props.quality,
             alpha: repr.props.alpha,
             colorTheme: repr.props.colorTheme,
+
+            resolutionFactor: (repr.props as any).resolutionFactor,
+            probeRadius: (repr.props as any).probeRadius,
+            isoValue: (repr.props as any).isoValue,
         }
         this.setState(newState)
     }
@@ -107,6 +139,39 @@ export class StructureRepresentationComponent extends React.Component<StructureR
                     >
                     </input>
                 </div>
+                { this.state.resolutionFactor !== undefined ? <div>
+                    <span>Resolution Factor </span>
+                    <input type='range'
+                        defaultValue={this.state.resolutionFactor.toString()}
+                        min='4'
+                        max='9'
+                        step='1'
+                        onInput={(e) => this.update({ resolutionFactor: parseInt(e.currentTarget.value) })}
+                    >
+                    </input>
+                </div> : '' }
+                { this.state.isoValue !== undefined ? <div>
+                    <span>Iso Value </span>
+                    <input type='range'
+                        defaultValue={this.state.isoValue.toString()}
+                        min='0.1'
+                        max='2'
+                        step='0.1'
+                        onInput={(e) => this.update({ isoValue: parseFloat(e.currentTarget.value) })}
+                    >
+                    </input>
+                </div> : '' }
+                { this.state.probeRadius !== undefined ? <div>
+                    <span>Probe Radius </span>
+                    <input type='range'
+                        defaultValue={this.state.probeRadius.toString()}
+                        min='0'
+                        max='10'
+                        step='0.1'
+                        onInput={(e) => this.update({ probeRadius: parseFloat(e.currentTarget.value) })}
+                    >
+                    </input>
+                </div> : '' }
                 <div>
                     <span>Color Theme </span>
                     <select value={colorTheme.name} onChange={(e) => this.update({ colorTheme: { name: e.target.value as ColorThemeName } }) }>

+ 6 - 3
src/apps/canvas/structure-view.ts

@@ -25,6 +25,7 @@ import { BehaviorSubject } from 'rxjs';
 import { SpacefillRepresentation } from 'mol-geo/representation/structure/representation/spacefill';
 import { DistanceRestraintRepresentation } from 'mol-geo/representation/structure/representation/distance-restraint';
 import { SurfaceRepresentation } from 'mol-geo/representation/structure/representation/surface';
+import { Progress } from 'mol-task';
 
 export interface StructureView {
     readonly viewer: Viewer
@@ -67,7 +68,7 @@ export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model>
     const active: { [k: string]: boolean } = {
         cartoon: true,
         point: false,
-        surface: true,
+        surface: false,
         ballAndStick: false,
         carbohydrate: false,
         spacefill: false,
@@ -208,7 +209,9 @@ export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model>
             console.log('createStructureRepr')
             for (const k in structureRepresentations) {
                 if (active[k]) {
-                    await structureRepresentations[k].createOrUpdate({}, structure).run()
+                    await structureRepresentations[k].createOrUpdate({}, structure).run(
+                        progress => console.log(Progress.format(progress)), 100
+                    )
                     viewer.add(structureRepresentations[k])
                 } else {
                     viewer.remove(structureRepresentations[k])
@@ -247,7 +250,7 @@ export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model>
 
         updated.next(null)
         viewer.requestDraw(true)
-        console.log(viewer.stats)
+        console.log('stats', viewer.stats)
     }
 
     async function createSymmetryRepr() {

+ 1 - 1
src/mol-geo/representation/structure/complex-representation.ts

@@ -20,7 +20,7 @@ export function ComplexRepresentation<P extends StructureProps>(label: string, v
     function createOrUpdate(props: Partial<P> = {}, structure?: Structure) {
         _props = Object.assign({}, _props, props)
 
-        return Task.create('Creating StructureRepresentation', async ctx => {
+        return Task.create('Creating or updating ComplexRepresentation', async ctx => {
             if (!visual) visual = visualCtor()
             await visual.createOrUpdate(ctx, _props, structure)
         });

+ 8 - 3
src/mol-geo/representation/structure/units-visual.ts

@@ -126,14 +126,19 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
             if (!group && !currentGroup) {
                 throw new Error('missing group')
             } else if (group && (!currentGroup || !renderObject)) {
+                // console.log('unit-visual first create')
                 await create(ctx, group, props)
             } else if (group && group.hashCode !== currentGroup.hashCode) {
+                // console.log('unit-visual group.hashCode !== currentGroup.hashCode')
                 await create(ctx, group, props)
             } else {
-                if (group && !areGroupsIdentical(group, currentGroup)) {
+                // console.log('unit-visual update')
+                if (group && !sameGroupConformation(group, currentGroup)) {
+                    // console.log('unit-visual new conformation')
                     currentGroup = group
+                } else {
+                    await update(ctx, props)
                 }
-                await update(ctx, props)
             }
         },
         getLoci(pickingId: PickingId) {
@@ -168,7 +173,7 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
     }
 }
 
-function areGroupsIdentical(groupA: Unit.SymmetryGroup, groupB: Unit.SymmetryGroup) {
+function sameGroupConformation(groupA: Unit.SymmetryGroup, groupB: Unit.SymmetryGroup) {
     return (
         groupA.units.length === groupB.units.length &&
         Unit.conformationId(groupA.units[0]) === Unit.conformationId(groupB.units[0])

+ 29 - 27
src/mol-geo/representation/structure/visual/gaussian-surface-mesh.ts

@@ -13,18 +13,21 @@ import { StructureElementIterator, getElementLoci, markElement } from './util/el
 import { computeMarchingCubes } from '../../../util/marching-cubes/algorithm';
 import { Tensor, Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { Box3D } from 'mol-math/geometry';
-import { ValueCell } from 'mol-util';
 import { smoothstep } from 'mol-math/interpolate';
-import { LocationIterator } from '../../../util/location-iterator';
+import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size';
 
 export interface GaussianSurfaceMeshProps {
+    sizeTheme: SizeThemeProps
 
+    resolutionFactor: number
+    probeRadius: number
+    isoValue: number
 }
 
-function getDelta(box: Box3D) {
+function getDelta(box: Box3D, resolutionFactor: number) {
     const extent = Vec3.sub(Vec3.zero(), box.max, box.min)
 
-    const n = Math.pow(128, 3)
+    const n = Math.pow(Math.pow(2, resolutionFactor), 3)
     const f = (extent[0] * extent[1] * extent[2]) / n
     const s = Math.pow(f, 1 / 3)
     const size = Vec3.zero()
@@ -35,17 +38,21 @@ function getDelta(box: Box3D) {
 }
 
 async function createGaussianSurfaceMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: GaussianSurfaceMeshProps, mesh?: Mesh): Promise<Mesh> {
+    const { resolutionFactor, probeRadius, isoValue } = props
 
     const { elements } = unit;
     const elementCount = elements.length;
-
-    const r = 2.5;
+    const sizeTheme = SizeTheme(props.sizeTheme)
 
     const v = Vec3.zero()
     const p = Vec3.zero()
     const pos = unit.conformation.invariantPosition
+    const l = StructureElement.create()
+    l.unit = unit
+
+    const pad = (probeRadius + 2) * 2 // TODO calculate max radius
     const box = unit.lookup3d.boundary.box
-    const expandedBox = Box3D.expand(Box3D.empty(), box, Vec3.create(r*3, r*3, r*3));
+    const expandedBox = Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad));
     const extent = Vec3.sub(Vec3.zero(), expandedBox.max, expandedBox.min)
     const min = expandedBox.min
 
@@ -63,7 +70,7 @@ async function createGaussianSurfaceMesh(ctx: RuntimeContext, unit: Unit, struct
     // console.log('s', s)
     // console.log('size', size)
     // console.log('delta', delta)
-    const delta = getDelta(Box3D.expand(Box3D.empty(), structure.boundary.box, Vec3.create(r*3, r*3, r*3)))
+    const delta = getDelta(Box3D.expand(Box3D.empty(), structure.boundary.box, Vec3.create(pad, pad, pad)), resolutionFactor)
     const dim = Vec3.zero()
     Vec3.ceil(dim, Vec3.mul(dim, extent, delta))
     // console.log('dim', dim, dim[0] * dim[1] * dim[2])
@@ -73,11 +80,12 @@ async function createGaussianSurfaceMesh(ctx: RuntimeContext, unit: Unit, struct
     const field = Tensor.create(space, data)
 
     for (let i = 0; i < elementCount; i++) {
+        l.element = elements[i]
         pos(elements[i], v)
 
         Vec3.mul(v, Vec3.sub(v, v, min), delta)
 
-        const size = r
+        const size = sizeTheme.size(l) + probeRadius
         const radius = size * delta[0]
 
         const minX = Math.floor(v[0] - radius)
@@ -107,11 +115,10 @@ async function createGaussianSurfaceMesh(ctx: RuntimeContext, unit: Unit, struct
     // console.log('data', data)
 
     const surface = await computeMarchingCubes({
-        isoLevel: 0.1,
+        isoLevel: isoValue,
         scalarField: field,
         oldSurface: mesh
-
-    }).runAsChild(ctx);
+    }).runAsChild(ctx)
 
     const t = Mat4.identity()
     Mat4.fromUniformScaling(t, 1 / delta[0])
@@ -132,6 +139,10 @@ export const DefaultGaussianSurfaceProps = {
 
     flipSided: true,
     // flatShaded: true,
+
+    resolutionFactor: 7,
+    probeRadius: 1.4,
+    isoValue: 0.1,
 }
 export type GaussianSurfaceProps = typeof DefaultGaussianSurfaceProps
 
@@ -142,19 +153,10 @@ export function GaussianSurfaceVisual(): UnitsVisual<GaussianSurfaceProps> {
         createLocationIterator: StructureElementIterator.fromGroup,
         getLoci: getElementLoci,
         mark: markElement,
-        setUpdateState: (state: MeshUpdateState, newProps: GaussianSurfaceProps, currentProps: GaussianSurfaceProps) => {}
+        setUpdateState: (state: MeshUpdateState, newProps: GaussianSurfaceProps, currentProps: GaussianSurfaceProps) => {
+            if (newProps.resolutionFactor !== currentProps.resolutionFactor) state.createMesh = true
+            if (newProps.probeRadius !== currentProps.probeRadius) state.createMesh = true
+            if (newProps.isoValue !== currentProps.isoValue) state.createMesh = true
+        }
     })
-}
-
-// function SingleGroupLocationIterator(group: Unit.SymmetryGroup): LocationIterator {
-//     const groupCount = 1
-//         const instanceCount = group.units.length
-//         const location = StructureElement.create()
-//         const getLocation = (groupIndex: number, instanceIndex: number) => {
-//             const unit = group.units[instanceIndex]
-//             location.unit = unit
-//             location.element = unit.elements[groupIndex]
-//             return location
-//         }
-//         return LocationIterator(groupCount, instanceCount, getLocation)
-// }
+}

+ 9 - 13
src/mol-geo/util/marching-cubes/algorithm.ts

@@ -28,7 +28,7 @@ export interface MarchingCubesParameters {
 
 export function computeMarchingCubes(parameters: MarchingCubesParameters) {
     return Task.create('Marching Cubes', async ctx => {
-        let comp = new MarchingCubesComputation(parameters, ctx);
+        const comp = new MarchingCubesComputation(parameters, ctx);
         return await comp.run();
     });
 }
@@ -64,17 +64,18 @@ class MarchingCubesComputation {
         this.state.clearEdgeVertexIndexSlice(k);
     }
 
-    private finish() {
+    private finish(): Mesh {
         const vb = ChunkedArray.compact(this.state.vertexBuffer, true) as Float32Array;
         const ib = ChunkedArray.compact(this.state.triangleBuffer, true) as Uint32Array;
         const gb = ChunkedArray.compact(this.state.groupBuffer, true) as Float32Array;
 
         this.state.vertexBuffer = <any>void 0;
         this.state.verticesOnEdges = <any>void 0;
+        this.state.groupBuffer = <any>void 0;
 
         const os = this.parameters.oldSurface
 
-        const ret: Mesh = {
+        return {
             vertexCount:  this.state.vertexCount,
             triangleCount: this.state.triangleCount,
             vertexBuffer: os ? ValueCell.update(os.vertexBuffer, vb) : ValueCell.create(vb),
@@ -83,8 +84,6 @@ class MarchingCubesComputation {
             normalBuffer: os ? os.normalBuffer : ValueCell.create(new Float32Array(0)),
             normalsComputed: false
         }
-
-        return ret;
     }
 
     async run() {
@@ -94,11 +93,8 @@ class MarchingCubesComputation {
         return this.finish();
     }
 
-    constructor(
-        parameters: MarchingCubesParameters,
-        private ctx: RuntimeContext) {
-
-        let params = { ...parameters };
+    constructor(parameters: MarchingCubesParameters, private ctx: RuntimeContext) {
+        const params = { ...parameters };
         this.parameters = params;
 
         if (!params.bottomLeft) params.bottomLeft = [0, 0, 0];
@@ -148,8 +144,8 @@ class MarchingCubesState {
     }
 
     private interpolate(edgeNum: number) {
-        const info = EdgeIdInfo[edgeNum],
-            edgeId = 3 * this.get3dOffsetFromEdgeInfo(info) + info.e;
+        const info = EdgeIdInfo[edgeNum];
+        const edgeId = 3 * this.get3dOffsetFromEdgeInfo(info) + info.e;
 
         const ret = this.verticesOnEdges[edgeId];
         if (ret > 0) return (ret - 1) | 0;
@@ -247,7 +243,7 @@ class MarchingCubesState {
         if ((edgeInfo & 1024) > 0) this.vertList[10] = this.interpolate(10); // 2 6
         if ((edgeInfo & 2048) > 0) this.vertList[11] = this.interpolate(11); // 3 7
 
-        let triInfo = TriTable[tableIndex];
+        const triInfo = TriTable[tableIndex];
         for (let t = 0; t < triInfo.length; t += 3) {
             this.triangleCount++;
             ChunkedArray.add3(this.triangleBuffer, this.vertList[triInfo[t]], this.vertList[triInfo[t + 1]], this.vertList[triInfo[t + 2]]);