Преглед изворни кода

fix marking of InteractionsInterUnitVisual

Alexander Rose пре 3 година
родитељ
комит
6810793015

+ 1 - 0
CHANGELOG.md

@@ -9,6 +9,7 @@ Note that since we don't clearly distinguish between a public and private interf
 - Fix marking pass not working with ``transparentBackground``
 - Fix pdbe xray maps url not https
 - Fix entity-id color theme broken for non-IHM models
+- Improve/fix marking of ``InteractionsInterUnitVisual`` (mark when all contact-feature members are given)
 
 ## [v3.0.0] - 2022-01-23
 

+ 15 - 24
src/mol-model-props/computed/interactions/common.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -98,29 +98,20 @@ class InteractionsInterContacts extends InterUnitGraph<number, Features.FeatureI
     constructor(map: Map<number, InterUnitGraph.UnitPairEdges<number, Features.FeatureIndex, InteractionsInterContacts.Props>[]>, unitsFeatures: IntMap<Features>) {
         super(map);
 
-        let count = 0;
-        const elementKeyIndex = new Map<string, number[]>();
-
-        const add = (index: StructureElement.UnitIndex, unitId: number) => {
-            const vertexKey = this.getElementKey(index, unitId);
-            const e = elementKeyIndex.get(vertexKey);
-            if (e === undefined) elementKeyIndex.set(vertexKey, [count]);
-            else e.push(count);
-        };
-
-        this.map.forEach(pairEdgesArray => {
-            pairEdgesArray.forEach(({ unitA, connectedIndices }) => {
-                connectedIndices.forEach(indexA => {
-                    const { offsets: offsetsA, members: membersA } = unitsFeatures.get(unitA);
-                    for (let j = offsetsA[indexA], jl = offsetsA[indexA + 1]; j < jl; ++j) {
-                        add(membersA[j], unitA);
-                    }
-                    count += 1;
-                });
-            });
-        });
-
-        this.elementKeyIndex = elementKeyIndex;
+        this.elementKeyIndex = new Map<string, number[]>();
+        for (let i = 0, il = this.edges.length; i < il; ++i) {
+            const { unitA, indexA } = this.edges[i];
+            const { offsets, members } = unitsFeatures.get(unitA);
+            for (let j = offsets[indexA], jl = offsets[indexA + 1]; j < jl; ++j) {
+                const vertexKey = this.getElementKey(members[j], unitA);
+                const e = this.elementKeyIndex.get(vertexKey);
+                if (e === undefined) {
+                    this.elementKeyIndex.set(vertexKey, [i]);
+                } else {
+                    e.push(i);
+                }
+            }
+        }
     }
 }
 namespace InteractionsInterContacts {

+ 41 - 10
src/mol-model-props/computed/representations/interactions-inter-unit-cylinder.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -74,10 +74,11 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S
                 if (!childUnitA) return true;
 
                 const unitA = structure.unitMap.get(b.unitA);
-                const fA = unitsFeatures.get(b.unitA);
-                // TODO: check all members
-                const eA = unitA.elements[fA.members[fA.offsets[b.indexA]]];
-                if (!SortedArray.has(childUnitA.elements, eA)) return true;
+                const { offsets, members } = unitsFeatures.get(b.unitA);
+                for (let i = offsets[b.indexA], il = offsets[b.indexA + 1]; i < il; ++i) {
+                    const eA = unitA.elements[members[i]];
+                    if (!SortedArray.has(childUnitA.elements, eA)) return true;
+                }
             }
 
             return false;
@@ -144,6 +145,9 @@ function getInteractionLoci(pickingId: PickingId, structure: Structure, id: numb
     return EmptyLoci;
 }
 
