Browse Source

wip, nominal Element and Element.Index

David Sehnal 6 years ago
parent
commit
e0283d88c7

+ 23 - 23
src/mol-data/int/ordered-set.ts

@@ -10,39 +10,39 @@ import SortedArray from './sorted-array';
 
 namespace OrderedSet {
     export const Empty: OrderedSet = Base.Empty as any;
-    export const ofSingleton: (value: number) => OrderedSet = Base.ofSingleton as any;
-    export const ofRange: (min: number, max: number) => OrderedSet = Base.ofRange as any;
-    export const ofBounds: (min: number, max: number) => OrderedSet = Base.ofBounds as any;
+    export const ofSingleton: <T extends number = number>(value: T) => OrderedSet<T> = Base.ofSingleton as any;
+    export const ofRange: <T extends number = number>(min: T, max: T) => OrderedSet<T> = Base.ofRange as any;
+    export const ofBounds: <T extends number = number>(min: T, max: T) => OrderedSet<T> = Base.ofBounds as any;
     /** It is the responsibility of the caller to ensure the array is sorted and contains unique values. */
-    export const ofSortedArray: (xs: ArrayLike<number>) => OrderedSet = Base.ofSortedArray as any;
+    export const ofSortedArray: <T extends number = number>(xs: ArrayLike<T>) => OrderedSet<T> = Base.ofSortedArray as any;
 
-    export const has: (set: OrderedSet, x: number) => boolean = Base.has as any;
-    export const indexOf: (set: OrderedSet, x: number) => number = Base.indexOf as any;
-    export const getAt: (set: OrderedSet, i: number) => number = Base.getAt as any;
+    export const has: <T extends number = number>(set: OrderedSet<T>, x: T) => boolean = Base.has as any;
+    export const indexOf: <T extends number = number>(set: OrderedSet<T>, x: T) => number = Base.indexOf as any;
+    export const getAt: <T extends number = number>(set: OrderedSet<T>, i: number) => T = Base.getAt as any;
 
-    export const min: (set: OrderedSet) => number = Base.min as any;
-    export const max: (set: OrderedSet) => number = Base.max as any;
-    export const size: (set: OrderedSet) => number = Base.size as any;
-    export const hashCode: (set: OrderedSet) => number = Base.hashCode as any;
+    export const min: <T extends number = number>(set: OrderedSet<T>) => T = Base.min as any;
+    export const max: <T extends number = number>(set: OrderedSet<T>) => T = Base.max as any;
+    export const size: <T extends number = number>(set: OrderedSet<T>) => number = Base.size as any;
+    export const hashCode: <T extends number = number>(set: OrderedSet<T>) => number = Base.hashCode as any;
 
-    export const areEqual: (a: OrderedSet, b: OrderedSet) => boolean = Base.areEqual as any;
-    export const areIntersecting: (a: OrderedSet, b: OrderedSet) => boolean = Base.areIntersecting as any;
-    export const isSubset: (a: OrderedSet, b: OrderedSet) => boolean = Base.isSubset as any;
+    export const areEqual: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => boolean = Base.areEqual as any;
+    export const areIntersecting: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => boolean = Base.areIntersecting as any;
+    export const isSubset: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => boolean = Base.isSubset as any;
 
-    export const union: (a: OrderedSet, b: OrderedSet) => OrderedSet = Base.union as any;
-    export const intersect: (a: OrderedSet, b: OrderedSet) => OrderedSet = Base.intersect as any;
-    export const subtract: (a: OrderedSet, b: OrderedSet) => OrderedSet = Base.subtract as any;
+    export const union: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => OrderedSet<T> = Base.union as any;
+    export const intersect: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => OrderedSet<T> = Base.intersect as any;
+    export const subtract: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => OrderedSet<T> = Base.subtract as any;
 
-    export const findPredecessorIndex: (set: OrderedSet, x: number) => number = Base.findPredecessorIndex as any;
-    export const findPredecessorIndexInInterval: (set: OrderedSet, x: number, range: Interval) => number = Base.findPredecessorIndexInInterval as any;
-    export const findRange: (set: OrderedSet, min: number, max: number) => Interval = Base.findRange as any;
+    export const findPredecessorIndex: <T extends number = number>(set: OrderedSet<T>, x: number) => number = Base.findPredecessorIndex as any;
+    export const findPredecessorIndexInInterval: <T extends number = number>(set: OrderedSet<T>, x: T, range: Interval) => number = Base.findPredecessorIndexInInterval as any;
+    export const findRange: <T extends number = number>(set: OrderedSet<T>, min: T, max: T) => Interval = Base.findRange as any;
 
-    export function forEach<Ctx>(set: OrderedSet, f: (v: number, i: number, ctx: Ctx) => void, ctx?: Ctx): Ctx {
-        return Base.forEach(set as any, f, ctx);
+    export function forEach<T extends number, Ctx>(set: OrderedSet<T>, f: (v: T, i: number, ctx: Ctx) => void, ctx?: Ctx): Ctx {
+        return Base.forEach(set as any, f as any, ctx);
     }
 }
 
-type OrderedSet = Interval | SortedArray
+type OrderedSet<T extends number = number> = Interval | SortedArray<T>
 //{ '@type': 'int-interval' | 'int-sorted-array' }
 
 export default OrderedSet

+ 35 - 33
src/mol-data/int/sorted-array.ts

@@ -9,43 +9,45 @@ import Interval from './interval'
 
 namespace SortedArray {
     export const Empty: SortedArray = Impl.Empty as any;
-    export const ofUnsortedArray: (xs: ArrayLike<number>) => SortedArray = Impl.ofUnsortedArray as any;
-    export const ofSingleton: (v: number) => SortedArray = Impl.ofSingleton as any;
-    export const ofSortedArray: (xs: ArrayLike<number>) => SortedArray = Impl.ofSortedArray as any;
+    export const ofUnsortedArray: <T extends number = number>(xs: ArrayLike<number>) => SortedArray<T> = Impl.ofUnsortedArray as any;
+    export const ofSingleton: <T extends number = number>(v: number) => SortedArray<T> = Impl.ofSingleton as any;
+    export const ofSortedArray: <T extends number = number>(xs: ArrayLike<number>) => SortedArray<T> = Impl.ofSortedArray as any;
     // create sorted array [min, max] (it DOES contain the max value)
-    export const ofRange: (min: number, max: number) => SortedArray = Impl.ofRange as any;
+    export const ofRange: <T extends number = number>(min: T, max: T) => SortedArray<T> = Impl.ofRange as any;
     // create sorted array [min, max) (it DOES not contain the max value)
-    export const ofBounds: (min: number, max: number) => SortedArray = (min, max) => Impl.ofRange(min, max - 1) as any;
-    export const is: (v: any) => v is Interval = Impl.is as any;
-
-    export const has: (array: SortedArray, x: number) => boolean = Impl.has as any;
-    export const indexOf: (array: SortedArray, x: number) => number = Impl.indexOf as any;
-    export const indexOfInInterval: (array: SortedArray, x: number, bounds: Interval) => number = Impl.indexOfInInterval as any;
-
-    export const start: (array: SortedArray) => number = Impl.start as any;
-    export const end: (array: SortedArray) => number = Impl.end as any;
-    export const min: (array: SortedArray) => number = Impl.min as any;
-    export const max: (array: SortedArray) => number = Impl.max as any;
-    export const size: (array: SortedArray) => number = Impl.size as any;
-    export const hashCode: (array: SortedArray) => number = Impl.hashCode as any;
-
-    export const areEqual: (a: SortedArray, b: SortedArray) => boolean = Impl.areEqual as any;
-    export const areIntersecting: (a: SortedArray, b: SortedArray) => boolean = Impl.areIntersecting as any;
-    export const isSubset: (a: SortedArray, b: SortedArray) => boolean = Impl.isSubset as any;
-
-    export const union: (a: SortedArray, b: SortedArray) => SortedArray = Impl.union as any;
-    export const intersect: (a: SortedArray, b: SortedArray) => SortedArray = Impl.intersect as any;
-    export const subtract: (a: SortedArray, b: SortedArray) => SortedArray = Impl.subtract as any;
-
-    export const findPredecessorIndex: (array: SortedArray, x: number) => number = Impl.findPredecessorIndex as any;
-    export const findPredecessorIndexInInterval: (array: SortedArray, x: number, bounds: Interval) => number = Impl.findPredecessorIndexInInterval as any;
-    export const findRange: (array: SortedArray, min: number, max: number) => Interval = Impl.findRange as any;
-
-    export const deduplicate: (array: SortedArray) => SortedArray = Impl.deduplicate as any;
+    export const ofBounds: <T extends number = number>(min: T, max: T) => SortedArray<T> = (min, max) => Impl.ofRange(min, max - 1) as any;
+    export const is: <T extends number = number>(v: any) => v is SortedArray<T> = Impl.is as any;
+
+    export const has: <T extends number = number>(array: SortedArray<T>, x: T) => boolean = Impl.has as any;
+    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;
+
+    // array[0]
+    export const start: <T extends number = number>(array: SortedArray<T>) => T = Impl.start as any;
+    // array[array.length - 1] + 1
+    export const end: <T extends number = number>(array: SortedArray<T>) => T = Impl.end as any;
+    export const min: <T extends number = number>(array: SortedArray<T>) => T = Impl.min as any;
+    export const max: <T extends number = number>(array: SortedArray<T>) => T = Impl.max as any;
+    export const size: <T extends number = number>(array: SortedArray<T>) => number = Impl.size as any;
+    export const hashCode: <T extends number = number>(array: SortedArray<T>) => number = Impl.hashCode as any;
+
+    export const areEqual: <T extends number = number>(a: SortedArray<T>, b: SortedArray<T>) => boolean = Impl.areEqual as any;
+    export const areIntersecting: <T extends number = number>(a: SortedArray<T>, b: SortedArray<T>) => boolean = Impl.areIntersecting as any;
+    export const isSubset: <T extends number = number>(a: SortedArray<T>, b: SortedArray<T>) => boolean = Impl.isSubset as any;
+
+    export const union: <T extends number = number>(a: SortedArray<T>, b: SortedArray<T>) => SortedArray<T> = Impl.union as any;
+    export const intersect: <T extends number = number>(a: SortedArray<T>, b: SortedArray<T>) => SortedArray<T> = Impl.intersect as any;
+    export const subtract: <T extends number = number>(a: SortedArray<T>, b: SortedArray<T>) => SortedArray<T> = Impl.subtract as any;
+
+    export const findPredecessorIndex: <T extends number = number>(array: SortedArray<T>, x: T) => number = Impl.findPredecessorIndex as any;
+    export const findPredecessorIndexInInterval: <T extends number = number>(array: SortedArray<T>, x: T, bounds: Interval) => number = Impl.findPredecessorIndexInInterval as any;
+    export const findRange: <T extends number = number>(array: SortedArray<T>, min: T, max: T) => Interval = Impl.findRange as any;
+
+    export const deduplicate: <T extends number = number>(array: SortedArray<T>) => SortedArray<T> = Impl.deduplicate as any;
     /** Returns indices of xs in the array. E.g. indicesOf([10, 11, 12], [10, 12]) ==> [0, 2] */
-    export const indicesOf: (array: SortedArray, xs: SortedArray) => SortedArray = Impl.indicesOf as any;
+    export const indicesOf: <T extends number = number, I extends number = number>(array: SortedArray<T>, xs: SortedArray<T>) => SortedArray<I> = Impl.indicesOf as any;
 }
 
-interface SortedArray extends ArrayLike<number> { '@type': 'int-sorted-array' }
+interface SortedArray<T extends number = number> extends ArrayLike<T> { '@type': 'int-sorted-array' }
 
 export default SortedArray

+ 1 - 1
src/mol-geo/representation/structure/point.ts

@@ -161,7 +161,7 @@ export default function PointUnitsRepresentation(): UnitsRepresentation<PointPro
             const { objectId, instanceId, elementId } = pickingId
             if (points.id === objectId) {
                 const unit = currentGroup.units[instanceId]
-                const indices = OrderedSet.ofSingleton(elementId)
+                const indices = OrderedSet.ofSingleton(elementId as Element.Index)
                 return Element.Loci([{ unit, indices }])
             }
             return EmptyLoci

+ 1 - 1
src/mol-geo/representation/structure/spacefill.ts

@@ -149,7 +149,7 @@ export default function SpacefillUnitsRepresentation(): UnitsRepresentation<Spac
             const { objectId, instanceId, elementId } = pickingId
             if (spheres.id === objectId) {
                 const unit = currentGroup.units[instanceId]
-                const indices = OrderedSet.ofSingleton(elementId);
+                const indices = OrderedSet.ofSingleton(elementId as Element.Index);
                 return Element.Loci([{ unit, indices }])
             }
             return EmptyLoci

+ 2 - 2
src/mol-model/structure/query/modifiers.ts

@@ -6,7 +6,7 @@
 
 import { Segmentation } from 'mol-data/int';
 import { RuntimeContext } from 'mol-task';
-import { Structure, Unit } from '../structure';
+import { Structure, Unit, Element } from '../structure';
 import Query from './query';
 import Selection from './selection';
 import { UniqueStructuresBuilder } from './utils/builders';
@@ -29,7 +29,7 @@ function getWholeResidues(ctx: RuntimeContext, source: Structure, structure: Str
         while (residuesIt.hasNext) {
             const rI = residuesIt.move().index;
             for (let j = residueSegments.segments[rI], _j = residueSegments.segments[rI + 1]; j < _j; j++) {
-                builder.addElement(j);
+                builder.addElement(j as Element);
             }
         }
         builder.commitUnit();

+ 2 - 2
src/mol-model/structure/query/selection.ts

@@ -36,12 +36,12 @@ namespace Selection {
     }
 
     export function toLoci(sel: Selection): Element.Loci {
-        const loci: { unit: Unit, indices: OrderedSet }[] = [];
+        const loci: { unit: Unit, indices: Element.Indices }[] = [];
         const { unitMap } = sel.source;
 
         for (const unit of unionStructure(sel).units) {
             if (unit === unitMap.get(unit.id)) {
-                loci[loci.length] = { unit, indices: OrderedSet.ofBounds(0, unit.elements.length) };
+                loci[loci.length] = { unit, indices: OrderedSet.ofBounds(0 as Element.Index, unit.elements.length as Element.Index) };
             } else {
                 loci[loci.length] = {
                     unit,

+ 1 - 1
src/mol-model/structure/query/utils/builders.ts

@@ -36,7 +36,7 @@ export class LinearGroupingBuilder {
     private builders: StructureSubsetBuilder[] = [];
     private builderMap = new Map<string, StructureSubsetBuilder>();
 
-    add(key: any, unit: number, element: number) {
+    add(key: any, unit: number, element: Element) {
         let b = this.builderMap.get(key);
         if (!b) {
             b = this.source.subsetBuilder(true);

+ 3 - 3
src/mol-model/structure/query/utils/structure.ts

@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { Structure, Unit } from '../../structure'
+import { Structure, Unit, Element } from '../../structure'
 import { SortedArray } from 'mol-data/int';
 import { StructureSubsetBuilder } from '../../structure/util/subset-builder';
 
@@ -12,7 +12,7 @@ export function structureUnion(source: Structure, structures: Structure[]) {
     if (structures.length === 0) return Structure.Empty;
     if (structures.length === 1) return structures[0];
 
-    const unitMap = new Map<number, SortedArray>();
+    const unitMap = new Map<number, Element.Set>();
     const fullUnits = new Set<number>();
 
     for (const { units } of structures) {
@@ -36,7 +36,7 @@ export function structureUnion(source: Structure, structures: Structure[]) {
     return builder.getStructure();
 }
 
-function buildUnion(this: StructureSubsetBuilder, elements: SortedArray, id: number) {
+function buildUnion(this: StructureSubsetBuilder, elements: Element.Set, id: number) {
     this.setUnit(id, elements);
 }
 

+ 23 - 22
src/mol-model/structure/structure/element.ts

@@ -4,40 +4,41 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { Tuple, OrderedSet } from 'mol-data/int'
+import { OrderedSet, SortedArray } from 'mol-data/int'
 import Unit from './unit'
-import Structure from './structure'
 
-/** Atom pointer */
-interface Element { '@type': Tuple['@type'] }
+/** Element index in Model */
+type Element = { readonly '@type': 'element' } & number
 
 namespace Element {
-    export const Zero: Element = Tuple.Zero;
-    export const create: (unit: number, index: number) => Element = Tuple.create;
-    export const is: (x: any) => x is Element = Tuple.is;
-    export const unitId: (e: Element) => number = Tuple.fst;
-    export const elementIndex: (e: Element) => number = Tuple.snd;
-    export const areEqual: (e: Element, b: Element) => boolean = Tuple.areEqual;
-    export const hashCode: (e: Element) => number = Tuple.hashCode;
+    export type Set = SortedArray<Element>
 
-    export function createEmptyArray(n: number): Element[] { return new Float64Array(n) as any; }
+    /** Index into Unit.elements */
+    export type Index = { readonly '@type': 'element-index' } & number
+    export type Indices = OrderedSet<Index>
+
+    // export interface Packed { '@type': Tuple['@type'] }
+    // export namespace Packed {
+    //     export const Zero: Packed = Tuple.Zero;
+    //     export const create: (unit: number, index: number) => Packed = Tuple.create;
+    //     export const is: (x: any) => x is Packed = Tuple.is;
+    //     export const unitId: (e: Packed) => number = Tuple.fst;
+    //     export const elementIndex: (e: Packed) => number = Tuple.snd;
+    //     export const areEqual: (e: Packed, b: Packed) => boolean = Tuple.areEqual;
+    //     export const hashCode: (e: Packed) => number = Tuple.hashCode;
+    //     export function createEmptyArray(n: number): Packed[] { return new Float64Array(n) as any; }
+    // }
 
     /** All the information required to access element properties */
     export interface Location<U = Unit> {
         unit: U,
         /** Index into element (atomic/coarse) properties of unit.model */
-        element: number
+        element: Element
     }
-    export function Location(unit?: Unit, element?: number): Location { return { unit: unit as any, element: element || 0 }; }
+    export function Location(unit?: Unit, element?: Element): Location { return { unit: unit as any, element: element || (0 as Element) }; }
     export interface Property<T> { (location: Location): T }
     export interface Predicate extends Property<boolean> { }
 
-    export function updateLocation(structure: Structure, l: Location, element: Element) {
-        l.unit = structure.units[unitId(element)];
-        l.element = elementIndex(element);
-        return l;
-    }
-
     export function property<T>(p: Property<T>) { return p; }
 
     function _wrongUnitKind(kind: string) { throw new Error(`Property only available for ${kind} models.`); }
@@ -59,11 +60,11 @@ namespace Element {
              * Indices into the unit.elements array.
              * Can use OrderedSet.forEach to iterate (or OrderedSet.size + OrderedSet.getAt)
              */
-            indices: OrderedSet
+            indices: Indices
         }>
     }
 
-    export function Loci(elements: ArrayLike<{ unit: Unit, indices: OrderedSet }>): Loci {
+    export function Loci(elements: ArrayLike<{ unit: Unit, indices: Indices }>): Loci {
         return { kind: 'element-loci', elements: elements as Loci['elements'] };
     }
 

+ 4 - 4
src/mol-model/structure/structure/structure.ts

@@ -114,7 +114,7 @@ namespace Structure {
                 c++;
             }
 
-            const elements = SortedArray.ofBounds(start, chains.segments[c + 1]);
+            const elements = SortedArray.ofBounds(start as Element, chains.segments[c + 1] as Element);
             builder.addUnit(Unit.Kind.Atomic, model, SymmetryOperator.Default, elements);
         }
 
@@ -134,7 +134,7 @@ namespace Structure {
     function addCoarseUnits(builder: StructureBuilder, model: Model, elements: CoarseElements, kind: Unit.Kind) {
         const { chainSegments } = elements;
         for (let cI = 0; cI < chainSegments.count; cI++) {
-            const elements = SortedArray.ofBounds(chainSegments.segments[cI], chainSegments.segments[cI + 1]);
+            const elements = SortedArray.ofBounds(chainSegments.segments[cI] as Element, chainSegments.segments[cI + 1] as Element);
             builder.addUnit(kind, model, SymmetryOperator.Default, elements);
         }
     }
@@ -142,7 +142,7 @@ namespace Structure {
     export class StructureBuilder {
         private units: Unit[] = [];
 
-        addUnit(kind: Unit.Kind, model: Model, operator: SymmetryOperator, elements: SortedArray): Unit {
+        addUnit(kind: Unit.Kind, model: Model, operator: SymmetryOperator, elements: Element.Set): Unit {
             const unit = Unit.create(this.units.length, kind, model, operator, elements);
             this.units.push(unit);
             return unit;
@@ -197,7 +197,7 @@ namespace Structure {
     export class ElementLocationIterator implements Iterator<Element.Location> {
         private current = Element.Location();
         private unitIndex = 0;
-        private elements: SortedArray;
+        private elements: Element.Set;
         private maxIdx = 0;
         private idx = -1;
 

+ 12 - 12
src/mol-model/structure/structure/unit.ts

@@ -7,12 +7,12 @@
 import { SymmetryOperator } from 'mol-math/geometry/symmetry-operator'
 import { Model } from '../model'
 import { GridLookup3D, Lookup3D } from 'mol-math/geometry'
-import { SortedArray } from 'mol-data/int';
 import { idFactory } from 'mol-util/id-factory';
 import { IntraUnitLinks, computeIntraUnitBonds } from './unit/links'
 import { CoarseElements, CoarseSphereConformation, CoarseGaussianConformation } from '../model/properties/coarse';
 import { ValueRef } from 'mol-util';
 import { UnitRings } from './unit/rings';
+import Element from './element'
 
 // A building block of a structure that corresponds to an atomic or a coarse grained representation
 // 'conveniently grouped together'.
@@ -26,7 +26,7 @@ namespace Unit {
     export function isSpheres(u: Unit): u is Spheres { return u.kind === Kind.Spheres; }
     export function isGaussians(u: Unit): u is Gaussians { return u.kind === Kind.Gaussians; }
 
-    export function create(id: number, kind: Kind, model: Model, operator: SymmetryOperator, elements: SortedArray): Unit {
+    export function create(id: number, kind: Kind, model: Model, operator: SymmetryOperator, elements: Element.Set): Unit {
         switch (kind) {
             case Kind.Atomic: return new Atomic(id, unitIdFactory(), model, elements, SymmetryOperator.createMapping(operator, model.atomicConformation), AtomicProperties());
             case Kind.Spheres: return createCoarse(id, unitIdFactory(), model, Kind.Spheres, elements, SymmetryOperator.createMapping(operator, model.coarseConformation.spheres));
@@ -35,7 +35,7 @@ namespace Unit {
     }
 
     /** A group of units that differ only by symmetry operators. */
-    export type SymmetryGroup = { readonly elements: SortedArray, readonly units: ReadonlyArray<Unit> }
+    export type SymmetryGroup = { readonly elements: Element.Set, readonly units: ReadonlyArray<Unit> }
 
     /** Find index of unit with given id, returns -1 if not found */
     export function findUnitById(id: number, units: ReadonlyArray<Unit>) {
@@ -49,11 +49,11 @@ namespace Unit {
         readonly id: number,
         // invariant ID stays the same even if the Operator/conformation changes.
         readonly invariantId: number,
-        readonly elements: SortedArray,
+        readonly elements: Element.Set,
         readonly model: Model,
         readonly conformation: SymmetryOperator.ArrayMapping,
 
-        getChild(elements: SortedArray): Unit,
+        getChild(elements: Element.Set): Unit,
         applyOperator(id: number, operator: SymmetryOperator, dontCompose?: boolean /* = false */): Unit,
 
         readonly lookup3d: Lookup3D
@@ -73,7 +73,7 @@ namespace Unit {
 
         readonly id: number;
         readonly invariantId: number;
-        readonly elements: SortedArray;
+        readonly elements: Element.Set;
         readonly model: Model;
         readonly conformation: SymmetryOperator.ArrayMapping;
 
@@ -83,7 +83,7 @@ namespace Unit {
 
         private props: AtomicProperties;
 
-        getChild(elements: SortedArray): Unit {
+        getChild(elements: Element.Set): Unit {
             if (elements.length === this.elements.length) return this;
             return new Atomic(this.id, this.invariantId, this.model, elements, this.conformation, AtomicProperties());
         }
@@ -112,7 +112,7 @@ namespace Unit {
             return this.props.rings.ref;
         }
 
-        constructor(id: number, invariantId: number, model: Model, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping, props: AtomicProperties) {
+        constructor(id: number, invariantId: number, model: Model, elements: Element.Set, conformation: SymmetryOperator.ArrayMapping, props: AtomicProperties) {
             this.id = id;
             this.invariantId = invariantId;
             this.model = model;
@@ -140,14 +140,14 @@ namespace Unit {
 
         readonly id: number;
         readonly invariantId: number;
-        readonly elements: SortedArray;
+        readonly elements: Element.Set;
         readonly model: Model;
         readonly conformation: SymmetryOperator.ArrayMapping;
 
         readonly coarseElements: CoarseElements;
         readonly coarseConformation: C;
 
-        getChild(elements: SortedArray): Unit {
+        getChild(elements: Element.Set): Unit {
             if (elements.length === this.elements.length) return this as any as Unit /** lets call this an ugly temporary hack */;
             return createCoarse(this.id, this.invariantId, this.model, this.kind, elements, this.conformation);
         }
@@ -172,7 +172,7 @@ namespace Unit {
             return this.kind === Kind.Spheres ? this.model.coarseConformation.spheres : this.model.coarseConformation.gaussians;
         }
 
-        constructor(id: number, invariantId: number, model: Model, kind: K, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping) {
+        constructor(id: number, invariantId: number, model: Model, kind: K, elements: Element.Set, conformation: SymmetryOperator.ArrayMapping) {
             this.kind = kind;
             this.id = id;
             this.invariantId = invariantId;
@@ -184,7 +184,7 @@ namespace Unit {
         }
     }
 
-    function createCoarse<K extends Kind.Gaussians | Kind.Spheres>(id: number, invariantId: number, model: Model, kind: K, elements: SortedArray, conformation: SymmetryOperator.ArrayMapping): Unit {
+    function createCoarse<K extends Kind.Gaussians | Kind.Spheres>(id: number, invariantId: number, model: Model, kind: K, elements: Element.Set, conformation: SymmetryOperator.ArrayMapping): Unit {
         return new Coarse(id, invariantId, model, kind, elements, conformation) as any as Unit /** lets call this an ugly temporary hack */;
     }
 

+ 22 - 24
src/mol-model/structure/structure/util/lookup3d.ts

@@ -5,43 +5,41 @@
  */
 
 import Structure from '../structure'
-import Element from '../element'
 import { Lookup3D, GridLookup3D, Result, Box3D, Sphere3D } from 'mol-math/geometry';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { computeStructureBoundary } from './boundary';
 import { OrderedSet } from 'mol-data/int';
 import { StructureUniqueSubsetBuilder } from './unique-subset-builder';
 
-export class StructureLookup3D implements Lookup3D<Element> {
+export class StructureLookup3D {
     private unitLookup: Lookup3D;
-    private result = Result.create<Element>();
     private pivot = Vec3.zero();
 
     findUnitIndices(x: number, y: number, z: number, radius: number): Result<number> {
         return this.unitLookup.find(x, y, z, radius);
     }
 
-    find(x: number, y: number, z: number, radius: number): Result<Element> {
-        Result.reset(this.result);
-        const { units } = this.structure;
-        const closeUnits = this.unitLookup.find(x, y, z, radius);
-        if (closeUnits.count === 0) return this.result;
-
-        for (let t = 0, _t = closeUnits.count; t < _t; t++) {
-            const unit = units[closeUnits.indices[t]];
-            Vec3.set(this.pivot, x, y, z);
-            if (!unit.conformation.operator.isIdentity) {
-                Vec3.transformMat4(this.pivot, this.pivot, unit.conformation.operator.inverse);
-            }
-            const unitLookup = unit.lookup3d;
-            const groupResult = unitLookup.find(this.pivot[0], this.pivot[1], this.pivot[2], radius);
-            for (let j = 0, _j = groupResult.count; j < _j; j++) {
-                Result.add(this.result, Element.create(unit.id, groupResult.indices[j]), groupResult.squaredDistances[j]);
-            }
-        }
-
-        return this.result;
-    }
+    // find(x: number, y: number, z: number, radius: number): Result<Element.Packed> {
+    //     Result.reset(this.result);
+    //     const { units } = this.structure;
+    //     const closeUnits = this.unitLookup.find(x, y, z, radius);
+    //     if (closeUnits.count === 0) return this.result;
+
+    //     for (let t = 0, _t = closeUnits.count; t < _t; t++) {
+    //         const unit = units[closeUnits.indices[t]];
+    //         Vec3.set(this.pivot, x, y, z);
+    //         if (!unit.conformation.operator.isIdentity) {
+    //             Vec3.transformMat4(this.pivot, this.pivot, unit.conformation.operator.inverse);
+    //         }
+    //         const unitLookup = unit.lookup3d;
+    //         const groupResult = unitLookup.find(this.pivot[0], this.pivot[1], this.pivot[2], radius);
+    //         for (let j = 0, _j = groupResult.count; j < _j; j++) {
+    //             Result.add(this.result, Element.Packed.create(unit.id, groupResult.indices[j]), groupResult.squaredDistances[j]);
+    //         }
+    //     }
+
+    //     return this.result;
+    // }
 
     findIntoBuilder(x: number, y: number, z: number, radius: number, builder: StructureUniqueSubsetBuilder) {
         const { units } = this.structure;

+ 6 - 6
src/mol-model/structure/structure/util/subset-builder.ts

@@ -13,12 +13,12 @@ import Structure from '../structure';
 
 export class StructureSubsetBuilder {
     private ids: number[] = [];
-    private unitMap = IntMap.Mutable<number[]>();
+    private unitMap = IntMap.Mutable<Element[]>();
     private parentId = -1;
-    private currentUnit: number[] = [];
+    private currentUnit: Element[] = [];
     elementCount = 0;
 
-    addToUnit(parentId: number, e: number) {
+    addToUnit(parentId: number, e: Element) {
         const unit = this.unitMap.get(parentId);
         if (!!unit) { unit[unit.length] = e; }
         else {
@@ -33,7 +33,7 @@ export class StructureSubsetBuilder {
         this.currentUnit = this.currentUnit.length > 0 ? [] : this.currentUnit;
     }
 
-    addElement(e: number) {
+    addElement(e: Element) {
         this.currentUnit[this.currentUnit.length] = e;
         this.elementCount++;
     }
@@ -45,9 +45,9 @@ export class StructureSubsetBuilder {
         this.parentId = -1;
     }
 
-    setUnit(parentId: number, elements: ArrayLike<number>) {
+    setUnit(parentId: number, elements: ArrayLike<Element>) {
         this.ids[this.ids.length] = parentId;
-        this.unitMap.set(parentId, elements as number[]);
+        this.unitMap.set(parentId, elements as Element[]);
         this.elementCount += elements.length;
     }
 

+ 2 - 1
src/mol-view/label.ts

@@ -22,7 +22,8 @@ export function labelFirst(loci: Loci): string {
         case 'element-loci':
             const e = loci.elements[0]
             if (e) {
-                return elementLabel(Element.Location(e.unit, OrderedSet.getAt(e.indices, 0)))
+                const el = e.unit.elements[OrderedSet.getAt(e.indices, 0)];
+                return elementLabel(Element.Location(e.unit, el))
             } else {
                 return 'Unknown'
             }

+ 3 - 3
src/perf-tests/lookup3d.ts

@@ -51,9 +51,9 @@ export async function test() {
     const result = lookup.find(-30.07, 8.178, -13.897, 10);
     console.log(result.count)//, sortArray(result.indices));
 
-    const sl = structures[0].lookup3d;
-    const result1 = sl.find(-30.07, 8.178, -13.897, 10);
-    console.log(result1.count);//, result1.indices);
+    // const sl = structures[0].lookup3d;
+    // const result1 = sl.find(-30.07, 8.178, -13.897, 10);
+    // console.log(result1.count);//, result1.indices);
 
     console.log(structures[0].boundary);
     console.log(lookup.boundary);