/** * Extract a sub-sequence from the sequence given a Range object * * @param range * @param sequence * @return the sub-sequence, null if the range or sequence is null */ public static String extractRangeSequence(Range range, String sequence) { if (range == null || sequence == null || (sequence != null && sequence.length() == 0)) { return null; } // when the range is valid if (validateRange(range, sequence).isEmpty()) { Position pos1 = range.getStart(); Position pos2 = range.getEnd(); // both the start position and the end position have a status // if both positions are undetermined, or of type 'n-?','n-n', 'c-c' or '?-c', no feature // sequence can be extracted // if the start position is negative, it means we cannot extract a sequence for this range if ((pos1.isPositionUndetermined() && pos2.isPositionUndetermined()) || pos1.getStart() < 0) { return null; } // a feature sequence can be extracted else { // the start position is the start position of the start interval long startSequence = pos1.getStart(); // the end position is the end position of the end interval long endSequence = pos2.getEnd(); // in case of undetermined, the start position is starting from 1 if (pos1.isPositionUndetermined() || PositionUtils.isLessThan(pos1)) { startSequence = 1; } // in case of greater than, the start position is starting from fromIntervalStart + 1 else if (PositionUtils.isGreaterThan(pos1)) { startSequence++; } // in case of undetermined, the end position is at the end of the sequence if (pos2.isPositionUndetermined() || PositionUtils.isGreaterThan(pos2)) { endSequence = sequence.length(); } // in case of less than, the end position is at 'toIntervalEnd' - 1 else if (PositionUtils.isLessThan(pos2)) { endSequence--; } return sequence.substring( (int) Math.max(0, startSequence - 1), (int) endSequence); // we make sure that we don't request index < 0. } } return null; }
/** * Checks if the interval positions of the range are overlapping * * @param range * @return true if the range intervals are overlapping */ public static boolean areRangePositionsOverlapping(Range range) { // get the range status Position start = range.getStart(); Position end = range.getEnd(); long fromStart = start.getStart(); long fromEnd = start.getEnd(); long toStart = end.getStart(); long toEnd = end.getEnd(); // both the end and the start have a specific status // in the specific case where the start is superior to a position and the end is inferior to // another position, we need to check that the // range is not invalid because 'greater than' and 'less than' are both exclusive if (PositionUtils.isGreaterThan(start) && PositionUtils.isLessThan(end) && toStart - fromEnd < 2) { return true; } // we have a greater than start position and the end position is equal to the start position else if (PositionUtils.isGreaterThan(start) && !PositionUtils.isGreaterThan(end) && fromStart == toEnd) { return true; } // we have a less than end position and the start position is equal to the start position else if (!PositionUtils.isLessThan(start) && PositionUtils.isLessThan(end) && fromStart == toEnd) { return true; } // As the range positions are 0 when the status is undetermined, we can only check if the ranges // are not overlapping when both start and end are not undetermined else if (!start.isPositionUndetermined() && !end.isPositionUndetermined()) { return PositionUtils.arePositionsOverlapping(fromStart, fromEnd, toStart, toEnd); } return false; }
/** * Method to check if the range is valid or not. If the range is valid, the method returns null * otherwise it returns a message. * * @param range : the range to check * @param sequence : the sequence of the polymer * @return empty list if the range is within the sequence, coherent with its fuzzy type and not * overlapping. If the range is not valid, it will return a list of error messages describing * why the range is invalid */ public static List<String> validateRange(Range range, String sequence) { if (range != null) { Position start = range.getStart(); Position end = range.getEnd(); List<String> messages = PositionUtils.validateRangePosition(start, sequence); messages.addAll(PositionUtils.validateRangePosition(end, sequence)); if (areRangeStatusInconsistent(range)) { messages.add( "The start status " + start.getStatus().getShortName() + " and end status " + end.getStatus().getShortName() + " are inconsistent"); } if (areRangePositionsOverlapping(range)) { messages.add( "The range positions overlap : (" + start.getStart() + "-" + start.getEnd() + ") - (" + end.getStart() + "-" + end.getEnd() + ")"); } return messages; } return Collections.EMPTY_LIST; }