Browse Source

improved element loci remap, added SortedArray.indexOfInRange

Alexander Rose 5 years ago
parent
commit
3cdfd04048

+ 3 - 1
src/mol-data/int/impl/sorted-array.ts

@@ -47,8 +47,10 @@ export function indexOf(xs: Nums, v: number) {
     return l === 0 ? -1 : xs[0] <= v && v <= xs[l - 1] ? binarySearchRange(xs, v, 0, l) : -1;
 }
 export function indexOfInInterval(xs: Nums, v: number, bounds: Interval) {
+    return indexOfInRange(xs, v, Interval.start(bounds), Interval.end(bounds))
+}
+export function indexOfInRange(xs: Nums, v: number, s: number, e: number) {
     const l = xs.length;
-    const s = Interval.start(bounds), e = Interval.end(bounds);
     return l === 0 || e <= s ? -1 : xs[s] <= v && v <= xs[e - 1] ? binarySearchRange(xs, v, s, e) : -1;
 }
 export function has(xs: Nums, v: number) { return indexOf(xs, v) >= 0; }

+ 1 - 0
src/mol-data/int/sorted-array.ts

@@ -22,6 +22,7 @@ namespace SortedArray {
     /** Returns the index of `x` in `set` or -1 if not found. */
     export const indexOf: <T extends number = number>(array: SortedArray<T>, x: T) => number = Impl.indexOf as any;
     export const indexOfInInterval: <T extends number = number>(array: SortedArray<T>, x: number, bounds: Interval) => number = Impl.indexOfInInterval as any;
+    export const indexOfInRange: <T extends number = number>(array: SortedArray<T>, x: number, start: number, end: number) => number = Impl.indexOfInRange as any;
 
     /** Returns `array[0]` */
     export const start: <T extends number = number>(array: SortedArray<T>) => T = Impl.start as any;

+ 21 - 11
src/mol-model/structure/structure/element.ts

@@ -137,23 +137,33 @@ namespace StructureElement {
 
             const elements: Loci['elements'][0][] = [];
             loci.elements.forEach(e => {
+                if (!structure.unitMap.has(e.unit.id)) return
                 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 _indices: UnitIndex[] = []
+                    const end = unit.elements.length
+                    let start = 0
+                    for (let i = 0; i < OrderedSet.size(e.indices); ++i) {
+                        const v = OrderedSet.getAt(e.indices, i)
                         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)
-                    })
+                        const uI = SortedArray.indexOfInRange(unit.elements, eI, start, end) as UnitIndex | -1
+                        if (uI !== -1) {
+                            _indices.push(uI)
+                            start = uI
+                        }
+                    }
+
+                    let indices: OrderedSet<UnitIndex>
+                    if (_indices.length > 12 && _indices[_indices.length - 1] - _indices[0] === _indices.length - 1) {
+                        indices = Interval.ofRange(_indices[0], _indices[_indices.length - 1])
+                    } else {
+                        indices = SortedArray.ofSortedArray(_indices)
+                    }
+
+                    elements.push({ unit, indices })
                 }
             });