UNPKG

molstar

Version:

A comprehensive macromolecular library.

255 lines (254 loc) 12.6 kB
/** * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { __assign } from "tslib"; import { ParamDefinition as PD } from '../../../mol-util/param-definition'; import { Structure, StructureElement } from '../../../mol-model/structure'; import { Mesh } from '../../../mol-geo/geometry/mesh/mesh'; import { Vec3 } from '../../../mol-math/linear-algebra'; import { createLinkCylinderMesh, LinkCylinderParams } from '../../../mol-repr/structure/visual/util/link'; import { ComplexMeshParams, ComplexMeshVisual } from '../../../mol-repr/structure/complex-visual'; import { EmptyLoci } from '../../../mol-model/loci'; import { Interval, OrderedSet, SortedArray } from '../../../mol-data/int'; import { Interactions } from '../interactions/interactions'; import { InteractionsProvider } from '../interactions'; import { LocationIterator } from '../../../mol-geo/util/location-iterator'; import { Unit } from '../../../mol-model/structure/structure'; import { Sphere3D } from '../../../mol-math/geometry'; import { assertUnreachable } from '../../../mol-util/type-helpers'; import { InteractionsSharedParams } from './shared'; function createInterUnitInteractionCylinderMesh(ctx, structure, theme, props, mesh) { if (!structure.hasAtomic) return Mesh.createEmpty(mesh); var l = StructureElement.Location.create(structure); var interactions = InteractionsProvider.get(structure).value; var contacts = interactions.contacts, unitsFeatures = interactions.unitsFeatures; var edgeCount = contacts.edgeCount, edges = contacts.edges; var sizeFactor = props.sizeFactor, parentDisplay = props.parentDisplay; if (!edgeCount) return Mesh.createEmpty(mesh); var child = structure.child; var builderProps = { linkCount: edgeCount, position: function (posA, posB, edgeIndex) { var _a = edges[edgeIndex], unitA = _a.unitA, indexA = _a.indexA, unitB = _a.unitB, indexB = _a.indexB; var fA = unitsFeatures.get(unitA); var fB = unitsFeatures.get(unitB); var uA = structure.unitMap.get(unitA); var uB = structure.unitMap.get(unitB); Vec3.set(posA, fA.x[indexA], fA.y[indexA], fA.z[indexA]); Vec3.transformMat4(posA, posA, uA.conformation.operator.matrix); Vec3.set(posB, fB.x[indexB], fB.y[indexB], fB.z[indexB]); Vec3.transformMat4(posB, posB, uB.conformation.operator.matrix); }, style: function (edgeIndex) { return 1 /* LinkStyle.Dashed */; }, radius: function (edgeIndex) { var b = edges[edgeIndex]; var fA = unitsFeatures.get(b.unitA); l.unit = structure.unitMap.get(b.unitA); l.element = l.unit.elements[fA.members[fA.offsets[b.indexA]]]; var sizeA = theme.size.size(l); var fB = unitsFeatures.get(b.unitB); l.unit = structure.unitMap.get(b.unitB); l.element = l.unit.elements[fB.members[fB.offsets[b.indexB]]]; var sizeB = theme.size.size(l); return Math.min(sizeA, sizeB) * sizeFactor; }, ignore: function (edgeIndex) { if (edges[edgeIndex].props.flag === 1 /* InteractionFlag.Filtered */) return true; if (child) { var b = edges[edgeIndex]; if (parentDisplay === 'stub') { var childUnitA = child.unitMap.get(b.unitA); if (!childUnitA) return true; var unitA = structure.unitMap.get(b.unitA); var _a = unitsFeatures.get(b.unitA), offsets = _a.offsets, members = _a.members; for (var i = offsets[b.indexA], il = offsets[b.indexA + 1]; i < il; ++i) { var eA = unitA.elements[members[i]]; if (!SortedArray.has(childUnitA.elements, eA)) return true; } } else if (parentDisplay === 'full' || parentDisplay === 'between') { var flagA = false; var flagB = false; var childUnitA = child.unitMap.get(b.unitA); if (!childUnitA) { flagA = true; } else { var unitA = structure.unitMap.get(b.unitA); var _b = unitsFeatures.get(b.unitA), offsets = _b.offsets, members = _b.members; for (var i = offsets[b.indexA], il = offsets[b.indexA + 1]; i < il; ++i) { var eA = unitA.elements[members[i]]; if (!SortedArray.has(childUnitA.elements, eA)) flagA = true; } } var childUnitB = child.unitMap.get(b.unitB); if (!childUnitB) { flagB = true; } else { var unitB = structure.unitMap.get(b.unitB); var _c = unitsFeatures.get(b.unitB), offsets = _c.offsets, members = _c.members; for (var i = offsets[b.indexB], il = offsets[b.indexB + 1]; i < il; ++i) { var eB = unitB.elements[members[i]]; if (!SortedArray.has(childUnitB.elements, eB)) flagB = true; } } return parentDisplay === 'full' ? flagA && flagB : flagA === flagB; } else { assertUnreachable(parentDisplay); } } return false; } }; var _a = createLinkCylinderMesh(ctx, builderProps, props, mesh), m = _a.mesh, boundingSphere = _a.boundingSphere; if (boundingSphere) { m.setBoundingSphere(boundingSphere); } else if (m.triangleCount > 0) { var child_1 = structure.child; var sphere = Sphere3D.expand(Sphere3D(), (child_1 !== null && child_1 !== void 0 ? child_1 : structure).boundary.sphere, 1 * sizeFactor); m.setBoundingSphere(sphere); } return m; } export var InteractionsInterUnitParams = __assign(__assign(__assign({}, ComplexMeshParams), LinkCylinderParams), InteractionsSharedParams); export function InteractionsInterUnitVisual(materialId) { return ComplexMeshVisual({ defaultProps: PD.getDefaultValues(InteractionsInterUnitParams), createGeometry: createInterUnitInteractionCylinderMesh, createLocationIterator: createInteractionsIterator, getLoci: getInteractionLoci, eachLocation: eachInteraction, setUpdateState: function (state, newProps, currentProps, newTheme, currentTheme, newStructure, currentStructure) { state.createGeometry = (newProps.sizeFactor !== currentProps.sizeFactor || newProps.dashCount !== currentProps.dashCount || newProps.dashScale !== currentProps.dashScale || newProps.dashCap !== currentProps.dashCap || newProps.radialSegments !== currentProps.radialSegments || newProps.parentDisplay !== currentProps.parentDisplay); var interactionsHash = InteractionsProvider.get(newStructure).version; if (state.info.interactionsHash !== interactionsHash) { state.createGeometry = true; state.updateTransform = true; state.updateColor = true; state.info.interactionsHash = interactionsHash; } } }, materialId); } function getInteractionLoci(pickingId, structure, id) { var objectId = pickingId.objectId, groupId = pickingId.groupId; if (id === objectId) { var interactions = InteractionsProvider.get(structure).value; var c = interactions.contacts.edges[groupId]; var unitA = structure.unitMap.get(c.unitA); var unitB = structure.unitMap.get(c.unitB); return Interactions.Loci(structure, interactions, [ { unitA: unitA, indexA: c.indexA, unitB: unitB, indexB: c.indexB }, { unitA: unitB, indexA: c.indexB, unitB: unitA, indexB: c.indexA }, ]); } return EmptyLoci; } var __unitMap = new Map(); var __contactIndicesSet = new Set(); function eachInteraction(loci, structure, apply, isMarking) { var changed = false; if (Interactions.isLoci(loci)) { if (!Structure.areEquivalent(loci.data.structure, structure)) return false; var interactions = InteractionsProvider.get(structure).value; if (loci.data.interactions !== interactions) return false; var contacts = interactions.contacts; for (var _i = 0, _a = loci.elements; _i < _a.length; _i++) { var c = _a[_i]; var idx = contacts.getEdgeIndex(c.indexA, c.unitA.id, c.indexB, c.unitB.id); if (idx !== -1) { if (apply(Interval.ofSingleton(idx))) changed = true; } } } else if (StructureElement.Loci.is(loci)) { if (!Structure.areEquivalent(loci.structure, structure)) return false; if (isMarking && loci.elements.length === 1) return false; // only a single unit var interactions = InteractionsProvider.get(structure).value; if (!interactions) return false; var contacts_1 = interactions.contacts, unitsFeatures_1 = interactions.unitsFeatures; for (var _b = 0, _c = loci.elements; _b < _c.length; _b++) { var e = _c[_b]; __unitMap.set(e.unit.id, e.indices); } var _loop_1 = function (e) { var unit = e.unit; if (!Unit.isAtomic(unit)) return "continue"; OrderedSet.forEach(e.indices, function (v) { for (var _i = 0, _a = contacts_1.getContactIndicesForElement(v, unit); _i < _a.length; _i++) { var idx = _a[_i]; __contactIndicesSet.add(idx); } }); }; for (var _d = 0, _e = loci.elements; _d < _e.length; _d++) { var e = _e[_d]; _loop_1(e); } __contactIndicesSet.forEach(function (i) { if (isMarking) { var _a = contacts_1.edges[i], indexA = _a.indexA, unitA = _a.unitA, indexB = _a.indexB, unitB = _a.unitB; var indicesA = __unitMap.get(unitA); var indicesB = __unitMap.get(unitB); if (!indicesA || !indicesB) return; var _b = unitsFeatures_1.get(unitA), offsetsA = _b.offsets, membersA = _b.members; for (var j = offsetsA[indexA], jl = offsetsA[indexA + 1]; j < jl; ++j) { if (!OrderedSet.has(indicesA, membersA[j])) return; } var _c = unitsFeatures_1.get(unitB), offsetsB = _c.offsets, membersB = _c.members; for (var 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; } function createInteractionsIterator(structure) { var interactions = InteractionsProvider.get(structure).value; var contacts = interactions.contacts; var groupCount = contacts.edgeCount; var instanceCount = 1; var location = Interactions.Location(interactions, structure); var element = location.element; var getLocation = function (groupIndex) { var c = contacts.edges[groupIndex]; element.unitA = structure.unitMap.get(c.unitA); element.indexA = c.indexA; element.unitB = structure.unitMap.get(c.unitB); element.indexB = c.indexB; return location; }; return LocationIterator(groupCount, instanceCount, 1, getLocation, true); }