Skip to content
Snippets Groups Projects
Commit ceecee37 authored by Alexander Rose's avatar Alexander Rose
Browse files

add parentDisplay param to interactions repr

parent 2935717a
No related branches found
No related tags found
No related merge requests found
...@@ -7,6 +7,7 @@ Note that since we don't clearly distinguish between a public and private interf ...@@ -7,6 +7,7 @@ Note that since we don't clearly distinguish between a public and private interf
## [Unreleased] ## [Unreleased]
- [Fix] Clone ``Canvas3DParams`` when creating a ``Canvas3D`` instance to prevent shared state between multiple instances. - [Fix] Clone ``Canvas3DParams`` when creating a ``Canvas3D`` instance to prevent shared state between multiple instances.
- [Add] New ``parentDisplay`` param for interactions representation.
## [v3.16.0] - 2022-08-25 ## [v3.16.0] - 2022-08-25
......
...@@ -22,6 +22,8 @@ import { LocationIterator } from '../../../mol-geo/util/location-iterator'; ...@@ -22,6 +22,8 @@ import { LocationIterator } from '../../../mol-geo/util/location-iterator';
import { InteractionFlag } from '../interactions/common'; import { InteractionFlag } from '../interactions/common';
import { Unit } from '../../../mol-model/structure/structure'; import { Unit } from '../../../mol-model/structure/structure';
import { Sphere3D } from '../../../mol-math/geometry'; import { Sphere3D } from '../../../mol-math/geometry';
import { assertUnreachable } from '../../../mol-util/type-helpers';
import { InteractionsSharedParams } from './shared';
function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<InteractionsInterUnitParams>, mesh?: Mesh) { function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<InteractionsInterUnitParams>, mesh?: Mesh) {
if (!structure.hasAtomic) return Mesh.createEmpty(mesh); if (!structure.hasAtomic) return Mesh.createEmpty(mesh);
...@@ -31,7 +33,7 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S ...@@ -31,7 +33,7 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S
const { contacts, unitsFeatures } = interactions; const { contacts, unitsFeatures } = interactions;
const { edgeCount, edges } = contacts; const { edgeCount, edges } = contacts;
const { sizeFactor } = props; const { sizeFactor, parentDisplay } = props;
if (!edgeCount) return Mesh.createEmpty(mesh); if (!edgeCount) return Mesh.createEmpty(mesh);
...@@ -70,14 +72,48 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S ...@@ -70,14 +72,48 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S
if (child) { if (child) {
const b = edges[edgeIndex]; const b = edges[edgeIndex];
const childUnitA = child.unitMap.get(b.unitA);
if (!childUnitA) return true; if (parentDisplay === 'stub') {
const childUnitA = child.unitMap.get(b.unitA);
const unitA = structure.unitMap.get(b.unitA); if (!childUnitA) return true;
const { offsets, members } = unitsFeatures.get(b.unitA);
for (let i = offsets[b.indexA], il = offsets[b.indexA + 1]; i < il; ++i) { const unitA = structure.unitMap.get(b.unitA);
const eA = unitA.elements[members[i]]; const { offsets, members } = unitsFeatures.get(b.unitA);
if (!SortedArray.has(childUnitA.elements, eA)) return true; 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;
}
} else if (parentDisplay === 'full' || parentDisplay === 'between') {
let flagA = false;
let flagB = false;
const childUnitA = child.unitMap.get(b.unitA);
if (!childUnitA) {
flagA = true;
} else {
const unitA = structure.unitMap.get(b.unitA);
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)) flagA = true;
}
}
const childUnitB = child.unitMap.get(b.unitB);
if (!childUnitB) {
flagB = true;
} else {
const unitB = structure.unitMap.get(b.unitB);
const { offsets, members } = unitsFeatures.get(b.unitB);
for (let i = offsets[b.indexB], il = offsets[b.indexB + 1]; i < il; ++i) {
const eB = unitB.elements[members[i]];
if (!SortedArray.has(childUnitB.elements, eB)) flagB = true;
}
}
return parentDisplay === 'full' ? flagA && flagB : flagA !== flagB;
} else {
assertUnreachable(parentDisplay);
} }
} }
...@@ -101,10 +137,7 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S ...@@ -101,10 +137,7 @@ function createInterUnitInteractionCylinderMesh(ctx: VisualContext, structure: S
export const InteractionsInterUnitParams = { export const InteractionsInterUnitParams = {
...ComplexMeshParams, ...ComplexMeshParams,
...LinkCylinderParams, ...LinkCylinderParams,
sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }), ...InteractionsSharedParams,
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 type InteractionsInterUnitParams = typeof InteractionsInterUnitParams export type InteractionsInterUnitParams = typeof InteractionsInterUnitParams
...@@ -121,7 +154,8 @@ export function InteractionsInterUnitVisual(materialId: number): ComplexVisual<I ...@@ -121,7 +154,8 @@ export function InteractionsInterUnitVisual(materialId: number): ComplexVisual<I
newProps.dashCount !== currentProps.dashCount || newProps.dashCount !== currentProps.dashCount ||
newProps.dashScale !== currentProps.dashScale || newProps.dashScale !== currentProps.dashScale ||
newProps.dashCap !== currentProps.dashCap || newProps.dashCap !== currentProps.dashCap ||
newProps.radialSegments !== currentProps.radialSegments newProps.radialSegments !== currentProps.radialSegments ||
newProps.parentDisplay !== currentProps.parentDisplay
); );
const interactionsHash = InteractionsProvider.get(newStructure).version; const interactionsHash = InteractionsProvider.get(newStructure).version;
......
...@@ -22,6 +22,8 @@ import { Interactions } from '../interactions/interactions'; ...@@ -22,6 +22,8 @@ import { Interactions } from '../interactions/interactions';
import { InteractionFlag } from '../interactions/common'; import { InteractionFlag } from '../interactions/common';
import { Sphere3D } from '../../../mol-math/geometry'; import { Sphere3D } from '../../../mol-math/geometry';
import { StructureGroup } from '../../../mol-repr/structure/visual/util/common'; import { StructureGroup } from '../../../mol-repr/structure/visual/util/common';
import { assertUnreachable } from '../../../mol-util/type-helpers';
import { InteractionsSharedParams } from './shared';
async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<InteractionsIntraUnitParams>, mesh?: Mesh) { async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: PD.Values<InteractionsIntraUnitParams>, mesh?: Mesh) {
if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh); if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh);
...@@ -38,7 +40,7 @@ async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit: ...@@ -38,7 +40,7 @@ async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit:
const { x, y, z, members, offsets } = features; const { x, y, z, members, offsets } = features;
const { edgeCount, a, b, edgeProps: { flag } } = contacts; const { edgeCount, a, b, edgeProps: { flag } } = contacts;
const { sizeFactor } = props; const { sizeFactor, parentDisplay } = props;
if (!edgeCount) return Mesh.createEmpty(mesh); if (!edgeCount) return Mesh.createEmpty(mesh);
...@@ -60,10 +62,31 @@ async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit: ...@@ -60,10 +62,31 @@ async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit:
if (flag[edgeIndex] === InteractionFlag.Filtered) return true; if (flag[edgeIndex] === InteractionFlag.Filtered) return true;
if (childUnit) { if (childUnit) {
const f = a[edgeIndex]; if (parentDisplay === 'stub') {
for (let i = offsets[f], jl = offsets[f + 1]; i < jl; ++i) { const f = a[edgeIndex];
const e = unit.elements[members[offsets[i]]]; for (let i = offsets[f], jl = offsets[f + 1]; i < jl; ++i) {
if (!SortedArray.has(childUnit.elements, e)) return true; const e = unit.elements[members[offsets[i]]];
if (!SortedArray.has(childUnit.elements, e)) return true;
}
} else if (parentDisplay === 'full' || parentDisplay === 'between') {
let flagA = false;
let flagB = false;
const fA = a[edgeIndex];
for (let i = offsets[fA], jl = offsets[fA + 1]; i < jl; ++i) {
const eA = unit.elements[members[offsets[i]]];
if (!SortedArray.has(childUnit.elements, eA)) flagA = true;
}
const fB = b[edgeIndex];
for (let i = offsets[fB], jl = offsets[fB + 1]; i < jl; ++i) {
const eB = unit.elements[members[offsets[i]]];
if (!SortedArray.has(childUnit.elements, eB)) flagB = true;
}
return parentDisplay === 'full' ? flagA && flagB : flagA !== flagB;
} else {
assertUnreachable(parentDisplay);
} }
} }
...@@ -86,10 +109,7 @@ async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit: ...@@ -86,10 +109,7 @@ async function createIntraUnitInteractionsCylinderMesh(ctx: VisualContext, unit:
export const InteractionsIntraUnitParams = { export const InteractionsIntraUnitParams = {
...UnitsMeshParams, ...UnitsMeshParams,
...LinkCylinderParams, ...LinkCylinderParams,
sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }), ...InteractionsSharedParams,
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 type InteractionsIntraUnitParams = typeof InteractionsIntraUnitParams export type InteractionsIntraUnitParams = typeof InteractionsIntraUnitParams
...@@ -106,7 +126,8 @@ export function InteractionsIntraUnitVisual(materialId: number): UnitsVisual<Int ...@@ -106,7 +126,8 @@ export function InteractionsIntraUnitVisual(materialId: number): UnitsVisual<Int
newProps.dashCount !== currentProps.dashCount || newProps.dashCount !== currentProps.dashCount ||
newProps.dashScale !== currentProps.dashScale || newProps.dashScale !== currentProps.dashScale ||
newProps.dashCap !== currentProps.dashCap || newProps.dashCap !== currentProps.dashCap ||
newProps.radialSegments !== currentProps.radialSegments newProps.radialSegments !== currentProps.radialSegments ||
newProps.parentDisplay !== currentProps.parentDisplay
); );
const interactionsHash = InteractionsProvider.get(newStructureGroup.structure).version; const interactionsHash = InteractionsProvider.get(newStructureGroup.structure).version;
......
/**
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
export const InteractionsSharedParams = {
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),
parentDisplay: PD.Select('stub', PD.arrayToOptions(['stub', 'full', 'between'] as const), { description: 'Only has an effect when "includeParent" is enabled. "Stub" shows just the child side of interactions to the parent. "Full" shows both sides of interactions to the parent. "Between" shows only interactions to the parent.' }),
};
export type InteractionsSharedParams = typeof InteractionsSharedParams
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment