diff --git a/src/mol-model/structure/structure/element.ts b/src/mol-model/structure/structure/element.ts index 6c84a030a254b689d0f89e41bd0dad9f0ed00bbe..80096d9695cff7950a898119c9da95470acf5824 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 3c115c376c6db742802dc8ec80d2ef5ab37ba2bc..8ea138d4d1d8fc8ef0d9e634513c5bb6a4064c13 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 7124442af98c2d3847ca631ec7982364b17e318b..711e98eb429477d22f20cc1ce97e8212823dfe26 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 5c35ab7216125842e4cccc7a43963e91f5543651..b5adcfe5c757b0c2cfa0c53f962283722c7e1492 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 30aae0eb7795003e57fe2a236054605a2ebf8a4c..b540d9d49a79f89f98d0d1f3ff0e7bd24a66d467 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 155ca3c165cd57a55e49277423f8aa57e68a8d16..b90daa355fa7a586ed872f7d689db3cc334318d5 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 37f0bb0ba619ecbb911ccc7928097534a55827b9..204015f873524fc7e1d8a6f83fd264ca189a2a6b 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 af8f091cd3620a2716a0172a14b15ec53fd38b62..55fe6843a1468b8be77a3b04168ad96e43e38d62 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 ec1a76717826923089a8fad264e99288d3c05742..e492772ed8429eb1c37bf32a7265ebda46f3345a 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 dd3d32c503b3d28b347b95799a03906b14346ec9..5406facc48d095ae677a67a8642349011c59acb2 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 325e631ca49d9e920bb6fa73bf83221c8e02edd2..b185f488350c3ea99ec4eacd04e32d1f1cb39419 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)