Browse Source

wip, repr.mark and repr.getLoci

Alexander Rose 6 years ago
parent
commit
dcd4f9cc51

+ 24 - 8
src/mol-repr/structure/visual/inter-unit-link-cylinder.ts

@@ -11,7 +11,7 @@ import { createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util
 import { Vec3 } from 'mol-math/linear-algebra';
 import { Loci, EmptyLoci } from 'mol-model/loci';
 import { ComplexMeshVisual, ComplexMeshParams } from '../complex-visual';
-import { Interval } from 'mol-data/int';
+import { Interval, OrderedSet } from 'mol-data/int';
 import { BitFlags } from 'mol-util';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
@@ -22,7 +22,7 @@ import { Theme } from 'mol-theme/theme';
 async function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<InterUnitLinkParams>, mesh?: Mesh) {
     const links = structure.links
     const { bondCount, bonds } = links
-    const { sizeFactor } = props
+    const { sizeFactor, sizeAspectRatio } = props
 
     if (!bondCount) return Mesh.createEmpty(mesh)
 
@@ -43,7 +43,7 @@ async function createInterUnitLinkCylinderMesh(ctx: VisualContext, structure: St
             const b = bonds[edgeIndex]
             location.unit = b.unitA
             location.element = b.unitA.elements[b.indexA]
-            return theme.size.size(location) * sizeFactor
+            return theme.size.size(location) * sizeFactor * sizeAspectRatio
         }
     }
 
@@ -85,6 +85,10 @@ function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
             Link.Location(
                 bond.unitA, bond.indexA as StructureElement.UnitIndex,
                 bond.unitB, bond.indexB as StructureElement.UnitIndex
+            ),
+            Link.Location(
+                bond.unitB, bond.indexB as StructureElement.UnitIndex,
+                bond.unitA, bond.indexA as StructureElement.UnitIndex
             )
         ])
     }
