diff --git a/src/mol-model/structure/structure/element.ts b/src/mol-model/structure/structure/element.ts index eb0cb0577633f1f545ad8b3267352537ab4ed4e0..ca472c6602a91541ee0776499be3031bf2c4da5c 100644 --- a/src/mol-model/structure/structure/element.ts +++ b/src/mol-model/structure/structure/element.ts @@ -282,7 +282,7 @@ namespace StructureElement { const elements: Loci['elements'][0][] = []; for (const lociElement of loci.elements) { - const newIndices: UnitIndex[] = []; + const _newIndices: UnitIndex[] = []; const unitElements = lociElement.unit.elements; const { index: chainIndex, offsets: chainOffsets } = getChainSegments(lociElement.unit) @@ -298,11 +298,18 @@ namespace StructureElement { for (let j = chainOffsets[cI], _j = chainOffsets[cI + 1]; j < _j; j++) { const idx = OrderedSet.indexOf(unitElements, j); - if (idx >= 0) newIndices[newIndices.length] = idx as UnitIndex; + if (idx >= 0) _newIndices[_newIndices.length] = idx as UnitIndex; } } - elements[elements.length] = { unit: lociElement.unit, indices: SortedArray.ofSortedArray(newIndices) }; + let newIndices: OrderedSet<UnitIndex> + if (_newIndices.length > 12 && _newIndices[_newIndices.length - 1] - _newIndices[0] === _newIndices.length - 1) { + newIndices = Interval.ofRange(_newIndices[0], _newIndices[_newIndices.length - 1]) + } else { + newIndices = SortedArray.ofSortedArray(_newIndices) + } + + elements[elements.length] = { unit: lociElement.unit, indices: newIndices }; } return Loci(loci.structure, elements); diff --git a/src/mol-repr/structure/units-representation.ts b/src/mol-repr/structure/units-representation.ts index cbc6eb0004feb8353e6273224624dbea0d96d2ca..63e2066044b5ee970df11f519088350dbf53050c 100644 --- a/src/mol-repr/structure/units-representation.ts +++ b/src/mol-repr/structure/units-representation.ts @@ -169,8 +169,10 @@ export function UnitsRepresentation<P extends UnitsParams>(label: string, ctx: R if (!Structure.areParentsEquivalent(loci.structure, _structure)) return false if (StructureElement.isLoci(loci)) { loci = StructureElement.Loci.remap(loci, _structure) + if (loci.elements.length === 0) return false } else if (Link.isLoci(loci)) { loci = Link.remapLoci(loci, _structure) + if (loci.links.length === 0) return false } visuals.forEach(({ visual }) => { changed = visual.mark(loci, action) || changed diff --git a/src/mol-repr/structure/visual/util/nucleotide.ts b/src/mol-repr/structure/visual/util/nucleotide.ts index e3d968dea150cd69f235c9075c308792f9e0cb25..9d9787fb63382ba5f69e82dd17ce5e639226808a 100644 --- a/src/mol-repr/structure/visual/util/nucleotide.ts +++ b/src/mol-repr/structure/visual/util/nucleotide.ts @@ -41,6 +41,10 @@ export function getNucleotideElementLoci(pickingId: PickingId, structureGroup: S return EmptyLoci } +/** + * Mark a nucleotide element (e.g. part of a cartoon block) + * - mark only when all its residue's elements are in a loci + */ export function eachNucleotideElement(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) { let changed = false if (!StructureElement.isLoci(loci)) return false @@ -56,19 +60,25 @@ export function eachNucleotideElement(loci: Loci, structureGroup: StructureGroup const unitIdx = group.unitIndexMap.get(e.unit.id) const eUnit = e.unit if (unitIdx !== undefined && Unit.isAtomic(eUnit)) { - // TODO optimized implementation for intervals - OrderedSet.forEach(e.indices, v => { - const rI = index[elements[v]] - const unitIndexMin = OrderedSet.findPredecessorIndex(elements, offsets[rI]) - const unitIndexMax = OrderedSet.findPredecessorIndex(elements, offsets[rI + 1] - 1) - const unitIndexInterval = Interval.ofRange(unitIndexMin, unitIndexMax) - if (!OrderedSet.isSubset(e.indices, unitIndexInterval)) return - const eI = traceElementIndex[rI] - const idx = OrderedSet.indexOf(eUnit.nucleotideElements, eI) - if (idx !== -1) { - if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true - } - }) + // TODO optimized implementation for intervals covering only part of the unit + if (Interval.is(e.indices) && Interval.start(e.indices) === 0 && Interval.end(e.indices) === e.unit.elements.length) { + const start = unitIdx * groupCount; + const end = unitIdx * groupCount + groupCount; + if (apply(Interval.ofBounds(start, end))) changed = true + } else { + OrderedSet.forEach(e.indices, v => { + const rI = index[elements[v]] + const unitIndexMin = OrderedSet.findPredecessorIndex(elements, offsets[rI]) + const unitIndexMax = OrderedSet.findPredecessorIndex(elements, offsets[rI + 1] - 1) + const unitIndexInterval = Interval.ofRange(unitIndexMin, unitIndexMax) + if (!OrderedSet.isSubset(e.indices, unitIndexInterval)) return + const eI = traceElementIndex[rI] + const idx = OrderedSet.indexOf(eUnit.nucleotideElements, eI) + if (idx !== -1) { + if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true + } + }) + } } } return changed diff --git a/src/mol-repr/structure/visual/util/polymer.ts b/src/mol-repr/structure/visual/util/polymer.ts index 401626df03ae2bbeb6b5def9eb02c0c108c8915d..33f99c023eeaf4d6d8d94483a70b56c0023a4360 100644 --- a/src/mol-repr/structure/visual/util/polymer.ts +++ b/src/mol-repr/structure/visual/util/polymer.ts @@ -104,19 +104,25 @@ export function eachPolymerElement(loci: Loci, structureGroup: StructureGroup, a const unitIdx = group.unitIndexMap.get(e.unit.id) if (unitIdx !== undefined) { if (Unit.isAtomic(e.unit)) { - // TODO optimized implementation for intervals - OrderedSet.forEach(e.indices, v => { - const rI = index[elements[v]] - const unitIndexMin = OrderedSet.findPredecessorIndex(elements, offsets[rI]) - const unitIndexMax = OrderedSet.findPredecessorIndex(elements, offsets[rI + 1] - 1) - const unitIndexInterval = Interval.ofRange(unitIndexMin, unitIndexMax) - if (!OrderedSet.isSubset(e.indices, unitIndexInterval)) return - const eI = traceElementIndex[rI] - const idx = OrderedSet.indexOf(e.unit.polymerElements, eI) - if (idx !== -1) { - if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true - } - }) + // TODO optimized implementation for intervals covering only part of the unit + if (Interval.is(e.indices) && Interval.start(e.indices) === 0 && Interval.end(e.indices) === e.unit.elements.length) { + const start = unitIdx * groupCount; + const end = unitIdx * groupCount + groupCount; + if (apply(Interval.ofBounds(start, end))) changed = true + } else { + OrderedSet.forEach(e.indices, v => { + const rI = index[elements[v]] + const unitIndexMin = OrderedSet.findPredecessorIndex(elements, offsets[rI]) + const unitIndexMax = OrderedSet.findPredecessorIndex(elements, offsets[rI + 1] - 1) + const unitIndexInterval = Interval.ofRange(unitIndexMin, unitIndexMax) + if (!OrderedSet.isSubset(e.indices, unitIndexInterval)) return + const eI = traceElementIndex[rI] + const idx = OrderedSet.indexOf(e.unit.polymerElements, eI) + if (idx !== -1) { + if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true + } + }) + } } else { if (Interval.is(e.indices)) { const start = unitIdx * groupCount + Interval.start(e.indices);