/*
* The MIT License (MIT)
*
* Copyright (c) 2007-2015 Broad Institute
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.broad.igv.data;
import org.broad.igv.feature.FeatureUtils;
import org.broad.igv.feature.LocusScore;
import java.util.*;
/**
* @deprecated Use {@link FeatureUtils}
* @author jrobinso
*/
public class LocusScoreUtils {
/**
* Segregate a list of possibly overlapping features into a list of
* non-overlapping lists of features.
*/
public static List<List<LocusScore>> segreateFeatures(List<LocusScore> features, double scale) {
// Create a list to hold the lists of non-overlapping features
List<List<LocusScore>> segmentedLists = new ArrayList();
// Make a working copy of the original list.
List<LocusScore> workingList = new LinkedList(features);
FeatureUtils.sortFeatureList(workingList);
// Loop until all features have been allocated to non-overlapping lists
while (workingList.size() > 0) {
List<LocusScore> nonOverlappingFeatures = new LinkedList();
List<LocusScore> overlappingFeatures = new LinkedList();
// Prime the loop with the first feature, it can't overlap itself
LocusScore f1 = workingList.remove(0);
nonOverlappingFeatures.add(f1);
while (workingList.size() > 0) {
LocusScore f2 = workingList.remove(0);
int scaledStart = (int) (f2.getStart() / scale);
int scaledEnd = (int) (f1.getEnd() / scale);
if (scaledStart > scaledEnd) {
nonOverlappingFeatures.add(f2);
f1 = f2;
} else {
overlappingFeatures.add(f2);
}
}
// Add the list of non-overlapping features and start again with whats left
segmentedLists.add(nonOverlappingFeatures);
workingList = overlappingFeatures;
}
return segmentedLists;
}
/**
* Sort the feature list by ascending start value
*/
public static void sortFeatureList(List<? extends LocusScore> features) {
Collections.sort(features, new Comparator() {
public int compare(Object o1, Object o2) {
LocusScore f1 = (LocusScore) o1;
LocusScore f2 = (LocusScore) o2;
return (int) (f1.getStart() - f2.getStart());
}
});
}
public static LocusScore getFeatureAt(double position, double minWidth,
List<? extends LocusScore> features) {
int startIdx = 0;
int endIdx = features.size();
while (startIdx != endIdx) {
int idx = (startIdx + endIdx) / 2;
LocusScore feature = features.get(idx);
// Correct for zero vs 1 based coordinates.
// TODO -- document this.
double effectiveStart = feature.getStart() + 1;
if (position >= effectiveStart) {
double effectiveWidth = Math.max(minWidth, feature.getEnd() - feature.getStart());
if (position <= effectiveStart + effectiveWidth) {
return features.get(idx);
} else {
if (idx == startIdx) {
return null;
} else {
startIdx = idx;
}
}
} else {
endIdx = idx;
}
}
return null;
}
/**
* Get the index of the feature just to the right of the given position.
* If there is no feature to the right return -1;
*
* @param position
* @param features
* @return
*/
public static LocusScore getFeatureAfter(double position, List<? extends LocusScore> features) {
if (features.size() == 0 ||
features.get(features.size() - 1).getStart() <= position) {
return null;
}
int startIdx = 0;
int endIdx = features.size();
// Narrow the list to ~ 10
while (startIdx != endIdx) {
int idx = (startIdx + endIdx) / 2;
double distance = features.get(idx).getStart() - position;
if (distance <= 0) {
startIdx = idx;
} else {
endIdx = idx;
}
if (endIdx - startIdx < 10) {
break;
}
}
// Now find feature
for (int idx = startIdx; idx < features.size(); idx++) {
if (features.get(idx).getStart() > position) {
return features.get(idx);
}
}
return null;
}
public static LocusScore getFeatureBefore(double position, List<? extends LocusScore> features) {
if (features.size() == 0 ||
features.get(features.size() - 1).getStart() <= position) {
return null;
}
int startIdx = 0;
int endIdx = features.size() - 1;
while (startIdx != endIdx) {
int idx = (startIdx + endIdx) / 2;
double distance = features.get(idx).getStart() - position;
if (distance <= 0) {
startIdx = idx;
} else {
endIdx = idx;
}
if (endIdx - startIdx < 10) {
break;
}
}
if (features.get(endIdx).getStart() >= position) {
for (int idx = endIdx; idx >= 0; idx--) {
if (features.get(idx).getStart() < position) {
return features.get(idx);
}
}
} else {
for (int idx = endIdx + 1; idx < features.size(); idx++) {
if (features.get(idx).getStart() >= position) {
return features.get(idx - 1);
}
}
}
return null;
}
}