Skip to content
Snippets Groups Projects
Commit 9ea8d6e5 authored by Alexander Rose's avatar Alexander Rose
Browse files

wip, gaussian surface

parent f3353b6e
No related branches found
No related tags found
No related merge requests found
......@@ -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 } }) }>
......
......@@ -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() {
......
......@@ -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)
});
......
......@@ -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])
......
......@@ -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)
// }
\ No newline at end of file
}
\ No newline at end of file
......@@ -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]]);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment