mirror of
https://github.com/molstar/molstar.git
synced 2026-06-04 13:30:24 +08:00
generalized support of interaction bridges
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
@@ -15,7 +15,7 @@ import { IntMap } from '../../../mol-data/int';
|
||||
import { addUnitContacts, ContactTester, addStructureContacts, ContactsParams, ContactsProps } from './contacts';
|
||||
import { HalogenDonorProvider, HalogenAcceptorProvider, HalogenBondsProvider } from './halogen-bonds';
|
||||
import { HydrogenDonorProvider, WeakHydrogenDonorProvider, HydrogenAcceptorProvider, HydrogenBondsProvider, WeakHydrogenBondsProvider } from './hydrogen-bonds';
|
||||
import { findWaterBridgeContacts, WaterBridgeContacts, WaterBridgesParams } from './water-bridges';
|
||||
import { findWaterBridgeContacts, WaterBridgesParams, WaterBridgeContact } from './water-bridges';
|
||||
import { NegativChargeProvider, PositiveChargeProvider, AromaticRingProvider, IonicProvider, PiStackingProvider, CationPiProvider } from './charged';
|
||||
import { HydrophobicAtomProvider, HydrophobicProvider } from './hydrophobic';
|
||||
import { SetUtils } from '../../../mol-util/set';
|
||||
@@ -30,6 +30,10 @@ import { bondLabel, LabelGranularity } from '../../../mol-theme/label';
|
||||
import { ObjectKeys } from '../../../mol-util/type-helpers';
|
||||
|
||||
export { Interactions };
|
||||
export type { BridgeContact, BridgeContacts };
|
||||
|
||||
type BridgeContact = WaterBridgeContact
|
||||
type BridgeContacts = ReadonlyArray<BridgeContact>
|
||||
|
||||
interface Interactions {
|
||||
/** Features of each unit */
|
||||
@@ -38,8 +42,8 @@ interface Interactions {
|
||||
unitsContacts: IntMap<InteractionsIntraContacts>
|
||||
/** Interactions between units */
|
||||
contacts: InteractionsInterContacts
|
||||
/** Water-mediated hydrogen bonds (donor → water → acceptor) */
|
||||
waterBridges: WaterBridgeContacts
|
||||
/** Bridge-mediated interactions covering the whole structure */
|
||||
bridges: BridgeContacts
|
||||
}
|
||||
|
||||
namespace Interactions {
|
||||
@@ -239,13 +243,9 @@ export async function computeInteractions(ctx: CustomProperty.Context, structure
|
||||
}
|
||||
|
||||
const contacts = findInterUnitContacts(structure, unitsFeatures, contactTesters, p.contacts, options);
|
||||
const bridges = findBridges(structure, unitsFeatures, p.waterBridges);
|
||||
const interactions = { unitsFeatures, unitsContacts, contacts, bridges };
|
||||
|
||||
const wbToggle = p.waterBridges['water-bridges'];
|
||||
const waterBridges = wbToggle.name === 'on'
|
||||
? findWaterBridgeContacts(structure, unitsFeatures, wbToggle.params)
|
||||
: [];
|
||||
|
||||
const interactions = { unitsFeatures, unitsContacts, contacts, waterBridges };
|
||||
refineInteractions(structure, interactions);
|
||||
return interactions;
|
||||
}
|
||||
@@ -276,6 +276,17 @@ function findIntraUnitContacts(structure: Structure, unit: Unit, features: Featu
|
||||
return builder.getContacts();
|
||||
}
|
||||
|
||||
function findBridges(structure: Structure, unitsFeatures: IntMap<Features>, props: PD.Values<typeof WaterBridgesToggleParams>): BridgeContacts {
|
||||
const bridges: BridgeContact[] = [];
|
||||
|
||||
const wb = props['water-bridges'];
|
||||
if (wb.name === 'on') {
|
||||
for (const b of findWaterBridgeContacts(structure, unitsFeatures, wb.params)) bridges.push(b);
|
||||
}
|
||||
|
||||
return bridges;
|
||||
}
|
||||
|
||||
function findInterUnitContacts(structure: Structure, unitsFeatures: IntMap<Features>, contactTesters: ReadonlyArray<ContactTester>, props: ContactsProps, options?: ComputeInterctionsOptions) {
|
||||
const builder = InterContactsBuilder.create();
|
||||
|
||||
|
||||
@@ -284,7 +284,7 @@ function metalCoordinationRefiner(structure: Structure, interactions: Interactio
|
||||
}
|
||||
|
||||
function waterBridgeRefiner(_structure: Structure, interactions: Interactions): ContactRefiner {
|
||||
const { contacts, waterBridges, unitsFeatures } = interactions;
|
||||
const { contacts, bridges, unitsFeatures } = interactions;
|
||||
|
||||
type AtomKey = number;
|
||||
type AtomPairSet = Map<AtomKey, Set<AtomKey>>;
|
||||
@@ -351,7 +351,9 @@ function waterBridgeRefiner(_structure: Structure, interactions: Interactions):
|
||||
|
||||
const bridgeLegs: AtomPairSet = new Map();
|
||||
|
||||
for (const wb of waterBridges) {
|
||||
for (const wb of bridges) {
|
||||
if (wb.props.type !== InteractionType.WaterBridge) continue;
|
||||
|
||||
const fA = unitsFeatures.get(wb.unitA);
|
||||
const fW = unitsFeatures.get(wb.unitW);
|
||||
const fB = unitsFeatures.get(wb.unitB);
|
||||
|
||||
@@ -15,7 +15,7 @@ import { StructureLookup3DResultContext } from '../../../mol-model/structure/str
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
import { CentroidHelper } from '../../../mol-math/geometry/centroid-helper';
|
||||
import { Features } from './features';
|
||||
import { FeatureType } from './common';
|
||||
import { FeatureType, InteractionType, InteractionFlag } from './common';
|
||||
import { GeometryOptions, checkGeometry } from './hydrogen-bonds';
|
||||
import { degToRad } from '../../../mol-math/misc';
|
||||
import { bundleLabel, LabelGranularity } from '../../../mol-theme/label';
|
||||
@@ -38,6 +38,7 @@ interface WaterBridgeContact {
|
||||
readonly indexWA: Features.FeatureIndex
|
||||
/** water oxygen as HydrogenDonor (leg: water → acceptor) */
|
||||
readonly indexWD: Features.FeatureIndex
|
||||
props: { type: InteractionType.WaterBridge, flag: InteractionFlag }
|
||||
}
|
||||
|
||||
type WaterBridgeContacts = ReadonlyArray<WaterBridgeContact>;
|
||||
@@ -315,6 +316,7 @@ export function findWaterBridgeContacts(
|
||||
unitW: unitW.id,
|
||||
indexWA: accFW,
|
||||
indexWD: donFW,
|
||||
props: { type: InteractionType.WaterBridge, flag: InteractionFlag.None },
|
||||
},
|
||||
combinedDistSq,
|
||||
});
|
||||
|
||||
@@ -19,7 +19,8 @@ import { NullLocation } from '../../../mol-model/location';
|
||||
import { Interval, OrderedSet } from '../../../mol-data/int';
|
||||
import { InteractionsProvider } from '../interactions';
|
||||
import { LocationIterator } from '../../../mol-geo/util/location-iterator';
|
||||
import { WaterBridges } from '../interactions/water-bridges';
|
||||
import { WaterBridges, WaterBridgeContact } from '../interactions/water-bridges';
|
||||
import { InteractionType } from '../interactions/common';
|
||||
import { Sphere3D } from '../../../mol-math/geometry';
|
||||
import { InteractionsSharedParams } from './shared';
|
||||
import { Features } from '../interactions/features';
|
||||
@@ -129,14 +130,15 @@ function createWaterBridgeCylinderMesh(ctx: VisualContext, structure: Structure,
|
||||
const interactions = InteractionsProvider.get(structure).value;
|
||||
if (!interactions) return Mesh.createEmpty(mesh);
|
||||
|
||||
const { waterBridges, unitsFeatures } = interactions;
|
||||
const { bridges, unitsFeatures } = interactions;
|
||||
const waterBridges = bridges.filter((b): b is WaterBridgeContact => b.props.type === InteractionType.WaterBridge);
|
||||
|
||||
const n = waterBridges.length;
|
||||
if (!n) return Mesh.createEmpty(mesh);
|
||||
|
||||
const l = StructureElement.Location.create(structure);
|
||||
const { sizeFactor } = props;
|
||||
const canonical = getCanonicalLegIndices(waterBridges);
|
||||
const canonical = getCanonicalLegIndices(bridges);
|
||||
|
||||
const builderProps = {
|
||||
// Four half-cylinders per bridge; createLinkCylinderMesh draws the A-side half per call:
|
||||
@@ -288,14 +290,15 @@ function getWaterBridgeLoci(pickingId: PickingId, structure: Structure, id: numb
|
||||
const interactions = InteractionsProvider.get(structure).value;
|
||||
if (!interactions) return EmptyLoci;
|
||||
|
||||
const { waterBridges, unitsFeatures } = interactions;
|
||||
const { bridges, unitsFeatures } = interactions;
|
||||
const waterBridges = bridges.filter((b): b is WaterBridgeContact => b.props.type === InteractionType.WaterBridge);
|
||||
const n = waterBridges.length;
|
||||
|
||||
if (!n || groupId < 0 || groupId >= 4 * n) return EmptyLoci;
|
||||
|
||||
const bridgeIndex = groupId % n;
|
||||
|
||||
return WaterBridges.Loci({ structure, waterBridges, unitsFeatures }, [{ bridgeIndex }]);
|
||||
return WaterBridges.Loci({ structure, waterBridges: bridges, unitsFeatures }, [{ bridgeIndex }]);
|
||||
}
|
||||
|
||||
const __unitMap = new Map<number, OrderedSet<StructureElement.UnitIndex>>();
|
||||
@@ -309,10 +312,11 @@ function eachWaterBridgeInteraction(loci: Loci, structure: Structure, apply: (in
|
||||
const interactions = InteractionsProvider.get(structure).value;
|
||||
if (!interactions) return false;
|
||||
|
||||
const n = interactions.waterBridges.length;
|
||||
const waterBridges = interactions.bridges.filter((b): b is WaterBridgeContact => b.props.type === InteractionType.WaterBridge);
|
||||
const n = waterBridges.length;
|
||||
if (!n) return false;
|
||||
|
||||
const canonical = getCanonicalLegIndices(interactions.waterBridges);
|
||||
const canonical = getCanonicalLegIndices(waterBridges);
|
||||
|
||||
for (const e of loci.elements) {
|
||||
if (e.bridgeIndex < 0 || e.bridgeIndex >= n) continue;
|
||||
@@ -326,7 +330,8 @@ function eachWaterBridgeInteraction(loci: Loci, structure: Structure, apply: (in
|
||||
const interactions = InteractionsProvider.get(structure).value;
|
||||
if (!interactions) return false;
|
||||
|
||||
const { waterBridges, unitsFeatures } = interactions;
|
||||
const { bridges, unitsFeatures } = interactions;
|
||||
const waterBridges = bridges.filter((b): b is WaterBridgeContact => b.props.type === InteractionType.WaterBridge);
|
||||
const n = waterBridges.length;
|
||||
if (!n) return false;
|
||||
|
||||
@@ -387,7 +392,8 @@ function createWaterBridgeIterator(structure: Structure): LocationIterator {
|
||||
const interactions = InteractionsProvider.get(structure).value;
|
||||
if (!interactions) return LocationIterator(0, 1, 1, () => NullLocation, true);
|
||||
|
||||
const { waterBridges, unitsFeatures } = interactions;
|
||||
const { bridges, unitsFeatures } = interactions;
|
||||
const waterBridges = bridges.filter((b): b is WaterBridgeContact => b.props.type === InteractionType.WaterBridge);
|
||||
|
||||
const n = waterBridges.length;
|
||||
const groupCount = 4 * n;
|
||||
|
||||
Reference in New Issue
Block a user