From 4fa489838e203b52432a075905d59fda7f643dc0 Mon Sep 17 00:00:00 2001 From: David Sehnal <david.sehnal@gmail.com> Date: Fri, 15 Jun 2018 21:02:32 +0200 Subject: [PATCH] "nomial types" for Element and Element.Index --- src/mol-data/int/impl/segmentation.ts | 6 +-- src/mol-data/int/interval.ts | 52 +++++++++---------- src/mol-data/int/ordered-set.ts | 10 +++- src/mol-data/int/segmentation.ts | 18 +++---- .../structure/model/formats/mmcif.ts | 7 +-- .../structure/model/formats/mmcif/ihm.ts | 5 +- .../model/properties/atomic/hierarchy.ts | 7 +-- .../model/properties/coarse/hierarchy.ts | 3 +- src/mol-model/structure/query/modifiers.ts | 4 +- src/mol-model/structure/structure/element.ts | 12 ----- .../structure/structure/util/lookup3d.ts | 1 + 11 files changed, 63 insertions(+), 62 deletions(-) diff --git a/src/mol-data/int/impl/segmentation.ts b/src/mol-data/int/impl/segmentation.ts index fed6a7fb7..63313431f 100644 --- a/src/mol-data/int/impl/segmentation.ts +++ b/src/mol-data/int/impl/segmentation.ts @@ -50,11 +50,11 @@ export function projectValue({ segments }: Segmentation, set: OrderedSet, value: return OrderedSet.findRange(set, OrderedSet.getAt(segments, idx), OrderedSet.getAt(segments, idx + 1) - 1); } -export class SegmentIterator implements Iterator<Segs.Segment> { +export class SegmentIterator<T extends number = number> implements Iterator<Segs.Segment<T>> { private segmentMin = 0; private segmentMax = 0; private setRange = Interval.Empty; - private value: Segs.Segment = { index: 0, start: 0, end: 0 }; + private value: Segs.Segment<T> = { index: 0, start: 0, end: 0 }; hasNext: boolean = false; @@ -94,7 +94,7 @@ export class SegmentIterator implements Iterator<Segs.Segment> { this.hasNext = this.segmentMax >= this.segmentMin; } - setSegment(segment: Segs.Segment) { + setSegment(segment: Segs.Segment<T>) { this.setRange = Interval.ofBounds(segment.start, segment.end); this.updateSegmentRange(); } diff --git a/src/mol-data/int/interval.ts b/src/mol-data/int/interval.ts index 2b4c6cd17..d5edcfc9e 100644 --- a/src/mol-data/int/interval.ts +++ b/src/mol-data/int/interval.ts @@ -9,48 +9,48 @@ import * as Impl from './impl/interval' namespace Interval { export const Empty: Interval = Impl.Empty as any; - export const ofSingleton: (value: number) => Interval = (v) => Impl.ofRange(v, v) as any; + export const ofSingleton: <T extends number = number>(value: T) => Interval<T> = (v) => Impl.ofRange(v, v) as any; /** Create interval from range [min, max] */ - export const ofRange: (min: number, max: number) => Interval = Impl.ofRange as any; + export const ofRange: <T extends number = number>(min: T, max: T) => Interval<T> = Impl.ofRange as any; /** Create interval from bounds [start, end), i.e. [start, end - 1] */ - export const ofBounds: (start: number, end: number) => Interval = Impl.ofBounds as any; - export const is: (v: any) => v is Interval = Impl.is as any; + export const ofBounds: <T extends number = number>(start: T, end: T) => Interval<T> = Impl.ofBounds as any; + export const is: <T extends number = number>(v: any) => v is Interval<T> = Impl.is as any; /** Test if a value is within the bounds of the interval */ - export const has: (interval: Interval, x: number) => boolean = Impl.has as any; - export const indexOf: (interval: Interval, x: number) => number = Impl.indexOf as any; - export const getAt: (interval: Interval, i: number) => number = Impl.getAt as any; - - /** Start value of the interval, same as min value */ - export const start: (interval: Interval) => number = Impl.start as any; - /** End value of the interval, same as max + 1 */ - export const end: (interval: Interval) => number = Impl.end as any; - /** Min value of the interval, same as start value */ - export const min: (interval: Interval) => number = Impl.min as any; - /** Max value of the interval, same as end - 1 */ - export const max: (interval: Interval) => number = Impl.max as any; + export const has: <T extends number = number>(interval: Interval<T>, x: T) => boolean = Impl.has as any; + export const indexOf: <T extends number = number>(interval: Interval<T>, x: T) => number = Impl.indexOf as any; + export const getAt: <T extends number = number>(interval: Interval<T>, i: number) => T = Impl.getAt as any; + + /** Start value of the Interval<T>, same as min value */ + export const start: <T extends number = number>(interval: Interval<T>) => T = Impl.start as any; + /** End value of the Interval<T>, same as max + 1 */ + export const end: <T extends number = number>(interval: Interval<T>) => T = Impl.end as any; + /** Min value of the Interval<T>, same as start value */ + export const min: <T extends number = number>(interval: Interval<T>) => T = Impl.min as any; + /** Max value of the Interval<T>, same as end - 1 */ + export const max: <T extends number = number>(interval: Interval<T>) => T = Impl.max as any; /** Number of values in the interval */ - export const size: (interval: Interval) => number = Impl.size as any; + export const size: <T extends number = number>(interval: Interval<T>) => number = Impl.size as any; /** Hash code describing the interval */ - export const hashCode: (interval: Interval) => number = Impl.hashCode as any; + export const hashCode: <T extends number = number>(interval: Interval<T>) => number = Impl.hashCode as any; /** Test if two intervals are identical */ - export const areEqual: (a: Interval, b: Interval) => boolean = Impl.areEqual as any; + export const areEqual: <T extends number = number>(a: Interval<T>, b: Interval<T>) => boolean = Impl.areEqual as any; /** Test if two intervals are intersecting, i.e. their bounds overlap */ - export const areIntersecting: (a: Interval, b: Interval) => boolean = Impl.areIntersecting as any; + export const areIntersecting: <T extends number = number>(a: Interval<T>, b: Interval<T>) => boolean = Impl.areIntersecting as any; /** Test if interval b is fully included in interval a */ - export const isSubInterval: (a: Interval, b: Interval) => boolean = Impl.isSubInterval as any; + export const isSubInterval: <T extends number = number>(a: Interval<T>, b: Interval<T>) => boolean = Impl.isSubInterval as any; - export const findPredecessorIndex: (interval: Interval, x: number) => number = Impl.findPredecessorIndex as any; - export const findPredecessorIndexInInterval: (interval: Interval, x: number, bounds: Interval) => number = Impl.findPredecessorIndexInInterval as any; - export const findRange: (interval: Interval, min: number, max: number) => Interval = Impl.findRange as any; + export const findPredecessorIndex: <T extends number = number>(interval: Interval<T>, x: T) => number = Impl.findPredecessorIndex as any; + export const findPredecessorIndexInInterval: <T extends number = number>(interval: Interval<T>, x: T, bounds: Interval) => number = Impl.findPredecessorIndexInInterval as any; + export const findRange: <T extends number = number>(interval: Interval<T>, min: T, max: T) => Interval = Impl.findRange as any; /** Get a new interval that is the intersection of the two intervals */ - export const intersect: (a: Interval, b: Interval) => Interval = Impl.intersect as any; + export const intersect: <T extends number = number>(a: Interval<T>, b: Interval<T>) => Interval<T> = Impl.intersect as any; } /** Interval describing a range [min, max] of values */ -interface Interval { '@type': 'int-interval' } +interface Interval<T extends number = number> { '@type': 'int-interval' } export default Interval \ No newline at end of file diff --git a/src/mol-data/int/ordered-set.ts b/src/mol-data/int/ordered-set.ts index ba2f61dcf..e9abea226 100644 --- a/src/mol-data/int/ordered-set.ts +++ b/src/mol-data/int/ordered-set.ts @@ -40,9 +40,17 @@ namespace OrderedSet { 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); } + + export function isInterval<T extends number = number>(set: OrderedSet<T>): set is Interval<T> { + return Interval.is(set); + } + + export function isSortedArray<T extends number = number>(set: OrderedSet<T>): set is SortedArray<T> { + return !Interval.is(set); + } } -type OrderedSet<T extends number = number> = Interval | SortedArray<T> +type OrderedSet<T extends number = number> = Interval<T> | SortedArray<T> //{ '@type': 'int-interval' | 'int-sorted-array' } export default OrderedSet \ No newline at end of file diff --git a/src/mol-data/int/segmentation.ts b/src/mol-data/int/segmentation.ts index 51f5c5ecd..8f7c58db6 100644 --- a/src/mol-data/int/segmentation.ts +++ b/src/mol-data/int/segmentation.ts @@ -9,22 +9,22 @@ import OrderedSet from './ordered-set' import * as Impl from './impl/segmentation' namespace Segmentation { - export interface Segment { index: number, start: number, end: number } + export interface Segment<T extends number = number> { index: number, start: number, end: number } - export const create: (segs: ArrayLike<number>) => Segmentation = Impl.create as any; - export const ofOffsets: (offsets: ArrayLike<number>, bounds: Interval) => Segmentation = Impl.ofOffsets as any; + export const create: <T extends number = number>(segs: ArrayLike<T>) => Segmentation<T> = Impl.create as any; + export const ofOffsets: <T extends number = number>(offsets: ArrayLike<T>, bounds: Interval) => Segmentation<T> = Impl.ofOffsets as any; - export const count: (segs: Segmentation) => number = Impl.count as any; - export const getSegment: (segs: Segmentation, value: number) => number = Impl.getSegment as any; - export const projectValue: (segs: Segmentation, set: OrderedSet, value: number) => Interval = Impl.projectValue as any; + export const count: <T extends number = number>(segs: Segmentation<T>) => number = Impl.count as any; + export const getSegment: <T extends number = number>(segs: Segmentation<T>, value: T) => number = Impl.getSegment as any; + export const projectValue: <T extends number = number>(segs: Segmentation<T>, set: OrderedSet<T>, value: T) => Interval = Impl.projectValue as any; // Segment iterator that mutates a single segment object to mark all the segments. - export const transientSegments: (segs: Segmentation, set: OrderedSet, segment?: Segment) => Impl.SegmentIterator = Impl.segments as any; + export const transientSegments: <T extends number = number>(segs: Segmentation<T>, set: OrderedSet<T>, segment?: Segment<T>) => Impl.SegmentIterator = Impl.segments as any; } -interface Segmentation { +interface Segmentation<T extends number = number> { '@type': 'segmentation', - readonly segments: ArrayLike<number>, + readonly segments: ArrayLike<T>, readonly segmentMap: ArrayLike<number>, readonly count: number } diff --git a/src/mol-model/structure/model/formats/mmcif.ts b/src/mol-model/structure/model/formats/mmcif.ts index 31f3abb45..abd3a7a59 100644 --- a/src/mol-model/structure/model/formats/mmcif.ts +++ b/src/mol-model/structure/model/formats/mmcif.ts @@ -23,6 +23,7 @@ import { getSecondaryStructureMmCif } from './mmcif/secondary-structure'; import { getSequence } from './mmcif/sequence'; import { sortAtomSite } from './mmcif/sort'; import { mmCIF_Database, mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif'; +import { Element } from '../../../structure' import mmCIF_Format = Format.mmCIF type AtomSite = mmCIF_Database['atom_site'] @@ -40,7 +41,7 @@ function findHierarchyOffsets(atom_site: AtomSite) { if (atom_site._rowCount === 0) return { residues: [], chains: [] }; const start = 0, end = atom_site._rowCount; - const residues = [start], chains = [start]; + const residues = [start as Element], chains = [start as Element]; const { label_entity_id, label_asym_id, label_seq_id, auth_seq_id, pdbx_PDB_ins_code, label_comp_id } = atom_site; @@ -52,8 +53,8 @@ function findHierarchyOffsets(atom_site: AtomSite) { || !pdbx_PDB_ins_code.areValuesEqual(i - 1, i) || !label_comp_id.areValuesEqual(i - 1, i); - if (newResidue) residues[residues.length] = i; - if (newChain) chains[chains.length] = i; + if (newResidue) residues[residues.length] = i as Element; + if (newChain) chains[chains.length] = i as Element; } return { residues, chains }; } diff --git a/src/mol-model/structure/model/formats/mmcif/ihm.ts b/src/mol-model/structure/model/formats/mmcif/ihm.ts index 1dfdc1c1d..8fe3b4f4a 100644 --- a/src/mol-model/structure/model/formats/mmcif/ihm.ts +++ b/src/mol-model/structure/model/formats/mmcif/ihm.ts @@ -12,6 +12,7 @@ import { getCoarseKeys } from '../../properties/utils/coarse-keys'; import { UUID } from 'mol-util'; import { Segmentation, Interval } from 'mol-data/int'; import { Mat3, Tensor } from 'mol-math/linear-algebra'; +import { Element } from '../../../structure' export function getIHMCoarse(data: mmCIF, entities: Entities): { hierarchy: CoarseHierarchy, conformation: CoarseConformation } { if (data.ihm_model_list._rowCount === 0) return { hierarchy: CoarseHierarchy.Empty, conformation: void 0 as any }; @@ -71,9 +72,9 @@ function getGaussianConformation(data: mmCIF['ihm_gaussian_obj_site']): CoarseGa } function getChainSegments(asym_id: Column<string>) { - const offsets = [0]; + const offsets = [0 as Element]; for (let i = 1, _i = asym_id.rowCount; i < _i; i++) { - if (!asym_id.areValuesEqual(i - 1, i)) offsets[offsets.length] = i; + if (!asym_id.areValuesEqual(i - 1, i)) offsets[offsets.length] = i as Element; } return Segmentation.ofOffsets(offsets, Interval.ofBounds(0, asym_id.rowCount)); diff --git a/src/mol-model/structure/model/properties/atomic/hierarchy.ts b/src/mol-model/structure/model/properties/atomic/hierarchy.ts index 9b04d0f36..513f36110 100644 --- a/src/mol-model/structure/model/properties/atomic/hierarchy.ts +++ b/src/mol-model/structure/model/properties/atomic/hierarchy.ts @@ -7,7 +7,8 @@ import { Column, Table } from 'mol-data/db' import { Segmentation } from 'mol-data/int' import { mmCIF_Schema as mmCIF } from 'mol-io/reader/cif/schema/mmcif' -import { ElementSymbol} from '../../types' +import { ElementSymbol } from '../../types' +import { Element } from '../../../structure' export const AtomsSchema = { type_symbol: Column.Schema.Aliased<ElementSymbol>(mmCIF.atom_site.type_symbol), @@ -47,8 +48,8 @@ export interface AtomicData { } export interface AtomicSegments { - residueSegments: Segmentation, - chainSegments: Segmentation + residueSegments: Segmentation<Element>, + chainSegments: Segmentation<Element> // TODO: include entity segments? } diff --git a/src/mol-model/structure/model/properties/coarse/hierarchy.ts b/src/mol-model/structure/model/properties/coarse/hierarchy.ts index 52748b367..81a7be2dd 100644 --- a/src/mol-model/structure/model/properties/coarse/hierarchy.ts +++ b/src/mol-model/structure/model/properties/coarse/hierarchy.ts @@ -7,6 +7,7 @@ import { mmCIF_Database as mmCIF } from 'mol-io/reader/cif/schema/mmcif' import { Column } from 'mol-data/db' import { Segmentation } from 'mol-data/int'; +import { Element } from '../../../structure' export interface CoarsedElementKeys { // assign a key to each element @@ -27,7 +28,7 @@ export interface CoarseElementData { seq_id_begin: Column<number>, seq_id_end: Column<number>, - chainSegments: Segmentation + chainSegments: Segmentation<Element> } export type CoarseElements = CoarsedElementKeys & CoarseElementData diff --git a/src/mol-model/structure/query/modifiers.ts b/src/mol-model/structure/query/modifiers.ts index a8497a16e..3b332ff7f 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, Element } from '../structure'; +import { Structure, Unit } 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 as Element); + builder.addElement(j); } } builder.commitUnit(); diff --git a/src/mol-model/structure/structure/element.ts b/src/mol-model/structure/structure/element.ts index b39c810dc..c9add11f9 100644 --- a/src/mol-model/structure/structure/element.ts +++ b/src/mol-model/structure/structure/element.ts @@ -17,18 +17,6 @@ namespace Element { 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, diff --git a/src/mol-model/structure/structure/util/lookup3d.ts b/src/mol-model/structure/structure/util/lookup3d.ts index c6cc3ce85..19187af2f 100644 --- a/src/mol-model/structure/structure/util/lookup3d.ts +++ b/src/mol-model/structure/structure/util/lookup3d.ts @@ -19,6 +19,7 @@ export class StructureLookup3D { return this.unitLookup.find(x, y, z, radius); } + // TODO: find another efficient way how to implement this instead of using "tuple". // find(x: number, y: number, z: number, radius: number): Result<Element.Packed> { // Result.reset(this.result); // const { units } = this.structure; -- GitLab