Browse Source

wip, carb mark/getLoci

Alexander Rose 6 years ago
parent
commit
6d0c2f8366

+ 4 - 0
src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts

@@ -105,6 +105,10 @@ function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
                 Link.Location(
                     carbA.unit, indexA as StructureElement.UnitIndex,
                     carbB.unit, indexB as StructureElement.UnitIndex
+                ),
+                Link.Location(
+                    carbB.unit, indexB as StructureElement.UnitIndex,
+                    carbA.unit, indexA as StructureElement.UnitIndex
                 )
             ])
         }

+ 19 - 12
src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts

@@ -25,6 +25,7 @@ import { OrderedSet, Interval } from 'mol-data/int';
 import { EmptyLoci, Loci } from 'mol-model/loci';
 import { VisualContext } from 'mol-repr/representation';
 import { Theme } from 'mol-theme/theme';
+import { getResidueLoci } from './util/common';
 
 const t = Mat4.identity()
 const sVec = Vec3.zero()
@@ -184,30 +185,36 @@ function CarbohydrateElementIterator(structure: Structure): LocationIterator {
     return LocationIterator(groupCount, instanceCount, getLocation, true, isSecondary)
 }
 
+/** Return a Loci for the elements of the whole residue of a carbohydrate. */
 function getCarbohydrateLoci(pickingId: PickingId, structure: Structure, id: number) {
     const { objectId, groupId } = pickingId
     if (id === objectId) {
         const carb = structure.carbohydrates.elements[Math.floor(groupId / 2)]
-        const { unit } = carb
-        const index = OrderedSet.indexOf(unit.elements, carb.anomericCarbon)
-        if (index !== -1) {
-            const indices = OrderedSet.ofSingleton(index as StructureElement.UnitIndex)
-            return StructureElement.Loci(structure, [{ unit, indices }])
-        }
+        return getResidueLoci(structure, carb.unit, carb.anomericCarbon)
     }
     return EmptyLoci
 }
 
