Browse Source

viewer tweaks, expose repr props

Alexander Rose 6 years ago
parent
commit
f56574eb70

+ 37 - 2
src/mol-app/ui/transform/ball-and-stick.tsx

@@ -15,9 +15,10 @@ import { Toggle } from '../controls/common';
 import { BallAndStickEntity } from 'mol-view/state/entity';
 import { BallAndStickUpdate } from 'mol-view/state/transform'
 import { StateContext } from 'mol-view/state/context';
-import { ColorTheme } from 'mol-geo/theme';
+import { ColorTheme, SizeTheme } from 'mol-geo/theme';
 import { Color, ColorNames } from 'mol-util/color';
 import { Slider } from '../controls/slider';
+import { VisualQuality } from 'mol-geo/representation';
 
 export const ColorThemeInfo = {
     'atom-index': {},
@@ -34,9 +35,17 @@ interface BallAndStickState {
     flatShaded: boolean
     colorTheme: ColorTheme
     colorValue: Color
+    sizeTheme: SizeTheme
     visible: boolean
     alpha: number
     depthMask: boolean
+    useFog: boolean
+    quality: VisualQuality
+    linkScale: number
+    linkSpacing: number
+    linkRadius: number
+    radialSegments: number
+    detail: number
 }
 
 export class BallAndStick extends View<Controller<any>, BallAndStickState, { transform: BallAndStickUpdate, entity: BallAndStickEntity, ctx: StateContext }> {
@@ -46,9 +55,21 @@ export class BallAndStick extends View<Controller<any>, BallAndStickState, { tra
         flatShaded: false,
         colorTheme: { name: 'element-symbol' } as ColorTheme,
         colorValue: 0x000000,
+        sizeTheme: { name: 'uniform' } as SizeTheme,
         visible: true,
         alpha: 1,
-        depthMask: true
+        depthMask: true,
+        useFog: true,
+        quality: 'auto' as VisualQuality,
+        linkScale: 0.4,
+        linkSpacing: 1,
+        linkRadius: 0.25,
+        radialSegments: 16,
+        detail: 1
+    }
+
+    componentWillMount() {
+        this.setState({ ...this.state, ...this.props.entity.value.props })
     }
 
     update(state?: Partial<BallAndStickState>) {
@@ -61,6 +82,10 @@ export class BallAndStick extends View<Controller<any>, BallAndStickState, { tra
     render() {
         const { transform } = this.props
 
+        const qualityOptions = ['auto', 'custom', 'highest', 'high', 'medium', 'low', 'lowest'].map((name, idx) => {
+            return <option key={name} value={name}>{name}</option>
+        })
+
         const colorThemeOptions = Object.keys(ColorThemeInfo).map((name, idx) => {
             return <option key={name} value={name}>{name}</option>
         })
@@ -82,6 +107,16 @@ export class BallAndStick extends View<Controller<any>, BallAndStickState, { tra
                 <div className='molstar-panel-body'>
                     <div>
                         <div className='molstar-control-row molstar-options-group'>
+                            <span>Quality</span>
+                            <div>
+                                <select
+                                    className='molstar-form-control'
+                                    value={this.state.quality}
+                                    onChange={(e) => this.update({ quality: e.target.value as VisualQuality })}
+                                >
+                                    {qualityOptions}
+                                </select>
+                            </div>
                             <span>Color theme</span>
                             <div>
                                 <select

+ 30 - 2
src/mol-app/ui/transform/spacefill.tsx

@@ -15,9 +15,10 @@ import { Toggle } from '../controls/common';
 import { SpacefillEntity } from 'mol-view/state/entity';
 import { SpacefillUpdate } from 'mol-view/state/transform'
 import { StateContext } from 'mol-view/state/context';
-import { ColorTheme } from 'mol-geo/theme';
+import { ColorTheme, SizeTheme } from 'mol-geo/theme';
 import { Color, ColorNames } from 'mol-util/color';
 import { Slider } from '../controls/slider';
+import { VisualQuality } from 'mol-geo/representation';
 
 export const ColorThemeInfo = {
     'atom-index': {},
@@ -35,9 +36,12 @@ interface SpacefillState {
     detail: number
     colorTheme: ColorTheme
     colorValue: Color
+    sizeTheme: SizeTheme
     visible: boolean
     alpha: number
     depthMask: boolean
+    useFog: boolean
+    quality: VisualQuality
 }
 
 export class Spacefill extends View<Controller<any>, SpacefillState, { transform: SpacefillUpdate, entity: SpacefillEntity, ctx: StateContext }> {
@@ -48,12 +52,20 @@ export class Spacefill extends View<Controller<any>, SpacefillState, { transform
         detail: 2,
         colorTheme: { name: 'element-symbol' } as ColorTheme,
         colorValue: 0x000000,
+        sizeTheme: { name: 'uniform' } as SizeTheme,
         visible: true,
         alpha: 1,
-        depthMask: true
+        depthMask: true,
+        useFog: true,
+        quality: 'auto' as VisualQuality
+    }
+
+    componentWillMount() {
+        this.setState({ ...this.state, ...this.props.entity.value.props })
     }
 
     update(state?: Partial<SpacefillState>) {
+        console.log(state)
         const { transform, entity, ctx } = this.props
         const newState = { ...this.state, ...state }
         this.setState(newState)
@@ -63,6 +75,10 @@ export class Spacefill extends View<Controller<any>, SpacefillState, { transform
     render() {
         const { transform } = this.props
 
+        const qualityOptions = ['auto', 'custom', 'highest', 'high', 'medium', 'low', 'lowest'].map((name, idx) => {
+            return <option key={name} value={name}>{name}</option>
+        })
+
         const sphereDetailOptions = [0, 1, 2, 3].map((value, idx) => {
             return <option key={value} value={value}>{value.toString()}</option>
         })
@@ -87,6 +103,18 @@ export class Spacefill extends View<Controller<any>, SpacefillState, { transform
                 </div>
                 <div className='molstar-panel-body'>
                     <div>
+                    <div className='molstar-control-row molstar-options-group'>
+                        <span>Quality</span>
+                            <div>
+                                <select
+                                    className='molstar-form-control'
+                                    value={this.state.quality}
+                                    onChange={(e) => this.update({ quality: e.target.value as VisualQuality })}
+                                >
+                                    {qualityOptions}
+                                </select>
+                            </div>
+                        </div>
                         <div className='molstar-control-row molstar-options-group'>
                             <span>Sphere detail</span>
                             <div>

+ 3 - 0
src/mol-geo/representation/index.ts

@@ -10,10 +10,13 @@ import { PickingId } from '../util/picking';
 import { Loci } from 'mol-model/loci';
 import { MarkerAction } from '../util/marker-data';
 
+export type VisualQuality = 'custom' | 'auto' | 'highest' | 'high' | 'medium' | 'low' | 'lowest'
+
 export interface RepresentationProps {}
 
 export interface Representation<D, P extends RepresentationProps = {}> {
     readonly renderObjects: ReadonlyArray<RenderObject>
+    readonly props: Readonly<P>
     create: (data: D, props?: P) => Task<void>
     update: (props: P) => Task<void>
     getLoci: (pickingId: PickingId) => Loci

+ 6 - 2
src/mol-geo/representation/structure/ball-and-stick.ts

@@ -32,6 +32,9 @@ export function BallAndStickRepresentation(): StructureRepresentation<BallAndSti
             // return linkRepr.renderObjects
             return [ ...elmementRepr.renderObjects, ...linkRepr.renderObjects ]
         },
+        get props() {
+            return { ...elmementRepr.props, ...linkRepr.props }
+        },
         create: (structure: Structure, props: BallAndStickProps = {} as BallAndStickProps) => {
             const p = Object.assign({}, DefaultBallAndStickProps, props)
             return Task.create('Creating BallAndStickRepresentation', async ctx => {
@@ -40,9 +43,10 @@ export function BallAndStickRepresentation(): StructureRepresentation<BallAndSti
             })
         },
         update: (props: BallAndStickProps) => {
+            const p = Object.assign({}, props)
             return Task.create('Updating BallAndStickRepresentation', async ctx => {
-                await elmementRepr.update(props).runInContext(ctx)
-                await linkRepr.update(props).runInContext(ctx)
+                await elmementRepr.update(p).runInContext(ctx)
+                await linkRepr.update(p).runInContext(ctx)
             })
         },
         getLoci: (pickingId: PickingId) => {

+ 59 - 3
src/mol-geo/representation/structure/index.ts

@@ -8,17 +8,65 @@
 import { Structure, StructureSymmetry, Unit } from 'mol-model/structure';
 import { Task } from 'mol-task'
 import { RenderObject } from 'mol-gl/render-object';
-import { Representation, RepresentationProps, Visual } from '..';
+import { Representation, RepresentationProps, Visual, VisualQuality } from '..';
 import { ColorTheme, SizeTheme } from '../../theme';
 import { PickingId } from '../../util/picking';
 import { Loci, EmptyLoci, isEmptyLoci } from 'mol-model/loci';
 import { MarkerAction } from '../../util/marker-data';
+import { defaults } from 'mol-util';
 
 export interface UnitsVisual<P extends RepresentationProps = {}> extends Visual<Unit.SymmetryGroup, P> { }
 export interface  StructureVisual<P extends RepresentationProps = {}> extends Visual<Structure, P> { }
 
 export interface StructureRepresentation<P extends RepresentationProps = {}> extends Representation<Structure, P> { }
 
+interface QualityProps {
+    quality: VisualQuality
+    detail: number
+    radialSegments: number
+}
+
+function getQualityProps(props: Partial<QualityProps>, structure: Structure) {
+    const quality = defaults(props.quality, 'auto' as VisualQuality)
+    let detail = 1
+    let radialSegments = 12
+
+    switch (quality) {
+        case 'highest':
+            detail = 3
+            radialSegments = 36
+            break
+        case 'high':
+            detail = 2
+            radialSegments = 24
+            break
+        case 'medium':
+            detail = 1
+            radialSegments = 12
+            break
+        case 'low':
+            detail = 0
+            radialSegments = 5
+            break
+        case 'lowest':
+            detail = 0
+            radialSegments = 3
+            break
+        case 'auto':
+            // TODO
+            break
+        case 'custom':
+            detail = defaults(props.detail, 1)
+            radialSegments = defaults(props.radialSegments, 12)
+            break
+    }
+
+    return {
+        detail,
+        radialSegments
+    }
+}
+
 export const DefaultStructureProps = {
     colorTheme: { name: 'instance-index' } as ColorTheme,
     sizeTheme: { name: 'physical' } as SizeTheme,
@@ -27,6 +75,7 @@ export const DefaultStructureProps = {
     doubleSided: false,
     depthMask: true,
     useFog: true,
+    quality: 'auto' as VisualQuality
 }
 export type StructureProps = Partial<typeof DefaultStructureProps>
 
@@ -39,7 +88,8 @@ export function StructureRepresentation<P extends StructureProps>(unitsVisualCto
     let _groups: ReadonlyArray<Unit.SymmetryGroup>
 
     function create(structure: Structure, props: P = {} as P) {
-        _props = Object.assign({}, DefaultStructureProps, _props, props)
+        _props = Object.assign({}, DefaultStructureProps, _props, props, getQualityProps(props, structure))
+        console.log('create struct', (_props as any).detail, (_props as any).radialSegments)
 
         return Task.create('Creating StructureRepresentation', async ctx => {
             if (!_structure) {
@@ -103,7 +153,10 @@ export function StructureRepresentation<P extends StructureProps>(unitsVisualCto
 
     function update(props: P) {
         return Task.create('Updating StructureRepresentation', async ctx => {
-            _props = Object.assign({}, DefaultStructureProps, _props, props)
+            console.log(getQualityProps(props, _structure))
+            _props = Object.assign({}, DefaultStructureProps, _props, props, getQualityProps(props, _structure))
+
+            console.log('update struct', (_props as any).detail, (_props as any).radialSegments)
 
             unitsVisuals.forEach(async ({ visual, group }) => {
                 if (!await visual.update(ctx, _props)) {
@@ -153,6 +206,9 @@ export function StructureRepresentation<P extends StructureProps>(unitsVisualCto
             if (structureVisual) renderObjects.push(...structureVisual.renderObjects)
             return renderObjects
         },
+        get props() {
+            return _props
+        },
         create,
         update,
         getLoci,

+ 2 - 2
src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts

@@ -118,7 +118,7 @@ export function InterUnitLinkVisual(): StructureVisual<InterUnitLinkProps> {
         async update(ctx: RuntimeContext, props: InterUnitLinkProps) {
             const newProps = Object.assign({}, currentProps, props)
 
-            if (!cylinders) return false
+            if (!cylinders || currentProps.radialSegments !== newProps.radialSegments) return false
             // TODO
 
             ValueCell.updateIfChanged(cylinders.values.uAlpha, newProps.alpha)
@@ -129,7 +129,7 @@ export function InterUnitLinkVisual(): StructureVisual<InterUnitLinkProps> {
             cylinders.state.visible = newProps.visible
             cylinders.state.depthMask = newProps.depthMask
 
-            return true
+            return false
         },
         getLoci(pickingId: PickingId) {
             return getLinkLoci(pickingId, currentStructure, cylinders.id)

+ 1 - 1
src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts

@@ -135,7 +135,7 @@ export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkProps> {
         async update(ctx: RuntimeContext, props: IntraUnitLinkProps) {
             const newProps = Object.assign({}, currentProps, props)
 
-            if (!cylinders) return false
+            if (!cylinders || currentProps.radialSegments !== newProps.radialSegments) return false
             // TODO
 
             ValueCell.updateIfChanged(cylinders.values.uAlpha, newProps.alpha)

+ 9 - 2
src/mol-geo/representation/volume/index.ts

@@ -19,8 +19,10 @@ export interface VolumeRepresentation<P extends RepresentationProps = {}> extend
 export function VolumeRepresentation<P>(visualCtor: (volumeData: VolumeData) => VolumeVisual<P>): VolumeRepresentation<P> {
     const renderObjects: RenderObject[] = []
     let _volumeData: VolumeData
+    let _props: P
 
     function create(volumeData: VolumeData, props: P = {} as P) {
+        _props = props
         return Task.create('VolumeRepresentation.create', async ctx => {
             _volumeData = volumeData
             const visual = visualCtor(_volumeData)
@@ -28,13 +30,18 @@ export function VolumeRepresentation<P>(visualCtor: (volumeData: VolumeData) =>
             renderObjects.push(...visual.renderObjects)
         });
     }
-    
+
     function update(props: P) {
         return Task.create('VolumeRepresentation.update', async ctx => {})
     }
 
     return {
-        renderObjects,
+        get renderObjects () {
+            return renderObjects
+        },
+        get props () {
+            return _props
+        },
         create,
         update,
         getLoci(pickingId: PickingId) {

+ 1 - 1
src/mol-util/index.ts

@@ -94,7 +94,7 @@ export function shallowEqual<T>(a: T, b: T) {
 }
 
 /** Returns `value` if not `undefined`, otherwise returns `defaultValue` */
-export function defaults(value: any, defaultValue: any) {
+export function defaults<T>(value: T | undefined, defaultValue: T): T {
     return value !== undefined ? value : defaultValue
 }
 

+ 5 - 6
src/mol-view/stage.ts

@@ -15,16 +15,15 @@ import { BallAndStickProps } from 'mol-geo/representation/structure/ball-and-sti
 
 const spacefillProps: SpacefillProps = {
     doubleSided: true,
-    detail: 0,
-    colorTheme: { name: 'atom-index' }
+    colorTheme: { name: 'atom-index' },
+    quality: 'medium'
 }
 
 const ballAndStickProps: BallAndStickProps = {
     doubleSided: true,
-    detail: 1,
-    radialSegments: 8,
     colorTheme: { name: 'chain-id' },
     sizeTheme: { name: 'uniform', value: 0.25 },
+    quality: 'medium'
 }
 
 export class Stage {
@@ -43,8 +42,8 @@ export class Stage {
         // this.loadPdbid('1jj2')
         // this.loadPdbid('4umt') // ligand has bond with order 3
         // this.loadPdbid('1crn') // small
-        this.loadPdbid('1blu') // metal coordination
-        // this.loadPdbid('3pqr') // inter unit bonds
+        // this.loadPdbid('1blu') // metal coordination
+        this.loadPdbid('3pqr') // inter unit bonds
         // this.loadPdbid('4v5a') // ribosome
         // this.loadMmcifUrl(`../../examples/1cbs_full.bcif`)
     }