diff --git a/CHANGELOG.md b/CHANGELOG.md index 4857c42c00e625844c92a7ae8c9d84ed4a4a4fa8..5e2ed51c3c46f6b0284cfe8de98a697bdb545698 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ Note that since we don't clearly distinguish between a public and private interf - Add ``includeResidueTest`` option to ``alignAndSuperposeWithSIFTSMapping`` - Add ``parentDisplay`` param for interactions representation. - Support for ``failIfMajorPerformanceCaveat`` webgl attribute. Add ``PluginConfig.General.AllowMajorPerformanceCaveat`` and ``allow-major-performance-caveat`` Viewer GET param. +- Fix handling of PDB TER records (#549) +- Add support for getting multiple loci from a representation (``.getAllLoci()``) +- Add ``key`` property to intra- and inter-bonds for referencing source data ## [v3.16.0] - 2022-08-25 diff --git a/src/mol-model-formats/structure/common/component.ts b/src/mol-model-formats/structure/common/component.ts index 948a01fcb7df8a3b8942d5798a106a5c13588416..770a095cac67716d4bb64b82157b2a6a4a5af33b 100644 --- a/src/mol-model-formats/structure/common/component.ts +++ b/src/mol-model-formats/structure/common/component.ts @@ -32,6 +32,7 @@ const DnaAtomIdsList = [ /** Used to reduce false positives for atom name-based type guessing */ const NonPolymerNames = new Set([ 'FMN', 'NCN', 'FNS', 'FMA', 'ATP', 'ADP', 'AMP', 'GTP', 'GDP', 'GMP', // Mononucleotides + 'LIG' ]); const StandardComponents = (function () { diff --git a/src/mol-model-formats/structure/pdb/atom-site.ts b/src/mol-model-formats/structure/pdb/atom-site.ts index 7de7aeed37eb9c36cd14b717f05b7b6b02f6b3f9..21d5364d6f546aa041e2992c94b84a156347cf52 100644 --- a/src/mol-model-formats/structure/pdb/atom-site.ts +++ b/src/mol-model-formats/structure/pdb/atom-site.ts @@ -39,7 +39,7 @@ export function getAtomSiteTemplate(data: string, count: number) { }; } -export function getAtomSite(sites: AtomSiteTemplate, hasTer: boolean): { [K in keyof mmCIF_Schema['atom_site'] | 'partial_charge']?: CifField } { +export function getAtomSite(sites: AtomSiteTemplate, terIndices: Set<number>): { [K in keyof mmCIF_Schema['atom_site'] | 'partial_charge']?: CifField } { const pdbx_PDB_model_num = CifField.ofStrings(sites.pdbx_PDB_model_num); const auth_asym_id = CifField.ofTokens(sites.auth_asym_id); const auth_seq_id = CifField.ofTokens(sites.auth_seq_id); @@ -91,7 +91,7 @@ export function getAtomSite(sites: AtomSiteTemplate, hasTer: boolean): { [K in k if (asymIdCounts.has(asymId)) { // only change the chains name if there are TER records // otherwise assume repeated chain name use is from interleaved chains - if (hasTer && asymIdChanged) { + if (terIndices.has(i)) { const asymIdCount = asymIdCounts.get(asymId)! + 1; asymIdCounts.set(asymId, asymIdCount); currLabelAsymId = `${asymId}_${asymIdCount}`; diff --git a/src/mol-model-formats/structure/pdb/to-cif.ts b/src/mol-model-formats/structure/pdb/to-cif.ts index 21a2a68f0593c6aeecf3d549600b0836290d167d..792d5a136d2c45388eba6ca8612803c890c7d32c 100644 --- a/src/mol-model-formats/structure/pdb/to-cif.ts +++ b/src/mol-model-formats/structure/pdb/to-cif.ts @@ -51,7 +51,7 @@ export async function pdbToMmCif(pdb: PdbFile): Promise<CifFrame> { let modelNum = 0, modelStr = ''; let conectRange: [number, number] | undefined = undefined; - let hasTer = false; + const terIndices = new Set<number>(); for (let i = 0, _i = lines.count; i < _i; i++) { let s = indices[2 * i], e = indices[2 * i + 1]; @@ -164,7 +164,7 @@ export async function pdbToMmCif(pdb: PdbFile): Promise<CifFrame> { break; case 'T': if (substringStartsWith(data, s, e, 'TER')) { - hasTer = true; + terIndices.add(atomSite.index); } } } @@ -183,7 +183,7 @@ export async function pdbToMmCif(pdb: PdbFile): Promise<CifFrame> { atomSite.label_entity_id[i] = entityBuilder.getEntityId(compId, moleculeType, asymIds.value(i)); } - const atom_site = getAtomSite(atomSite, hasTer); + const atom_site = getAtomSite(atomSite, terIndices); if (!isPdbqt) delete atom_site.partial_charge; if (conectRange) { diff --git a/src/mol-model-formats/structure/property/bonds/chem_comp.ts b/src/mol-model-formats/structure/property/bonds/chem_comp.ts index b3f64adcff90adfd48410aa33035248c7f740ada..6ba2bc374891a16fff526ee3e8b7b96a3db37b70 100644 --- a/src/mol-model-formats/structure/property/bonds/chem_comp.ts +++ b/src/mol-model-formats/structure/property/bonds/chem_comp.ts @@ -65,7 +65,7 @@ export namespace ComponentBond { return e; } - const { comp_id, atom_id_1, atom_id_2, value_order, pdbx_aromatic_flag, _rowCount } = data; + const { comp_id, atom_id_1, atom_id_2, value_order, pdbx_aromatic_flag, _rowCount, pdbx_ordinal } = data; let entry = addEntry(comp_id.value(0)!); for (let i = 0; i < _rowCount; i++) { @@ -74,6 +74,7 @@ export namespace ComponentBond { const nameB = atom_id_2.value(i)!; const order = value_order.value(i)!; const aromatic = pdbx_aromatic_flag.value(i) === 'y'; + const key = pdbx_ordinal.value(i); if (entry.id !== id) { entry = addEntry(id); @@ -89,29 +90,29 @@ export namespace ComponentBond { case 'quad': ord = 4; break; } - entry.add(nameA, nameB, ord, flags); + entry.add(nameA, nameB, ord, flags, key); } return entries; } export class Entry { - readonly map: Map<string, Map<string, { order: number, flags: number }>> = new Map(); + readonly map: Map<string, Map<string, { order: number, flags: number, key: number }>> = new Map(); - add(a: string, b: string, order: number, flags: number, swap = true) { + add(a: string, b: string, order: number, flags: number, key: number, swap = true) { const e = this.map.get(a); if (e !== void 0) { const f = e.get(b); if (f === void 0) { - e.set(b, { order, flags }); + e.set(b, { order, flags, key }); } } else { - const map = new Map<string, { order: number, flags: number }>(); - map.set(b, { order, flags }); + const map = new Map<string, { order: number, flags: number, key: number }>(); + map.set(b, { order, flags, key }); this.map.set(a, map); } - if (swap) this.add(b, a, order, flags, false); + if (swap) this.add(b, a, order, flags, key, false); } constructor(public readonly id: string) { } diff --git a/src/mol-model/structure/query/context.ts b/src/mol-model/structure/query/context.ts index 43b2538b98ba727032ab231948c203283e123f61..c51b441a77da6cfffd623877b0734df8e87fc757 100644 --- a/src/mol-model/structure/query/context.ts +++ b/src/mol-model/structure/query/context.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { Structure, StructureElement, Unit } from '../structure'; @@ -113,6 +114,7 @@ class QueryContextBondInfo<U extends Unit = Unit> { bIndex: StructureElement.UnitIndex = 0 as StructureElement.UnitIndex; type: BondType = BondType.Flag.None; order: number = 0; + key: number = -1; private testFn: QueryPredicate = defaultBondTest; diff --git a/src/mol-model/structure/query/queries/filters.ts b/src/mol-model/structure/query/queries/filters.ts index 128f9b4fa7d0b698d88a7f939140d5737c3f8e21..81e698f1649ada29eafa19194f1d2af23c5ab1a1 100644 --- a/src/mol-model/structure/query/queries/filters.ts +++ b/src/mol-model/structure/query/queries/filters.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { SetUtils } from '../../../../mol-util/set'; @@ -248,7 +249,7 @@ function checkConnected(ctx: IsConnectedToCtx, structure: Structure) { const inputUnit = input.unitMap.get(unit.id) as Unit.Atomic; - const { offset, b, edgeProps: { flags, order } } = inputUnit.bonds; + const { offset, b, edgeProps: { flags, order, key } } = inputUnit.bonds; const bondedUnits = interBonds.getConnectedUnits(unit.id); const buCount = bondedUnits.length; @@ -273,6 +274,7 @@ function checkConnected(ctx: IsConnectedToCtx, structure: Structure) { atomicBond.bIndex = b[l] as StructureElement.UnitIndex; atomicBond.type = flags[l]; atomicBond.order = order[l]; + atomicBond.key = key[l]; if (atomicBond.test(queryCtx, true)) return true; } @@ -295,6 +297,7 @@ function checkConnected(ctx: IsConnectedToCtx, structure: Structure) { atomicBond.bIndex = bond.indexB; atomicBond.type = bond.props.flag; atomicBond.order = bond.props.order; + atomicBond.key = bond.props.key; if (atomicBond.test(queryCtx, true)) return true; } } diff --git a/src/mol-model/structure/query/queries/generators.ts b/src/mol-model/structure/query/queries/generators.ts index e963dc2a5b2eb62f408ccde5f5bbfbf000c9510e..807114c5e2ccde81788992acb01c9719c19ec92e 100644 --- a/src/mol-model/structure/query/queries/generators.ts +++ b/src/mol-model/structure/query/queries/generators.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -322,7 +322,7 @@ export function bondedAtomicPairs(bondTest?: QueryPredicate): StructureQuery { for (const unit of structure.units) { if (unit.kind !== Unit.Kind.Atomic) continue; - const { offset: intraBondOffset, b: intraBondB, edgeProps: { flags, order } } = unit.bonds; + const { offset: intraBondOffset, b: intraBondB, edgeProps: { flags, order, key } } = unit.bonds; atomicBond.a.unit = unit; atomicBond.b.unit = unit; for (let i = 0 as StructureElement.UnitIndex, _i = unit.elements.length; i < _i; i++) { @@ -335,6 +335,7 @@ export function bondedAtomicPairs(bondTest?: QueryPredicate): StructureQuery { atomicBond.b.element = unit.elements[intraBondB[lI]]; atomicBond.type = flags[lI]; atomicBond.order = order[lI]; + atomicBond.key = key[lI]; // No need to "swap test" because each bond direction will be visited eventually. if (atomicBond.test(ctx, false)) { const b = structure.subsetBuilder(false); @@ -358,6 +359,7 @@ export function bondedAtomicPairs(bondTest?: QueryPredicate): StructureQuery { atomicBond.bIndex = bond.indexB; atomicBond.order = bond.props.order; atomicBond.type = bond.props.flag; + atomicBond.key = bond.props.key; // No need to "swap test" because each bond direction will be visited eventually. if (atomicBond.test(ctx, false)) { diff --git a/src/mol-model/structure/query/queries/modifiers.ts b/src/mol-model/structure/query/queries/modifiers.ts index c860695950b6b3430e8d6f8effa9843e4456b396..f10e9f7c7683243b6795c70e74c994d624678b5d 100644 --- a/src/mol-model/structure/query/queries/modifiers.ts +++ b/src/mol-model/structure/query/queries/modifiers.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { Segmentation, SortedArray } from '../../../../mol-data/int'; @@ -370,7 +371,7 @@ function expandConnected(ctx: QueryContext, structure: Structure) { } const inputUnitA = inputStructure.unitMap.get(unit.id) as Unit.Atomic; - const { offset: intraBondOffset, b: intraBondB, edgeProps: { flags, order } } = inputUnitA.bonds; + const { offset: intraBondOffset, b: intraBondB, edgeProps: { flags, order, key } } = inputUnitA.bonds; atomicBond.setStructure(inputStructure); @@ -397,6 +398,7 @@ function expandConnected(ctx: QueryContext, structure: Structure) { atomicBond.b.element = bElement; atomicBond.type = flags[lI]; atomicBond.order = order[lI]; + atomicBond.key = key[lI]; if (atomicBond.test(ctx, true)) { builder.addToUnit(unit.id, bElement); @@ -427,6 +429,7 @@ function expandConnected(ctx: QueryContext, structure: Structure) { atomicBond.b.element = bElement; atomicBond.type = bond.props.flag; atomicBond.order = bond.props.order; + atomicBond.key = bond.props.key; if (atomicBond.test(ctx, true)) { builder.addToUnit(bondedUnit.unitB, bElement); diff --git a/src/mol-model/structure/structure/unit/bonds/data.ts b/src/mol-model/structure/structure/unit/bonds/data.ts index b05df8ed1d0e27a6a5e1c4720741bcc6ae11d356..f2ab500a86fbb09a31bc4f4d72dc6ecd99cf195d 100644 --- a/src/mol-model/structure/structure/unit/bonds/data.ts +++ b/src/mol-model/structure/structure/unit/bonds/data.ts @@ -15,16 +15,17 @@ import { InterUnitGraph } from '../../../../../mol-math/graph/inter-unit-graph'; type IntraUnitBonds = IntAdjacencyGraph<StructureElement.UnitIndex, { readonly order: ArrayLike<number>, readonly flags: ArrayLike<BondType.Flag> + readonly key: ArrayLike<number>, }, { /** can remap even with dynamicBonds on, e.g., for water molecules */ readonly canRemap?: boolean }> namespace IntraUnitBonds { - export const Empty: IntraUnitBonds = IntAdjacencyGraph.create([], [], [], 0, { flags: [], order: [] }); + export const Empty: IntraUnitBonds = IntAdjacencyGraph.create([], [], [], 0, { flags: [], order: [], key: [] }); } -type InterUnitEdgeProps = { readonly order: number, readonly flag: BondType.Flag } +type InterUnitEdgeProps = { readonly order: number, readonly flag: BondType.Flag, readonly key: number } class InterUnitBonds extends InterUnitGraph<number, StructureElement.UnitIndex, InterUnitEdgeProps> { /** Get inter-unit bond given a bond-location */ diff --git a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts index ba0327c3fc2ffaecbc25b4abe2ed8b434a40373d..74f5127df14aabdc3ba3ec71e6ca40ba1c92804c 100644 --- a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts @@ -80,7 +80,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput if (!props.forceCompute && indexPairs) { const { maxDistance } = indexPairs; - const { offset, b, edgeProps: { order, distance, flag } } = indexPairs.bonds; + const { offset, b, edgeProps: { order, distance, flag, key } } = indexPairs.bonds; const srcA = sourceIndex.value(aI); const aeI = getElementIdx(type_symbolA.value(aI)); @@ -113,7 +113,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput } if (add) { - builder.add(_aI, _bI, { order: order[i], flag: flag[i] }); + builder.add(_aI, _bI, { order: order[i], flag: flag[i], key: key[i] }); } } continue; // assume `indexPairs` supplies all bonds @@ -131,7 +131,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput // check if the bond is within MAX_RADIUS for this pair of units if (getDistance(unitA, aI, unitB, p.atomIndex) > maxRadius) continue; - builder.add(_aI, _bI, { order: se.order, flag: se.flags }); + builder.add(_aI, _bI, { order: se.order, flag: se.flags, key: se.rowIndex }); added = true; } // assume, for an atom, that if any inter unit bond is given @@ -187,7 +187,8 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput const compIdB = label_comp_idB.value(residueIndexB[bI]); builder.add(_aI, _bI, { order: getInterBondOrderFromTable(compIdA, compIdB, atomIdA, atomIdB), - flag: (isMetal ? BondType.Flag.MetallicCoordination : BondType.Flag.Covalent) | BondType.Flag.Computed + flag: (isMetal ? BondType.Flag.MetallicCoordination : BondType.Flag.Covalent) | BondType.Flag.Computed, + key: -1 }); } } diff --git a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts index a4be859321bf19f44ea5c7902fff9d373e7565d8..29fd505381b21fd4791c49718f3900b8eeb001cb 100644 --- a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts @@ -24,17 +24,19 @@ import { Model } from '../../../model/model'; // avoiding namespace lookup improved performance in Chrome (Aug 2020) const v3distance = Vec3.distance; -function getGraph(atomA: StructureElement.UnitIndex[], atomB: StructureElement.UnitIndex[], _order: number[], _flags: number[], atomCount: number, canRemap: boolean): IntraUnitBonds { +function getGraph(atomA: StructureElement.UnitIndex[], atomB: StructureElement.UnitIndex[], _order: number[], _flags: number[], _key: number[], atomCount: number, canRemap: boolean): IntraUnitBonds { const builder = new IntAdjacencyGraph.EdgeBuilder(atomCount, atomA, atomB); const flags = new Uint16Array(builder.slotCount); const order = new Int8Array(builder.slotCount); + const key = new Uint32Array(builder.slotCount); for (let i = 0, _i = builder.edgeCount; i < _i; i++) { builder.addNextEdge(); builder.assignProperty(flags, _flags[i]); builder.assignProperty(order, _order[i]); + builder.assignProperty(key, _key[i]); } - return builder.createGraph({ flags, order }, { canRemap }); + return builder.createGraph({ flags, order, key }, { canRemap }); } const tmpDistVecA = Vec3(); @@ -53,7 +55,7 @@ function findIndexPairBonds(unit: Unit.Atomic) { const { type_symbol } = unit.model.atomicHierarchy.atoms; const atomCount = unit.elements.length; const { maxDistance } = indexPairs; - const { offset, b, edgeProps: { order, distance, flag } } = indexPairs.bonds; + const { offset, b, edgeProps: { order, distance, flag, key } } = indexPairs.bonds; const { atomSourceIndex: sourceIndex } = unit.model.atomicHierarchy; const { invertedIndex } = Model.getInvertedAtomSourceIndex(unit.model); @@ -62,6 +64,7 @@ function findIndexPairBonds(unit: Unit.Atomic) { const atomB: StructureElement.UnitIndex[] = []; const flags: number[] = []; const orders: number[] = []; + const keys: number[] = []; for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) { const aI = atoms[_aI]; @@ -104,11 +107,12 @@ function findIndexPairBonds(unit: Unit.Atomic) { atomB[atomB.length] = _bI; orders[orders.length] = order[i]; flags[flags.length] = flag[i]; + keys[keys.length] = key[i]; } } } - return getGraph(atomA, atomB, orders, flags, atomCount, false); + return getGraph(atomA, atomB, orders, flags, keys, atomCount, false); } function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBonds { @@ -132,9 +136,10 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon const atomB: StructureElement.UnitIndex[] = []; const flags: number[] = []; const order: number[] = []; + const key: number[] = []; let lastResidue = -1; - let componentMap: Map<string, Map<string, { flags: number, order: number }>> | undefined = void 0; + let componentMap: Map<string, Map<string, { flags: number, order: number, key: number }>> | undefined = void 0; let isWatery = true, isDictionaryBased = true, isSequenced = true; @@ -162,6 +167,7 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon atomB[atomB.length] = _bI; flags[flags.length] = se.flags; order[order.length] = se.order; + key[key.length] = se.rowIndex; if (!hasStructConn) structConnAdded.clear(); hasStructConn = true; @@ -230,6 +236,7 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon flag |= BondType.Flag.MetallicCoordination; } flags[flags.length] = flag; + key[key.length] = e.key; } continue; } @@ -243,6 +250,7 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon atomB[atomB.length] = _bI; order[order.length] = getIntraBondOrderFromTable(compId, atomIdA, label_atom_id.value(bI)); flags[flags.length] = (isMetal ? BondType.Flag.MetallicCoordination : BondType.Flag.Covalent) | BondType.Flag.Computed; + key[key.length] = -1; const seqIdB = label_seq_id.value(rbI); @@ -253,7 +261,7 @@ function findBonds(unit: Unit.Atomic, props: BondComputationProps): IntraUnitBon } const canRemap = isWatery || (isDictionaryBased && isSequenced); - return getGraph(atomA, atomB, order, flags, atomCount, canRemap); + return getGraph(atomA, atomB, order, flags, key, atomCount, canRemap); } function computeIntraUnitBonds(unit: Unit.Atomic, props?: Partial<BondComputationProps>) { diff --git a/src/mol-plugin-ui/structure/measurements.tsx b/src/mol-plugin-ui/structure/measurements.tsx index cd26069728850817262781ff669b27c229f9c573..f60269f9056abd696e2f4378d0f4313539f1966e 100644 --- a/src/mol-plugin-ui/structure/measurements.tsx +++ b/src/mol-plugin-ui/structure/measurements.tsx @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2020-2022 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> @@ -288,7 +288,12 @@ class MeasurementEntry extends PurePluginUIComponent<{ cell: StructureMeasuremen for (const loci of this.lociArray) { this.plugin.managers.interactivity.lociHighlights.highlight({ loci }, false); } - this.plugin.managers.interactivity.lociHighlights.highlight({ loci: this.props.cell.obj?.data.repr.getLoci()! }, false); + const reprLocis = this.props.cell.obj?.data.repr.getAllLoci(); + if (reprLocis) { + for (const loci of reprLocis) { + this.plugin.managers.interactivity.lociHighlights.highlight({ loci }, false); + } + } }; clearHighlight = () => { diff --git a/src/mol-plugin/behavior/static/state.ts b/src/mol-plugin/behavior/static/state.ts index b02ae119a5e34ec6981c8437eb2668eeed021ec6..e4270736da5816cc6b6b5ce7287a6878169b5b24 100644 --- a/src/mol-plugin/behavior/static/state.ts +++ b/src/mol-plugin/behavior/static/state.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -119,7 +119,9 @@ export function Highlight(ctx: PluginContext) { ctx.managers.interactivity.lociHighlights.highlight({ loci: Structure.Loci(cell.obj.data) }, false); } else if (cell && SO.isRepresentation3D(cell.obj)) { const { repr } = cell.obj.data; - ctx.managers.interactivity.lociHighlights.highlight({ loci: repr.getLoci(), repr }, false); + for (const loci of repr.getAllLoci()) { + ctx.managers.interactivity.lociHighlights.highlight({ loci, repr }, false); + } } else if (SO.Molecule.Structure.Selections.is(cell.obj)) { for (const entry of cell.obj.data) { ctx.managers.interactivity.lociHighlights.highlight({ loci: entry.loci }, false); diff --git a/src/mol-repr/representation.ts b/src/mol-repr/representation.ts index 246e34eb625d176da85f0221531742c4c93ca499..17da5156448dd9e75ff88ae586a1106c9386825d 100644 --- a/src/mol-repr/representation.ts +++ b/src/mol-repr/representation.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -154,8 +154,8 @@ interface Representation<D, P extends PD.Params = {}, S extends Representation.S createOrUpdate: (props?: Partial<PD.Values<P>>, data?: D) => Task<void> setState: (state: Partial<S>) => void setTheme: (theme: Theme) => void - /** If no pickingId is given, returns a Loci for the whole representation */ - getLoci: (pickingId?: PickingId) => ModelLoci + getLoci: (pickingId: PickingId) => ModelLoci + getAllLoci: () => ModelLoci[] mark: (loci: ModelLoci, action: MarkerAction) => boolean destroy: () => void } @@ -227,6 +227,7 @@ namespace Representation { setState: () => {}, setTheme: () => {}, getLoci: () => EmptyLoci, + getAllLoci: () => [], mark: () => false, destroy: () => {} }; @@ -327,7 +328,7 @@ namespace Representation { }, get state() { return currentState; }, get theme() { return currentTheme; }, - getLoci: (pickingId?: PickingId) => { + getLoci: (pickingId: PickingId) => { const { visuals } = currentProps; for (let i = 0, il = reprList.length; i < il; ++i) { if (!visuals || visuals.includes(reprMap[i])) { @@ -337,6 +338,16 @@ namespace Representation { } return EmptyLoci; }, + getAllLoci: () => { + const loci: ModelLoci[] = []; + const { visuals } = currentProps; + for (let i = 0, il = reprList.length; i < il; ++i) { + if (!visuals || visuals.includes(reprMap[i])) { + loci.push(...reprList[i].getAllLoci()); + } + } + return loci; + }, mark: (loci: ModelLoci, action: MarkerAction) => { let marked = false; for (let i = 0, il = reprList.length; i < il; ++i) { @@ -399,6 +410,10 @@ namespace Representation { // TODO return EmptyLoci; }, + getAllLoci: () => { + // TODO + return []; + }, mark: (loci: ModelLoci, action: MarkerAction) => { // TODO return false; diff --git a/src/mol-repr/shape/representation.ts b/src/mol-repr/shape/representation.ts index 803199b180ff825601d3c1c88b2d5c69eef1f6c7..45c4c68776db007b38a7e0568bd9c0f3c1581095 100644 --- a/src/mol-repr/shape/representation.ts +++ b/src/mol-repr/shape/representation.ts @@ -213,14 +213,16 @@ export function ShapeRepresentation<D, G extends Geometry, P extends Geometry.Pa get geometryVersion() { return geometryVersion; }, updated, createOrUpdate, - getLoci(pickingId?: PickingId) { - if (pickingId === undefined) return Shape.Loci(_shape); + getLoci(pickingId: PickingId) { const { objectId, groupId, instanceId } = pickingId; if (_renderObject && _renderObject.id === objectId) { return ShapeGroup.Loci(_shape, [{ ids: OrderedSet.ofSingleton(groupId), instance: instanceId }]); } return EmptyLoci; }, + getAllLoci() { + return [Shape.Loci(_shape)]; + }, mark(loci: Loci, action: MarkerAction) { if (!MarkerActions.is(_state.markerActions, action)) return false; if (ShapeGroup.isLoci(loci) || Shape.isLoci(loci)) { diff --git a/src/mol-repr/structure/complex-representation.ts b/src/mol-repr/structure/complex-representation.ts index f1edcbae4f58c5fe4938f2c4e2f2923ecf27b7a3..a50d04ae0c47bda3e592bfd93e2aa2b25dcc4de3 100644 --- a/src/mol-repr/structure/complex-representation.ts +++ b/src/mol-repr/structure/complex-representation.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 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> @@ -72,11 +72,14 @@ export function ComplexRepresentation<P extends StructureParams>(label: string, }); } - function getLoci(pickingId?: PickingId) { - if (pickingId === undefined) return Structure.Loci(_structure.target); + function getLoci(pickingId: PickingId) { return visual ? visual.getLoci(pickingId) : EmptyLoci; } + function getAllLoci() { + return [Structure.Loci(_structure.target)]; + } + function mark(loci: Loci, action: MarkerAction) { if (!_structure) return false; if (!MarkerActions.is(_state.markerActions, action)) return false; @@ -157,6 +160,7 @@ export function ComplexRepresentation<P extends StructureParams>(label: string, setState, setTheme, getLoci, + getAllLoci, mark, destroy }; diff --git a/src/mol-repr/structure/units-representation.ts b/src/mol-repr/structure/units-representation.ts index bc3130700ca2fe75673b471f9b4a3aa4ff634369..d7a2b6e0634e71156342aff34217ec67b23ac55b 100644 --- a/src/mol-repr/structure/units-representation.ts +++ b/src/mol-repr/structure/units-representation.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 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> @@ -185,8 +185,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct }); } - function getLoci(pickingId?: PickingId) { - if (pickingId === undefined) return Structure.Loci(_structure.target); + function getLoci(pickingId: PickingId) { let loci: Loci = EmptyLoci; visuals.forEach(({ visual }) => { const _loci = visual.getLoci(pickingId); @@ -195,6 +194,10 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct return loci; } + function getAllLoci() { + return [Structure.Loci(_structure.target)]; + } + function mark(loci: Loci, action: MarkerAction) { if (!_structure) return false; if (!MarkerActions.is(_state.markerActions, action)) return false; @@ -302,6 +305,7 @@ export function UnitsRepresentation<P extends StructureParams>(label: string, ct setState, setTheme, getLoci, + getAllLoci, mark, destroy }; diff --git a/src/mol-repr/volume/representation.ts b/src/mol-repr/volume/representation.ts index fae57da2554529ff0eee4d13a229d8cc6c956271..c6de383731b5f36a097cd321d19660c7e4502651 100644 --- a/src/mol-repr/volume/representation.ts +++ b/src/mol-repr/volume/representation.ts @@ -358,10 +358,12 @@ export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx: createOrUpdate, setState, setTheme, - getLoci: (pickingId?: PickingId): Loci => { - if (pickingId === undefined) return getLoci(_volume, _props); + getLoci: (pickingId: PickingId): Loci => { return visual ? visual.getLoci(pickingId) : EmptyLoci; }, + getAllLoci: (): Loci[] => { + return [getLoci(_volume, _props)]; + }, mark, destroy }; diff --git a/src/mol-script/language/symbol-table/structure-query.ts b/src/mol-script/language/symbol-table/structure-query.ts index 9e765f41649288a054b01a69b4a6a7d06b1c2bf6..209da4376e81c413caada96b2a2b544146e3de48 100644 --- a/src/mol-script/language/symbol-table/structure-query.ts +++ b/src/mol-script/language/symbol-table/structure-query.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2019 Mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 Mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -333,6 +333,7 @@ const bondProperty = { flags: bondProp(Types.BondFlags), order: bondProp(Type.Num), + key: bondProp(Type.Num), length: bondProp(Type.Num), atomA: bondProp(Types.ElementReference), atomB: bondProp(Types.ElementReference) @@ -356,5 +357,5 @@ export const structureQuery = { combinator, atomSet, atomProperty, - bondProperty: bondProperty + bondProperty }; \ No newline at end of file diff --git a/src/mol-script/runtime/query/table.ts b/src/mol-script/runtime/query/table.ts index dc32f889628e0958a518ed074a31cbb8390d4780..dcb18e9fef74f4744f7d7e92625e29943a1ca0e4 100644 --- a/src/mol-script/runtime/query/table.ts +++ b/src/mol-script/runtime/query/table.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2019 Mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 Mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -356,6 +356,7 @@ const symbols = [ // ============= BOND PROPERTIES ================ D(MolScript.structureQuery.bondProperty.order, (ctx, xs) => ctx.atomicBond.order), D(MolScript.structureQuery.bondProperty.flags, (ctx, xs) => ctx.atomicBond.type), + D(MolScript.structureQuery.bondProperty.key, (ctx, xs) => ctx.atomicBond.key), D(MolScript.structureQuery.bondProperty.atomA, (ctx, xs) => ctx.atomicBond.a), D(MolScript.structureQuery.bondProperty.atomB, (ctx, xs) => ctx.atomicBond.b), D(MolScript.structureQuery.bondProperty.length, (ctx, xs) => ctx.atomicBond.length),