From e0283d88c7d11acf0b3dc4c6dcec60e5490e7170 Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Fri, 15 Jun 2018 20:43:02 +0200 Subject: [PATCH] wip, nominal Element and Element.Index --- src/mol-data/int/ordered-set.ts | 46 ++++++------- src/mol-data/int/sorted-array.ts | 68 ++++++++++--------- src/mol-geo/representation/structure/point.ts | 2 +- .../representation/structure/spacefill.ts | 2 +- src/mol-model/structure/query/modifiers.ts | 4 +- src/mol-model/structure/query/selection.ts | 4 +- .../structure/query/utils/builders.ts | 2 +- .../structure/query/utils/structure.ts | 6 +- src/mol-model/structure/structure/element.ts | 45 ++++++------ .../structure/structure/structure.ts | 8 +-- src/mol-model/structure/structure/unit.ts | 24 +++---- .../structure/structure/util/lookup3d.ts | 46 ++++++------- .../structure/util/subset-builder.ts | 12 ++-- src/mol-view/label.ts | 3 +- src/perf-tests/lookup3d.ts | 6 +- 15 files changed, 140 insertions(+), 138 deletions(-) diff --git a/src/mol-data/int/ordered-set.ts b/src/mol-data/int/ordered-set.ts index 8a11562f2..ba2f61dcf 100644 --- a/src/mol-data/int/ordered-set.ts +++ b/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 \ No newline at end of file diff --git a/src/mol-data/int/sorted-array.ts b/src/mol-data/int/sorted-array.ts index 2c92aa329..3e343fd5e 100644 --- a/src/mol-data/int/sorted-array.ts +++ b/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 \ No newline at end of file diff --git a/src/mol-geo/representation/structure/point.ts b/src/mol-geo/representation/structure/point.ts index 9e82a77a4..6595224d4 100644 --- a/src/mol-geo/representation/structure/point.ts +++ b/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 diff --git a/src/mol-geo/representation/structure/spacefill.ts b/src/mol-geo/representation/structure/spacefill.ts index fe18eb7a1..15551433d 100644 --- a/src/mol-geo/representation/structure/spacefill.ts +++ b/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 diff --git a/src/mol-model/structure/query/modifiers.ts b/src/mol-model/structure/query/modifiers.ts index 3b332ff7f..a8497a16e 100644 --- a/src/mol-model/structure/query/modifiers.ts +++ b/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(); diff --git a/src/mol-model/structure/query/selection.ts b/src/mol-model/structure/query/selection.ts index a68971d3c..5bd8f7626 100644 --- a/src/mol-model/structure/query/selection.ts +++ b/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, diff --git a/src/mol-model/structure/query/utils/builders.ts b/src/mol-model/structure/query/utils/builders.ts index 6e1d6d7cf..0abce36d0 100644 --- a/src/mol-model/structure/query/utils/builders.ts +++ b/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); diff --git a/src/mol-model/structure/query/utils/structure.ts b/src/mol-model/structure/query/utils/structure.ts index f30fd20e6..c1e942439 100644 --- a/src/mol-model/structure/query/utils/structure.ts +++ b/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); } diff --git a/src/mol-model/structure/structure/element.ts b/src/mol-model/structure/structure/element.ts index 845dfe791..b39c810dc 100644 --- a/src/mol-model/structure/structure/element.ts +++ b/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'] }; } diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index 78ef1b470..09a9db336 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/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; diff --git a/src/mol-model/structure/structure/unit.ts b/src/mol-model/structure/structure/unit.ts index c5488a09b..948e429cb 100644 --- a/src/mol-model/structure/structure/unit.ts +++ b/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 */; } diff --git a/src/mol-model/structure/structure/util/lookup3d.ts b/src/mol-model/structure/structure/util/lookup3d.ts index 3c7b8b6ac..c6cc3ce85 100644 --- a/src/mol-model/structure/structure/util/lookup3d.ts +++ b/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; diff --git a/src/mol-model/structure/structure/util/subset-builder.ts b/src/mol-model/structure/structure/util/subset-builder.ts index 7c1437742..96732ebb5 100644 --- a/src/mol-model/structure/structure/util/subset-builder.ts +++ b/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; } diff --git a/src/mol-view/label.ts b/src/mol-view/label.ts index aa6b01e71..3107afeb8 100644 --- a/src/mol-view/label.ts +++ b/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' } diff --git a/src/perf-tests/lookup3d.ts b/src/perf-tests/lookup3d.ts index e2629a368..ee62fe604 100644 --- a/src/perf-tests/lookup3d.ts +++ b/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); -- GitLab