diff --git a/src/mol-data/int/_spec/interval.spec.ts b/src/mol-data/int/_spec/interval.spec.ts index 0373891338e14a3df9a2390023780dee51d80063..0b981d35b7fe0364b825965618c76ebb26edf5fb 100644 --- a/src/mol-data/int/_spec/interval.spec.ts +++ b/src/mol-data/int/_spec/interval.spec.ts @@ -73,4 +73,10 @@ describe('interval', () => { test('predIndexInt3', Interval.findPredecessorIndexInInterval(Interval.ofRange(3, 10), 5, Interval.ofRange(2, 6)), 2); testI('findRange', Interval.findRange(r05, 2, 3), Interval.ofRange(2, 3)); + + test('intersectionSize1', Interval.intersectionSize(Interval.ofRange(0, 5), Interval.ofRange(0, 5)), 6); + test('intersectionSize2', Interval.intersectionSize(Interval.ofRange(0, 5), Interval.ofRange(1, 2)), 2); + test('intersectionSize3', Interval.intersectionSize(Interval.ofRange(1, 2), Interval.ofRange(0, 5)), 2); + test('intersectionSize4', Interval.intersectionSize(Interval.ofRange(0, 5), Interval.ofRange(3, 8)), 3); + test('intersectionSize5', Interval.intersectionSize(Interval.ofRange(0, 5), Interval.ofRange(6, 8)), 0); }); \ No newline at end of file diff --git a/src/mol-data/int/_spec/ordered-set.spec.ts b/src/mol-data/int/_spec/ordered-set.spec.ts index e39cb3c0933aae2aae90a6a2a29907e86e043c26..401bff07e298b66caaee62914e110a480c66b10f 100644 --- a/src/mol-data/int/_spec/ordered-set.spec.ts +++ b/src/mol-data/int/_spec/ordered-set.spec.ts @@ -116,6 +116,13 @@ describe('ordered set', () => { expect(OrderedSet.findRange(arr136, 2, 7)).toEqual(iB(1, 3)); }) + it('intersectionSize', () => { + expect(OrderedSet.intersectionSize(arr136, range1_4)).toEqual(2); + expect(OrderedSet.intersectionSize(arr12369, range1_4)).toEqual(3); + expect(OrderedSet.intersectionSize(OrderedSet.ofSortedArray([12, 13, 16]), range1_4)).toEqual(0); + expect(OrderedSet.intersectionSize(OrderedSet.ofSortedArray([1, 2, 4]), range1_4)).toEqual(3); + }) + testEq('union ES', OrderedSet.union(empty, singleton10), [10]); testEq('union ER', OrderedSet.union(empty, range1_4), [1, 2, 3, 4]); testEq('union EA', OrderedSet.union(empty, arr136), [1, 3, 6]); diff --git a/src/mol-data/int/_spec/sorted-array.spec.ts b/src/mol-data/int/_spec/sorted-array.spec.ts index c5ca33cf506892bc90d9da503a241d0fc0f2bfe4..2f38bb0469c9d9d38919438c29517d6fb7b40c55 100644 --- a/src/mol-data/int/_spec/sorted-array.spec.ts +++ b/src/mol-data/int/_spec/sorted-array.spec.ts @@ -63,6 +63,8 @@ describe('sortedArray', () => { compareArrays(SortedArray.indicesOf(SortedArray.ofSortedArray([10, 11, 12]), SortedArray.ofSortedArray([10, 12, 14])), [0, 2]); }) + test('intersectionSize', SortedArray.intersectionSize(a1234, a2468), 2); + // console.log(Interval.findPredecessorIndexInInterval(Interval.ofBounds(0, 3), 2, Interval.ofBounds(0, 3))) // console.log(SortedArray.findPredecessorIndexInInterval(SortedArray.ofSortedArray([0, 1, 2]), 2, Interval.ofBounds(0, 3))) }); \ No newline at end of file diff --git a/src/mol-data/int/impl/interval.ts b/src/mol-data/int/impl/interval.ts index 540b7b38bafb8c096d241948ea96421d58b8d2a0..f7568480900db112b77c934e7e4d856a923062b8 100644 --- a/src/mol-data/int/impl/interval.ts +++ b/src/mol-data/int/impl/interval.ts @@ -58,4 +58,8 @@ export function findRange(int: Tuple, min: number, max: number) { export function intersect(a: Tuple, b: Tuple) { if (!areIntersecting(a, b)) return Empty; return ofBounds(Math.max(start(a), start(b)), Math.min(end(a), end(b))); +} + +export function intersectionSize(a: Tuple, b: Tuple) { + return size(findRange(a, min(b), max(b))) } \ No newline at end of file diff --git a/src/mol-data/int/impl/ordered-set.ts b/src/mol-data/int/impl/ordered-set.ts index e6b3bec702a30c90388908490a4935ca826e4038..27ee1f1db798f09ebc789a2043520656c63ebec3 100644 --- a/src/mol-data/int/impl/ordered-set.ts +++ b/src/mol-data/int/impl/ordered-set.ts @@ -72,6 +72,14 @@ export function findRange(set: OrderedSetImpl, min: number, max: number) { return I.is(set) ? I.findRange(set, min, max) : S.findRange(set, min, max); } +export function intersectionSize(a: OrderedSetImpl, b: OrderedSetImpl): number { + if (I.is(a)) { + if (I.is(b)) return I.intersectionSize(a, b); + return intersectionSizeSI(b, a); + } else if (I.is(b)) return intersectionSizeSI(a, b); + return S.intersectionSize(a, b); +} + export function union(a: OrderedSetImpl, b: OrderedSetImpl) { if (I.is(a)) { if (I.is(b)) return unionII(a, b); @@ -165,6 +173,12 @@ function unionSI(a: S, b: I) { return ofSortedArray(indices); } +function intersectionSizeSI(a: S, b: I): number { + if (!I.size(b)) return 0; + const r = S.findRange(a, I.min(b), I.max(b)); + return I.end(r) - I.start(r); +} + function intersectSI(a: S, b: I) { if (!I.size(b)) return Empty; diff --git a/src/mol-data/int/impl/sorted-array.ts b/src/mol-data/int/impl/sorted-array.ts index e603bbcfb954820ec5dc5b00b085927f65f44a79..2d441bc3fdf4304e7808e9a417d64a98060441a6 100644 --- a/src/mol-data/int/impl/sorted-array.ts +++ b/src/mol-data/int/impl/sorted-array.ts @@ -161,15 +161,8 @@ export function isSubset(a: Nums, b: Nums) { export function union(a: Nums, b: Nums) { if (a === b) return a; - const { startI: sI, startJ: sJ, endI, endJ } = getSuitableIntersectionRange(a, b); - let i = sI, j = sJ; - let commonCount = 0; - while (i < endI && j < endJ) { - const x = a[i], y = b[j]; - if (x < y) { i++; } - else if (x > y) { j++; } - else { i++; j++; commonCount++; } - } + const { startI, startJ, endI, endJ } = getSuitableIntersectionRange(a, b); + const commonCount = getCommonCount(a, b, startI, startJ, endI, endJ); const lenA = a.length, lenB = b.length; // A === B || B is subset of A ==> A @@ -181,12 +174,12 @@ export function union(a: Nums, b: Nums) { let offset = 0; // insert the "prefixes" - for (let k = 0; k < sI; k++) indices[offset++] = a[k]; - for (let k = 0; k < sJ; k++) indices[offset++] = b[k]; + for (let k = 0; k < startI; k++) indices[offset++] = a[k]; + for (let k = 0; k < startJ; k++) indices[offset++] = b[k]; // insert the common part - i = sI; - j = sJ; + let i = startI; + let j = startJ; while (i < endI && j < endJ) { const x = a[i], y = b[j]; if (x < y) { indices[offset++] = x; i++; } @@ -201,11 +194,14 @@ export function union(a: Nums, b: Nums) { return ofSortedArray(indices); } -export function intersect(a: Nums, b: Nums) { - if (a === b) return a; +export function intersectionSize(a: Nums, b: Nums) { + if (a === b) return size(a); + const { startI, startJ, endI, endJ } = getSuitableIntersectionRange(a, b); + return getCommonCount(a, b, startI, startJ, endI, endJ); +} - const { startI: sI, startJ: sJ, endI, endJ } = getSuitableIntersectionRange(a, b); - let i = sI, j = sJ; +function getCommonCount(a: Nums, b: Nums, startI: number, startJ: number, endI: number, endJ: number) { + let i = startI, j = startJ; let commonCount = 0; while (i < endI && j < endJ) { const x = a[i], y = b[j]; @@ -213,6 +209,14 @@ export function intersect(a: Nums, b: Nums) { else if (x > y) { j++; } else { i++; j++; commonCount++; } } + return commonCount; +} + +export function intersect(a: Nums, b: Nums) { + if (a === b) return a; + + const { startI, startJ, endI, endJ } = getSuitableIntersectionRange(a, b); + const commonCount = getCommonCount(a, b, startI, startJ, endI, endJ); const lenA = a.length, lenB = b.length; // no common elements @@ -224,8 +228,8 @@ export function intersect(a: Nums, b: Nums) { const indices = new Int32Array(commonCount); let offset = 0; - i = sI; - j = sJ; + let i = startI; + let j = startJ; while (i < endI && j < endJ) { const x = a[i], y = b[j]; if (x < y) { i++; } diff --git a/src/mol-data/int/interval.ts b/src/mol-data/int/interval.ts index d5edcfc9e7cf2f69491cfe1edce92a10d60806d3..b2ab7fb8350624c57d88f4d39960e6f41465abe7 100644 --- a/src/mol-data/int/interval.ts +++ b/src/mol-data/int/interval.ts @@ -45,6 +45,8 @@ namespace Interval { 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; + /** Size of the intersection of the two intervals */ + export const intersectionSize: <T extends number = number>(a: Interval<T>, b: Interval<T>) => number = Impl.intersectionSize as any; /** Get a new interval that is the intersection of the two intervals */ export const intersect: <T extends number = number>(a: Interval<T>, b: Interval<T>) => Interval<T> = Impl.intersect as any; diff --git a/src/mol-data/int/ordered-set.ts b/src/mol-data/int/ordered-set.ts index ff1aee372e2c2c7202c5c941bc23de85c0636638..d18e61446d77582a7c5e8d6af78c586db838f875 100644 --- a/src/mol-data/int/ordered-set.ts +++ b/src/mol-data/int/ordered-set.ts @@ -40,6 +40,7 @@ namespace OrderedSet { 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 const intersectionSize: <T extends number = number>(a: OrderedSet<T>, b: OrderedSet<T>) => number = Base.intersectionSize as any; 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); diff --git a/src/mol-data/int/sorted-array.ts b/src/mol-data/int/sorted-array.ts index 921700b6790baa00794ea6e1d7966d084b15d5f1..c0f1248db3f25e3c7764c67164412d1baafb0c7a 100644 --- a/src/mol-data/int/sorted-array.ts +++ b/src/mol-data/int/sorted-array.ts @@ -42,6 +42,7 @@ namespace SortedArray { 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 intersectionSize: <T extends number = number>(a: SortedArray<T>, b: SortedArray<T>) => number = Impl.intersectionSize 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] */ diff --git a/src/mol-geo/representation/structure/visual/util/polymer.ts b/src/mol-geo/representation/structure/visual/util/polymer.ts index 5f58974e37c4ab8d684145b5307317c933d7e9e8..2a6e5eeadf805412d4a1d5a492b206b79fef51d4 100644 --- a/src/mol-geo/representation/structure/visual/util/polymer.ts +++ b/src/mol-geo/representation/structure/visual/util/polymer.ts @@ -41,8 +41,7 @@ export function getPolymerElementCount(unit: Unit) { case Unit.Kind.Gaussians: while (polymerIt.hasNext) { const { start, end } = polymerIt.move() - // TODO add OrderedSet.intersectionSize - count += OrderedSet.size(OrderedSet.intersect(Interval.ofBounds(elements[start], elements[end - 1]), elements)) + count += OrderedSet.intersectionSize(Interval.ofBounds(elements[start], elements[end - 1]), elements) } break } @@ -222,7 +221,7 @@ export class AtomicPolymerBackboneIterator<T extends number = number> implements } this.hasNext = residueIt.hasNext || polymerIt.hasNext - + // console.log('hasNext', this.hasNext) // console.log('value', this.value)