Browse Source

optimized repr loci iteration, marking and extendToWholeChains

Alexander Rose 5 years ago
parent
commit
ed1ae71f71

+ 10 - 3
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);

+ 2 - 0
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

+ 23 - 13
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

+ 19 - 13
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);