+/** Mark a carbohydrate (usually a monosaccharide) when all its residue's elements are in a loci. */
 function markCarbohydrate(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) {
-    const { getElementIndex } = structure.carbohydrates
-
+    const { getElementIndex, getAnomericCarbon } = structure.carbohydrates
     let changed = false
     if (StructureElement.isLoci(loci)) {
         for (const e of loci.elements) {
-            OrderedSet.forEach(e.indices, index => {
-                const idx = getElementIndex(e.unit, e.unit.elements[index])
-                if (idx !== undefined) {
-                    if (apply(Interval.ofBounds(idx * 2, idx * 2 + 2))) changed = true
+            OrderedSet.forEach(e.indices, v => {
+                const { model, elements } = e.unit
+                const { index, offsets } = model.atomicHierarchy.residueAtomSegments        
+                const rI = index[elements[v]]
+                const unitIndexMin = OrderedSet.findPredecessorIndex(elements, offsets[rI])
+                const unitIndexMax = OrderedSet.findPredecessorIndex(elements, offsets[rI + 1] - 1)
+                const unitIndexInterval = Interval.ofRange(unitIndexMin, unitIndexMax)
+                if(!OrderedSet.isSubset(e.indices, unitIndexInterval)) return
+                const eI = getAnomericCarbon(e.unit, rI)
+                if (eI !== undefined) {
+                    const idx = getElementIndex(e.unit, eI)
+                    if (idx !== undefined) {
+                        if (apply(Interval.ofBounds(idx * 2, idx * 2 + 2))) changed = true
+                    }
                 }
             })
         }

+ 11 - 15
src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts

@@ -114,25 +114,21 @@ function getTerminalLinkLoci(pickingId: PickingId, structure: Structure, id: num
         const carb = elements[l.carbohydrateIndex]
         const carbIndex = OrderedSet.indexOf(carb.unit.elements, carb.anomericCarbon)
 
-        if (l.fromCarbohydrate) {
-            return Link.Loci(structure, [
-                Link.Location(
-                    carb.unit, carbIndex as StructureElement.UnitIndex,
-                    l.elementUnit, l.elementIndex
-                )
-            ])
-        } else {
-            return Link.Loci(structure, [
-                Link.Location(
-                    l.elementUnit, l.elementIndex,
-                    carb.unit, carbIndex as StructureElement.UnitIndex
-                )
-            ])
-        }
+        return Link.Loci(structure, [
+            Link.Location(
+                carb.unit, carbIndex as StructureElement.UnitIndex,
+                l.elementUnit, l.elementIndex
+            ),
+            Link.Location(
+                l.elementUnit, l.elementIndex,
+                carb.unit, carbIndex as StructureElement.UnitIndex
+            )
+        ])    
     }
     return EmptyLoci
 }
 
+// TODO mark link when both (or one) of the link elements are in a StructureElement.Loci
 function markTerminalLink(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) {
     const { getTerminalLinkIndex } = structure.carbohydrates
 

+ 22 - 1
src/mol-repr/structure/visual/util/common.ts

@@ -4,7 +4,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { Unit, Structure } from 'mol-model/structure';
+import { Unit, Structure, ElementIndex, StructureElement } from 'mol-model/structure';
 import { createMeshRenderObject, createPointsRenderObject, createLinesRenderObject, createDirectVolumeRenderObject } from 'mol-gl/render-object';
 import { Mat4 } from 'mol-math/linear-algebra';
 import { TransformData, createTransform, createIdentityTransform } from 'mol-geo/geometry/transform-data';
@@ -18,6 +18,27 @@ import { VisualContext } from 'mol-repr/representation';
 import { Theme } from 'mol-theme/theme';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { StructureMeshParams, StructurePointsParams, StructureLinesParams, StructureDirectVolumeParams } from 'mol-repr/structure/representation';
+import { OrderedSet, SortedArray } from 'mol-data/int';
+import { EmptyLoci, Loci } from 'mol-model/loci';
+
+/** Return a Loci for the elements of a whole residue the elementIndex belongs to. */
+export function getResidueLoci(structure: Structure, unit: Unit, elementIndex: ElementIndex): Loci {
+    const { elements, model } = unit
+    if (OrderedSet.indexOf(elements, elementIndex) !== -1) {
+        const { index, offsets } = model.atomicHierarchy.residueAtomSegments
+        const rI = index[elementIndex]
+        const _indices: number[] = []
+        for (let i = offsets[rI], il = offsets[rI + 1]; i < il; ++i) {
+            const unitIndex = OrderedSet.indexOf(elements, i)
+            if (unitIndex !== -1) _indices.push(unitIndex)
+        }
+        const indices = OrderedSet.ofSortedArray<StructureElement.UnitIndex>(SortedArray.ofSortedArray(_indices))
+        return StructureElement.Loci(structure, [{ unit, indices }])
+    }
+    return EmptyLoci
+}
+
+//
 
 export function createUnitsTransform({ units }: Unit.SymmetryGroup, transformData?: TransformData) {
     const unitCount = units.length

+ 13 - 18
src/mol-repr/structure/visual/util/polymer.ts

@@ -6,12 +6,13 @@
 
 import { Unit, ElementIndex, StructureElement, Link } from 'mol-model/structure';
 import SortedRanges from 'mol-data/int/sorted-ranges';
-import { OrderedSet, Interval, SortedArray } from 'mol-data/int';
+import { OrderedSet, Interval } from 'mol-data/int';
 import { EmptyLoci, Loci } from 'mol-model/loci';
 import { LocationIterator } from 'mol-geo/util/location-iterator';
 import { PickingId } from 'mol-geo/geometry/picking';
 import { StructureGroup } from 'mol-repr/structure/units-visual';
 import { getElementIndexForAtomRole } from 'mol-model/structure/util';
+import { getResidueLoci } from './common';
 
 export * from './polymer/backbone-iterator'
 export * from './polymer/gap-iterator'
@@ -66,28 +67,18 @@ export namespace PolymerGapLocationIterator {
     }
 }
 
-/** Return a Loci for the elements of a whole residue. */
+/** Return a Loci for the elements of the whole residue of a polymer element. */
 export function getPolymerElementLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number) {
     const { objectId, instanceId, groupId } = pickingId
     if (id === objectId) {
         const { structure, group } = structureGroup
         const unit = group.units[instanceId]
-        const { elements, polymerElements, model } = unit
-        if (OrderedSet.indexOf(elements, polymerElements[groupId]) !== -1) {
-            const { index, offsets } = model.atomicHierarchy.residueAtomSegments
-            const rI = index[polymerElements[groupId]]
-            const _indices: number[] = []
-            for (let i = offsets[rI], il = offsets[rI + 1]; i < il; ++i) {
-                const unitIndex = OrderedSet.indexOf(elements, i)
-                if (unitIndex !== -1) _indices.push(unitIndex)
-            }
-            const indices = OrderedSet.ofSortedArray<StructureElement.UnitIndex>(SortedArray.ofSortedArray(_indices))
-            return StructureElement.Loci(structure, [{ unit, indices }])
-        }
+        return getResidueLoci(structure, unit, unit.polymerElements[groupId])
     }
     return EmptyLoci
 }
 
+/** Mark a polymer element (e.g. part of a cartoon trace) when all its residue's elements are in a loci. */
 export function markPolymerElement(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {
     let changed = false
     if (!StructureElement.isLoci(loci)) return false
@@ -102,9 +93,9 @@ export function markPolymerElement(loci: Loci, structureGroup: StructureGroup, a
             // TODO optimized implementation for intervals
             OrderedSet.forEach(e.indices, v => {
                 const rI = index[elements[v]]
-                const unitIndexBeg = OrderedSet.indexOf(elements, offsets[rI])
-                const unitIndexEnd = OrderedSet.indexOf(elements, offsets[rI + 1])
-                const unitIndexInterval = Interval.ofBounds(unitIndexBeg, unitIndexEnd)
+                const unitIndexMin = OrderedSet.findPredecessorIndex(elements, offsets[rI])
+                const unitIndexMax = OrderedSet.findPredecessorIndex(elements, offsets[rI + 1] - 1)
+                const unitIndexInterval = Interval.ofRange(unitIndexMin, unitIndexMax)
                 if(!OrderedSet.isSubset(e.indices, unitIndexInterval)) return
                 const eI = getElementIndexForAtomRole(model, rI, 'trace')
                 const idx = OrderedSet.indexOf(e.unit.polymerElements, eI)
@@ -117,6 +108,7 @@ export function markPolymerElement(loci: Loci, structureGroup: StructureGroup, a
     return changed
 }
 
+/** Return a Loci for both directions of the polymer gap element. */
 export function getPolymerGapElementLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number) {
     const { objectId, instanceId, groupId } = pickingId
     if (id === objectId) {
@@ -125,7 +117,10 @@ export function getPolymerGapElementLoci(pickingId: PickingId, structureGroup: S
         const unitIndexA = OrderedSet.indexOf(unit.elements, unit.gapElements[groupId]) as StructureElement.UnitIndex
         const unitIndexB = OrderedSet.indexOf(unit.elements, unit.gapElements[groupId % 2 ? groupId - 1 : groupId + 1]) as StructureElement.UnitIndex
         if (unitIndexA !== -1 && unitIndexB !== -1) {
-            return Link.Loci(structure, [ Link.Location(unit, unitIndexA, unit, unitIndexB) ])
+            return Link.Loci(structure, [
+                Link.Location(unit, unitIndexA, unit, unitIndexB),
+                Link.Location(unit, unitIndexB, unit, unitIndexA)
+            ])
         }
     }
     return EmptyLoci