X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2Ffeatures%2FFeatureStore.java;h=686ac26cf17b48ceaa9c1bbcbb5bf6173ce584ee;hb=fbf6a124e2ffe81bcde747fda6f004748eb3b479;hp=54c0d59f90b164a1f62d890b60e32be94cfd383b;hpb=0f9c3a6ae35a2f6841fdb8700f85a563fbaeb7e3;p=jalview.git diff --git a/src/jalview/datamodel/features/FeatureStore.java b/src/jalview/datamodel/features/FeatureStore.java index 54c0d59..686ac26 100644 --- a/src/jalview/datamodel/features/FeatureStore.java +++ b/src/jalview/datamodel/features/FeatureStore.java @@ -90,6 +90,10 @@ public class FeatureStore float nonPositionalMaxScore; + private SequenceFeature[] temp = new SequenceFeature[3]; + + private boolean isTainted; + /** * Constructor */ @@ -250,6 +254,7 @@ public class FeatureStore features = new IntervalStore<>(); } features.add(feature); + isTainted = true; } /** @@ -602,7 +607,7 @@ public class FeatureStore positionalMaxScore = Float.NaN; nonPositionalMinScore = Float.NaN; nonPositionalMaxScore = Float.NaN; - + isTainted = true; /* * scan non-positional features for groups and scores */ @@ -851,4 +856,107 @@ public class FeatureStore } return modified; } + + /** + * Find all features containing this position. + * Uses isTainted field to know when to reconstruct its temporary array. + * + * @param pos + * @return list of SequenceFeatures + * @author Bob Hanson 2019.07.30 + */ + public void findOverlappingFeatures(int pos, List result) + { + + if (contactFeatureStarts != null) + { + findContacts(contactFeatureStarts, pos, result, true); + findContacts(contactFeatureEnds, pos, result, false); + } + if (features != null) + { + int n = features.size(); + if (isTainted) + { + isTainted = false; + if (temp.length < n) + { + temp = new SequenceFeature[n << 1]; + } + features.toArray(temp); + } + findOverlaps(temp, n, pos, result); + } + } + + /** + * Binary search for contact start or end at a given (Overview) position. + * + * @param l + * @param pos + * @param result + * @param isStart + * + * @author Bob Hanson 2019.07.30 + */ + private static void findContacts(List l, int pos, + List result, boolean isStart) + { + int low = 0; + int high = l.size() - 1; + while (low <= high) + { + int mid = (low + high) >>> 1; + SequenceFeature f = l.get(mid); + switch (Long.signum((isStart ? f.begin : f.end) - pos)) + { + case -1: + low = mid + 1; + continue; + case 1: + high = mid - 1; + continue; + case 0: + 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) + { + result.add(f); + } + while (--m >= low && (f = l.get(m)) != null + && (isStart ? f.begin : f.end) == pos) + { + result.add(f); + } + return; + } + } + } + + /** + * Brute force point-interval overlap test + * + * @param features + * @param n + * @param pos + * @param result + */ + private static void findOverlaps(SequenceFeature[] features, int n, + int pos, + List result) + { + // BH I know, brute force. We need a single-position overlap + // method for IntervalStore, I think. + for (int i = n; --i >= 0;) + { + SequenceFeature f = features[i]; + if (f.begin <= pos && f.end >= pos) + { + result.add(f); + } + } + } + }