Browse Source

Updated carb representation (indicate whether it has a ring; geometry is a single property)

David Sehnal 6 years ago
parent
commit
5dc0a5e5b4

+ 18 - 15
src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts

@@ -47,50 +47,53 @@ async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Stru
     const linkParams = { radiusTop: 0.4, radiusBottom: 0.4 }
 
     for (let i = 0, il = carbohydrates.elements.length; i < il; ++i) {
-        const c = carbohydrates.elements[i]
+        const c = carbohydrates.elements[i];
+        if (!c.hasRing) continue;
+
+        const cGeo = c.geometry!
         const shapeType = getSaccharideShape(c.component.type)
         switch (shapeType) {
             case SaccharideShapes.FilledSphere:
-                builder.addIcosahedron(c.center, radius, 2)
+                builder.addIcosahedron(cGeo.center, radius, 2)
                 break;
             case SaccharideShapes.FilledCube:
-                centerAlign(c.center, c.normal, c.direction)
+                centerAlign(cGeo.center, cGeo.normal, cGeo.direction)
                 builder.addBox(t, { width: side, height: side, depth: side })
                 break;
             case SaccharideShapes.CrossedCube:
                 // TODO split
-                centerAlign(c.center, c.normal, c.direction)
+                centerAlign(cGeo.center, cGeo.normal, cGeo.direction)
                 builder.addBox(t, { width: side, height: side, depth: side })
                 break;
             case SaccharideShapes.FilledCone:
-                Vec3.scaleAndAdd(p1, c.center, c.direction, radius)
-                Vec3.scaleAndSub(p2, c.center, c.direction, radius)
+                Vec3.scaleAndAdd(p1, cGeo.center, cGeo.direction, radius)
+                Vec3.scaleAndSub(p2, cGeo.center, cGeo.direction, radius)
                 builder.addCylinder(p1, p2, 1, coneParams)
                 break
             case SaccharideShapes.DevidedCone:
                 // TODO split
-                Vec3.scaleAndAdd(p1, c.center, c.direction, radius)
-                Vec3.scaleAndSub(p2, c.center, c.direction, radius)
+                Vec3.scaleAndAdd(p1, cGeo.center, cGeo.direction, radius)
+                Vec3.scaleAndSub(p2, cGeo.center, cGeo.direction, radius)
                 builder.addCylinder(p1, p2, 1, coneParams)
                 break
             case SaccharideShapes.FlatBox:
-                centerAlign(c.center, c.normal, c.direction)
+                centerAlign(cGeo.center, cGeo.normal, cGeo.direction)
                 builder.addBox(t, { width: side, height: side / 2, depth: side })
                 break
             case SaccharideShapes.FilledStar:
-                centerAlign(c.center, c.normal, c.direction)
+                centerAlign(cGeo.center, cGeo.normal, cGeo.direction)
                 builder.addStar(t, { outerRadius: side, innerRadius: side / 2, thickness: side / 2, pointCount: 5 })
                 break
             case SaccharideShapes.FilledDiamond:
             case SaccharideShapes.DividedDiamond:
             case SaccharideShapes.FlatDiamond:
             case SaccharideShapes.Pentagon:
-                centerAlign(c.center, c.normal, c.direction)
+                centerAlign(cGeo.center, cGeo.normal, cGeo.direction)
                 builder.addBox(t, { width: side, height: side, depth: 0.5 })
                 break
             case SaccharideShapes.FlatHexagon:
             default:
-                centerAlign(c.center, c.normal, c.direction)
+                centerAlign(cGeo.center, cGeo.normal, cGeo.direction)
                 builder.addBox(t, { width: side, height: side, depth: 0.1 })
                 break
         }
@@ -98,14 +101,14 @@ async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Stru
 
     for (let i = 0, il = carbohydrates.links.length; i < il; ++i) {
         const l = carbohydrates.links[i]
-        const centerA = carbohydrates.elements[l.carbohydrateIndexA].center
-        const centerB = carbohydrates.elements[l.carbohydrateIndexB].center
+        const centerA = carbohydrates.elements[l.carbohydrateIndexA].geometry!.center
+        const centerB = carbohydrates.elements[l.carbohydrateIndexB].geometry!.center
         builder.addCylinder(centerA, centerB, 0.5, linkParams)
     }
 
     for (let i = 0, il = carbohydrates.terminalLinks.length; i < il; ++i) {
         const tl = carbohydrates.terminalLinks[i]
-        const center = carbohydrates.elements[tl.carbohydrateIndex].center
+        const center = carbohydrates.elements[tl.carbohydrateIndex].geometry!.center
         tl.elementUnit.conformation.position(tl.elementUnit.elements[tl.elementIndex], p)
         if (tl.fromCarbohydrate) {
             builder.addCylinder(center, p, 0.5, linkParams)

+ 18 - 11
src/mol-model/structure/structure/carbohydrates/compute.ts

@@ -90,22 +90,22 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
     const terminalLinks: CarbohydrateTerminalLink[] = []
     const elements: CarbohydrateElement[] = []
 
-    const elementsMap = new Map<string, number>()
+    const elementsWithRingMap = new Map<string, number>()
 
     function elementKey(residueIndex: number, unitId: number) {
         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)
+        Vec3.sub(elements[iA].geometry!.direction, elements[iB].geometry!.center, elements[iA].geometry!.center)
+        Vec3.normalize(elements[iA].geometry!.direction, elements[iA].geometry!.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)
+        const pos = unitB.conformation.position, geo = elements[iA].geometry!;
+        Vec3.sub(geo.direction, pos(unitB.elements[indexB], tmpV), geo.center)
+        Vec3.normalize(geo.direction, geo.direction)
     }
 
     // get carbohydrate elements and carbohydrate links induced by intra-residue bonds
@@ -140,7 +140,10 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
                 const sugarRings = sugarResidueMap.get(residueIndex);
 
                 if (!sugarRings || !sugarRings.length) {
-                    console.warn(`No ring found for carbohydrate on residue with index ${residueIndex}, unit ${unit.id}. Residue skipped.`);
+                    elements.push({
+                        hasRing: false,
+                        unit, residueIndex, component: saccharideComp
+                    })
                     continue;
                 }
 
@@ -158,8 +161,12 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
 
                     const elementIndex = elements.length
                     ringElements.push(elementIndex)
-                    elementsMap.set(elementKey(residueIndex, unit.id), elementIndex)
-                    elements.push({ center, normal, direction, unit, residueIndex, component: saccharideComp })
+                    elementsWithRingMap.set(elementKey(residueIndex, unit.id), elementIndex)
+                    elements.push({
+                        geometry: { center, normal, direction, },
+                        hasRing: true,
+                        unit, residueIndex, component: saccharideComp
+                    })
                 }
 
                 // add carbohydrate links induced by intra-residue bonds
@@ -195,8 +202,8 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
                 pairBonds.getBonds(indexA).forEach(bondInfo => {
                     const { unitA, unitB } = pairBonds
                     const indexB = bondInfo.indexB
-                    const elementIndexA = elementsMap.get(elementKey(getResidueIndex(indexA, unitA), unitA.id))
-                    const elementIndexB = elementsMap.get(elementKey(getResidueIndex(indexB, unitB), unitB.id))
+                    const elementIndexA = elementsWithRingMap.get(elementKey(getResidueIndex(indexA, unitA), unitA.id))
+                    const elementIndexB = elementsWithRingMap.get(elementKey(getResidueIndex(indexB, unitB), unitB.id))
 
                     if (elementIndexA !== undefined && elementIndexB !== undefined) {
                         if (getAtomId(unitA, indexA).startsWith('C1')) {

+ 5 - 5
src/mol-model/structure/structure/carbohydrates/data.ts

@@ -23,11 +23,11 @@ export interface CarbohydrateTerminalLink {
 }
 
 export interface CarbohydrateElement {
-    readonly center: Vec3,
-    readonly normal: Vec3,
-    readonly direction: Vec3,
-    readonly unit: Unit.Atomic
-    readonly residueIndex: ResidueIndex
+    // geometry is only defined if at least one ring is present.
+    readonly geometry?: { readonly center: Vec3, readonly normal: Vec3, readonly direction: Vec3 },
+    readonly hasRing: boolean,
+    readonly unit: Unit.Atomic,
+    readonly residueIndex: ResidueIndex,
     readonly component: SaccharideComponent
 }