Kaynağa Gözat

added Structure.eachUnitPair

Alexander Rose 5 yıl önce
ebeveyn
işleme
20266a229b

+ 8 - 29
src/mol-model-props/computed/interactions/interactions.ts

@@ -11,7 +11,6 @@ import { ValenceModelProvider } from '../valence-model';
 import { InteractionsIntraContacts, InteractionsInterContacts, FeatureType } from './common';
 import { IntraContactsBuilder, InterContactsBuilder } from './contacts-builder';
 import { IntMap } from '../../../mol-data/int';
-import { Vec3 } from '../../../mol-math/linear-algebra';
 import { addUnitContacts, ContactTester, addStructureContacts, ContactProvider, ContactsParams, ContactsProps } from './contacts';
 import { HalogenDonorProvider, HalogenAcceptorProvider, HalogenBondsProvider } from './halogen-bonds';
 import { HydrogenDonorProvider, WeakHydrogenDonorProvider, HydrogenAcceptorProvider, HydrogenBondsProvider, WeakHydrogenBondsProvider } from './hydrogen-bonds';
@@ -20,7 +19,6 @@ import { HydrophobicAtomProvider, HydrophobicProvider } from './hydrophobic';
 import { SetUtils } from '../../../mol-util/set';
 import { MetalCoordinationProvider, MetalProvider, MetalBindingProvider } from './metal';
 import { refineInteractions } from './refine';
-import { Result } from '../../../mol-math/geometry';
 import { CustomProperty } from '../../common/custom-property';
 
 export { Interactions }
@@ -208,34 +206,15 @@ function findIntraUnitContacts(structure: Structure, unit: Unit, features: Featu
 function findInterUnitContacts(structure: Structure, unitsFeatures: IntMap<Features>, contactTesters: ReadonlyArray<ContactTester>, props: ContactsProps) {
     const builder = InterContactsBuilder.create()
 
-    const maxDistance = Math.max(...contactTesters.map(t => t.maxDistance))
-
-    const lookup = structure.lookup3d;
-    const imageCenter = Vec3.zero();
-    const closeUnits = Result.create()
-
-    for (const unitA of structure.units) {
-        if (!Unit.isAtomic(unitA)) continue;
-
+    Structure.eachUnitPair(structure, (unitA: Unit, unitB: Unit) => {
         const featuresA = unitsFeatures.get(unitA.id)
-
-        const bs = unitA.lookup3d.boundary.sphere;
-        Vec3.transformMat4(imageCenter, bs.center, unitA.conformation.operator.matrix);
-        Result.copy(closeUnits, lookup.findUnitIndices(imageCenter[0], imageCenter[1], imageCenter[2], bs.radius + maxDistance));
-
-        for (let i = 0; i < closeUnits.count; i++) {
-            const unitB = structure.units[closeUnits.indices[i]];
-            if (!Unit.isAtomic(unitB) || unitA.id >= unitB.id || !Structure.validUnitPair(structure, unitA, unitB)) continue;
-
-            const featuresB = unitsFeatures.get(unitB.id)
-
-            if (unitB.elements.length >= unitA.elements.length) {
-                addStructureContacts(structure, unitA, featuresA, unitB, featuresB, builder, contactTesters, props)
-            } else {
-                addStructureContacts(structure, unitB, featuresB, unitA, featuresA, builder, contactTesters, props)
-            }
-        }
-    }
+        const featuresB = unitsFeatures.get(unitB.id)
+        addStructureContacts(structure, unitA as Unit.Atomic, featuresA, unitB as Unit.Atomic, featuresB, builder, contactTesters, props)
+    }, {
+        maxRadius: Math.max(...contactTesters.map(t => t.maxDistance)),
+        validUnit: (unit: Unit) => Unit.isAtomic(unit),
+        validUnitPair: (unitA: Unit, unitB: Unit) => Structure.validUnitPair(structure, unitA, unitB)
+    })
 
     return builder.getContacts(unitsFeatures)
 }

+ 33 - 0
src/mol-model/structure/structure/structure.ts

@@ -965,6 +965,39 @@ namespace Structure {
             ? a.model === b.model || a.model === s.masterModel || b.model === s.masterModel
             : a.model === b.model
     }
+
+    export interface EachUnitPairProps {
+        maxRadius: number
+        validUnit: (unit: Unit) => boolean
+        validUnitPair: (unitA: Unit, unitB: Unit) => boolean
+    }
+
+    /**
+     * Iterate over all unit pairs of a structure and invokes callback for valid units
+     * and unit pairs if within a max distance.
+     */
+    export function eachUnitPair(structure: Structure, callback: (unitA: Unit, unitB: Unit) => void, props: EachUnitPairProps) {
+        const { maxRadius, validUnit, validUnitPair } = props
+        if (!structure.units.some(u => validUnit(u))) return;
+
+        const lookup = structure.lookup3d;
+        const imageCenter = Vec3.zero();
+
+        for (const unit of structure.units) {
+            if (!validUnit(unit)) continue;
+
+            const bs = unit.lookup3d.boundary.sphere;
+            Vec3.transformMat4(imageCenter, bs.center, unit.conformation.operator.matrix);
+            const closeUnits = lookup.findUnitIndices(imageCenter[0], imageCenter[1], imageCenter[2], bs.radius + maxRadius);
+            for (let i = 0; i < closeUnits.count; i++) {
+                const other = structure.units[closeUnits.indices[i]];
+                if (!validUnit(other) || unit.id >= other.id || !validUnitPair(unit, other)) continue;
+
+                if (other.elements.length >= unit.elements.length) callback(unit, other);
+                else callback(other, unit);
+            }
+        }
+    }
 }
 
 export default Structure

