Browse Source

wip, carbohydrate visual refactoring

Alexander Rose 6 years ago
parent
commit
2c60df1a70

+ 59 - 44
src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts

@@ -15,14 +15,13 @@ import { MeshValues } from 'mol-gl/renderable';
 import { getMeshData } from '../../../util/mesh-data';
 import { Mesh } from '../../../shape/mesh';
 import { PickingId } from '../../../util/picking';
-import { createMarkers, MarkerAction, MarkerData } from '../../../util/marker-data';
-import { Loci, EmptyLoci } from 'mol-model/loci';
+import { createMarkers, MarkerAction, MarkerData, applyMarkerAction } from '../../../util/marker-data';
+import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci';
 import { SizeTheme } from '../../../theme';
 import { createMeshValues, updateMeshValues, updateRenderableState, createRenderableState, DefaultMeshProps } from '../../util';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { deepEqual } from 'mol-util';
 import { LocationIterator } from './util/location-iterator';
-import { createValueColor } from '../../../util/color-data';
 import { createLinkCylinderMesh, DefaultLinkCylinderProps, LinkCylinderProps } from './util/link';
 import { OrderedSet } from 'mol-data/int';
 
@@ -86,7 +85,7 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps>
             // console.log(mesh)
 
             const transforms = createIdentityTransform()
-            const color = createValueColor(0x119911)//createColors(colorTheme)
+            const color = createColors(createCarbohydrateLinkIterator(structure), colorTheme)
             const marker = createMarkers(instanceCount * elementCount)
 
             const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount }
@@ -97,8 +96,7 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps>
                 ...marker,
                 aTransform: transforms,
                 elements: mesh.indexBuffer,
-                ...createMeshValues(currentProps, counts),
-                aColor: ValueCell.create(new Float32Array(mesh.vertexCount * 3))
+                ...createMeshValues(currentProps, counts)
             }
             const state = createRenderableState(currentProps)
 
@@ -111,13 +109,13 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps>
 
             let updateColor = false
 
-            // if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) {
-            //     updateColor = true
-            // }
+            if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) {
+                updateColor = true
+            }
 
-            // if (updateColor) {
-            //     createColors(LinkIterator.fromGroup(currentGroup), newProps.colorTheme, renderObject.values)
-            // }
+            if (updateColor) {
+                createColors(createCarbohydrateLinkIterator(currentStructure), newProps.colorTheme, renderObject.values)
+            }
 
             updateMeshValues(renderObject.values, newProps)
             updateRenderableState(renderObject.state, newProps)
@@ -129,8 +127,7 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps>
             return getLinkLoci(pickingId, currentStructure, renderObject.id)
         },
         mark(loci: Loci, action: MarkerAction) {
-            // TODO
-            // markLink(loci, action, currentStructure, renderObject.values)
+            markLink(loci, action, currentStructure, renderObject.values)
         },
         destroy() {
             // TODO
@@ -138,6 +135,26 @@ export function CarbohydrateLinkVisual(): StructureVisual<CarbohydrateLinkProps>
     }
 }
 
+function createCarbohydrateLinkIterator(structure: Structure): LocationIterator {
+    const { elements, links } = structure.carbohydrates
+    const elementCount = links.length
+    const instanceCount = 1
+    const location = Link.Location()
+    const getLocation = (elementIndex: number, instanceIndex: number) => {
+        const link = links[elementIndex]
+        const carbA = elements[link.carbohydrateIndexA]
+        const carbB = elements[link.carbohydrateIndexB]
+        const indexA = OrderedSet.findPredecessorIndex(carbA.unit.elements, carbA.anomericCarbon)
+        const indexB = OrderedSet.findPredecessorIndex(carbB.unit.elements, carbB.anomericCarbon)
+        location.aUnit = carbA.unit
+        location.aIndex = indexA as StructureElement.UnitIndex
+        location.bUnit = carbB.unit
+        location.bIndex = indexB as StructureElement.UnitIndex
+        return location
+    }
+    return LocationIterator(elementCount, instanceCount, getLocation)
+}
+
 function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
     const { objectId, elementId } = pickingId
     if (id === objectId) {
@@ -157,33 +174,31 @@ function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
     return EmptyLoci
 }
 
