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

added cross-link distance restraints

parent 253e6a11
No related branches found
No related tags found
No related merge requests found
Showing
with 674 additions and 36 deletions
......@@ -19,6 +19,7 @@ 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/util';
import { Unit } from 'mol-model/structure';
export const ColorThemeInfo = {
'atom-index': {},
......@@ -46,6 +47,7 @@ interface BallAndStickState {
linkRadius: number
radialSegments: number
detail: number
unitKinds: Unit.Kind[]
}
export class BallAndStick extends View<Controller<any>, BallAndStickState, { transform: BallAndStickUpdate, entity: BallAndStickEntity, ctx: StateContext }> {
......@@ -65,7 +67,8 @@ export class BallAndStick extends View<Controller<any>, BallAndStickState, { tra
linkSpacing: 1,
linkRadius: 0.25,
radialSegments: 16,
detail: 1
detail: 1,
unitKinds: [] as Unit.Kind[]
}
componentWillMount() {
......
......@@ -19,6 +19,7 @@ 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/util';
import { Unit } from 'mol-model/structure';
export const ColorThemeInfo = {
'atom-index': {},
......@@ -42,6 +43,7 @@ interface SpacefillState {
depthMask: boolean
useFog: boolean
quality: VisualQuality
unitKinds: Unit.Kind[]
}
export class Spacefill extends View<Controller<any>, SpacefillState, { transform: SpacefillUpdate, entity: SpacefillEntity, ctx: StateContext }> {
......@@ -57,7 +59,8 @@ export class Spacefill extends View<Controller<any>, SpacefillState, { transform
alpha: 1,
depthMask: true,
useFog: true,
quality: 'auto' as VisualQuality
quality: 'auto' as VisualQuality,
unitKinds: [] as Unit.Kind[]
}
componentWillMount() {
......
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { StructureRepresentation } from '.';
import { PickingId } from '../../util/picking';
import { Structure } from 'mol-model/structure';
import { Task } from 'mol-task';
import { Loci } from 'mol-model/loci';
import { MarkerAction } from '../../util/marker-data';
import { SizeTheme } from '../../theme';
import { CrossLinkRestraintVisual, DefaultCrossLinkRestraintProps } from './visual/cross-link-restraint-cylinder';
export const DefaultDistanceRestraintProps = {
...DefaultCrossLinkRestraintProps,
sizeTheme: { name: 'uniform', value: 0.25 } as SizeTheme,
}
export type DistanceRestraintProps = Partial<typeof DefaultDistanceRestraintProps>
export function DistanceRestraintRepresentation(): StructureRepresentation<DistanceRestraintProps> {
const crossLinkRepr = StructureRepresentation(CrossLinkRestraintVisual)
return {
get renderObjects() {
return [ ...crossLinkRepr.renderObjects ]
},
get props() {
return { ...crossLinkRepr.props }
},
create: (structure: Structure, props: DistanceRestraintProps = {} as DistanceRestraintProps) => {
const p = Object.assign({}, DefaultDistanceRestraintProps, props)
return Task.create('DistanceRestraintRepresentation', async ctx => {
await crossLinkRepr.create(structure, p).runInContext(ctx)
})
},
update: (props: DistanceRestraintProps) => {
const p = Object.assign({}, props)
return Task.create('Updating DistanceRestraintRepresentation', async ctx => {
await crossLinkRepr.update(p).runInContext(ctx)
})
},
getLoci: (pickingId: PickingId) => {
return crossLinkRepr.getLoci(pickingId)
},
mark: (loci: Loci, action: MarkerAction) => {
crossLinkRepr.mark(loci, action)
},
destroy() {
crossLinkRepr.destroy()
}
}
}
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ValueCell } from 'mol-util/value-cell'
import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object'
import { Link, Structure } from 'mol-model/structure';
import { DefaultStructureProps, StructureVisual } from '../index';
import { RuntimeContext } from 'mol-task'
import { LinkCylinderProps, DefaultLinkCylinderProps, createLinkCylinderMesh } from './util/link';
import { MeshValues } from 'mol-gl/renderable';
import { getMeshData } from '../../../util/mesh-data';
import { Mesh } from '../../../shape/mesh';
import { PickingId } from '../../../util/picking';
import { Vec3 } from 'mol-math/linear-algebra';
import { createUniformColor } from '../../../util/color-data';
import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci';
import { MarkerAction, applyMarkerAction, createMarkers, MarkerData } from '../../../util/marker-data';
import { SizeTheme } from '../../../theme';
import { createIdentityTransform } from './util/common';
import { updateMeshValues, updateRenderableState, createMeshValues, createRenderableState } from '../../util';
// import { chainIdLinkColorData } from '../../../theme/structure/color/chain-id';
async function createCrossLinkRestraintCylinderMesh(ctx: RuntimeContext, structure: Structure, props: LinkCylinderProps, mesh?: Mesh) {
const crossLinks = structure.crossLinkRestraints
if (!crossLinks.count) return Mesh.createEmpty(mesh)
const builderProps = {
linkCount: crossLinks.count,
referencePosition: (edgeIndex: number) => null,
position: (posA: Vec3, posB: Vec3, edgeIndex: number) => {
const b = crossLinks.pairs[edgeIndex]
// console.log(b)
const uA = b.unitA, uB = b.unitB
uA.conformation.position(uA.elements[b.indexA], posA)
uB.conformation.position(uB.elements[b.indexB], posB)
// console.log(posA, posB)
},
order: (edgeIndex: number) => 1,
flags: (edgeIndex: number) => 0
}
return createLinkCylinderMesh(ctx, builderProps, props, mesh)
}
export const DefaultCrossLinkRestraintProps = {
...DefaultStructureProps,
...DefaultLinkCylinderProps,
sizeTheme: { name: 'physical', factor: 0.3 } as SizeTheme,
flipSided: false,
flatShaded: false,
}
export type CrossLinkRestraintProps = Partial<typeof DefaultCrossLinkRestraintProps>
export function CrossLinkRestraintVisual(): StructureVisual<CrossLinkRestraintProps> {
const renderObjects: RenderObject[] = []
let cylinders: MeshRenderObject
let currentProps: typeof DefaultCrossLinkRestraintProps
let mesh: Mesh
let currentStructure: Structure
return {
renderObjects,
async create(ctx: RuntimeContext, structure: Structure, props: CrossLinkRestraintProps = {}) {
currentProps = Object.assign({}, DefaultCrossLinkRestraintProps, props)
renderObjects.length = 0 // clear
currentStructure = structure
const elementCount = structure.crossLinkRestraints.count
const instanceCount = 1
mesh = await createCrossLinkRestraintCylinderMesh(ctx, structure, currentProps)
if (ctx.shouldUpdate) await ctx.update('Computing link transforms');
const transforms = createIdentityTransform()
if (ctx.shouldUpdate) await ctx.update('Computing link colors');
const color = createUniformColor({ value: 0x119911 }) // TODO
if (ctx.shouldUpdate) await ctx.update('Computing link marks');
const marker = createMarkers(instanceCount * elementCount)
const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount }
const values: MeshValues = {
...getMeshData(mesh),
...color,
...marker,
aTransform: transforms,
elements: mesh.indexBuffer,
...createMeshValues(currentProps, counts),
}
const state = createRenderableState(currentProps)
cylinders = createMeshRenderObject(values, state)
console.log(values, instanceCount, elementCount)
renderObjects.push(cylinders)
},
async update(ctx: RuntimeContext, props: CrossLinkRestraintProps) {
const newProps = Object.assign({}, currentProps, props)
if (!cylinders) return false
// TODO create in-place
if (currentProps.radialSegments !== newProps.radialSegments) return false
updateMeshValues(cylinders.values, newProps)
updateRenderableState(cylinders.state, newProps)
return false
},
getLoci(pickingId: PickingId) {
return getLinkLoci(pickingId, currentStructure, cylinders.id)
},
mark(loci: Loci, action: MarkerAction) {
markLink(loci, action, currentStructure, cylinders.values)
},
destroy() {
// TODO
}
}
}
function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
const { objectId, elementId } = pickingId
if (id === objectId) {
const pair = structure.crossLinkRestraints.pairs[elementId]
if (pair) {
return Link.Loci([{
aUnit: pair.unitA,
aIndex: pair.indexA,
bUnit: pair.unitB,
bIndex: pair.indexB
}])
}
}
return EmptyLoci
}
function markLink(loci: Loci, action: MarkerAction, structure: Structure, values: MarkerData) {
const tMarker = values.tMarker
const crossLinks = structure.crossLinkRestraints
const elementCount = crossLinks.count
const instanceCount = 1
let changed = false
const array = tMarker.ref.value.array
if (isEveryLoci(loci)) {
applyMarkerAction(array, 0, elementCount * instanceCount, action)
changed = true
} else if (Link.isLoci(loci)) {
for (const b of loci.links) {
const indices = crossLinks.getPairIndices(b.aIndex, b.aUnit, b.bIndex, b.bUnit)
if (indices) {
for (let i = 0, il = indices.length; i < il; ++i) {
const idx = indices[i]
if (applyMarkerAction(array, idx, idx + 1, action) && !changed) {
changed = true
}
}
}
}
} else {
return
}
if (changed) {
ValueCell.update(tMarker, tMarker.ref.value)
}
}
\ No newline at end of file
......@@ -103,15 +103,15 @@ export function getQualityProps(props: Partial<QualityProps>, structure: Structu
switch (quality) {
case 'highest':
detail = 3
detail = 2
radialSegments = 36
break
case 'high':
detail = 2
detail = 1
radialSegments = 24
break
case 'medium':
detail = 1
detail = 0
radialSegments = 12
break
case 'low':
......
......@@ -5,6 +5,8 @@
*/
import { Color } from 'mol-util/color';
// import { Loci } from 'mol-model/loci';
// import { Structure } from 'mol-model/structure';
export interface UniformColorTheme {
name: 'uniform'
......@@ -16,6 +18,22 @@ export interface ScaleColorTheme {
domain?: [number, number]
}
// interface StructureColorProvider {
// uniform(): Color
// instance(instanceIdx: number): Color
// element(elementIdx: number): Color
// elementInstance(elementIdx: number, instanceIdx: number): Color
// lociColor(loci: Loci): Color
// }
// export namespace ColorProvider {
// export function fromLociColor(lociColor: (loci: Loci) => Color) {
// return
// }
// }
export type ColorTheme = UniformColorTheme | ScaleColorTheme
export interface UniformSizeTheme {
......
/**
* Copyright (c) 2018 Mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
// ihm_predicted_contact_restraint: {
// id: int,
// entity_id_1: str,
// entity_id_2: str,
// asym_id_1: str,
// asym_id_2: str,
// comp_id_1: str,
// comp_id_2: str,
// seq_id_1: int,
// seq_id_2: int,
// atom_id_1: str,
// atom_id_2: str,
// distance_upper_limit: float,
// probability: float,
// restraint_type: Aliased<'lower bound' | 'upper bound' | 'lower and upper bound'>(str),
// model_granularity: Aliased<'by-residue' | 'by-feature' | 'by-atom'>(str),
// dataset_list_id: int,
// software_id: int,
// },
// ihm_cross_link_restraint: {
// id: int,
// group_id: int,
// entity_id_1: str,
// entity_id_2: str,
// asym_id_1: str,
// asym_id_2: str,
// comp_id_1: str,
// comp_id_2: str,
// seq_id_1: int,
// seq_id_2: int,
// atom_id_1: str,
// atom_id_2: str,
// restraint_type: Aliased<'harmonic' | 'upper bound' | 'lower bound'>(str),
// conditional_crosslink_flag: Aliased<'ALL' | 'ANY'>(str),
// model_granularity: Aliased<'by-residue' | 'by-feature' | 'by-atom'>(str),
// distance_threshold: float,
// psi: float,
// sigma_1: float,
// sigma_2: float,
// },
import Model from '../../model'
import { Table } from 'mol-data/db'
import { mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif';
import { findAtomIndexByLabelName } from './util';
import { Element, Unit } from '../../../structure';
function findAtomIndex(model: Model, entityId: string, asymId: string, compId: string, seqId: number, atomId: string) {
if (!model.atomicHierarchy.atoms.auth_atom_id.isDefined) return -1
const residueIndex = model.atomicHierarchy.findResidueKey(entityId, compId, asymId, seqId, '')
if (residueIndex < 0) return -1
return findAtomIndexByLabelName(model, residueIndex, atomId, '') as Element
}
// function findElementIndex(model: Model, entityId: string, asymId: string, compId: string, seqId: number, atomId: string) {
// }
// function key(entityId: string, asymId: string, compId: string, seqId: number, atomId: string) {
// return `${entityId}|${asymId}|${compId}|${seqId}|${atomId}`
// }
export interface IHMCrossLinkRestraint {
getIndicesByElement: (element: Element, kind: Unit.Kind) => number[]
data: Table<mmCIF_Schema['ihm_cross_link_restraint']>
}
export namespace IHMCrossLinkRestraint {
export const PropName = '__CrossLinkRestraint__';
export function fromModel(model: Model): IHMCrossLinkRestraint | undefined {
if (model.properties[PropName]) return model.properties[PropName]
if (model.sourceData.kind !== 'mmCIF') return
const { ihm_cross_link_restraint } = model.sourceData.data;
if (!ihm_cross_link_restraint._rowCount) return
const p1 = {
entity_id: ihm_cross_link_restraint.entity_id_1,
asym_id: ihm_cross_link_restraint.asym_id_1,
comp_id: ihm_cross_link_restraint.comp_id_1,
seq_id: ihm_cross_link_restraint.seq_id_1,
atom_id: ihm_cross_link_restraint.atom_id_1,
}
const p2: typeof p1 = {
entity_id: ihm_cross_link_restraint.entity_id_2,
asym_id: ihm_cross_link_restraint.asym_id_2,
comp_id: ihm_cross_link_restraint.comp_id_2,
seq_id: ihm_cross_link_restraint.seq_id_2,
atom_id: ihm_cross_link_restraint.atom_id_2,
}
function _add(map: Map<Element, number[]>, element: Element, row: number) {
const indices = map.get(element)
if (indices) indices.push(row)
else map.set(element, [ row ])
}
function add(row: number, ps: typeof p1) {
const entityId = ps.entity_id.value(row)
const asymId = ps.asym_id.value(row)
const seqId = ps.seq_id.value(row)
if (ihm_cross_link_restraint.model_granularity.value(row) === 'by-atom') {
const atomicElement = findAtomIndex(model, entityId, asymId, ps.comp_id.value(row), seqId, ps.atom_id.value(row))
if (atomicElement >= 0) _add(atomicElementMap, atomicElement as Element, row)
} else if (model.coarseHierarchy.isDefined) {
const sphereElement = model.coarseHierarchy.spheres.findSequenceKey(entityId, asymId, seqId)
if (sphereElement >= 0) {
_add(sphereElementMap, sphereElement as Element, row)
} else {
const gaussianElement = model.coarseHierarchy.gaussians.findSequenceKey(entityId, asymId, seqId)
if (gaussianElement >= 0) _add(gaussianElementMap, gaussianElement as Element, row)
}
}
}
function getMapByKind(kind: Unit.Kind) {
switch (kind) {
case Unit.Kind.Atomic: return atomicElementMap;
case Unit.Kind.Spheres: return sphereElementMap;
case Unit.Kind.Gaussians: return gaussianElementMap;
}
}
/** map from atomic element to cross link indices */
const atomicElementMap: Map<Element, number[]> = new Map()
/** map from sphere element to cross link indices */
const sphereElementMap: Map<Element, number[]> = new Map()
/** map from gaussian element to cross link indices */
const gaussianElementMap: Map<Element, number[]> = new Map()
const emptyIndexArray: number[] = [];
for (let i = 0; i < ihm_cross_link_restraint._rowCount; ++i) {
add(i, p1)
add(i, p2)
}
const crossLinkRestraint = {
getIndicesByElement: (element: Element, kind: Unit.Kind) => {
const map = getMapByKind(kind)
const idx = map.get(element)
return idx !== undefined ? idx : emptyIndexArray
},
data: ihm_cross_link_restraint
}
model.properties[PropName] = crossLinkRestraint
return crossLinkRestraint
}
}
\ No newline at end of file
......@@ -16,10 +16,12 @@ import { CoarseElements } from '../model/properties/coarse';
import { StructureSubsetBuilder } from './util/subset-builder';
import { Queries } from '../query';
import { InterUnitBonds, computeInterUnitBonds } from './unit/links';
import { CrossLinkRestraints, extractCrossLinkRestraints } from './unit/pair-restraints';
class Structure {
readonly unitMap: IntMap<Unit>;
readonly units: ReadonlyArray<Unit>;
/** Count of all elements in the structure, i.e. the sum of the elements in the units */
readonly elementCount: number;
private _hashCode = 0;
......@@ -68,6 +70,13 @@ class Structure {
return this._links;
}
private _crossLinkRestraints?: CrossLinkRestraints = void 0;
get crossLinkRestraints() {
if (this._crossLinkRestraints) return this._crossLinkRestraints;
this._crossLinkRestraints = extractCrossLinkRestraints(this);
return this._crossLinkRestraints;
}
constructor(units: ArrayLike<Unit>) {
const map = IntMap.Mutable<Unit>();
let elementCount = 0;
......
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
export * from './pair-restraints/data'
export * from './pair-restraints/extract-cross-links'
// export * from './pair-restraints/extract-predicted_contacts'
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import Unit from '../../unit';
const emptyArray: number[] = []
class CrossLinkRestraints {
readonly count: number
private readonly pairKeyIndices: Map<string, number[]>
/** Indices into this.pairs */
getPairIndices(indexA: number, unitA: Unit, indexB: number, unitB: Unit): ReadonlyArray<number> {
const key = CrossLinkRestraints.getPairKey(indexA, unitA, indexB, unitB)
const indices = this.pairKeyIndices.get(key)
return indices !== undefined ? indices : emptyArray
}
getPairs(indexA: number, unitA: Unit, indexB: number, unitB: Unit): CrossLinkRestraints.Pair[] | undefined {
const indices = this.getPairIndices(indexA, unitA, indexB, unitB)
return indices.length ? indices.map(idx => this.pairs[idx]) : undefined
}
constructor(public pairs: ReadonlyArray<CrossLinkRestraints.Pair>) {
const pairKeyIndices = new Map<string, number[]>()
this.pairs.forEach((p, i) => {
const key = CrossLinkRestraints.getPairKey(p.indexA, p.unitA, p.indexB, p.unitB)
const indices = pairKeyIndices.get(key)
if (indices) indices.push(i)
else pairKeyIndices.set(key, [i])
})
this.count = pairs.length
this.pairKeyIndices = pairKeyIndices
}
}
namespace CrossLinkRestraints {
export interface Pair {
readonly unitA: Unit,
readonly unitB: Unit,
readonly indexA: number,
readonly indexB: number,
readonly restraintType: 'harmonic' | 'upper bound' | 'lower bound',
readonly distanceThreshold: number,
readonly psi: number,
readonly sigma1: number,
readonly sigma2: number,
}
export function getPairKey(indexA: number, unitA: Unit, indexB: number, unitB: Unit) {
return `${indexA}|${unitA.id}|${indexB}|${unitB.id}`
}
}
export { CrossLinkRestraints }
\ No newline at end of file
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import Unit from '../../unit';
import Structure from '../../structure';
import { IHMCrossLinkRestraint } from '../../../model/formats/mmcif/pair-restraint';
import { CrossLinkRestraints } from './data';
function _addRestraints(map: Map<number, number>, unit: Unit, restraints: IHMCrossLinkRestraint) {
const { elements } = unit;
const elementCount = elements.length;
const kind = unit.kind
for (let i = 0; i < elementCount; i++) {
const e = elements[i];
restraints.getIndicesByElement(e, kind).forEach(ri => map.set(ri, i))
}
}
function extractInter(pairs: CrossLinkRestraints.Pair[], unitA: Unit, unitB: Unit) {
if (unitA.model !== unitB.model) return
if (unitA.model.sourceData.kind !== 'mmCIF') return
const restraints = IHMCrossLinkRestraint.fromModel(unitA.model)
if (!restraints) return
const rA = new Map<number, number>();
const rB = new Map<number, number>();
_addRestraints(rA, unitA, restraints)
_addRestraints(rB, unitB, restraints)
rA.forEach((indexA, ri) => {
const indexB = rB.get(ri)
if (indexB !== undefined) {
pairs.push(
createCrossLinkRestraint(unitA, indexA, unitB, indexB, restraints, ri),
createCrossLinkRestraint(unitB, indexB, unitA, indexA, restraints, ri)
)
}
})
}
function extractIntra(pairs: CrossLinkRestraints.Pair[], unit: Unit) {
if (unit.model.sourceData.kind !== 'mmCIF') return
const restraints = IHMCrossLinkRestraint.fromModel(unit.model)
if (!restraints) return
const { elements } = unit;
const elementCount = elements.length;
const kind = unit.kind
const r = new Map<number, number[]>();
for (let i = 0; i < elementCount; i++) {
const e = elements[i];
restraints.getIndicesByElement(e, kind).forEach(ri => {
const il = r.get(ri)
if (il) il.push(i)
else r.set(ri, [i])
})
}
r.forEach((il, ri) => {
if (il.length < 2) return
const [ indexA, indexB ] = il
pairs.push(
createCrossLinkRestraint(unit, indexA, unit, indexB, restraints, ri),
createCrossLinkRestraint(unit, indexB, unit, indexA, restraints, ri)
)
})
}
function createCrossLinkRestraint(unitA: Unit, indexA: number, unitB: Unit, indexB: number, restraints: IHMCrossLinkRestraint, row: number): CrossLinkRestraints.Pair {
return {
unitA, indexA, unitB, indexB,
restraintType: restraints.data.restraint_type.value(row),
distanceThreshold: restraints.data.distance_threshold.value(row),
psi: restraints.data.psi.value(row),
sigma1: restraints.data.sigma_1.value(row),
sigma2: restraints.data.sigma_2.value(row),
}
}
function extractCrossLinkRestraints(structure: Structure): CrossLinkRestraints {
const pairs: CrossLinkRestraints.Pair[] = []
const n = structure.units.length
for (let i = 0; i < n; ++i) {
const unitA = structure.units[i]
extractIntra(pairs, unitA)
for (let j = i + 1; j < n; ++j) {
const unitB = structure.units[j]
extractInter(pairs, unitA, unitB)
}
}
return new CrossLinkRestraints(pairs)
}
export { extractCrossLinkRestraints };
/**
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
// TODO extract from `ihm_predicted_contact_restraint`
\ No newline at end of file
......@@ -7,7 +7,7 @@
import Viewer from 'mol-view/viewer'
import { StateContext } from './state/context';
import { Progress } from 'mol-task';
import { MmcifUrlToModel, ModelToStructure, StructureToSpacefill, StructureToBallAndStick } from './state/transform';
import { MmcifUrlToModel, ModelToStructure, StructureToSpacefill, StructureToBallAndStick, StructureToDistanceRestraint } from './state/transform';
import { UrlEntity } from './state/entity';
import { SpacefillProps } from 'mol-geo/representation/structure/spacefill';
import { Context } from 'mol-app/context/context';
......@@ -15,15 +15,17 @@ import { BallAndStickProps } from 'mol-geo/representation/structure/ball-and-sti
const spacefillProps: SpacefillProps = {
doubleSided: true,
colorTheme: { name: 'atom-index' },
quality: 'medium'
colorTheme: { name: 'chain-id' },
quality: 'auto',
useFog: false
}
const ballAndStickProps: BallAndStickProps = {
doubleSided: true,
colorTheme: { name: 'chain-id' },
sizeTheme: { name: 'uniform', value: 0.25 },
quality: 'medium'
quality: 'auto',
useFog: false
}
export class Stage {
......@@ -42,10 +44,13 @@ export class Stage {
// this.loadPdbid('1jj2')
// this.loadPdbid('4umt') // ligand has bond with order 3
// this.loadPdbid('1crn') // small
// this.loadPdbid('1rb8') // virus
// this.loadPdbid('1blu') // metal coordination
this.loadPdbid('3pqr') // inter unit bonds
// this.loadPdbid('3pqr') // inter unit bonds
// this.loadPdbid('4v5a') // ribosome
// this.loadMmcifUrl(`../../examples/1cbs_full.bcif`)
this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000001.cif`)
}
async loadMmcifUrl (url: string) {
......@@ -53,8 +58,9 @@ export class Stage {
const modelEntity = await MmcifUrlToModel.apply(this.ctx, urlEntity)
const structureEntity = await ModelToStructure.apply(this.ctx, modelEntity)
StructureToSpacefill.apply(this.ctx, structureEntity, { ...spacefillProps, visible: false })
StructureToBallAndStick.apply(this.ctx, structureEntity, ballAndStickProps)
StructureToSpacefill.apply(this.ctx, structureEntity, { ...spacefillProps, visible: true })
// StructureToBallAndStick.apply(this.ctx, structureEntity, ballAndStickProps)
StructureToDistanceRestraint.apply(this.ctx, structureEntity, ballAndStickProps)
this.globalContext.components.sequenceView.setState({ structure: structureEntity.value });
}
......
......@@ -14,6 +14,7 @@ import { Model, Structure } from 'mol-model/structure';
import { StructureRepresentation } from 'mol-geo/representation/structure';
import { SpacefillProps } from 'mol-geo/representation/structure/spacefill';
import { BallAndStickProps } from 'mol-geo/representation/structure/ball-and-stick';
import { DistanceRestraintProps } from 'mol-geo/representation/structure/distance-restraint';
const getNextId = idFactory(1)
......@@ -128,3 +129,10 @@ export namespace BallAndStickEntity {
return StateEntity.create(ctx, 'ballandstick', repr )
}
}
export type DistanceRestraintEntity = StateEntity<StructureRepresentation<DistanceRestraintProps>, 'distancerestraint'>
export namespace DistanceRestraintEntity {
export function ofRepr(ctx: StateContext, repr: StructureRepresentation<DistanceRestraintProps>): DistanceRestraintEntity {
return StateEntity.create(ctx, 'distancerestraint', repr )
}
}
\ No newline at end of file
......@@ -5,13 +5,14 @@
*/
import CIF from 'mol-io/reader/cif'
import { FileEntity, DataEntity, UrlEntity, CifEntity, MmcifEntity, ModelEntity, StructureEntity, SpacefillEntity, AnyEntity, NullEntity, BallAndStickEntity } from './entity';
import { FileEntity, DataEntity, UrlEntity, CifEntity, MmcifEntity, ModelEntity, StructureEntity, SpacefillEntity, AnyEntity, NullEntity, BallAndStickEntity, DistanceRestraintEntity } from './entity';
import { Model, Structure, Format } from 'mol-model/structure';
import { StateContext } from './context';
import StructureSymmetry from 'mol-model/structure/structure/symmetry';
import { SpacefillProps, SpacefillRepresentation } from 'mol-geo/representation/structure/spacefill';
import { BallAndStickProps, BallAndStickRepresentation } from 'mol-geo/representation/structure/ball-and-stick';
import { DistanceRestraintRepresentation, DistanceRestraintProps } from 'mol-geo/representation/structure/distance-restraint';
type transformer<I extends AnyEntity, O extends AnyEntity, P extends {}> = (ctx: StateContext, inputEntity: I, props?: P) => Promise<O>
......@@ -113,6 +114,17 @@ export type StructureToBallAndStick = StateTransform<StructureEntity, BallAndSti
return BallAndStickEntity.ofRepr(ctx, ballAndStickRepr)
})
export type StructureToDistanceRestraint = StateTransform<StructureEntity, DistanceRestraintEntity, DistanceRestraintProps>
export const StructureToDistanceRestraint: StructureToDistanceRestraint = StateTransform.create('structure', 'distancerestraint', 'structure-to-distancerestraint',
async function (ctx: StateContext, structureEntity: StructureEntity, props: DistanceRestraintProps = {}) {
const distanceRestraintRepr = DistanceRestraintRepresentation()
await distanceRestraintRepr.create(structureEntity.value, props).run(ctx.log)
ctx.viewer.add(distanceRestraintRepr)
ctx.viewer.requestDraw()
console.log('stats', ctx.viewer.stats)
return DistanceRestraintEntity.ofRepr(ctx, distanceRestraintRepr)
})
export type SpacefillUpdate = StateTransform<SpacefillEntity, NullEntity, SpacefillProps>
export const SpacefillUpdate: SpacefillUpdate = StateTransform.create('spacefill', 'null', 'spacefill-update',
async function (ctx: StateContext, spacefillEntity: SpacefillEntity, props: SpacefillProps = {}) {
......@@ -135,6 +147,17 @@ export type BallAndStickUpdate = StateTransform<BallAndStickEntity, NullEntity,
return NullEntity
})
export type DistanceRestraintUpdate = StateTransform<DistanceRestraintEntity, NullEntity, DistanceRestraintProps>
export const DistanceRestraintUpdate: DistanceRestraintUpdate = StateTransform.create('distancerestraint', 'null', 'distancerestraint-update',
async function (ctx: StateContext, distanceRestraintEntity: DistanceRestraintEntity, props: DistanceRestraintProps = {}) {
const distanceRestraintRepr = distanceRestraintEntity.value
await distanceRestraintRepr.update(props).run(ctx.log)
ctx.viewer.add(distanceRestraintRepr)
ctx.viewer.requestDraw()
console.log('stats', ctx.viewer.stats)
return NullEntity
})
// composed
export type MmcifUrlToModel = StateTransform<UrlEntity, ModelEntity, {}>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment