*/
package jalview.util;
+
import jalview.analysis.AlignmentSorter;
import jalview.api.AlignViewportI;
+import jalview.bin.Console;
import jalview.commands.CommandI;
import jalview.commands.EditCommand;
import jalview.commands.EditCommand.Action;
import jalview.datamodel.AlignmentOrder;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.Mapping;
import jalview.datamodel.SearchResultMatchI;
import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-
/**
* Helper methods for manipulations involving sequence mappings.
*
action = action.getUndoAction();
}
// TODO write this
- System.err.println("MappingUtils.mapCutOrPaste not yet implemented");
+ Console.error("MappingUtils.mapCutOrPaste not yet implemented");
}
/**
int startResiduePos = selected.findPosition(firstUngappedPos);
int endResiduePos = selected.findPosition(lastUngappedPos);
- for (AlignedCodonFrame acf : codonFrames)
+ for (SequenceI seq : mapTo.getAlignment().getSequences())
{
- for (SequenceI seq : mapTo.getAlignment().getSequences())
+ int mappedStartResidue = 0;
+ int mappedEndResidue = 0;
+ for (AlignedCodonFrame acf : codonFrames)
{
- SequenceI peptide = targetIsNucleotide ? selected : seq;
- SequenceI cds = targetIsNucleotide ? seq : selected;
- SequenceToSequenceMapping s2s = acf.getCoveringMapping(cds,
- peptide);
- if (s2s == null)
- {
- continue;
- }
- int mappedStartResidue = 0;
- int mappedEndResidue = 0;
- List<AlignedCodonFrame> mapping = Arrays.asList(acf);
- SearchResultsI sr = buildSearchResults(selected, startResiduePos,
- mapping);
- for (SearchResultMatchI m : sr.getResults())
+ // rather than use acf.getCoveringMapping() we iterate through all
+ // mappings to make sure all CDS are selected for a protein
+ for (SequenceToSequenceMapping map : acf.getMappings())
{
- mappedStartResidue = m.getStart();
- mappedEndResidue = m.getEnd();
- }
- sr = buildSearchResults(selected, endResiduePos, mapping);
- for (SearchResultMatchI m : sr.getResults())
- {
- mappedStartResidue = Math.min(mappedStartResidue, m.getStart());
- mappedEndResidue = Math.max(mappedEndResidue, m.getEnd());
- }
+ if (map.covers(selected) && map.covers(seq))
+ {
+ /*
+ * Found a sequence mapping. Locate the start/end mapped residues.
+ */
+ List<AlignedCodonFrame> mapping = Arrays
+ .asList(new AlignedCodonFrame[]
+ { acf });
+ // locate start
+ SearchResultsI sr = buildSearchResults(selected,
+ startResiduePos, mapping);
+ for (SearchResultMatchI m : sr.getResults())
+ {
+ mappedStartResidue = m.getStart();
+ mappedEndResidue = m.getEnd();
+ }
+ // locate end - allowing for adjustment of start range
+ sr = buildSearchResults(selected, endResiduePos, mapping);
+ for (SearchResultMatchI m : sr.getResults())
+ {
+ mappedStartResidue = Math.min(mappedStartResidue,
+ m.getStart());
+ mappedEndResidue = Math.max(mappedEndResidue, m.getEnd());
+ }
- /*
- * Find the mapped aligned columns, save the range. Note findIndex
- * returns a base 1 position, SequenceGroup uses base 0
- */
- int mappedStartCol = seq.findIndex(mappedStartResidue) - 1;
- minStartCol = minStartCol == -1 ? mappedStartCol
- : Math.min(minStartCol, mappedStartCol);
- int mappedEndCol = seq.findIndex(mappedEndResidue) - 1;
- maxEndCol = maxEndCol == -1 ? mappedEndCol
- : Math.max(maxEndCol, mappedEndCol);
- mappedGroup.addSequence(seq, false);
- break;
+ /*
+ * Find the mapped aligned columns, save the range. Note findIndex
+ * returns a base 1 position, SequenceGroup uses base 0
+ */
+ int mappedStartCol = seq.findIndex(mappedStartResidue) - 1;
+ minStartCol = minStartCol == -1 ? mappedStartCol
+ : Math.min(minStartCol, mappedStartCol);
+ int mappedEndCol = seq.findIndex(mappedEndResidue) - 1;
+ maxEndCol = maxEndCol == -1 ? mappedEndCol
+ : Math.max(maxEndCol, mappedEndCol);
+ mappedGroup.addSequence(seq, false);
+ break;
+ }
+ }
}
}
}
{
for (AlignedCodonFrame acf : mappings)
{
- SequenceI mappedSeq = mappingToNucleotide ? acf.getDnaForAaSeq(seq)
- : acf.getAaForDnaSeq(seq);
- if (mappedSeq != null)
+ for (SequenceI seq2 : mapTo.getSequences())
{
- for (SequenceI seq2 : mapTo.getSequences())
+ /*
+ * the corresponding peptide / CDS is the one for which there is
+ * a complete ('covering') mapping to 'seq'
+ */
+ SequenceI peptide = mappingToNucleotide ? seq2 : seq;
+ SequenceI cds = mappingToNucleotide ? seq : seq2;
+ SequenceToSequenceMapping s2s = acf.getCoveringMapping(cds,
+ peptide);
+ if (s2s != null)
{
- if (seq2.getDatasetSequence() == mappedSeq)
- {
- mappedOrder.add(seq2);
- j++;
- break;
- }
+ mappedOrder.add(seq2);
+ j++;
+ break;
}
}
}
if (colsel == null)
{
- return;
+ return; // mappedColumns;
}
char fromGapChar = mapFrom.getAlignment().getGapCharacter();
while (regions.hasNext())
{
mapHiddenColumns(regions.next(), codonFrames, newHidden,
- fromSequences, toSequences, fromGapChar);
+ fromSequences,
+ toSequences, fromGapChar);
}
- return;
+ return; // mappedColumns;
}
/**
{
if (range.length % 2 != 0)
{
- System.err.println(
+ Console.error(
"Error unbalance start/end ranges: " + ranges.toString());
return 0;
}
/*
* not coded for [start1, end1, start2, end2, ...]
*/
- System.err.println(
+ Console.error(
"MappingUtils.removeEndPositions doesn't handle multiple ranges");
return;
}
/*
* not coded for a reverse strand range (end < start)
*/
- System.err.println(
+ Console.error(
"MappingUtils.removeEndPositions doesn't handle reverse strand");
return;
}
}
}
}
+ /**
+ * Adds the given range to a list of ranges. If the new range just extends
+ * existing ranges, the current endpoint is updated instead.
+ *
+ * @param range
+ * @param addTo
+ */
+ public static void addRange(int[] range, List<int[]> addTo)
+ {
+ /*
+ * list is empty - add to it!
+ */
+ if (addTo.size() == 0)
+ {
+ addTo.add(range);
+ return;
+ }
+
+ int[] last = addTo.get(addTo.size() - 1);
+ boolean lastForward = last[1] >= last[0];
+ boolean newForward = range[1] >= range[0];
+
+ /*
+ * contiguous range in the same direction - just update endpoint
+ */
+ if (lastForward == newForward && last[1] == range[0])
+ {
+ last[1] = range[1];
+ return;
+ }
+
+ /*
+ * next range starts at +1 in forward sense - update endpoint
+ */
+ if (lastForward && newForward && range[0] == last[1] + 1)
+ {
+ last[1] = range[1];
+ return;
+ }
+
+ /*
+ * next range starts at -1 in reverse sense - update endpoint
+ */
+ if (!lastForward && !newForward && range[0] == last[1] - 1)
+ {
+ last[1] = range[1];
+ return;
+ }
+
+ /*
+ * just add the new range
+ */
+ addTo.add(range);
+ }
/**
- * Converts a list of [start, end] ranges to a single array of [start, end,
- * start, end ...]
+ * Converts a list of {@code start-end} ranges to a single array of
+ * {@code start1, end1, start2, ... } ranges
*
* @param ranges
* @return
*/
- public static int[] listToArray(List<int[]> ranges)
+ public static int[] rangeListToArray(List<int[]> ranges)
{
- int[] result = new int[ranges.size() * 2];
- int i = 0;
- for (int[] range : ranges)
+ int rangeCount = ranges.size();
+ int[] result = new int[rangeCount * 2];
+ int j = 0;
+ for (int i = 0; i < rangeCount; i++)
{
- result[i++] = range[0];
- result[i++] = range[1];
+ int[] range = ranges.get(i);
+ result[j++] = range[0];
+ result[j++] = range[1];
}
return result;
}
+
+ /*
+ * Returns the maximal start-end positions in the given (ordered) list of
+ * ranges which is overlapped by the given begin-end range, or null if there
+ * is no overlap.
+ *
+ * <pre>
+ * Examples:
+ * if ranges is {[4, 8], [10, 12], [16, 19]}
+ * then
+ * findOverlap(ranges, 1, 20) == [4, 19]
+ * findOverlap(ranges, 6, 11) == [6, 11]
+ * findOverlap(ranges, 9, 15) == [10, 12]
+ * findOverlap(ranges, 13, 15) == null
+ * </pre>
+ *
+ * @param ranges
+ * @param begin
+ * @param end
+ * @return
+ */
+ protected static int[] findOverlap(List<int[]> ranges, final int begin,
+ final int end)
+ {
+ boolean foundStart = false;
+ int from = 0;
+ int to = 0;
+
+ /*
+ * traverse the ranges to find the first position (if any) >= begin,
+ * and the last position (if any) <= end
+ */
+ for (int[] range : ranges)
+ {
+ if (!foundStart)
+ {
+ if (range[0] >= begin)
+ {
+ /*
+ * first range that starts with, or follows, begin
+ */
+ foundStart = true;
+ from = Math.max(range[0], begin);
+ }
+ else if (range[1] >= begin)
+ {
+ /*
+ * first range that contains begin
+ */
+ foundStart = true;
+ from = begin;
+ }
+ }
+
+ if (range[0] <= end)
+ {
+ to = Math.min(end, range[1]);
+ }
+ }
+
+ return foundStart && to >= from ? new int[] { from, to } : null;
+ }
}