/* * 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; } }