@@ -93,11 +97,23 @@ function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) {
 
 function markLink(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) {
     let changed = false
-    if (!Link.isLoci(loci)) return false
-    for (const b of loci.links) {
-        const idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit)
-        if (idx !== -1) {
-            if (apply(Interval.ofSingleton(idx))) changed = true
+    if (Link.isLoci(loci)) {
+        if (loci.structure !== structure) return false
+        for (const b of loci.links) {
+            const idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit)
+            if (idx !== -1) {
+                if (apply(Interval.ofSingleton(idx))) changed = true
+            }
+        }
+    } else if (StructureElement.isLoci(loci)) {
+        if (loci.structure !== structure) return false
+        for (const e of loci.elements) {
+            OrderedSet.forEach(e.indices, v => {
+                const indices = structure.links.getBondIndices(v, e.unit)
+                for (let i = 0, il = indices.length; i < il; ++i) {
+                    if (apply(Interval.ofSingleton(indices[i]))) changed = true
+                }
+            })
         }
     }
     return changed

+ 35 - 13
src/mol-repr/structure/visual/intra-unit-link-cylinder.ts

@@ -12,7 +12,7 @@ import { createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util
 import { Vec3 } from 'mol-math/linear-algebra';
 import { Loci, EmptyLoci } from 'mol-model/loci';
 import { UnitsMeshVisual, UnitsMeshParams, StructureGroup } from '../units-visual';
-import { Interval } from 'mol-data/int';
+import { Interval, OrderedSet } from 'mol-data/int';
 import { BitFlags } from 'mol-util';
 import { ParamDefinition as PD } from 'mol-util/param-definition';
 import { Mesh } from 'mol-geo/geometry/mesh/mesh';
@@ -101,6 +101,10 @@ function getLinkLoci(pickingId: PickingId, structureGroup: StructureGroup, id: n
                 Link.Location(
                     unit, unit.links.a[groupId] as StructureElement.UnitIndex,
                     unit, unit.links.b[groupId] as StructureElement.UnitIndex
+                ),
+                Link.Location(
+                    unit, unit.links.b[groupId] as StructureElement.UnitIndex,
+                    unit, unit.links.a[groupId] as StructureElement.UnitIndex
                 )
             ])
         }
@@ -110,18 +114,36 @@ function getLinkLoci(pickingId: PickingId, structureGroup: StructureGroup, id: n
 
 function markLink(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {
     let changed = false
-    if (!Link.isLoci(loci)) return false
-    const { structure, group } = structureGroup
-    if (loci.structure !== structure) return false
-    const unit = group.units[0]
-    if (!Unit.isAtomic(unit)) return false
-    const groupCount = unit.links.edgeCount * 2
-    for (const b of loci.links) {
-        const unitIdx = group.unitIndexMap.get(b.aUnit.id)
-        if (unitIdx !== undefined) {
-            const idx = unit.links.getDirectedEdgeIndex(b.aIndex, b.bIndex)
-            if (idx !== -1) {
-                if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true
+    if (Link.isLoci(loci)) {
+        const { structure, group } = structureGroup
+        if (loci.structure !== structure) return false
+        const unit = group.units[0]
+        if (!Unit.isAtomic(unit)) return false
+        const groupCount = unit.links.edgeCount * 2
+        for (const b of loci.links) {
+            const unitIdx = group.unitIndexMap.get(b.aUnit.id)
+            if (unitIdx !== undefined) {
+                const idx = unit.links.getDirectedEdgeIndex(b.aIndex, b.bIndex)
+                if (idx !== -1) {
+                    if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true
+                }
+            }
+        }
+    } else if (StructureElement.isLoci(loci)) {
+        const { structure, group } = structureGroup
+        if (loci.structure !== structure) return false
+        const unit = group.units[0]
+        if (!Unit.isAtomic(unit)) return false
+        const groupCount = unit.links.edgeCount * 2
+        for (const e of loci.elements) {
+            const unitIdx = group.unitIndexMap.get(e.unit.id)
+            if (unitIdx !== undefined) {
+                const { offset } = unit.links
+                OrderedSet.forEach(e.indices, v => {
+                    for (let t = offset[v], _t = offset[v + 1]; t < _t; t++) {
+                        if (apply(Interval.ofSingleton(unitIdx * groupCount + t))) changed = true
+                    }
+                })
             }
         }
     }

+ 28 - 21
src/mol-repr/structure/visual/util/polymer.ts

@@ -6,11 +6,12 @@
 
 import { Unit, ElementIndex, StructureElement, Link } from 'mol-model/structure';
 import SortedRanges from 'mol-data/int/sorted-ranges';
-import { OrderedSet, Interval } from 'mol-data/int';
+import { OrderedSet, Interval, SortedArray } 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';
 
 export * from './polymer/backbone-iterator'
 export * from './polymer/gap-iterator'
@@ -65,17 +66,22 @@ export namespace PolymerGapLocationIterator {
     }
 }
 
+/** Return a Loci for the elements of a whole residue. */
 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]
-        if (unit === undefined) {
-            console.log(id, { objectId, instanceId, groupId }, group.units)
-        }
-        const unitIndex = OrderedSet.indexOf(unit.elements, unit.polymerElements[groupId]) as StructureElement.UnitIndex
-        if (unitIndex !== -1) {
-            const indices = OrderedSet.ofSingleton(unitIndex)
+        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 }])
         }
     }
@@ -87,24 +93,25 @@ export function markPolymerElement(loci: Loci, structureGroup: StructureGroup, a
     if (!StructureElement.isLoci(loci)) return false
     const { structure, group } = structureGroup
     if (loci.structure !== structure) return false
-    const groupCount = group.units[0].polymerElements.length
+    const { polymerElements, model, elements } = group.units[0]
+    const { index, offsets } = model.atomicHierarchy.residueAtomSegments
+    const groupCount = polymerElements.length
     for (const e of loci.elements) {
         const unitIdx = group.unitIndexMap.get(e.unit.id)
         if (unitIdx !== undefined) {
-            if (Interval.is(e.indices)) {
-                const min = OrderedSet.indexOf(e.unit.polymerElements, e.unit.elements[Interval.min(e.indices)])
-                const max = OrderedSet.indexOf(e.unit.polymerElements, e.unit.elements[Interval.max(e.indices)])
-                if (min !== -1 && max !== -1) {
-                    if (apply(Interval.ofRange(unitIdx * groupCount + min, unitIdx * groupCount + max))) changed = true
+            // 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)
+                if(!OrderedSet.isSubset(e.indices, unitIndexInterval)) return
+                const eI = getElementIndexForAtomRole(model, rI, 'trace')
+                const idx = OrderedSet.indexOf(e.unit.polymerElements, eI)
+                if (idx !== -1) {
+                    if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true
                 }
-            } else {
-                for (let i = 0, _i = e.indices.length; i < _i; i++) {
-                    const idx = OrderedSet.indexOf(e.unit.polymerElements, e.unit.elements[e.indices[i]])
-                    if (idx !== -1) {
-                        if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true
-                    }
-                }
-            }
+            })
         }
     }
     return changed