From 1d502cbb54e7fef134d2390300b84f32f361cbc6 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alex.rose@rcsb.org> Date: Thu, 25 Jul 2019 13:49:04 -0700 Subject: [PATCH] loci remapping --- src/mol-model/structure/structure/element.ts | 27 ++++++++++++++++--- .../structure/structure/unit/links.ts | 23 ++++++++++++++++ .../visual/carbohydrate-link-cylinder.ts | 2 ++ .../visual/carbohydrate-symbol-mesh.ts | 1 + .../carbohydrate-terminal-link-cylinder.ts | 2 ++ .../visual/cross-link-restraint-cylinder.ts | 1 + .../visual/inter-unit-link-cylinder.ts | 2 ++ .../visual/intra-unit-link-cylinder.ts | 2 ++ src/mol-repr/structure/visual/util/element.ts | 1 + .../structure/visual/util/nucleotide.ts | 1 + src/mol-repr/structure/visual/util/polymer.ts | 3 +++ 11 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/mol-model/structure/structure/element.ts b/src/mol-model/structure/structure/element.ts index 6c84a030a..80096d969 100644 --- a/src/mol-model/structure/structure/element.ts +++ b/src/mol-model/structure/structure/element.ts @@ -141,10 +141,29 @@ namespace StructureElement { export function remap(loci: Loci, structure: Structure): Loci { if (structure === loci.structure) return loci - return Loci(structure, loci.elements.map(e => ({ - unit: structure.unitMap.get(e.unit.id)!, - indices: e.indices - }))); + const elements: Loci['elements'][0][] = []; + loci.elements.forEach(e => { + const unit = structure.unitMap.get(e.unit.id) + if (!unit) return + + if (SortedArray.areEqual(e.unit.elements, unit.elements)) { + elements.push({ unit, indices: e.indices }) + } else { + // TODO optimize + const indices: UnitIndex[] = [] + OrderedSet.forEach(e.indices, (v) => { + const eI = e.unit.elements[v] + const uI = SortedArray.indexOf(unit.elements, eI) as UnitIndex | -1 + if (uI !== -1) indices.push(uI) + }) + elements.push({ + unit, + indices: SortedArray.ofSortedArray(indices) + }) + } + }); + + return Loci(structure, elements); } export function union(xs: Loci, ys: Loci): Loci { diff --git a/src/mol-model/structure/structure/unit/links.ts b/src/mol-model/structure/structure/unit/links.ts index 3c115c376..8ea138d4d 100644 --- a/src/mol-model/structure/structure/unit/links.ts +++ b/src/mol-model/structure/structure/unit/links.ts @@ -62,6 +62,29 @@ namespace Link { return true } + export function remapLoci(loci: Loci, structure: Structure): Loci { + if (structure === loci.structure) return loci + + const links: Loci['links'][0][] = []; + loci.links.forEach(l => { + const unitA = structure.unitMap.get(l.aUnit.id) + if (!unitA) return + const unitB = structure.unitMap.get(l.bUnit.id) + if (!unitB) return + + const elementA = l.aUnit.elements[l.aIndex] + const indexA = SortedArray.indexOf(unitA.elements, elementA) as StructureElement.UnitIndex | -1 + if (indexA === -1) return + const elementB = l.bUnit.elements[l.bIndex] + const indexB = SortedArray.indexOf(unitB.elements, elementB) as StructureElement.UnitIndex | -1 + if (indexB === -1) return + + links.push(Location(unitA, indexA, unitB, indexB)) + }); + + return Loci(structure, links); + } + export function toStructureElementLoci(loci: Loci): StructureElement.Loci { const elements: StructureElement.Loci['elements'][0][] = [] const map = new Map<number, number[]>() diff --git a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts index 7124442af..711e98eb4 100644 --- a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts +++ b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts @@ -120,6 +120,7 @@ function eachCarbohydrateLink(loci: Loci, structure: Structure, apply: (interval let changed = false if (Link.isLoci(loci)) { if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = Link.remapLoci(loci, structure) const { getLinkIndex } = structure.carbohydrates for (const l of loci.links) { const idx = getLinkIndex(l.aUnit, l.aUnit.elements[l.aIndex], l.bUnit, l.bUnit.elements[l.bIndex]) @@ -129,6 +130,7 @@ function eachCarbohydrateLink(loci: Loci, structure: Structure, apply: (interval } } else if (StructureElement.isLoci(loci)) { if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = StructureElement.Loci.remap(loci, structure) // TODO mark link only when both of the link elements are in a StructureElement.Loci const { getElementIndex, getLinkIndices, elements } = structure.carbohydrates for (const e of loci.elements) { diff --git a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts index 5c35ab721..b5adcfe5c 100644 --- a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts +++ b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts @@ -197,6 +197,7 @@ function eachCarbohydrate(loci: Loci, structure: Structure, apply: (interval: In let changed = false if (!StructureElement.isLoci(loci)) return false if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = StructureElement.Loci.remap(loci, structure) for (const e of loci.elements) { // TODO make more efficient by handling/grouping `e.indices` by residue index // TODO only call apply when the full alt-residue of the unit is part of `e` diff --git a/src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts b/src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts index 30aae0eb7..b540d9d49 100644 --- a/src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts +++ b/src/mol-repr/structure/visual/carbohydrate-terminal-link-cylinder.ts @@ -134,6 +134,7 @@ function eachTerminalLink(loci: Loci, structure: Structure, apply: (interval: In let changed = false if (Link.isLoci(loci)) { if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = Link.remapLoci(loci, structure) for (const l of loci.links) { const idx = getTerminalLinkIndex(l.aUnit, l.aUnit.elements[l.aIndex], l.bUnit, l.bUnit.elements[l.bIndex]) if (idx !== undefined) { @@ -142,6 +143,7 @@ function eachTerminalLink(loci: Loci, structure: Structure, apply: (interval: In } } else if (StructureElement.isLoci(loci)) { if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = StructureElement.Loci.remap(loci, structure) // TODO mark link only when both of the link elements are in a StructureElement.Loci const { getElementIndex, getTerminalLinkIndices, elements } = structure.carbohydrates for (const e of loci.elements) { diff --git a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts index 155ca3c16..b90daa355 100644 --- a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts +++ b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts @@ -108,6 +108,7 @@ function eachCrossLink(loci: Loci, structure: Structure, apply: (interval: Inter let changed = false if (Link.isLoci(loci)) { if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = Link.remapLoci(loci, structure) for (const b of loci.links) { const indices = crossLinks.getPairIndices(b.aIndex, b.aUnit, b.bIndex, b.bUnit) if (indices) { diff --git a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts index 37f0bb0ba..204015f87 100644 --- a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts @@ -98,6 +98,7 @@ function eachLink(loci: Loci, structure: Structure, apply: (interval: Interval) let changed = false if (Link.isLoci(loci)) { if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = Link.remapLoci(loci, structure) for (const b of loci.links) { const idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit) if (idx !== -1) { @@ -106,6 +107,7 @@ function eachLink(loci: Loci, structure: Structure, apply: (interval: Interval) } } else if (StructureElement.isLoci(loci)) { if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = StructureElement.Loci.remap(loci, structure) // TODO mark link only when both of the link elements are in a StructureElement.Loci for (const e of loci.elements) { OrderedSet.forEach(e.indices, v => { diff --git a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts index af8f091cd..55fe6843a 100644 --- a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts @@ -122,6 +122,7 @@ function eachLink(loci: Loci, structureGroup: StructureGroup, apply: (interval: if (Link.isLoci(loci)) { const { structure, group } = structureGroup if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = Link.remapLoci(loci, structure) const unit = group.units[0] if (!Unit.isAtomic(unit)) return false const groupCount = unit.links.edgeCount * 2 @@ -137,6 +138,7 @@ function eachLink(loci: Loci, structureGroup: StructureGroup, apply: (interval: } else if (StructureElement.isLoci(loci)) { const { structure, group } = structureGroup if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = StructureElement.Loci.remap(loci, structure) const unit = group.units[0] if (!Unit.isAtomic(unit)) return false const groupCount = unit.links.edgeCount * 2 diff --git a/src/mol-repr/structure/visual/util/element.ts b/src/mol-repr/structure/visual/util/element.ts index ec1a76717..e492772ed 100644 --- a/src/mol-repr/structure/visual/util/element.ts +++ b/src/mol-repr/structure/visual/util/element.ts @@ -73,6 +73,7 @@ export function eachElement(loci: Loci, structureGroup: StructureGroup, apply: ( if (!StructureElement.isLoci(loci)) return false const { structure, group } = structureGroup if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = StructureElement.Loci.remap(loci, structure) const elementCount = group.elements.length for (const e of loci.elements) { const unitIdx = group.unitIndexMap.get(e.unit.id) diff --git a/src/mol-repr/structure/visual/util/nucleotide.ts b/src/mol-repr/structure/visual/util/nucleotide.ts index dd3d32c50..5406facc4 100644 --- a/src/mol-repr/structure/visual/util/nucleotide.ts +++ b/src/mol-repr/structure/visual/util/nucleotide.ts @@ -46,6 +46,7 @@ export function eachNucleotideElement(loci: Loci, structureGroup: StructureGroup if (!StructureElement.isLoci(loci)) return false const { structure, group } = structureGroup if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = StructureElement.Loci.remap(loci, structure) const unit = group.units[0] if (!Unit.isAtomic(unit)) return false const { nucleotideElements, model, elements } = unit diff --git a/src/mol-repr/structure/visual/util/polymer.ts b/src/mol-repr/structure/visual/util/polymer.ts index 325e631ca..b185f4883 100644 --- a/src/mol-repr/structure/visual/util/polymer.ts +++ b/src/mol-repr/structure/visual/util/polymer.ts @@ -96,6 +96,7 @@ export function eachPolymerElement(loci: Loci, structureGroup: StructureGroup, a if (!StructureElement.isLoci(loci)) return false const { structure, group } = structureGroup if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = StructureElement.Loci.remap(loci, structure) const { polymerElements, model, elements } = group.units[0] const { index, offsets } = model.atomicHierarchy.residueAtomSegments const { traceElementIndex } = model.atomicHierarchy.derived.residue @@ -157,6 +158,7 @@ export function eachPolymerGapElement(loci: Loci, structureGroup: StructureGroup if (Link.isLoci(loci)) { const { structure, group } = structureGroup if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = Link.remapLoci(loci, structure) const groupCount = group.units[0].gapElements.length for (const b of loci.links) { const unitIdx = group.unitIndexMap.get(b.aUnit.id) @@ -171,6 +173,7 @@ export function eachPolymerGapElement(loci: Loci, structureGroup: StructureGroup } else if (StructureElement.isLoci(loci)) { const { structure, group } = structureGroup if (!Structure.areParentsEquivalent(loci.structure, structure)) return false + loci = StructureElement.Loci.remap(loci, structure) const groupCount = group.units[0].gapElements.length for (const e of loci.elements) { const unitIdx = group.unitIndexMap.get(e.unit.id) -- GitLab