Skip to content
Snippets Groups Projects
assembly-symmetry.ts 4.02 KiB
Newer Older
Alexander Rose's avatar
wip
Alexander Rose committed
/**
 * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
 *
 * @author Alexander Rose <alexander.rose@weirdbyte.de>
 */

import { AssemblySymmetry } from 'mol-model-props/rcsb/symmetry';
import { Table } from 'mol-data/db';
import { Color, ColorScale } from 'mol-util/color';
import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
import { Tensor } from 'mol-math/linear-algebra';
import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere';
import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder';
import { Shape } from 'mol-model/shape';
import { ColorTheme } from 'mol-canvas3d/theme/color';
import { Location } from 'mol-model/location';
import { StructureElement, Unit, StructureProperties } from 'mol-model/structure';
Alexander Rose's avatar
wip
Alexander Rose committed

export function getAxesShape(featureId: number, assemblySymmetry: AssemblySymmetry) {
    const f = assemblySymmetry.db.rcsb_assembly_symmetry_feature
    const feature = Table.pickRow(f, i => f.id.value(i) === featureId)
    if (!feature) return

    const axes = assemblySymmetry.getAxes(featureId)
    if (!axes._rowCount) return

    const vectorSpace = AssemblySymmetry.Schema.rcsb_assembly_symmetry_axis.start.space;

    const colors: Color[] = []
    const labels: string[] = []

    const radius = 0.4
    const cylinderProps = { radiusTop: radius, radiusBottom: radius }
    const meshBuilder = MeshBuilder.create(256, 128)

    for (let i = 0, il = axes._rowCount; i < il; ++i) {
        const start = Tensor.toVec3(vectorSpace, axes.start.value(i))
        const end = Tensor.toVec3(vectorSpace, axes.end.value(i))
        meshBuilder.setGroup(i)
        addSphere(meshBuilder, start, radius, 2)
        addSphere(meshBuilder, end, radius, 2)
        addCylinder(meshBuilder, start, end, 1, cylinderProps)
        colors.push(Color(0xCCEE11))
        labels.push(`Axis ${i + 1} for ${feature.symmetry_value} ${feature.type.toLowerCase()} symmetry`)
    }
    const mesh = meshBuilder.getMesh()
    const shape = Shape.create('Axes', mesh, colors, labels)
    return shape
}

function getAsymId(unit: Unit): StructureElement.Property<string> {
    switch (unit.kind) {
        case Unit.Kind.Atomic:
            return StructureProperties.chain.auth_asym_id // TODO
        case Unit.Kind.Spheres:
        case Unit.Kind.Gaussians:
            return StructureProperties.coarse.asym_id
    }
}

function memberKey (asym_id: string, oper_list_id?: number) {
    return `${asym_id}|${oper_list_id}`
}

export function getClusterColorTheme(featureId: number, assemblySymmetry: AssemblySymmetry): ColorTheme {
    const DefaultColor = Color(0xCCCCCC)
Alexander Rose's avatar
wip
Alexander Rose committed
    const f = assemblySymmetry.db.rcsb_assembly_symmetry_feature
    const feature = Table.pickRow(f, i => f.id.value(i) === featureId)
    if (!feature) return { granularity: 'uniform', color: () => DefaultColor }
Alexander Rose's avatar
wip
Alexander Rose committed

    const clusters = assemblySymmetry.getClusters(featureId)
    if (!clusters._rowCount) return { granularity: 'uniform', color: () => DefaultColor }
Alexander Rose's avatar
wip
Alexander Rose committed

    const clusterByMember = new Map<string, number>()
Alexander Rose's avatar
wip
Alexander Rose committed
    for (let i = 0, il = clusters._rowCount; i < il; ++i) {
        clusters.members.value(i).forEach(m => {
            const ms = m.split('_')
            const asym_id = ms[0]
            const oper_list_id = ms.length === 2 ? parseInt(ms[1]) : undefined
            clusterByMember.set(memberKey(asym_id, oper_list_id), i)
        })
    }

    const scale = ColorScale.create({ domain: [ 0, clusters._rowCount - 1 ] })

    return {
        granularity: 'instance',
        color: (location: Location): Color => {
            if (StructureElement.isLocation(location)) {
                const ns = location.unit.conformation.operator.name.split('-')
                const asym_id = getAsymId(location.unit)
                const oper_list_id = ns.length === 2 ? parseInt(ns[1]) : undefined
                const cluster = clusterByMember.get(memberKey(asym_id(location), oper_list_id))
                return cluster !== undefined ? scale.color(cluster) : DefaultColor
            }
            return DefaultColor
        }
Alexander Rose's avatar
wip
Alexander Rose committed
    }
}