+const __unitMap = new Map<number, OrderedSet<StructureElement.UnitIndex>>();
+const __contactIndicesSet = new Set<number>();
+
 function eachInteraction(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean, isMarking: boolean) {
     let changed = false;
     if (Interactions.isLoci(loci)) {
@@ -162,21 +166,48 @@ function eachInteraction(loci: Loci, structure: Structure, apply: (interval: Int
         if (!Structure.areEquivalent(loci.structure, structure)) return false;
         if (isMarking && loci.elements.length === 1) return false; // only a single unit
 
-        const contacts = InteractionsProvider.get(structure).value?.contacts;
-        if (!contacts) return false;
+        const interactions = InteractionsProvider.get(structure).value;
+        if (!interactions) return false;
+
+        const { contacts, unitsFeatures } = interactions;
+
+        for (const e of loci.elements) __unitMap.set(e.unit.id, e.indices);
 
-        // TODO when isMarking, all elements of contact features need to be in the loci
         for (const e of loci.elements) {
             const { unit } = e;
             if (!Unit.isAtomic(unit)) continue;
-            if (isMarking && OrderedSet.size(e.indices) === 1) continue;
 
             OrderedSet.forEach(e.indices, v => {
                 for (const idx of contacts.getContactIndicesForElement(v, unit)) {
-                    if (apply(Interval.ofSingleton(idx))) changed = true;
+                    __contactIndicesSet.add(idx);
                 }
             });
         }
+
+        __contactIndicesSet.forEach(i => {
+            if (isMarking) {
+                const { indexA, unitA, indexB, unitB } = contacts.edges[i];
+
+                const indicesA = __unitMap.get(unitA);
+                const indicesB = __unitMap.get(unitB);
+                if (!indicesA || !indicesB) return;
+
+                const { offsets: offsetsA, members: membersA } = unitsFeatures.get(unitA);
+                for (let j = offsetsA[indexA], jl = offsetsA[indexA + 1]; j < jl; ++j) {
+                    if (!OrderedSet.has(indicesA, membersA[j])) return;
+                }
+
+                const { offsets: offsetsB, members: membersB } = unitsFeatures.get(unitB);
+                for (let j = offsetsB[indexB], jl = offsetsB[indexB + 1]; j < jl; ++j) {
+                    if (!OrderedSet.has(indicesB, membersB[j])) return;
+                }
+            }
+
+            if (apply(Interval.ofSingleton(i))) changed = true;
+        });
+
+        __unitMap.clear();
+        __contactIndicesSet.clear();
     }
     return changed;
 }

+ 15 - 6
src/mol-model-props/computed/representations/interactions-intra-unit-cylinder.ts

@@ -56,11 +56,19 @@ async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit:
             const sizeB = theme.size.size(location);
             return Math.min(sizeA, sizeB) * sizeFactor;
         },
-        ignore: (edgeIndex: number) => (
-            flag[edgeIndex] === InteractionFlag.Filtered ||
-            // TODO: check all members
-            (!!childUnit && !SortedArray.has(childUnit.elements, unit.elements[members[offsets[a[edgeIndex]]]]))
-        )
+        ignore: (edgeIndex: number) => {
+            if (flag[edgeIndex] === InteractionFlag.Filtered) return true;
+
+            if (childUnit) {
+                const f = a[edgeIndex];
+                for (let i = offsets[f], jl = offsets[f + 1]; i < jl; ++i) {
+                    const e = unit.elements[members[offsets[i]]];
+                    if (!SortedArray.has(childUnit.elements, e)) return true;
+                }
+            }
+
+            return false;
+        }
     };
 
     const m = createLinkCylinderMesh(ctx, builderProps, props, mesh);
@@ -164,7 +172,6 @@ function eachInteraction(loci: Loci, structureGroup: StructureGroup, apply: (int
             const unitIdx = group.unitIndexMap.get(e.unit.id);
             if (unitIdx === undefined) continue;
 
-            __contactIndicesSet.clear();
             OrderedSet.forEach(e.indices, v => {
                 for (let i = fOffsets[v], il = fOffsets[v + 1]; i < il; ++i) {
                     const fI = fIndices[i];
@@ -188,6 +195,8 @@ function eachInteraction(loci: Loci, structureGroup: StructureGroup, apply: (int
 
                 if (apply(Interval.ofSingleton(unitIdx * groupCount + i))) changed = true;
             });
+
+            __contactIndicesSet.clear();
         }
     }
     return changed;

+ 7 - 4
src/mol-repr/structure/visual/util/bond.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -224,6 +224,8 @@ export function getInterBondLoci(pickingId: PickingId, structure: Structure, id:
     return EmptyLoci;
 }
 
+const __unitMap = new Map<number, OrderedSet<StructureElement.UnitIndex>>();
+
 export function eachInterBond(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean, isMarking: boolean) {
     let changed = false;
     if (Bond.isLoci(loci)) {
@@ -238,14 +240,13 @@ export function eachInterBond(loci: Loci, structure: Structure, apply: (interval
         if (!Structure.areEquivalent(loci.structure, structure)) return false;
         if (isMarking && loci.elements.length === 1) return false; // only a single unit
 
-        const map = new Map<number, OrderedSet<StructureElement.UnitIndex>>();
-        for (const e of loci.elements) map.set(e.unit.id, e.indices);
+        for (const e of loci.elements) __unitMap.set(e.unit.id, e.indices);
 
         for (const e of loci.elements) {
             const { unit } = e;
             if (!Unit.isAtomic(unit)) continue;
             structure.interUnitBonds.getConnectedUnits(unit.id).forEach(b => {
-                const otherLociIndices = map.get(b.unitB);
+                const otherLociIndices = __unitMap.get(b.unitB);
                 if (!isMarking || otherLociIndices) {
                     OrderedSet.forEach(e.indices, v => {
                         if (!b.connectedIndices.includes(v)) return;
@@ -259,6 +260,8 @@ export function eachInterBond(loci: Loci, structure: Structure, apply: (interval
                 }
             });
         }
+
+        __unitMap.clear();
     }
     return changed;
 }