molstar
Version:
A comprehensive macromolecular library.
184 lines • 9.18 kB
JavaScript
/**
* Copyright (c) 2019-2021 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';
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;
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 /* 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 /* Filtered */)
return true;
if (child) {
var b = edges[edgeIndex];
var childUnitA = child.unitMap.get(b.unitA);
if (!childUnitA)
return true;
var unitA = structure.unitMap.get(b.unitA);
var fA = unitsFeatures.get(b.unitA);
// TODO: check all members
var eA = unitA.elements[fA.members[fA.offsets[b.indexA]]];
if (!SortedArray.has(childUnitA.elements, eA))
return true;
}
return false;
}
};
var m = createLinkCylinderMesh(ctx, builderProps, props, mesh);
var sphere = Sphere3D.expand(Sphere3D(), (child !== null && child !== void 0 ? child : structure).boundary.sphere, 1 * sizeFactor);
m.setBoundingSphere(sphere);
return m;
}
export var InteractionsInterUnitParams = __assign(__assign(__assign({}, ComplexMeshParams), LinkCylinderParams), { sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }), dashCount: PD.Numeric(6, { min: 2, max: 10, step: 2 }), dashScale: PD.Numeric(0.4, { min: 0, max: 2, step: 0.1 }), includeParent: PD.Boolean(false) });
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);
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;
}
function eachInteraction(loci, structure, apply, isMarking) {
var _a;
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, _b = loci.elements; _i < _b.length; _i++) {
var c = _b[_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 contacts_1 = (_a = InteractionsProvider.get(structure).value) === null || _a === void 0 ? void 0 : _a.contacts;
if (!contacts_1)
return false;
var _loop_1 = function (e) {
var unit = e.unit;
if (!Unit.isAtomic(unit))
return "continue";
if (isMarking && OrderedSet.size(e.indices) === 1)
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];
if (apply(Interval.ofSingleton(idx)))
changed = true;
}
});
};
// TODO when isMarking, all elements of contact features need to be in the loci
for (var _c = 0, _d = loci.elements; _c < _d.length; _c++) {
var e = _d[_c];
_loop_1(e);
}
}
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);
}
//# sourceMappingURL=interactions-inter-unit-cylinder.js.map