Browse Source

wip, carbohydrates

Alexander Rose 6 years ago
parent
commit
a4ee34afc0

+ 7 - 8
src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts

@@ -42,7 +42,7 @@ async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Stru
 
     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 coneParams = { radiusTop: 0.0, radiusBottom: radius, bottomCap: true }
 
     const linkParams = { radiusTop: 0.4, radiusBottom: 0.4 }
 
@@ -63,15 +63,14 @@ async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Stru
                 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)
-                // TODO fix cylinder direction flipping code
+                Vec3.scaleAndAdd(p1, c.center, c.direction, radius)
+                Vec3.scaleAndSub(p2, c.center, c.direction, 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)
+                Vec3.scaleAndAdd(p1, c.center, c.direction, radius)
+                Vec3.scaleAndSub(p2, c.center, c.direction, radius)
                 builder.addCylinder(p1, p2, 1, coneParams)
                 break
             case SaccharideShapes.FlatBox:
@@ -87,12 +86,12 @@ async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Stru
             case SaccharideShapes.FlatDiamond:
             case SaccharideShapes.Pentagon:
                 centerAlign(c.center, c.normal, c.direction)
-                builder.addBox(t, { width: side, height: 0.5, depth: side })
+                builder.addBox(t, { width: side, height: side, depth: 0.5 })
                 break
             case SaccharideShapes.FlatHexagon:
             default:
                 centerAlign(c.center, c.normal, c.direction)
-                builder.addBox(t, { width: side, height: 0.1, depth: side })
+                builder.addBox(t, { width: side, height: side, depth: 0.1 })
                 break
         }
     }

+ 5 - 3
src/mol-geo/shape/mesh-builder.ts

@@ -60,14 +60,16 @@ const tmpCylinderCenter = Vec3.zero()
 const tmpCylinderMat = Mat4.zero()
 // const tmpCylinderMatTrans = Mat4.zero()
 const tmpCylinderStart = Vec3.zero()
+const tmpUp = Vec3.zero()
 
 function setCylinderMat(m: Mat4, start: Vec3, dir: Vec3, length: number) {
     Vec3.setMagnitude(tmpCylinderMatDir, dir, length / 2)
     Vec3.add(tmpCylinderCenter, start, tmpCylinderMatDir)
-    // ensure the direction use to create the rotation is always pointing in the same
+    // ensure the direction used to create the rotation is always pointing in the same
     // direction so the triangles of adjacent cylinder will line up
-    if (Vec3.dot(tmpCylinderMatDir, up) < 0) Vec3.scale(tmpCylinderMatDir, tmpCylinderMatDir, -1)
-    Vec3.makeRotation(m, up, tmpCylinderMatDir)
+    Vec3.copy(tmpUp, up)
+    if (Vec3.dot(tmpCylinderMatDir, tmpUp) < 0) Vec3.scale(tmpUp, tmpUp, -1)
+    Vec3.makeRotation(m, tmpUp, tmpCylinderMatDir)
     return Mat4.setTranslation(m, tmpCylinderCenter)
 }
 

+ 27 - 0
src/mol-model/structure/structure/carbohydrates/compute.ts

@@ -67,6 +67,12 @@ function getDirection(direction: Vec3, unit: Unit.Atomic, indices: ReadonlyArray
     return direction
 }
 
+function getAtomId(unit: Unit.Atomic, index: number) {
+    const { elements } = unit
+    const { label_atom_id } = unit.model.atomicHierarchy.atoms
+    return label_atom_id.value(elements[index])
+}
+
 export function computeCarbohydrates(structure: Structure): Carbohydrates {
     const links: CarbohydrateLink[] = []
     const terminalLinks: CarbohydrateTerminalLink[] = []
@@ -78,6 +84,18 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
         return `${residueIndex}|${unitId}`
     }
 
+    function fixLinkDirection(iA: number, iB: number) {
+        Vec3.sub(elements[iA].direction, elements[iB].center, elements[iA].center)
+        Vec3.normalize(elements[iA].direction, elements[iA].direction)
+    }
+
+    const tmpV = Vec3.zero()
+    function fixTerminalLinkDirection(iA: number, indexB: number, unitB: Unit.Atomic) {
+        const pos = unitB.conformation.position
+        Vec3.sub(elements[iA].direction, pos(unitB.elements[indexB], tmpV), elements[iA].center)
+        Vec3.normalize(elements[iA].direction, elements[iA].direction)
+    }
+
     // get carbohydrate elements and carbohydrate links induced by intra-residue bonds
     for (let i = 0, il = structure.units.length; i < il; ++i) {
         const unit = structure.units[i]
@@ -122,6 +140,9 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
                 for (let j = 0, jl = ringCombinations.length; j < jl; ++j) {
                     const rc = ringCombinations[j]
                     if (areConnected(sugarRings[rc[0]], sugarRings[rc[1]], unit.links, 2)) {
+                        // fix both directions as it is unlcear where the C1 atom is
+                        fixLinkDirection(ringElements[rc[0]], ringElements[rc[1]])
+                        fixLinkDirection(ringElements[rc[1]], ringElements[rc[0]])
                         links.push({
                             carbohydrateIndexA: ringElements[rc[0]],
                             carbohydrateIndexB: ringElements[rc[1]]
@@ -154,11 +175,17 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
                     const elementIndexB = elementsMap.get(elementKey(getResidueIndex(indexB, unitB), unitB.id))
 
                     if (elementIndexA !== undefined && elementIndexB !== undefined) {
+                        if (getAtomId(unitA, indexA).startsWith('C1')) {
+                            fixLinkDirection(elementIndexA, elementIndexB)
+                        }
                         links.push({
                             carbohydrateIndexA: elementIndexA,
                             carbohydrateIndexB: elementIndexB
                         })
                     } else if (elementIndexA !== undefined) {
+                        if (getAtomId(unitA, indexA).startsWith('C1')) {
+                            fixTerminalLinkDirection(elementIndexA, indexB, unitB)
+                        }
                         terminalLinks.push({
                             carbohydrateIndex: elementIndexA,
                             elementIndex: indexB,

+ 2 - 1
src/mol-model/structure/structure/carbohydrates/constants.ts

@@ -178,7 +178,8 @@ const CommonSaccharideNames: { [k: string]: string[] } = {
     Glc: [
         'GLC', 'BGC',
         'BOG', // via GlyFinder
-        'TRE', // via GlyFinder, disaccharide but homomer
+        'TRE', // via GlyFinder, di-saccharide but homomer
+        'MLR', // via GlyFinder, tri-saccharide but homomer
     ],
     Man: ['MAN', 'BMA'],
     Gal: ['GAL', 'GLA'],

+ 2 - 2
src/mol-view/stage.ts

@@ -78,7 +78,7 @@ export class Stage {
         // this.loadPdbid('1hrv') // viral assembly
         // this.loadPdbid('1rb8') // virus
         // this.loadPdbid('1blu') // metal coordination
-        // this.loadPdbid('3pqr') // inter unit bonds, two polymer chains, ligands, water, carbohydrates linked to protein
+        this.loadPdbid('3pqr') // inter unit bonds, two polymer chains, ligands, water, carbohydrates linked to protein
         // this.loadPdbid('4v5a') // ribosome
         // this.loadPdbid('3j3q') // ...
         // this.loadPdbid('2np2') // dna
@@ -99,7 +99,7 @@ export class Stage {
         // 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('1umz') // contains Xyl (Xyloglucan)
         // this.loadPdbid('1mfb') // contains Abe
         // this.loadPdbid('2gdu') // contains sucrose
         // this.loadPdbid('2fnc') // contains maltotriose