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

wip, carbohydrates orientation

parent 5e73b587
Branches
Tags
No related merge requests found
...@@ -22,20 +22,75 @@ import { createMeshValues, updateMeshValues, updateRenderableState, createRender ...@@ -22,20 +22,75 @@ import { createMeshValues, updateMeshValues, updateRenderableState, createRender
import { MeshBuilder } from '../../../shape/mesh-builder'; import { MeshBuilder } from '../../../shape/mesh-builder';
import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { Vec3, Mat4 } from 'mol-math/linear-algebra';
import { createUniformColor } from '../../../util/color-data'; import { createUniformColor } from '../../../util/color-data';
import { getSaccharideShape, SaccharideShapes } from 'mol-model/structure/structure/carbohydrates/constants';
async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Structure, mesh?: Mesh) { async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Structure, mesh?: Mesh) {
const builder = MeshBuilder.create(256, 128, mesh) const builder = MeshBuilder.create(256, 128, mesh)
const t = Mat4.identity() const t = Mat4.identity()
const p = Vec3.zero() const p = Vec3.zero()
const pd = Vec3.zero()
const p1 = Vec3.zero()
const p2 = Vec3.zero()
const carbohydrates = structure.carbohydrates const carbohydrates = structure.carbohydrates
const linkParams = { radiusTop: 0.2, radiusBottom: 0.2 } function centerAlign(center: Vec3, normal: Vec3, direction: Vec3) {
Vec3.add(pd, center, direction)
Mat4.targetTo(t, center, pd, normal)
Mat4.setTranslation(t, center)
}
const side = 1.75 * 2 * 0.806; // 0.806 == Math.cos(Math.PI / 4)
const radius = 1.75
const coneParams = { radiusTop: radius, radiusBottom: 0.0, topCap: true }
const linkParams = { radiusTop: 0.4, radiusBottom: 0.4 }
for (let i = 0, il = carbohydrates.elements.length; i < il; ++i) { for (let i = 0, il = carbohydrates.elements.length; i < il; ++i) {
const c = carbohydrates.elements[i] const c = carbohydrates.elements[i]
Mat4.setTranslation(t, c.center) const shapeType = getSaccharideShape(c.component.type)
builder.addBox(t, { width: 2, height: 2, depth: 2 }) switch (shapeType) {
case SaccharideShapes.FilledSphere:
builder.addIcosahedron(c.center, radius, 1)
break;
case SaccharideShapes.FilledCube:
centerAlign(c.center, c.normal, c.direction)
builder.addBox(t, { width: side, height: side, depth: side })
break;
case SaccharideShapes.CrossedCube:
// TODO split
centerAlign(c.center, c.normal, c.direction)
builder.addBox(t, { width: side, height: side, depth: side })
break;
case SaccharideShapes.FilledCone:
Vec3.scaleAndAdd(p1, c.center, c.normal, radius)
Vec3.scaleAndSub(p2, c.center, c.normal, radius)
builder.addCylinder(p1, p2, 1, coneParams)
break
case SaccharideShapes.DevidedCone:
// TODO split
Vec3.scaleAndAdd(p1, c.center, c.normal, radius)
Vec3.scaleAndSub(p2, c.center, c.normal, radius)
builder.addCylinder(p1, p2, 1, coneParams)
break
case SaccharideShapes.FlatBox:
centerAlign(c.center, c.normal, c.direction)
builder.addBox(t, { width: side, height: side / 2, depth: side })
break
case SaccharideShapes.FilledDiamond:
case SaccharideShapes.DividedDiamond:
case SaccharideShapes.FilledStar:
case SaccharideShapes.FlatDiamond:
case SaccharideShapes.Pentagon:
centerAlign(c.center, c.normal, c.direction)
builder.addBox(t, { width: side, height: 0.5, depth: side })
break
case SaccharideShapes.FlatHexagon:
default:
centerAlign(c.center, c.normal, c.direction)
builder.addBox(t, { width: side, height: 0.1, depth: side })
break
}
} }
for (let i = 0, il = carbohydrates.links.length; i < il; ++i) { for (let i = 0, il = carbohydrates.links.length; i < il; ++i) {
......
...@@ -132,6 +132,14 @@ namespace Vec3 { ...@@ -132,6 +132,14 @@ namespace Vec3 {
return out; return out;
} }
/** Scales b, then subtracts b from a */
export function scaleAndSub(out: Vec3, a: Vec3, b: Vec3, scale: number) {
out[0] = a[0] - (b[0] * scale);
out[1] = a[1] - (b[1] * scale);
out[2] = a[2] - (b[2] * scale);
return out;
}
/** /**
* Math.round the components of a Vec3 * Math.round the components of a Vec3
*/ */
......
...@@ -11,11 +11,12 @@ import Structure from '../structure'; ...@@ -11,11 +11,12 @@ import Structure from '../structure';
import { Carbohydrates, CarbohydrateLink, CarbohydrateTerminalLink, CarbohydrateElement } from './data'; import { Carbohydrates, CarbohydrateLink, CarbohydrateTerminalLink, CarbohydrateElement } from './data';
import { SaccharideNameMap, UnknownSaccharideComponent } from './constants'; import { SaccharideNameMap, UnknownSaccharideComponent } from './constants';
import { Vec3 } from 'mol-math/linear-algebra'; import { Vec3 } from 'mol-math/linear-algebra';
import { getCenterAndRadius, getMoleculeType } from '../../util'; import { getMoleculeType, getPositionMatrix } from '../../util';
import { MoleculeType } from '../../model/types'; import { MoleculeType, ElementSymbol } from '../../model/types';
import { areConnected } from 'mol-math/graph'; import { areConnected } from 'mol-math/graph';
import { combinations } from 'mol-data/util/combination'; import { combinations } from 'mol-data/util/combination';
import { fillSerial } from 'mol-util/array'; import { fillSerial } from 'mol-util/array';
import PrincipalAxes from 'mol-math/linear-algebra/matrix/principal-axes';
function getResidueIndex(elementIndex: number, unit: Unit.Atomic) { function getResidueIndex(elementIndex: number, unit: Unit.Atomic) {
return unit.model.atomicHierarchy.residueAtomSegments.index[unit.elements[elementIndex]] return unit.model.atomicHierarchy.residueAtomSegments.index[unit.elements[elementIndex]]
...@@ -40,6 +41,32 @@ function getRingIndices(unit: Unit.Atomic, rI: ResidueIndex) { ...@@ -40,6 +41,32 @@ function getRingIndices(unit: Unit.Atomic, rI: ResidueIndex) {
return sugarRings return sugarRings
} }
const C = ElementSymbol('C')
function getDirection(direction: Vec3, unit: Unit.Atomic, indices: ReadonlyArray<number>, center: Vec3) {
let indexC1 = -1, indexC1X = -1, indexC = -1
const { elements } = unit
const { position } = unit.conformation
const { label_atom_id, type_symbol } = unit.model.atomicHierarchy.atoms
for (let i = 0, il = indices.length; i < il; ++i) {
const ei = elements[indices[i]]
const atomId = label_atom_id.value(ei)
if (atomId === 'C1') {
indexC1 = ei
break
} else if (indexC1X === -1 && atomId.startsWith('C1')) {
indexC1X = ei
} else if (indexC === -1 && type_symbol.value(ei) === C) {
indexC = ei
}
}
const index = indexC1 !== -1 ? indexC1
: indexC1X !== -1 ? indexC1X
: indexC !== -1 ? indexC
: elements[indices[0]]
Vec3.normalize(direction, Vec3.sub(direction, center, position(index, direction)))
return direction
}
export function computeCarbohydrates(structure: Structure): Carbohydrates { export function computeCarbohydrates(structure: Structure): Carbohydrates {
const links: CarbohydrateLink[] = [] const links: CarbohydrateLink[] = []
const terminalLinks: CarbohydrateTerminalLink[] = [] const terminalLinks: CarbohydrateTerminalLink[] = []
...@@ -76,15 +103,15 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates { ...@@ -76,15 +103,15 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
const sugarRings = getRingIndices(unit, residueIndex) const sugarRings = getRingIndices(unit, residueIndex)
const ringElements: number[] = [] const ringElements: number[] = []
console.log('sugarRings', sugarRings)
for (let j = 0, jl = sugarRings.length; j < jl; ++j) { for (let j = 0, jl = sugarRings.length; j < jl; ++j) {
const center = Vec3.zero() const pa = new PrincipalAxes(getPositionMatrix(unit, sugarRings[j]))
const normal = Vec3.zero() const center = Vec3.copy(Vec3.zero(), pa.center)
const direction = Vec3.zero() const normal = Vec3.copy(Vec3.zero(), pa.normVecC)
const elementIndex = elements.length const direction = getDirection(Vec3.zero(), unit, sugarRings[j], center)
getCenterAndRadius(center, unit, sugarRings[j]) Vec3.orthogonalize(direction, normal, direction)
const elementIndex = elements.length
ringElements.push(elementIndex) ringElements.push(elementIndex)
elementsMap.set(elementKey(residueIndex, unit.id), elementIndex) elementsMap.set(elementKey(residueIndex, unit.id), elementIndex)
elements.push({ center, normal, direction, unit, residueIndex, component: saccharideComp }) elements.push({ center, normal, direction, unit, residueIndex, component: saccharideComp })
......
...@@ -175,7 +175,11 @@ const Monosaccharides: SaccharideComponent[] = [ ...@@ -175,7 +175,11 @@ const Monosaccharides: SaccharideComponent[] = [
const CommonSaccharideNames: { [k: string]: string[] } = { const CommonSaccharideNames: { [k: string]: string[] } = {
// Hexose // Hexose
Glc: ['GLC', 'BGC'], Glc: [
'GLC', 'BGC',
'BOG', // via GlyFinder
'TRE', // via GlyFinder, disaccharide but homomer
],
Man: ['MAN', 'BMA'], Man: ['MAN', 'BMA'],
Gal: ['GAL', 'GLA'], Gal: ['GAL', 'GLA'],
Gul: ['GUP', 'GL0'], Gul: ['GUP', 'GL0'],
...@@ -192,7 +196,10 @@ const CommonSaccharideNames: { [k: string]: string[] } = { ...@@ -192,7 +196,10 @@ const CommonSaccharideNames: { [k: string]: string[] } = {
TalNAc: [], TalNAc: [],
IdoNAc: ['HSQ'], IdoNAc: ['HSQ'],
// Hexosamine // Hexosamine
GlcN: ['GCS', 'PA1'], GlcN: [
'GCS', 'PA1',
'IDU', 'SGN', 'SUS', // via GlyFinder
],
ManN: ['95Z'], ManN: ['95Z'],
GalN: ['X6X', '1GN'], GalN: ['X6X', '1GN'],
GulN: [], GulN: [],
...@@ -208,7 +215,10 @@ const CommonSaccharideNames: { [k: string]: string[] } = { ...@@ -208,7 +215,10 @@ const CommonSaccharideNames: { [k: string]: string[] } = {
AltA: [], AltA: [],
AllA: [], AllA: [],
TalA: ['X0X', 'X1X'], TalA: ['X0X', 'X1X'],
IdoA: ['IDR'], IdoA: [
'IDR',
'IDS', // via GlyFinder
],
// Deoxyhexose // Deoxyhexose
Qui: ['G6D'], Qui: ['G6D'],
Rha: ['RAM', 'RM4'], Rha: ['RAM', 'RM4'],
......
...@@ -8,6 +8,7 @@ import { Model, ResidueIndex, ElementIndex } from './model'; ...@@ -8,6 +8,7 @@ import { Model, ResidueIndex, ElementIndex } from './model';
import { MoleculeType, AtomRole, MoleculeTypeAtomRoleId } from './model/types'; import { MoleculeType, AtomRole, MoleculeTypeAtomRoleId } from './model/types';
import { Vec3 } from 'mol-math/linear-algebra'; import { Vec3 } from 'mol-math/linear-algebra';
import { Unit } from './structure'; import { Unit } from './structure';
import Matrix from 'mol-math/linear-algebra/matrix/matrix';
export function getMoleculeType(model: Model, rI: ResidueIndex) { export function getMoleculeType(model: Model, rI: ResidueIndex) {
const compId = model.atomicHierarchy.residues.label_comp_id.value(rI) const compId = model.atomicHierarchy.residues.label_comp_id.value(rI)
...@@ -60,4 +61,16 @@ export function getCenterAndRadius(centroid: Vec3, unit: Unit, indices: ArrayLik ...@@ -60,4 +61,16 @@ export function getCenterAndRadius(centroid: Vec3, unit: Unit, indices: ArrayLik
} }
Vec3.scale(centroid, centroid, 1/indices.length) Vec3.scale(centroid, centroid, 1/indices.length)
return Vec3.distance(centerMin, centroid) return Vec3.distance(centerMin, centroid)
}
const matrixPos = Vec3.zero()
export function getPositionMatrix(unit: Unit, indices: ArrayLike<number>) {
const pos = unit.conformation.position
const mat = Matrix.create(3, indices.length)
const { elements } = unit
for (let i = 0, il = indices.length; i < il; ++i) {
pos(elements[indices[i]], matrixPos)
Vec3.toArray(matrixPos, mat.data, i * 3)
}
return mat
} }
\ No newline at end of file
...@@ -96,14 +96,20 @@ export class Stage { ...@@ -96,14 +96,20 @@ export class Stage {
// this.loadPdbid('1gfl') // GFP, flourophore has carbonyl oxygen removed // this.loadPdbid('1gfl') // GFP, flourophore has carbonyl oxygen removed
// this.loadPdbid('1sfi') // contains cyclic peptid // this.loadPdbid('1sfi') // contains cyclic peptid
// this.loadPdbid('3sn6') // discontinuous chains // this.loadPdbid('3sn6') // discontinuous chains
// this.loadPdbid('2zex') // small, contains carbohydrate polymer // this.loadPdbid('2zex') // contains carbohydrate polymer
// this.loadPdbid('3sgj') // contains carbohydrate polymer
// this.loadPdbid('3ina') // contains GlcN and IdoA
this.loadPdbid('1umz') // contains Xyl (Xyloglucan)
// this.loadPdbid('1mfb') // contains Abe
// this.loadPdbid('2gdu') // contains sucrose // this.loadPdbid('2gdu') // contains sucrose
// this.loadPdbid('2fnc') // contains maltotriose // this.loadPdbid('2fnc') // contains maltotriose
this.loadPdbid('4zs9') // contains raffinose // this.loadPdbid('4zs9') // contains raffinose
// this.loadPdbid('2yft') // contains kestose
// this.loadPdbid('2b5t') // contains large carbohydrate polymer // this.loadPdbid('2b5t') // contains large carbohydrate polymer
// this.loadMmcifUrl(`../../examples/1cbs_full.bcif`) // this.loadMmcifUrl(`../../examples/1cbs_full.bcif`)
// this.loadMmcifUrl(`../../examples/1cbs_updated.cif`) // this.loadMmcifUrl(`../../examples/1cbs_updated.cif`)
// this.loadMmcifUrl(`../../examples/1crn.cif`) // this.loadMmcifUrl(`../../examples/1crn.cif`)
// this.loadPdbid('1zag') // temp
// this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000001.cif`) // ok // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000001.cif`) // ok
// this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000002.cif`) // ok // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000002.cif`) // ok
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment