Browse Source

added putty structure repr

Alexander Rose 6 years ago
parent
commit
ededc674d7

+ 3 - 1
src/mol-repr/structure/registry.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>
  */
@@ -15,6 +15,7 @@ import { SpacefillRepresentationProvider } from './representation/spacefill';
 import { DistanceRestraintRepresentationProvider } from './representation/distance-restraint';
 import { PointRepresentationProvider } from './representation/point';
 import { StructureRepresentationState } from './representation';
+import { PuttyRepresentationProvider } from './representation/putty';
 
 export class StructureRepresentationRegistry extends RepresentationRegistry<Structure, StructureRepresentationState> {
     constructor() {
@@ -34,6 +35,7 @@ export const BuiltInStructureRepresentations = {
     'molecular-surface': MolecularSurfaceRepresentationProvider,
     'molecular-volume': MolecularVolumeRepresentationProvider,
     'point': PointRepresentationProvider,
+    'putty': PuttyRepresentationProvider,
     'spacefill': SpacefillRepresentationProvider,
 }
 export type BuiltInStructureRepresentationsName = keyof typeof BuiltInStructureRepresentations

+ 1 - 1
src/mol-repr/structure/representation/cartoon.ts

@@ -54,7 +54,7 @@ export function CartoonRepresentation(ctx: RepresentationContext, getParams: Rep
 
 export const CartoonRepresentationProvider: StructureRepresentationProvider<CartoonParams> = {
     label: 'Cartoon',
-    description: 'Displays a ribbon smoothly following the trace atoms of polymers.',
+    description: 'Displays ribbons, planks, tubes smoothly following the trace atoms of polymers.',
     factory: CartoonRepresentation,
     getParams: getCartoonParams,
     defaultValues: PD.getDefaultValues(CartoonParams),

+ 56 - 0
src/mol-repr/structure/representation/putty.ts

@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { PolymerTubeVisual,  PolymerTubeParams } from '../visual/polymer-tube-mesh';
+import { PolymerGapVisual, PolymerGapParams } from '../visual/polymer-gap-cylinder';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
+import { UnitsRepresentation } from '../units-representation';
+import { StructureRepresentation, StructureRepresentationProvider, StructureRepresentationStateBuilder } from '../representation';
+import { Representation, RepresentationParamsGetter, RepresentationContext } from 'mol-repr/representation';
+import { Structure, Unit } from 'mol-model/structure';
+import { ThemeRegistryContext } from 'mol-theme/theme';
+
+const PuttyVisuals = {
+    'polymer-tube': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, PolymerTubeParams>) => UnitsRepresentation('Polymer tube mesh', ctx, getParams, PolymerTubeVisual),
+    'polymer-gap': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, PolymerGapParams>) => UnitsRepresentation('Polymer gap cylinder', ctx, getParams, PolymerGapVisual),
+}
+type PuttyVisualName = keyof typeof PuttyVisuals
+const PuttyVisualOptions = Object.keys(PuttyVisuals).map(name => [name, name] as [PuttyVisualName, string])
+
+export const PuttyParams = {
+    ...PolymerTubeParams,
+    ...PolymerGapParams,
+    sizeFactor: PD.Numeric(0.2, { min: 0, max: 10, step: 0.01 }),
+    visuals: PD.MultiSelect<PuttyVisualName>(['polymer-tube', 'polymer-gap'], PuttyVisualOptions),
+}
+export type PuttyParams = typeof PuttyParams
+export function getPuttyParams(ctx: ThemeRegistryContext, structure: Structure) {
+    const params = PD.clone(PuttyParams)
+    let hasNucleotides = false
+    let hasGaps = false
+    structure.units.forEach(u => {
+        if (!hasNucleotides && Unit.isAtomic(u) && u.nucleotideElements.length) hasNucleotides = true
+        if (!hasGaps && u.gapElements.length) hasGaps = true
+    })
+    params.visuals.defaultValue = ['polymer-tube']
+    if (hasGaps) params.visuals.defaultValue.push('polymer-gap')
+    return params
+}
+
+export type PuttyRepresentation = StructureRepresentation<PuttyParams>
+export function PuttyRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<Structure, PuttyParams>): PuttyRepresentation {
+    return Representation.createMulti('Putty', ctx, getParams, StructureRepresentationStateBuilder, PuttyVisuals as unknown as Representation.Def<Structure, PuttyParams>)
+}
+
+export const PuttyRepresentationProvider: StructureRepresentationProvider<PuttyParams> = {
+    label: 'Putty',
+    description: 'Displays a tube smoothly following the trace atoms of polymers.',
+    factory: PuttyRepresentation,
+    getParams: getPuttyParams,
+    defaultValues: PD.getDefaultValues(PuttyParams),
+    defaultColorTheme: 'polymer-id',
+    defaultSizeTheme: 'uncertainty'
+}

+ 88 - 0
src/mol-repr/structure/visual/polymer-tube-mesh.ts

@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2019 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 { UnitsVisual } from '../representation';
+import { VisualUpdateState } from '../../util';
+import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, eachPolymerElement, interpolateSizes } from './util/polymer';
+import { isNucleic } from 'mol-model/structure/model/types';
+import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual';
+import { ParamDefinition as PD } from 'mol-util/param-definition';
+import { Mesh } from 'mol-geo/geometry/mesh/mesh';
+import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
+import { addTube } from 'mol-geo/geometry/mesh/builder/tube';
+import { VisualContext } from 'mol-repr/visual';
+import { Theme } from 'mol-theme/theme';
+
+export const PolymerTubeMeshParams = {
+    sizeFactor: PD.Numeric(0.2, { min: 0, max: 10, step: 0.01 }),
+    linearSegments: PD.Numeric(8, { min: 1, max: 48, step: 1 }),
+    radialSegments: PD.Numeric(16, { min: 3, max: 56, step: 1 }),
+}
+export const DefaultPolymerTubeMeshProps = PD.getDefaultValues(PolymerTubeMeshParams)
+export type PolymerTubeMeshProps = typeof DefaultPolymerTubeMeshProps
+
+// TODO handle polymer ends properly
+
+function createPolymerTubeMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PolymerTubeMeshProps, mesh?: Mesh) {
+    const polymerElementCount = unit.polymerElements.length
+
+    if (!polymerElementCount) return Mesh.createEmpty(mesh)
+    const { sizeFactor, linearSegments, radialSegments } = props
+
+    const vertexCount = linearSegments * radialSegments * polymerElementCount + (radialSegments + 1) * polymerElementCount * 2
+    const builderState = MeshBuilder.createState(vertexCount, vertexCount / 10, mesh)
+
+    const state = createCurveSegmentState(linearSegments)
+    const { curvePoints, normalVectors, binormalVectors, widthValues, heightValues } = state
+
+    let i = 0
+    const polymerTraceIt = PolymerTraceIterator(unit)
+    while (polymerTraceIt.hasNext) {
+        const v = polymerTraceIt.move()
+        builderState.currentGroup = i
+
+        const isNucleicType = isNucleic(v.moleculeType)
+        const tension = isNucleicType ? 0.5 : 0.9
+        const shift = isNucleicType ? 0.3 : 0.5
+
+        interpolateCurveSegment(state, v, tension, shift)
+
+        let s0 = theme.size.size(v.centerPrev) * sizeFactor
+        let s1 = theme.size.size(v.center) * sizeFactor
+        let s2 = theme.size.size(v.centerNext) * sizeFactor
+
+        interpolateSizes(state, s0, s1, s2, s0, s1, s2, shift)
+        addTube(builderState, curvePoints, normalVectors, binormalVectors, linearSegments, radialSegments, widthValues, heightValues, 1, v.first, v.last)
+
+        ++i
+    }
+
+    return MeshBuilder.getMesh(builderState)
+}
+
+export const PolymerTubeParams = {
+    ...UnitsMeshParams,
+    ...PolymerTubeMeshParams
+}
+export type PolymerTubeParams = typeof PolymerTubeParams
+
+export function PolymerTubeVisual(): UnitsVisual<PolymerTubeParams> {
+    return UnitsMeshVisual<PolymerTubeParams>({
+        defaultProps: PD.getDefaultValues(PolymerTubeParams),
+        createGeometry: createPolymerTubeMesh,
+        createLocationIterator: PolymerLocationIterator.fromGroup,
+        getLoci: getPolymerElementLoci,
+        eachLocation: eachPolymerElement,
+        setUpdateState: (state: VisualUpdateState, newProps: PD.Values<PolymerTubeParams>, currentProps: PD.Values<PolymerTubeParams>) => {
+            state.createGeometry = (
+                newProps.sizeFactor !== currentProps.sizeFactor ||
+                newProps.linearSegments !== currentProps.linearSegments ||
+                newProps.radialSegments !== currentProps.radialSegments
+            )
+        }
+    })
+}

+ 1 - 0
src/mol-theme/color/uncertainty.ts

@@ -36,6 +36,7 @@ export function getUncertainty(unit: Unit, element: ElementIndex): number {
 
 export function UncertaintyColorTheme(ctx: ThemeDataContext, props: PD.Values<UncertaintyColorThemeParams>): ColorTheme<UncertaintyColorThemeParams> {
     const scale = ColorScale.create({
+        reverse: true,
         domain: props.domain,
         listOrName: props.list,
     })