From 3e88c926f9e1fc649f9c0932b57eb088052473ec Mon Sep 17 00:00:00 2001 From: hansonr Date: Mon, 26 Aug 2019 22:11:02 -0500 Subject: [PATCH] JAL-3253-applet no-NCList IntervalStore fixes --- src/intervalstore/nonc/IntervalStore.java | 81 +++++++++++++++++++- src/jalview/datamodel/features/FeatureStoreJS.java | 61 ++++++++++++--- src/jalview/renderer/OverviewResColourFinder.java | 42 ++++++++-- .../datamodel/features/FeatureStoreJSTest.java | 1 + .../renderer/OverviewResColourFinderTest.java | 36 +++++++-- 5 files changed, 196 insertions(+), 25 deletions(-) diff --git a/src/intervalstore/nonc/IntervalStore.java b/src/intervalstore/nonc/IntervalStore.java index 5914516..1ea9ee0 100644 --- a/src/intervalstore/nonc/IntervalStore.java +++ b/src/intervalstore/nonc/IntervalStore.java @@ -268,7 +268,9 @@ public class IntervalStore } if (deleted > 0) + { finalizeDeletion(); + } if (!isTainted) { offsets = null; @@ -301,9 +303,13 @@ public class IntervalStore return false; } if (index < 0) + { index = -1 - index; + } else + { index++; + } } } @@ -313,7 +319,7 @@ public class IntervalStore { return false; } - + isSorted = false; } if (index == intervalCount) @@ -328,7 +334,9 @@ public class IntervalStore // System.out.println("stashed " + pt + " " + interval + " for " // + index + " " + intervals[index]); if (offsets == null) + { offsets = new int[capacity]; + } offsets[pt] = offsets[index]; @@ -344,7 +352,9 @@ public class IntervalStore private IntervalI[] finalizeAddition(IntervalI[] dest) { if (dest == null) + { dest = intervals; + } if (added == 0) { if (intervalCount > 0 && dest != intervals) @@ -362,16 +372,24 @@ public class IntervalStore { int pt0 = pt; while (--pt >= 0 && offsets[pt] == 0) + { ; + } if (pt < 0) + { pt = 0; + } int nOK = pt0 - pt; // shift upper intervals right ptShift -= nOK; if (nOK > 0) + { System.arraycopy(intervals, pt, dest, ptShift, nOK); + } if (added == 0) + { break; + } for (int offset = offsets[pt]; offset > 0; offset = offsets[offset]) { dest[--ptShift] = intervals[offset]; @@ -404,9 +422,13 @@ public class IntervalStore int r1 = interval.getEnd(); int end = intervalCount - 1; if (end < 0 || r0 < minStart) + { return -1; + } if (r0 > maxStart) + { return -1 - intervalCount; + } while (start <= end) { int mid = (start + end) >>> 1; @@ -423,25 +445,35 @@ public class IntervalStore IntervalI iv = intervals[mid]; if ((bsIgnore == null || !bsIgnore.get(mid)) && iv.equalsInterval(interval)) + { return mid; // found one; just scan up and down now, first checking the range, but // also checking other possible aspects of equivalence. + } for (int i = mid; ++i <= end;) { if ((iv = intervals[i]).getBegin() != r0 || iv.getEnd() != r1) + { break; + } if ((bsIgnore == null || !bsIgnore.get(i)) && iv.equalsInterval(interval)) + { return i; + } } for (int i = mid; --i >= start;) { if ((iv = intervals[i]).getBegin() != r0 || iv.getEnd() < r1) + { return -1 - ++i; + } if ((bsIgnore == null || !bsIgnore.get(i)) && iv.equalsInterval(interval)) + { return i; + } } return -1 - start; } @@ -501,7 +533,9 @@ public class IntervalStore private int compareRange(IntervalI t, long from, long to) { if (t == null) + { System.out.println("???"); + } int order = Long.signum(t.getBegin() - from); return (order == 0 ? Long.signum(bigendian ? to - t.getEnd() : t.getEnd() - to) @@ -512,7 +546,9 @@ public class IntervalStore public boolean contains(Object entry) { if (entry == null || intervalCount == 0) + { return false; + } if (!isSorted || deleted > 0) { sort(); @@ -525,6 +561,7 @@ public class IntervalStore ensureFinalized(); int index = binaryIdentitySearch(inner, null); if (index >= 0) + { while ((index = index - Math.abs(offsets[index])) >= 0) { if (intervals[index] == outer) @@ -532,19 +569,22 @@ public class IntervalStore return true; } } + } return false; } private void ensureFinalized() { - if (isTainted && intervalCount + added > 1) + if (isTainted) { if (!isSorted || added > 0 || deleted > 0) { sort(); } if (offsets == null || offsets.length < intervalCount) + { offsets = new int[intervalCount]; + } linkFeatures(); isTainted = false; } @@ -595,11 +635,15 @@ public class IntervalStore ensureFinalized(); if (from > maxEnd || to < minStart) + { return result; + } int index = binaryLastIntervalSearch(from, to, ret); int index1 = ret[0]; if (index1 < 0) + { return result; + } if (index1 > index + 1) { @@ -631,7 +675,9 @@ public class IntervalStore public IntervalI get(int i) { if (i < 0 || i >= intervalCount + added) + { return null; + } ensureFinalized(); return intervals[i]; } @@ -716,7 +762,7 @@ public class IntervalStore @Override public Iterator iterator() { - finalizeAddition(null); + ensureFinalized(); return new Iterator() { @@ -733,7 +779,9 @@ public class IntervalStore public T next() { if (next >= intervalCount) + { throw new NoSuchElementException(); + } return (T) intervals[next++]; } @@ -743,7 +791,9 @@ public class IntervalStore private void linkFeatures() { if (intervalCount == 0) + { return; + } maxEnd = intervals[0].getEnd(); offsets[0] = IntervalI.NOT_CONTAINED; if (intervalCount == 1) @@ -824,7 +874,9 @@ public class IntervalStore // if (addPt == intervalCount || offsets[pt] == 0) // return pt; if (pt >= 0 || added == 0 || pt == -1 - intervalCount) + { return pt; + } pt = -1 - pt; int start = interval.getBegin(); int end = interval.getEnd(); @@ -840,7 +892,9 @@ public class IntervalStore break; case 0: if (iv.equalsInterval(interval)) + { return pt; + } // fall through case 1: match = pt; @@ -853,7 +907,9 @@ public class IntervalStore { int i = intervalCount; while (--i >= 0 && !intervals[i].equalsInterval(interval)) + { ; + } return i; } } @@ -873,13 +929,19 @@ public class IntervalStore } int i = binaryIdentitySearch(interval, bsDeleted); if (i < 0) + { return false; + } if (deleted == 0) { if (bsDeleted == null) + { bsDeleted = new BitSet(intervalCount); + } else + { bsDeleted.clear(); + } } bsDeleted.set(i); deleted++; @@ -889,7 +951,9 @@ public class IntervalStore private void finalizeDeletion() { if (deleted == 0) + { return; + } // ......xxx.....xxxx.....xxxxx.... // ......^i,pt @@ -900,14 +964,18 @@ public class IntervalStore i = bsDeleted.nextClearBit(i + 1); int pt1 = bsDeleted.nextSetBit(i + 1); if (pt1 < 0) + { pt1 = intervalCount; + } int n = pt1 - i; System.arraycopy(intervals, i, intervals, pt, n); pt += n; if (pt1 == intervalCount) { for (i = pt1; --i >= pt;) + { intervals[i] = null; + } intervalCount -= deleted; deleted = 0; bsDeleted.clear(); @@ -934,6 +1002,13 @@ public class IntervalStore return intervalCount + added - deleted; } + @Override + public Object[] toArray() + { + ensureFinalized(); + return super.toArray(); + } + /** * Sort intervals by start (lowest first) and end (highest first). */ diff --git a/src/jalview/datamodel/features/FeatureStoreJS.java b/src/jalview/datamodel/features/FeatureStoreJS.java index dbf1413..4f49360 100644 --- a/src/jalview/datamodel/features/FeatureStoreJS.java +++ b/src/jalview/datamodel/features/FeatureStoreJS.java @@ -244,8 +244,8 @@ public class FeatureStoreJS extends FeatureStore { if (start == end) { - getContactPoints(contactFeatureStarts, start, result, true); - getContactPoints(contactFeatureEnds, start, result, false); + getContactPointStarts(contactFeatureStarts, start, result); + getContactPointEnds(contactFeatureEnds, end, result); } else { @@ -309,8 +309,8 @@ public class FeatureStoreJS extends FeatureStore * * @author Bob Hanson 2019.07.30 */ - private void getContactPoints(List l, long pos, - List result, boolean isStart) + private void getContactPointStarts(List l, long pos, + List result) { int low = 0; int high = l.size() - 1; @@ -318,7 +318,7 @@ public class FeatureStoreJS extends FeatureStore { int mid = (low + high) >>> 1; SequenceFeature f = l.get(mid); - switch (Long.signum((isStart ? f.begin : f.end) - pos)) + switch (Long.signum(f.begin - pos)) { case -1: low = mid + 1; @@ -330,13 +330,11 @@ public class FeatureStoreJS extends FeatureStore int m = mid; result.add(f); // could be "5" in 12345556788 ? - while (++mid <= high && (f = l.get(mid)) != null - && (isStart ? f.begin : f.end) == pos) + while (++mid <= high && (f = l.get(mid)) != null && f.begin == pos) { result.add(f); } - while (--m >= low && (f = l.get(m)) != null - && (isStart ? f.begin : f.end) == pos) + while (--m >= low && (f = l.get(m)) != null && f.begin == pos) { result.add(f); } @@ -345,6 +343,51 @@ public class FeatureStoreJS extends FeatureStore } } + private void getContactPointEnds(List l, long pos, + List result) + { + int low = 0; + int high = l.size() - 1; + while (low <= high) + { + int mid = (low + high) >>> 1; + SequenceFeature f = l.get(mid); + switch (Long.signum(f.end - pos)) + { + case -1: + low = mid + 1; + continue; + case 1: + high = mid - 1; + continue; + case 0: + int m = mid; + if (f.begin != f.end) + { + result.add(f); + } + // could be "5" in 12345556788 ? + while (++mid <= high && (f = l.get(mid)) != null + && f.end == pos) + { + if (f.begin != f.end) + { + result.add(f); + } + } + while (--m >= low && (f = l.get(m)) != null + && f.end == pos) + { + if (f.begin != f.end) + { + result.add(f); + } + } + return; + } + } + } + /** * Adds contact features whose start position lies in the from-to range to the * result list diff --git a/src/jalview/renderer/OverviewResColourFinder.java b/src/jalview/renderer/OverviewResColourFinder.java index 94e7c5b..a98f3b3 100644 --- a/src/jalview/renderer/OverviewResColourFinder.java +++ b/src/jalview/renderer/OverviewResColourFinder.java @@ -78,6 +78,15 @@ public class OverviewResColourFinder extends ResidueColourFinder HIDDEN_COLOUR = hiddenCol; } + @Override + /** + * for Test suite only. + */ + public Color getBoxColour(ResidueShaderI shader, SequenceI seq, int i) + { + return new Color(getBoxColourInt(shader, seq, i)); + } + public int getBoxColourInt(ResidueShaderI shader, SequenceI seq, int i) { char currentChar = seq.getCharAt(i); @@ -93,6 +102,19 @@ public class OverviewResColourFinder extends ResidueColourFinder : shader.findColourInt(currentChar, i, seq)); } + /** + * For test suite only. + */ + @Override + public Color getResidueColour(boolean showBoxes, ResidueShaderI shader, + SequenceGroup[] allGroups, final SequenceI seq, int i, + FeatureColourFinder finder) + { + return new Color(getResidueColourInt(showBoxes, shader, allGroups, seq, + i, finder)); + } + + public int getResidueColourInt(boolean showBoxes, ResidueShaderI shader, SequenceGroup[] allGroups, final SequenceI seq, int i, FeatureColourFinder finder) @@ -104,17 +126,27 @@ public class OverviewResColourFinder extends ResidueColourFinder return c; } - int col = getResidueBoxColourInt(showBoxes, shader, allGroups, seq, - i); - + int col = getResidueBoxColourInt(showBoxes, shader, allGroups, seq, i); // if there's a FeatureColourFinder we might override the residue colour // here with feature colouring return seq.setColor(i, finder == null || finder.noFeaturesDisplayed() ? col - : finder.findFeatureColourInt(col, seq, i)); + : finder.findFeatureColourInt(col, seq, i)); } - + + /** + * For test suite only. + */ + @Override + protected Color getResidueBoxColour(boolean showBoxes, + ResidueShaderI shader, SequenceGroup[] allGroups, SequenceI seq, + int i) + { + return new Color( + getResidueBoxColourInt(showBoxes, shader, allGroups, seq, i)); + } + /** * In the overview, the showBoxes setting is ignored, as the overview displays * the colours regardless. diff --git a/test/jalview/datamodel/features/FeatureStoreJSTest.java b/test/jalview/datamodel/features/FeatureStoreJSTest.java index 12b6c74..09fe410 100644 --- a/test/jalview/datamodel/features/FeatureStoreJSTest.java +++ b/test/jalview/datamodel/features/FeatureStoreJSTest.java @@ -36,6 +36,7 @@ public class FeatureStoreJSTest assertEquals(overlaps.get(1).getEnd(), 20); overlaps = fs.findOverlappingFeatures(12, 16); + assertEquals(overlaps.size(), 3); assertEquals(overlaps.get(0).getEnd(), 20); assertEquals(overlaps.get(1).getEnd(), 20); diff --git a/test/jalview/renderer/OverviewResColourFinderTest.java b/test/jalview/renderer/OverviewResColourFinderTest.java index 1687516..0585a07 100644 --- a/test/jalview/renderer/OverviewResColourFinderTest.java +++ b/test/jalview/renderer/OverviewResColourFinderTest.java @@ -59,19 +59,20 @@ public class OverviewResColourFinderTest final AlignViewport av = new AlignViewport(al); ResidueColourFinder rcf = new OverviewResColourFinder(); + ResidueShaderI sh = av.getResidueShading(); + // gaps are grey, residues white - assertEquals(Color.white, rcf.getResidueColour(true, - av.getResidueShading(), - null, seq, 0, null)); - assertEquals(Color.lightGray, rcf - .getResidueColour(true, av.getResidueShading(), null, seq, 2, - null)); + assertEquals(Color.white, + rcf.getResidueColour(true, sh, null, seq, 0, null)); + System.out.println(rcf.getResidueColour(true, sh, null, seq, 2, null)); + assertEquals(Color.lightGray, rcf.getResidueColour(true, + sh, null, seq, 2, null)); // unaffected by showBoxes setting assertEquals(Color.white, rcf.getResidueColour(false, - av.getResidueShading(), null, seq, 0, null)); + sh, null, seq, 0, null)); assertEquals(Color.lightGray, rcf.getResidueColour(false, - av.getResidueShading(), null, seq, 2, null)); + sh, null, seq, 2, null)); } @Test(groups = { "Functional" }) @@ -136,6 +137,7 @@ public class OverviewResColourFinderTest } av.setGlobalColourScheme(new UserColourScheme(newColours)); + seq.resetColors(); // gap colour not specified so gaps are lightGray assertEquals(Color.lightGray, rcf @@ -144,6 +146,7 @@ public class OverviewResColourFinderTest newColours[23] = Color.pink; av.setGlobalColourScheme(new UserColourScheme(newColours)); + seq.resetColors(); // gap colour specified as pink assertEquals(Color.pink, rcf.getResidueColour(true, @@ -153,11 +156,14 @@ public class OverviewResColourFinderTest // unaffected by showBoxes setting // gap colour not specified so gaps are lightGray newColours[23] = null; + seq.resetColors(); + assertEquals(Color.lightGray, rcf.getResidueColour(false, av.getResidueShading(), null, seq, 3, null)); newColours[23] = Color.pink; av.setGlobalColourScheme(new UserColourScheme(newColours)); + seq.resetColors(); // gap colour specified as pink assertEquals(Color.pink, rcf.getResidueColour(false, @@ -196,6 +202,8 @@ public class OverviewResColourFinderTest // use legacy colouring rcf = new OverviewResColourFinder(true, Color.blue, Color.red); + + seq.resetColors(); // G in group specified as magenta in Zappo assertEquals(Color.magenta, rcf.getResidueColour(false, @@ -212,6 +220,8 @@ public class OverviewResColourFinderTest // use new colouring rcf = new OverviewResColourFinder(false, Color.blue, Color.red); + seq.resetColors(); + // G in group specified as magenta in Zappo assertEquals(Color.magenta, rcf.getResidueColour(false, av.getResidueShading(), groups, seq, 7, null)); @@ -237,6 +247,8 @@ public class OverviewResColourFinderTest ResidueColourFinder rcf = new OverviewResColourFinder(); ResidueShaderI shader = new ResidueShader(); + seq.resetColors(); + // residues white Color c = rcf.getBoxColour(shader, seq, 0); assertEquals(Color.white, c); @@ -251,6 +263,8 @@ public class OverviewResColourFinderTest rcf = new OverviewResColourFinder(true, Color.blue, Color.red); shader = new ResidueShader(); + seq.resetColors(); + // residues light gray c = rcf.getBoxColour(shader, seq, 0); assertEquals(Color.lightGray, c); @@ -263,6 +277,8 @@ public class OverviewResColourFinderTest rcf = new OverviewResColourFinder(); shader = new ResidueShader(); + seq.resetColors(); + // residues white c = rcf.getBoxColour(shader, seq, 0); assertEquals(Color.white, c); @@ -277,6 +293,8 @@ public class OverviewResColourFinderTest rcf = new OverviewResColourFinder(false, Color.blue, Color.red); shader = new ResidueShader(new ZappoColourScheme()); + seq.resetColors(); + // M residue pink c = rcf.getBoxColour(shader, seq, 0); assertEquals(Color.pink, c); @@ -288,6 +306,8 @@ public class OverviewResColourFinderTest // legacy colouring with colour scheme rcf = new OverviewResColourFinder(true, Color.blue, Color.red); + seq.resetColors(); + // M residue pink c = rcf.getBoxColour(shader, seq, 0); assertEquals(Color.pink, c); -- 1.7.10.2