@teselagen/range-utils 0.1.21 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +6542 -18010
- package/index.mjs +6593 -18007
- package/index.umd.js +6836 -18306
- package/package.json +3 -2
- package/src/adjustRangeToDeletionOfAnotherRange.js +53 -0
- package/src/adjustRangeToDeletionOfAnotherRange.test.js +107 -0
- package/src/adjustRangeToInsert.js +28 -0
- package/src/adjustRangeToInsert.test.js +111 -0
- package/src/adjustRangeToRotation.js +24 -0
- package/src/adjustRangeToRotation.test.js +123 -0
- package/src/checkIfNonCircularRangesOverlap.js +30 -0
- package/src/checkIfNonCircularRangesOverlap.test.js +45 -0
- package/src/checkIfPotentiallyCircularRangesOverlap.js +16 -0
- package/src/checkIfPotentiallyCircularRangesOverlap.test.js +73 -0
- package/src/collapseOverlapsGeneratedFromRangeComparisonIfPossible.js +47 -0
- package/src/collapseOverlapsGeneratedFromRangeComparisonIfPossible.test.js +124 -0
- package/src/convertRangeIndices.js +22 -0
- package/src/convertRangeIndices.test.js +22 -0
- package/src/convertRangeTo0Based.js +5 -0
- package/src/convertRangeTo1Based.js +5 -0
- package/src/doesRangeSpanEntireSequence.js +7 -0
- package/src/doesRangeSpanOrigin.js +3 -0
- package/src/expandOrContractCircularRangeToPosition.js +41 -0
- package/src/expandOrContractNonCircularRangeToPosition.js +25 -0
- package/src/expandOrContractRangeByLength.js +12 -0
- package/src/expandOrContractRangeByLength.test.js +77 -0
- package/src/expandOrContractRangeToPosition.js +10 -0
- package/src/flipContainedRange.js +85 -0
- package/src/flipContainedRange.test.js +124 -0
- package/src/generateRandomRange.js +20 -0
- package/src/generateRandomRange.test.js +24 -0
- package/src/getAnnotationRangeType.js +24 -0
- package/src/getAnnotationRangeType.test.js +59 -0
- package/src/getEachPositionInRangeAsArray.js +15 -0
- package/src/getEachPositionInRangeAsArray.test.js +9 -0
- package/src/getLengthOfOverlappingRegionsBetweenTwoRanges.js +9 -0
- package/src/getLengthOfOverlappingRegionsBetweenTwoRanges.test.js +24 -0
- package/src/getMiddleOfRange.js +10 -0
- package/src/getMiddleOfRange.test.js +44 -0
- package/src/getOverlapOfNonCircularRanges.js +35 -0
- package/src/getOverlapsOfPotentiallyCircularRanges.js +54 -0
- package/src/getOverlapsOfPotentiallyCircularRanges.test.js +199 -0
- package/src/getPositionFromAngle.js +7 -0
- package/src/getRangeAngles.js +33 -0
- package/src/getRangeAngles.test.js +77 -0
- package/src/getRangeLength.js +14 -0
- package/src/getRangeLength.test.js +30 -0
- package/src/getRangesBetweenTwoRanges.js +28 -0
- package/src/getSequenceWithinRange.js +17 -0
- package/src/getSequenceWithinRange.test.js +49 -0
- package/src/getShortestDistanceBetweenTwoPositions.js +12 -0
- package/src/getShortestDistanceBetweenTwoPositions.test.js +14 -0
- package/src/getYOffsetForPotentiallyCircularRange.js +24 -0
- package/src/getYOffsetsForPotentiallyCircularRanges.js +20 -0
- package/src/getYOffsetsForPotentiallyCircularRanges.test.js +29 -0
- package/src/getZeroedRangeOverlaps.js +17 -0
- package/src/getZeroedRangeOverlaps.test.js +36 -0
- package/src/index.js +51 -0
- package/src/index.test.js +33 -0
- package/src/invertRange.js +21 -0
- package/src/invertRange.test.js +96 -0
- package/src/isPositionCloserToRangeStartThanRangeEnd.js +8 -0
- package/src/isPositionCloserToRangeStartThanRangeEnd.test.js +17 -0
- package/src/isPositionWithinRange.js +31 -0
- package/src/isRangeOrPositionWithinRange.js +29 -0
- package/src/isRangeOrPositionWithinRange.test.js +150 -0
- package/src/isRangeWithinRange.js +17 -0
- package/src/loopEachPositionInRange.js +5 -0
- package/src/modulatePositionByRange.js +10 -0
- package/src/modulatePositionByRange.test.js +12 -0
- package/src/modulateRangeBySequenceLength.js +11 -0
- package/src/modulateRangeBySequenceLength.test.js +16 -0
- package/src/normalizePositionByRangeLength.js +20 -0
- package/src/normalizePositionByRangeLength.test.js +23 -0
- package/src/normalizePositionByRangeLength1Based.js +5 -0
- package/src/normalizePositionByRangeLength1Based.test.js +9 -0
- package/src/normalizeRange.js +11 -0
- package/src/normalizeRange.test.js +9 -0
- package/src/provideInclusiveOptions.js +26 -0
- package/src/reversePositionInRange.js +13 -0
- package/src/splitRangeIntoTwoPartsIfItIsCircular.js +31 -0
- package/src/splitRangeIntoTwoPartsIfItIsCircular.test.js +33 -0
- package/src/translateRange.js +9 -0
- package/src/translateRange.test.js +20 -0
- package/src/trimNonCicularRangeByAnotherNonCircularRange.js +57 -0
- package/src/trimNumberToFitWithin0ToAnotherNumber.js +12 -0
- package/src/trimRangeByAnotherRange.js +102 -0
- package/src/trimRangeByAnotherRange.test.js +314 -0
- package/src/zeroSubrangeByContainerRange.js +36 -0
- package/src/zeroSubrangeByContainerRange.test.js +51 -0
package/package.json
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
import splitRangeIntoTwoPartsIfItIsCircular from "./splitRangeIntoTwoPartsIfItIsCircular";
|
2
|
+
import trimRangeByAnotherRange from "./trimRangeByAnotherRange";
|
3
|
+
|
4
|
+
//takes in two potentially circular ranges and returns the first one trimmed by the second one
|
5
|
+
//returns null if no range is left after the trimming
|
6
|
+
export default function adjustRangeToDeletionOfAnotherRange(
|
7
|
+
rangeToBeAdjusted,
|
8
|
+
anotherRange,
|
9
|
+
maxLength
|
10
|
+
) {
|
11
|
+
// ac.throw(ac.range, rangeToBeAdjusted)
|
12
|
+
// ac.throw(ac.range, anotherRange)
|
13
|
+
// ac.throw(ac.posInt, maxLength)
|
14
|
+
|
15
|
+
const trimmedRange = trimRangeByAnotherRange(
|
16
|
+
rangeToBeAdjusted,
|
17
|
+
anotherRange,
|
18
|
+
maxLength
|
19
|
+
);
|
20
|
+
if (trimmedRange) {
|
21
|
+
//if there is a range left after being trimmed, adjust it by the deleted anotherRange
|
22
|
+
//we can make some awesome logical simplifications because we know that the two ranges do not overlap (since we've already trimmed the rangeToBeAdjusted)
|
23
|
+
const nonCircularDeletionRanges = splitRangeIntoTwoPartsIfItIsCircular(
|
24
|
+
anotherRange,
|
25
|
+
maxLength
|
26
|
+
);
|
27
|
+
nonCircularDeletionRanges.forEach(function (nonCircularDeletionRange) {
|
28
|
+
const deletionLength =
|
29
|
+
nonCircularDeletionRange.end - nonCircularDeletionRange.start + 1;
|
30
|
+
if (trimmedRange.start > trimmedRange.end) {
|
31
|
+
//the trimmed range is circular
|
32
|
+
if (nonCircularDeletionRange.start < trimmedRange.end) {
|
33
|
+
trimmedRange.start -= deletionLength;
|
34
|
+
trimmedRange.end -= deletionLength;
|
35
|
+
} else if (nonCircularDeletionRange.start < trimmedRange.start) {
|
36
|
+
trimmedRange.start -= deletionLength;
|
37
|
+
} else {
|
38
|
+
//do nothing
|
39
|
+
}
|
40
|
+
} else {
|
41
|
+
if (nonCircularDeletionRange.start < trimmedRange.start) {
|
42
|
+
trimmedRange.start -= deletionLength;
|
43
|
+
trimmedRange.end -= deletionLength;
|
44
|
+
} else if (nonCircularDeletionRange.start < trimmedRange.end) {
|
45
|
+
trimmedRange.end -= deletionLength;
|
46
|
+
} else {
|
47
|
+
//do nothing
|
48
|
+
}
|
49
|
+
}
|
50
|
+
});
|
51
|
+
}
|
52
|
+
return trimmedRange;
|
53
|
+
}
|
@@ -0,0 +1,107 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
import adjustRangeToDeletionOfAnotherRange from './adjustRangeToDeletionOfAnotherRange.js';
|
4
|
+
|
5
|
+
import assert from 'assert';
|
6
|
+
describe('adjustRangeToDeletionOfAnotherRange', function() {
|
7
|
+
it('deletes non circular range if fully overlapped', function() {
|
8
|
+
assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
|
9
|
+
start: 10,
|
10
|
+
end: 20
|
11
|
+
}, {
|
12
|
+
start: 10,
|
13
|
+
end: 20
|
14
|
+
}, 30), null);
|
15
|
+
});
|
16
|
+
it('deletes circular range if fully overlapped', function() {
|
17
|
+
assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
|
18
|
+
start: 20,
|
19
|
+
end: 10
|
20
|
+
}, {
|
21
|
+
start: 20,
|
22
|
+
end: 10
|
23
|
+
}, 30), null);
|
24
|
+
});
|
25
|
+
it('shifts start and end if deleting before non circular range', function() {
|
26
|
+
assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
|
27
|
+
name: 'happy',
|
28
|
+
start: 10,
|
29
|
+
end: 20
|
30
|
+
}, {
|
31
|
+
start: 5,
|
32
|
+
end: 8
|
33
|
+
}, 30), {
|
34
|
+
name: 'happy',
|
35
|
+
start: 6,
|
36
|
+
end: 16
|
37
|
+
});
|
38
|
+
});
|
39
|
+
it('shifts start if deleting in middle of non circular range', function() {
|
40
|
+
assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
|
41
|
+
name: 'happy',
|
42
|
+
start: 20,
|
43
|
+
end: 10
|
44
|
+
}, {
|
45
|
+
start: 15,
|
46
|
+
end: 20
|
47
|
+
}, 30), {
|
48
|
+
name: 'happy',
|
49
|
+
start: 15,
|
50
|
+
end: 10
|
51
|
+
});
|
52
|
+
assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
|
53
|
+
start: 20,
|
54
|
+
end: 10
|
55
|
+
}, {
|
56
|
+
start: 15,
|
57
|
+
end: 15
|
58
|
+
}, 30), {
|
59
|
+
start: 19,
|
60
|
+
end: 10
|
61
|
+
});
|
62
|
+
});
|
63
|
+
it('shifts start and end if deleting before end of non circular range', function() {
|
64
|
+
assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
|
65
|
+
start: 20,
|
66
|
+
end: 10
|
67
|
+
}, {
|
68
|
+
start: 0,
|
69
|
+
end: 0
|
70
|
+
}, 30), {
|
71
|
+
start: 19,
|
72
|
+
end: 9
|
73
|
+
});
|
74
|
+
assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
|
75
|
+
start: 20,
|
76
|
+
end: 10
|
77
|
+
}, {
|
78
|
+
start: 5,
|
79
|
+
end: 15
|
80
|
+
}, 30), {
|
81
|
+
start: 9,
|
82
|
+
end: 4
|
83
|
+
});
|
84
|
+
});
|
85
|
+
it('shifts neither start nor end if deleting after start of non circular range', function() {
|
86
|
+
assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
|
87
|
+
start: 20,
|
88
|
+
end: 10
|
89
|
+
}, {
|
90
|
+
start: 25,
|
91
|
+
end: 27
|
92
|
+
}, 30), {
|
93
|
+
start: 20,
|
94
|
+
end: 10
|
95
|
+
});
|
96
|
+
assert.deepEqual(adjustRangeToDeletionOfAnotherRange({
|
97
|
+
start: 20,
|
98
|
+
end: 10
|
99
|
+
}, {
|
100
|
+
start: 20,
|
101
|
+
end: 25
|
102
|
+
}, 30), {
|
103
|
+
start: 20,
|
104
|
+
end: 10
|
105
|
+
});
|
106
|
+
});
|
107
|
+
});
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
import {assign} from "lodash";
|
3
|
+
|
4
|
+
export default function adjustRangeToInsert(rangeToBeAdjusted, insertStart, insertLength) {
|
5
|
+
// ac.throw([ac.range, ac.posInt, ac.posInt], arguments);
|
6
|
+
const newRange = assign({}, rangeToBeAdjusted);
|
7
|
+
if (rangeToBeAdjusted.start > rangeToBeAdjusted.end) {
|
8
|
+
//circular range
|
9
|
+
if (rangeToBeAdjusted.end >= insertStart) {
|
10
|
+
//adjust both start and end
|
11
|
+
newRange.start += insertLength;
|
12
|
+
newRange.end += insertLength;
|
13
|
+
} else if (rangeToBeAdjusted.start >= insertStart) {
|
14
|
+
//adjust just the start
|
15
|
+
newRange.start += insertLength;
|
16
|
+
}
|
17
|
+
} else {
|
18
|
+
if (rangeToBeAdjusted.start >= insertStart) {
|
19
|
+
//adjust both start and end
|
20
|
+
newRange.start += insertLength;
|
21
|
+
newRange.end += insertLength;
|
22
|
+
} else if (rangeToBeAdjusted.end >= insertStart) {
|
23
|
+
//adjust just the end
|
24
|
+
newRange.end += insertLength;
|
25
|
+
}
|
26
|
+
}
|
27
|
+
return newRange;
|
28
|
+
};
|
@@ -0,0 +1,111 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
import adjustRangeToInsert from './adjustRangeToInsert.js';
|
5
|
+
|
6
|
+
import assert from 'assert';
|
7
|
+
describe('adjustRangeToInsert', function() {
|
8
|
+
it('shifts start and end if inserting before non circular range', function() {
|
9
|
+
assert.deepEqual(adjustRangeToInsert({
|
10
|
+
start: 10,
|
11
|
+
end: 20
|
12
|
+
}, 4, 5), {
|
13
|
+
start: 15,
|
14
|
+
end: 25
|
15
|
+
});
|
16
|
+
assert.deepEqual(adjustRangeToInsert({
|
17
|
+
start: 10,
|
18
|
+
end: 20
|
19
|
+
}, 10, 5), {
|
20
|
+
start: 15,
|
21
|
+
end: 25
|
22
|
+
});
|
23
|
+
assert.deepEqual(adjustRangeToInsert({
|
24
|
+
start: 10,
|
25
|
+
end: 20
|
26
|
+
}, 0, 5), {
|
27
|
+
start: 15,
|
28
|
+
end: 25
|
29
|
+
});
|
30
|
+
});
|
31
|
+
it('shifts end if inserting in middle of non circular range', function() {
|
32
|
+
assert.deepEqual(adjustRangeToInsert({
|
33
|
+
start: 10,
|
34
|
+
end: 20
|
35
|
+
}, 11, 5), {
|
36
|
+
start: 10,
|
37
|
+
end: 25
|
38
|
+
});
|
39
|
+
assert.deepEqual(adjustRangeToInsert({
|
40
|
+
start: 10,
|
41
|
+
end: 20
|
42
|
+
}, 20, 5), {
|
43
|
+
start: 10,
|
44
|
+
end: 25
|
45
|
+
});
|
46
|
+
});
|
47
|
+
it('shifts neither start nor end if inserting in after end of non circular range', function() {
|
48
|
+
assert.deepEqual(adjustRangeToInsert({
|
49
|
+
start: 10,
|
50
|
+
end: 20
|
51
|
+
}, 24, 5), {
|
52
|
+
start: 10,
|
53
|
+
end: 20
|
54
|
+
});
|
55
|
+
assert.deepEqual(adjustRangeToInsert({
|
56
|
+
start: 10,
|
57
|
+
end: 20
|
58
|
+
}, 21, 5), {
|
59
|
+
start: 10,
|
60
|
+
end: 20
|
61
|
+
});
|
62
|
+
});
|
63
|
+
it('shifts neither start nor end if inserting in after start of circular range', function() {
|
64
|
+
assert.deepEqual(adjustRangeToInsert({
|
65
|
+
start: 20,
|
66
|
+
end: 10
|
67
|
+
}, 24, 5), {
|
68
|
+
start: 20,
|
69
|
+
end: 10
|
70
|
+
});
|
71
|
+
assert.deepEqual(adjustRangeToInsert({
|
72
|
+
start: 20,
|
73
|
+
end: 10
|
74
|
+
}, 21, 5), {
|
75
|
+
start: 20,
|
76
|
+
end: 10
|
77
|
+
});
|
78
|
+
});
|
79
|
+
it('shifts both start and end if inserting in before end of circular range', function() {
|
80
|
+
assert.deepEqual(adjustRangeToInsert({
|
81
|
+
start: 20,
|
82
|
+
end: 10
|
83
|
+
}, 5, 5), {
|
84
|
+
start: 25,
|
85
|
+
end: 15
|
86
|
+
});
|
87
|
+
assert.deepEqual(adjustRangeToInsert({
|
88
|
+
start: 20,
|
89
|
+
end: 10
|
90
|
+
}, 10, 5), {
|
91
|
+
start: 25,
|
92
|
+
end: 15
|
93
|
+
});
|
94
|
+
});
|
95
|
+
it('shifts just start if inserting in after end but before start of circular range', function() {
|
96
|
+
assert.deepEqual(adjustRangeToInsert({
|
97
|
+
start: 20,
|
98
|
+
end: 10
|
99
|
+
}, 11, 5), {
|
100
|
+
start: 25,
|
101
|
+
end: 10
|
102
|
+
});
|
103
|
+
assert.deepEqual(adjustRangeToInsert({
|
104
|
+
start: 20,
|
105
|
+
end: 10
|
106
|
+
}, 20, 5), {
|
107
|
+
start: 25,
|
108
|
+
end: 10
|
109
|
+
});
|
110
|
+
});
|
111
|
+
});
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
import {assign} from "lodash";
|
3
|
+
|
4
|
+
import {identity} from 'lodash';
|
5
|
+
|
6
|
+
export default function adjustRangeToRotation(
|
7
|
+
rangeToBeAdjusted,
|
8
|
+
rotateTo = 0,
|
9
|
+
rangeLength
|
10
|
+
) {
|
11
|
+
// ac.throw([ac.range, ac.posInt, ac.posInt], arguments);
|
12
|
+
const mod = rangeLength ? modulo : identity
|
13
|
+
|
14
|
+
const newRange = assign({}, rangeToBeAdjusted, {
|
15
|
+
start: mod(rangeToBeAdjusted.start - (rotateTo || 0), rangeLength),
|
16
|
+
end: mod(rangeToBeAdjusted.end - (rotateTo || 0), rangeLength)
|
17
|
+
});
|
18
|
+
|
19
|
+
return newRange;
|
20
|
+
};
|
21
|
+
|
22
|
+
function modulo(n, m) {
|
23
|
+
return ((n % m) + m) % m;
|
24
|
+
}
|
@@ -0,0 +1,123 @@
|
|
1
|
+
import adjustRangeToRotation from './adjustRangeToRotation.js';
|
2
|
+
|
3
|
+
import assert from 'assert';
|
4
|
+
|
5
|
+
|
6
|
+
;
|
7
|
+
describe('adjustRangeToRotation', function() {
|
8
|
+
it('defaults to a rotateBy=0 if a null or undefined is passed ', () => {
|
9
|
+
assert.deepEqual(adjustRangeToRotation({
|
10
|
+
start: 1,
|
11
|
+
end: 2
|
12
|
+
}, null, 10), {
|
13
|
+
start: 1,
|
14
|
+
end: 2
|
15
|
+
});
|
16
|
+
|
17
|
+
assert.deepEqual(adjustRangeToRotation({
|
18
|
+
start: 1,
|
19
|
+
end: 2
|
20
|
+
}, undefined, 10), {
|
21
|
+
start: 1,
|
22
|
+
end: 2
|
23
|
+
});
|
24
|
+
assert.deepEqual(adjustRangeToRotation({
|
25
|
+
start: 1,
|
26
|
+
end: 2
|
27
|
+
}, NaN, 10), {
|
28
|
+
start: 1,
|
29
|
+
end: 2
|
30
|
+
});
|
31
|
+
|
32
|
+
});
|
33
|
+
it('defaults to an infinite length if no length is passed', () => {
|
34
|
+
assert.deepEqual(adjustRangeToRotation({
|
35
|
+
start: 1,
|
36
|
+
end: 2
|
37
|
+
}, 1, null), {
|
38
|
+
start: 0,
|
39
|
+
end: 1
|
40
|
+
});
|
41
|
+
assert.deepEqual(adjustRangeToRotation({
|
42
|
+
start: 1,
|
43
|
+
end: 2
|
44
|
+
}, 1, undefined), {
|
45
|
+
start: 0,
|
46
|
+
end: 1
|
47
|
+
});
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
});
|
52
|
+
it('shifts start and end if rotating before non circular range', function() {
|
53
|
+
//0123456789
|
54
|
+
//atgcatgccc
|
55
|
+
// rr
|
56
|
+
//
|
57
|
+
assert.deepEqual(adjustRangeToRotation({
|
58
|
+
start: 1,
|
59
|
+
end: 2
|
60
|
+
}, 1, 10), {
|
61
|
+
start: 0,
|
62
|
+
end: 1
|
63
|
+
});
|
64
|
+
assert.deepEqual(adjustRangeToRotation({
|
65
|
+
start: 1,
|
66
|
+
end: 2
|
67
|
+
}, undefined, 10), {
|
68
|
+
start: 1,
|
69
|
+
end: 2
|
70
|
+
});
|
71
|
+
assert.deepEqual(adjustRangeToRotation({
|
72
|
+
start: 1,
|
73
|
+
end: 2
|
74
|
+
}, 2, 10), {
|
75
|
+
start: 9,
|
76
|
+
end: 0
|
77
|
+
});
|
78
|
+
assert.deepEqual(adjustRangeToRotation({
|
79
|
+
start: 1,
|
80
|
+
end: 2
|
81
|
+
}, 3, 10), {
|
82
|
+
start: 8,
|
83
|
+
end: 9
|
84
|
+
});
|
85
|
+
//0123456789
|
86
|
+
//atgcatgccc
|
87
|
+
//rrrrr rrr
|
88
|
+
//
|
89
|
+
assert.deepEqual(adjustRangeToRotation({
|
90
|
+
start: 7,
|
91
|
+
end: 4
|
92
|
+
}, 3, 10), {
|
93
|
+
start: 4,
|
94
|
+
end: 1
|
95
|
+
});
|
96
|
+
assert.deepEqual(adjustRangeToRotation({
|
97
|
+
start: 7,
|
98
|
+
end: 4
|
99
|
+
}, 5, 10), {
|
100
|
+
start: 2,
|
101
|
+
end: 9
|
102
|
+
});
|
103
|
+
assert.deepEqual(adjustRangeToRotation({
|
104
|
+
start: 7,
|
105
|
+
end: 4
|
106
|
+
}, 6, 10), {
|
107
|
+
start: 1,
|
108
|
+
end: 8
|
109
|
+
});
|
110
|
+
//0123456 789
|
111
|
+
//atgcatg ccc
|
112
|
+
//rrrrrrr rrr
|
113
|
+
//
|
114
|
+
assert.deepEqual(adjustRangeToRotation({
|
115
|
+
start: 7,
|
116
|
+
end: 6
|
117
|
+
}, 3, 10), {
|
118
|
+
start: 4,
|
119
|
+
end: 3
|
120
|
+
});
|
121
|
+
});
|
122
|
+
|
123
|
+
});
|
@@ -0,0 +1,30 @@
|
|
1
|
+
//
|
2
|
+
// ac.throw([ac.posInt, ac.posInt, ac.bool], arguments);
|
3
|
+
export default function checkIfNonCircularRangesOverlap(range, comparisonRange) {
|
4
|
+
// ac.throw([ac.range, ac.range], arguments);
|
5
|
+
if (range.start < comparisonRange.start) {
|
6
|
+
if (range.end < comparisonRange.start) {
|
7
|
+
//----llll
|
8
|
+
//--------cccc
|
9
|
+
//no overlap
|
10
|
+
return false;
|
11
|
+
} else {
|
12
|
+
//----llll
|
13
|
+
//-------cccc
|
14
|
+
//overlap
|
15
|
+
return true;
|
16
|
+
}
|
17
|
+
} else {
|
18
|
+
if (range.start > comparisonRange.end) {
|
19
|
+
//------llll
|
20
|
+
// -cccc
|
21
|
+
//no overlap
|
22
|
+
return false;
|
23
|
+
} else {
|
24
|
+
//-----llll
|
25
|
+
// -cccc
|
26
|
+
//overlap
|
27
|
+
return true;
|
28
|
+
}
|
29
|
+
}
|
30
|
+
};
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import {expect} from 'chai';
|
2
|
+
|
3
|
+
import checkIfNonCircularRangesOverlap from './checkIfNonCircularRangesOverlap.js';
|
4
|
+
// checkIfNonCircularRangesOverlap(frame, sequence, minimumOrfSize, forward, circular)
|
5
|
+
describe('checkIfNonCircularRangesOverlap', function() {
|
6
|
+
it('returns true if non circular ranges do overlap', function() {
|
7
|
+
expect(checkIfNonCircularRangesOverlap({
|
8
|
+
start: 5,
|
9
|
+
end: 100
|
10
|
+
}, {
|
11
|
+
start: 50,
|
12
|
+
end: 50
|
13
|
+
})).to.equal(true);
|
14
|
+
expect(checkIfNonCircularRangesOverlap({
|
15
|
+
start: 5,
|
16
|
+
end: 100
|
17
|
+
}, {
|
18
|
+
start: 50,
|
19
|
+
end: 500
|
20
|
+
})).to.equal(true);
|
21
|
+
expect(checkIfNonCircularRangesOverlap({
|
22
|
+
start: 5,
|
23
|
+
end: 100
|
24
|
+
}, {
|
25
|
+
start: 0,
|
26
|
+
end: 5
|
27
|
+
})).to.equal(true);
|
28
|
+
});
|
29
|
+
it('returns false if non circular ranges do not overlap', function() {
|
30
|
+
expect(checkIfNonCircularRangesOverlap({
|
31
|
+
start: 5,
|
32
|
+
end: 100
|
33
|
+
}, {
|
34
|
+
start: 1,
|
35
|
+
end: 4
|
36
|
+
})).to.equal(false);
|
37
|
+
expect(checkIfNonCircularRangesOverlap({
|
38
|
+
start: 5,
|
39
|
+
end: 100
|
40
|
+
}, {
|
41
|
+
start: 101,
|
42
|
+
end: 101
|
43
|
+
})).to.equal(false);
|
44
|
+
});
|
45
|
+
});
|
@@ -0,0 +1,16 @@
|
|
1
|
+
//
|
2
|
+
import checkIfNonCircularRangesOverlap from './checkIfNonCircularRangesOverlap';
|
3
|
+
|
4
|
+
import splitRangeIntoTwoPartsIfItIsCircular from './splitRangeIntoTwoPartsIfItIsCircular';
|
5
|
+
// ac.throw([ac.posInt, ac.posInt, ac.bool], arguments);
|
6
|
+
|
7
|
+
export default function checkIfPotentiallyCircularRangesOverlap(range, comparisonRange) {
|
8
|
+
// ac.throw([ac.range, ac.range], arguments);
|
9
|
+
//split the potentially circular ranges and compare each part for overlap
|
10
|
+
return splitRangeIntoTwoPartsIfItIsCircular(range, Infinity).some(function (splitRange) {
|
11
|
+
return splitRangeIntoTwoPartsIfItIsCircular(comparisonRange, Infinity).some(function (splitComparisonRange) {
|
12
|
+
return checkIfNonCircularRangesOverlap(splitRange, splitComparisonRange);
|
13
|
+
})
|
14
|
+
})
|
15
|
+
};
|
16
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
import {expect} from 'chai';
|
2
|
+
|
3
|
+
import checkIfPotentiallyCircularRangesOverlap from './checkIfPotentiallyCircularRangesOverlap.js';
|
4
|
+
// checkIfPotentiallyCircularRangesOverlap(frame, sequence, minimumOrfSize, forward, circular)
|
5
|
+
describe('checkIfPotentiallyCircularRangesOverlap', function() {
|
6
|
+
it('returns true if ranges do overlap', function() {
|
7
|
+
expect(checkIfPotentiallyCircularRangesOverlap({
|
8
|
+
start: 5,
|
9
|
+
end: 100
|
10
|
+
}, {
|
11
|
+
start: 50,
|
12
|
+
end: 50
|
13
|
+
})).to.equal(true);
|
14
|
+
expect(checkIfPotentiallyCircularRangesOverlap({
|
15
|
+
start: 5,
|
16
|
+
end: 100
|
17
|
+
}, {
|
18
|
+
start: 50,
|
19
|
+
end: 500
|
20
|
+
})).to.equal(true);
|
21
|
+
expect(checkIfPotentiallyCircularRangesOverlap({
|
22
|
+
start: 5,
|
23
|
+
end: 100
|
24
|
+
}, {
|
25
|
+
start: 0,
|
26
|
+
end: 5
|
27
|
+
})).to.equal(true);
|
28
|
+
expect(checkIfPotentiallyCircularRangesOverlap({
|
29
|
+
start: 50,
|
30
|
+
end: 10
|
31
|
+
}, {
|
32
|
+
start: 0,
|
33
|
+
end: 5
|
34
|
+
})).to.equal(true);
|
35
|
+
expect(checkIfPotentiallyCircularRangesOverlap({
|
36
|
+
start: 50,
|
37
|
+
end: 10
|
38
|
+
}, {
|
39
|
+
start: 20,
|
40
|
+
end: 5
|
41
|
+
})).to.equal(true);
|
42
|
+
expect(checkIfPotentiallyCircularRangesOverlap({
|
43
|
+
start: 50,
|
44
|
+
end: 10
|
45
|
+
}, {
|
46
|
+
start: 20,
|
47
|
+
end: 51
|
48
|
+
})).to.equal(true);
|
49
|
+
});
|
50
|
+
it('returns false if ranges do not overlap', function() {
|
51
|
+
expect(checkIfPotentiallyCircularRangesOverlap({
|
52
|
+
start: 5,
|
53
|
+
end: 100
|
54
|
+
}, {
|
55
|
+
start: 1,
|
56
|
+
end: 4
|
57
|
+
})).to.equal(false);
|
58
|
+
expect(checkIfPotentiallyCircularRangesOverlap({
|
59
|
+
start: 50,
|
60
|
+
end: 10
|
61
|
+
}, {
|
62
|
+
start: 20,
|
63
|
+
end: 49
|
64
|
+
})).to.equal(false);
|
65
|
+
expect(checkIfPotentiallyCircularRangesOverlap({
|
66
|
+
start: 5,
|
67
|
+
end: 100
|
68
|
+
}, {
|
69
|
+
start: 101,
|
70
|
+
end: 101
|
71
|
+
})).to.equal(false);
|
72
|
+
});
|
73
|
+
});
|
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
//this function is a little confusing, but basically it takes an array of overlaps
|
4
|
+
//generated from a range overlaps calculation, and it sews them together if possible
|
5
|
+
export default function collapseOverlapsGeneratedFromRangeComparisonIfPossible(overlaps, sequenceLength, optionalOriginalRange) {
|
6
|
+
const originalRangeLinear = optionalOriginalRange && (optionalOriginalRange.start <= optionalOriginalRange.end)
|
7
|
+
if (overlaps.length === 1 || overlaps.length === 0) {
|
8
|
+
return overlaps;
|
9
|
+
} else if (overlaps.length === 2) {
|
10
|
+
if (overlaps[0].start === 0 && overlaps[1].end + 1 === sequenceLength && !originalRangeLinear) {
|
11
|
+
return [{
|
12
|
+
start: overlaps[1].start,
|
13
|
+
end: overlaps[0].end
|
14
|
+
}];
|
15
|
+
} else if (overlaps[1].start === 0 && overlaps[0].end + 1 === sequenceLength && !originalRangeLinear) {
|
16
|
+
return [{
|
17
|
+
start: overlaps[0].start,
|
18
|
+
end: overlaps[1].end
|
19
|
+
}];
|
20
|
+
} else {
|
21
|
+
return overlaps;
|
22
|
+
}
|
23
|
+
} else if (overlaps.length === 3) {
|
24
|
+
const firstOverlap = overlaps[0];
|
25
|
+
const secondOverlap = overlaps[1];
|
26
|
+
const thirdOverlap = overlaps[2];
|
27
|
+
let collapsedOverlaps = collapseOverlapsGeneratedFromRangeComparisonIfPossible([firstOverlap, secondOverlap], sequenceLength, optionalOriginalRange);
|
28
|
+
if (collapsedOverlaps.length === 1) {
|
29
|
+
collapsedOverlaps.push(thirdOverlap);
|
30
|
+
return collapsedOverlaps;
|
31
|
+
} else {
|
32
|
+
collapsedOverlaps = collapseOverlapsGeneratedFromRangeComparisonIfPossible([firstOverlap, thirdOverlap], sequenceLength, optionalOriginalRange);
|
33
|
+
if (collapsedOverlaps.length === 1) {
|
34
|
+
collapsedOverlaps.push(secondOverlap);
|
35
|
+
return collapsedOverlaps;
|
36
|
+
} else {
|
37
|
+
collapsedOverlaps = collapseOverlapsGeneratedFromRangeComparisonIfPossible([secondOverlap, thirdOverlap], sequenceLength, optionalOriginalRange);
|
38
|
+
if (collapsedOverlaps.length === 1) {
|
39
|
+
collapsedOverlaps.push(firstOverlap);
|
40
|
+
return collapsedOverlaps;
|
41
|
+
} else {
|
42
|
+
return overlaps;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
};
|