-// TODO
-// function markLink(loci: Loci, action: MarkerAction, structure: Structure, values: MarkerData) {
-//     const tMarker = values.tMarker
-
-//     const links = structure.links
-//     const elementCount = links.bondCount
-//     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 _idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit)
-//             if (_idx !== -1) {
-//                 const idx = _idx
-//                 if (applyMarkerAction(array, idx, idx + 1, action) && !changed) {
-//                     changed = true
-//                 }
-//             }
-//         }
-//     } else {
-//         return
-//     }
-//     if (changed) {
-//         ValueCell.update(tMarker, tMarker.ref.value)
-//     }
-// }
+function markLink(loci: Loci, action: MarkerAction, structure: Structure, values: MarkerData) {
+    const tMarker = values.tMarker
+
+    const { getLinkIndex } = structure.carbohydrates
+    const elementCount = structure.carbohydrates.elements.length
+
+    let changed = false
+    const array = tMarker.ref.value.array
+    if (isEveryLoci(loci)) {
+        if (applyMarkerAction(array, 0, elementCount, action)) {
+            changed = true
+        }
+    } else if (Link.isLoci(loci)) {
+        for (const l of loci.links) {
+            const idx = getLinkIndex(l.aUnit, l.aUnit.elements[l.aIndex], l.bUnit, l.bUnit.elements[l.bIndex])
+            if (idx !== undefined) {
+                if (applyMarkerAction(array, idx, idx + 1, action) && !changed) {
+                    changed = true
+                }
+            }
+        }
+    } else {
+        return
+    }
+    if (changed) {
+        ValueCell.update(tMarker, tMarker.ref.value)
+    }
+}

+ 9 - 10
src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts

@@ -141,7 +141,7 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr
             mesh = await createCarbohydrateSymbolMesh(ctx, currentStructure, mesh)
 
             const transforms = createIdentityTransform()
-            const color = createColors(createCarbohydrateIterator(structure), colorTheme)
+            const color = createColors(createCarbohydrateElementIterator(structure), colorTheme)
             const marker = createMarkers(instanceCount * elementCount)
 
             const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount }
@@ -152,8 +152,7 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr
                 ...marker,
                 aTransform: transforms,
                 elements: mesh.indexBuffer,
-                ...createMeshValues(currentProps, counts),
-                aColor: ValueCell.create(new Float32Array(mesh.vertexCount * 3))
+                ...createMeshValues(currentProps, counts)
             }
             const state = createRenderableState(currentProps)
 
@@ -171,7 +170,7 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr
             }
 
             if (updateColor) {
-                createColors(createCarbohydrateIterator(currentStructure), newProps.colorTheme, renderObject.values)
+                createColors(createCarbohydrateElementIterator(currentStructure), newProps.colorTheme, renderObject.values)
             }
 
             updateMeshValues(renderObject.values, newProps)
@@ -192,13 +191,13 @@ export function CarbohydrateSymbolVisual(): StructureVisual<CarbohydrateSymbolPr
     }
 }
 