+ 7 - 19
src/mol-model/structure/structure/unit/bonds/inter-compute.ts

@@ -199,7 +199,6 @@ export interface InterBondComputationProps extends BondComputationProps {
 
 function findBonds(structure: Structure, props: InterBondComputationProps) {
     const map = new Map<number, InterUnitBonds.UnitPairBonds[]>();
-    if (!structure.units.some(u => Unit.isAtomic(u))) return new InterUnitBonds(map);
 
     if (props.noCompute) {
         // TODO add function that only adds bonds defined in structConn and avoids using
@@ -208,24 +207,13 @@ function findBonds(structure: Structure, props: InterBondComputationProps) {
         return new InterUnitBonds(map);
     }
 
-    const { validUnitPair } = props;
-    const lookup = structure.lookup3d;
-    const imageCenter = Vec3.zero();
-
-    for (const unit of structure.units) {
-        if (!Unit.isAtomic(unit)) continue;
-
-        const bs = unit.lookup3d.boundary.sphere;
-        Vec3.transformMat4(imageCenter, bs.center, unit.conformation.operator.matrix);
-        const closeUnits = lookup.findUnitIndices(imageCenter[0], imageCenter[1], imageCenter[2], bs.radius + MAX_RADIUS);
-        for (let i = 0; i < closeUnits.count; i++) {
-            const other = structure.units[closeUnits.indices[i]];
-            if (!Unit.isAtomic(other) || unit.id >= other.id || !validUnitPair(structure, unit, other)) continue;
-
-            if (other.elements.length >= unit.elements.length) findPairBonds(unit, other, props, map);
-            else findPairBonds(other, unit, props, map);
-        }
-    }
+    Structure.eachUnitPair(structure, (unitA: Unit, unitB: Unit) => {
+        findPairBonds(unitA as Unit.Atomic, unitB as Unit.Atomic, props, map)
+    }, {
+        maxRadius: MAX_RADIUS,
+        validUnit: (unit: Unit) => Unit.isAtomic(unit),
+        validUnitPair: (unitA: Unit, unitB: Unit) => props.validUnitPair(structure, unitA, unitB)
+    })
 
     return new InterUnitBonds(map);
 }