-function createCarbohydrateIterator(structure: Structure): LocationIterator {
-    const carbs = structure.carbohydrates.elements
-    const elementCount = carbs.length
+function createCarbohydrateElementIterator(structure: Structure): LocationIterator {
+    const carbElements = structure.carbohydrates.elements
+    const elementCount = carbElements.length
     const instanceCount = 1
     const location = StructureElement.create()
     const getLocation = (elementIndex: number, instanceIndex: number) => {
-        const carb = carbs[elementIndex]
+        const carb = carbElements[elementIndex]
         location.unit = carb.unit
         location.element = carb.anomericCarbon
         return location
@@ -221,7 +220,7 @@ function getCarbohydrateLoci(pickingId: PickingId, structure: Structure, id: num
 function markCarbohydrate(loci: Loci, action: MarkerAction, structure: Structure, values: MarkerData) {
     const tMarker = values.tMarker
 
-    const { byUnitAndElement } = structure.carbohydrates
+    const { getElementIndex } = structure.carbohydrates
     const elementCount = structure.carbohydrates.elements.length
 
     let changed = false
@@ -233,7 +232,7 @@ function markCarbohydrate(loci: Loci, action: MarkerAction, structure: Structure
     } else if (StructureElement.isLoci(loci)) {
         for (const e of loci.elements) {
             OrderedSet.forEach(e.indices, index => {
-                const idx = byUnitAndElement(e.unit, e.unit.elements[index])
+                const idx = getElementIndex(e.unit, e.unit.elements[index])
                 if (idx !== undefined) {
                     if (applyMarkerAction(array, idx, idx + 1, action) && !changed) {
                         changed = true

+ 3 - 3
src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts

@@ -144,13 +144,13 @@ function markLink(loci: Loci, action: MarkerAction, structure: Structure, values
 
     const links = structure.links
     const elementCount = links.bondCount
-    const instanceCount = 1
 
     let changed = false
     const array = tMarker.ref.value.array
     if (isEveryLoci(loci)) {
-        applyMarkerAction(array, 0, elementCount * instanceCount, action)
-        changed = true
+        if (applyMarkerAction(array, 0, elementCount, action)) {
+            changed = true
+        }
     } else if (Link.isLoci(loci)) {
         for (const b of loci.links) {
             const _idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit)

+ 46 - 23
src/mol-model/structure/structure/carbohydrates/compute.ts

@@ -126,7 +126,7 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
 
     const elementsWithRingMap = new Map<string, number>()
 
-    function elementKey(residueIndex: number, unitId: number, altId: string) {
+    function ringElementKey(residueIndex: number, unitId: number, altId: string) {
         return `${residueIndex}|${unitId}|${altId}`
     }
 
@@ -194,7 +194,7 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
                     const altId = getRingAltId(unit, ringAtoms)
                     const elementIndex = elements.length
                     ringElements.push(elementIndex)
-                    elementsWithRingMap.set(elementKey(residueIndex, unit.id, altId), elementIndex)
+                    elementsWithRingMap.set(ringElementKey(residueIndex, unit.id, altId), elementIndex)
                     elements.push({
                         geometry: { center, normal, direction },
                         component: saccharideComp,
@@ -227,8 +227,8 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
         }
     }
 
-    function getElementIndex(unit: Unit.Atomic, index: StructureElement.UnitIndex) {
-        return elementsWithRingMap.get(elementKey(unit.getResidueIndex(index), unit.id, getAltId(unit, index)))
+    function getRingElementIndex(unit: Unit.Atomic, index: StructureElement.UnitIndex) {
+        return elementsWithRingMap.get(ringElementKey(unit.getResidueIndex(index), unit.id, getAltId(unit, index)))
     }
 
     // get carbohydrate links induced by inter-unit bonds
@@ -241,32 +241,32 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
                 pairBonds.getBonds(indexA).forEach(bondInfo => {
                     const { unitA, unitB } = pairBonds
                     const indexB = bondInfo.indexB
-                    const elementIndexA = getElementIndex(unitA, indexA)
-                    const elementIndexB = getElementIndex(unitB, indexB)
+                    const ringElementIndexA = getRingElementIndex(unitA, indexA)
+                    const ringElementIndexB = getRingElementIndex(unitB, indexB)
 
-                    if (elementIndexA !== undefined && elementIndexB !== undefined) {
+                    if (ringElementIndexA !== undefined && ringElementIndexB !== undefined) {
                         const atomIdA = getAtomId(unitA, indexA)
                         if (atomIdA.startsWith('O1') || atomIdA.startsWith('C1')) {
-                            fixLinkDirection(elementIndexA, elementIndexB)
+                            fixLinkDirection(ringElementIndexA, ringElementIndexB)
                         }
                         links.push({
-                            carbohydrateIndexA: elementIndexA,
-                            carbohydrateIndexB: elementIndexB
+                            carbohydrateIndexA: ringElementIndexA,
+                            carbohydrateIndexB: ringElementIndexB
                         })
-                    } else if (elementIndexA !== undefined) {
+                    } else if (ringElementIndexA !== undefined) {
                         const atomIdA = getAtomId(unitA, indexA)
                         if (atomIdA.startsWith('O1') || atomIdA.startsWith('C1')) {
-                            fixTerminalLinkDirection(elementIndexA, indexB, unitB)
+                            fixTerminalLinkDirection(ringElementIndexA, indexB, unitB)
                         }
                         terminalLinks.push({
-                            carbohydrateIndex: elementIndexA,
+                            carbohydrateIndex: ringElementIndexA,
                             elementIndex: indexB,
                             elementUnit: unitB,
                             fromCarbohydrate: true
                         })
-                    } else if (elementIndexB !== undefined) {
+                    } else if (ringElementIndexB !== undefined) {
                         terminalLinks.push({
-                            carbohydrateIndex: elementIndexB,
+                            carbohydrateIndex: ringElementIndexB,
                             elementIndex: indexA,
                             elementUnit: unitA,
                             fromCarbohydrate: false
@@ -277,20 +277,43 @@ export function computeCarbohydrates(structure: Structure): Carbohydrates {
         })
     }
 
-    // build lookup map
-    const map = new Map<string, number>()
+    return { links, terminalLinks, elements, partialElements, ...buildLookups(elements, links) }
+}
+
+function buildLookups (elements: CarbohydrateElement[], links: CarbohydrateLink[]) {
+    // element lookup
+
+    function elementKey(unit: Unit, anomericCarbon: ElementIndex) {
+        return `${unit.id}|${anomericCarbon}`
+    }
+
+    const elementMap = new Map<string, number>()
     for (let i = 0, il = elements.length; i < il; ++i) {
         const { unit, anomericCarbon } = elements[i]
-        map.set(key(unit, anomericCarbon), i)
+        elementMap.set(elementKey(unit, anomericCarbon), i)
     }
 
-    function key(unit: Unit, anomericCarbon: ElementIndex) {
-        return `${unit.id}|${anomericCarbon}`
+    function getElementIndex(unit: Unit, anomericCarbon: ElementIndex) {
+        return elementMap.get(elementKey(unit, anomericCarbon))
+    }
+
+    // link lookup
+
+    function linkKey(unitA: Unit, anomericCarbonA: ElementIndex, unitB: Unit, anomericCarbonB: ElementIndex) {
+        return `${unitA.id}|${anomericCarbonA}|${unitB.id}|${anomericCarbonB}`
+    }
+
+    const linkMap = new Map<string, number>()
+    for (let i = 0, il = links.length; i < il; ++i) {
+        const l = links[i]
+        const { unit: unitA, anomericCarbon: anomericCarbonA } = elements[l.carbohydrateIndexA]
+        const { unit: unitB, anomericCarbon: anomericCarbonB } = elements[l.carbohydrateIndexB]
+        linkMap.set(linkKey(unitA, anomericCarbonA, unitB, anomericCarbonB), i)
     }
 
-    function byUnitAndElement(unit: Unit, anomericCarbon: ElementIndex) {
-        return map.get(key(unit, anomericCarbon))
+    function getLinkIndex(unitA: Unit, anomericCarbonA: ElementIndex, unitB: Unit, anomericCarbonB: ElementIndex) {
+        return linkMap.get(linkKey(unitA, anomericCarbonA, unitB, anomericCarbonB))
     }
 
-    return { links, terminalLinks, elements, partialElements, byUnitAndElement }
+    return { getElementIndex, getLinkIndex }
 }

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

@@ -42,5 +42,6 @@ export interface Carbohydrates {
     terminalLinks: ReadonlyArray<CarbohydrateTerminalLink>
     elements: ReadonlyArray<CarbohydrateElement>
     partialElements: ReadonlyArray<PartialCarbohydrateElement>
-    byUnitAndElement: (unit: Unit, element: ElementIndex) => number | undefined
+    getElementIndex: (unit: Unit, anomericCarbon: ElementIndex) => number | undefined
+    getLinkIndex: (unitA: Unit, anomericCarbonA: ElementIndex, unitB: Unit, anomericCarbonB: ElementIndex) => number | undefined
 }