*/
package jalview.datamodel;
-import jalview.util.MapList;
-import jalview.util.MappingUtils;
-
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
+import jalview.util.MapList;
+import jalview.util.MappingUtils;
+
/**
* Stores mapping between the columns of a protein alignment and a DNA alignment
* and a list of individual codon to amino acid mappings between sequences.
*/
public boolean covers(SequenceI seq)
{
- return covers(seq,false);
+ return covers(seq, false, false);
}
+
/**
*
* @param seq
- * @param localCover - when true - compare extent of seq's dataset sequence rather than the local extent
- * @return true if mapping covers full length of given sequence
+ * @param localCover
+ * - when true - compare extent of seq's dataset sequence rather
+ * than the local extent
+ * @param either
+ * - when true coverage is required for either seq or the mapped
+ * sequence
+ * @return true if mapping covers full length of given sequence (or the
+ * other if either==true)
*/
- public boolean covers(SequenceI seq, boolean localCover)
+ public boolean covers(SequenceI seq, boolean localCover, boolean either)
{
- List<int[]> mappedRanges = null;
+ List<int[]> mappedRanges = null, otherRanges = null;
MapList mapList = mapping.getMap();
- int mstart=seq.getStart(),mend=seq.getEnd()
- ;
+ int mstart = seq.getStart(), mend = seq.getEnd(), ostart, oend;
+ ;
if (fromSeq == seq || fromSeq == seq.getDatasetSequence())
{
- if (localCover && fromSeq !=seq)
+ if (localCover && fromSeq != seq)
{
- mstart=fromSeq.getStart();
- mend=fromSeq.getEnd();
+ mstart = fromSeq.getStart();
+ mend = fromSeq.getEnd();
}
mappedRanges = mapList.getFromRanges();
+ otherRanges = mapList.getToRanges();
+ ostart = mapping.to.getStart();
+ oend = mapping.to.getEnd();
}
else if (mapping.to == seq || mapping.to == seq.getDatasetSequence())
{
- if (localCover && mapping.to !=seq)
+ if (localCover && mapping.to != seq)
{
- mstart=mapping.to.getStart();
- mend=mapping.to.getEnd();
+ mstart = mapping.to.getStart();
+ mend = mapping.to.getEnd();
}
mappedRanges = mapList.getToRanges();
+ otherRanges = mapList.getFromRanges();
+ ostart = fromSeq.getStart();
+ oend = fromSeq.getEnd();
}
else
{
}
/*
- * check that each mapped range lieS with the sequence range
+ * check that each mapped range lies within the sequence range
* (necessary for circular CDS - example EMBL:J03321:AAA91567)
* and mapped length covers (at least) sequence length
*/
+ int length = countRange(mappedRanges, mstart, mend);
+
+ if (length != -1)
+ {
+ // add 3 to mapped length to allow for a mapped stop codon
+ if (length + 3 >= (mend - mstart + 1))
+ {
+ return true;
+ }
+ }
+ if (either)
+ {
+ // also check coverage of the other range
+ length = countRange(otherRanges, ostart, oend);
+ if (length != -1)
+ {
+ if (length + 1 >= (oend - ostart + 1))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private int countRange(List<int[]> mappedRanges, int mstart, int mend)
+ {
int length = 0;
for (int[] range : mappedRanges)
{
int to = Math.max(range[0], range[1]);
if (from < mstart || to > mend)
{
- return false;
+ return -1;
}
length += (to - from + 1);
}
- // add 1 to mapped length to allow for a mapped stop codon
- if (length + 1 < (mend - mstart + 1))
+ return length;
+ }
+
+ /**
+ * Adds any regions mapped to or from position {@code pos} in sequence
+ * {@code seq} to the given search results Note: recommend first using the
+ * .covers(,true,true) to ensure mapping covers both sequences
+ *
+ * @param seq
+ * @param pos
+ * @param sr
+ */
+ public void markMappedRegion(SequenceI seq, int pos, SearchResultsI sr)
+ {
+ int[] codon = null;
+ SequenceI mappedSeq = null;
+ SequenceI ds = seq.getDatasetSequence();
+ if (ds == null)
{
- return false;
+ ds = seq;
+ }
+
+ if (this.fromSeq == seq || this.fromSeq == ds)
+ {
+ codon = this.mapping.map.locateInTo(pos, pos);
+ mappedSeq = this.mapping.to;
+ }
+ else if (this.mapping.to == seq || this.mapping.to == ds)
+ {
+ codon = this.mapping.map.locateInFrom(pos, pos);
+ mappedSeq = this.fromSeq;
+ }
+
+ if (codon != null)
+ {
+ for (int i = 0; i < codon.length; i += 2)
+ {
+ sr.addResult(mappedSeq, codon[i], codon[i + 1]);
+ }
}
- return true;
}
}
/**
* Add search results for regions in other sequences that translate or are
- * translated from a particular position in seq
+ * translated from a particular position in seq (which may be an aligned or
+ * dataset sequence)
*
* @param seq
* @param index
public void markMappedRegion(SequenceI seq, int index,
SearchResultsI results)
{
- int[] codon;
SequenceI ds = seq.getDatasetSequence();
- for (SequenceToSequenceMapping ssm : mappings)
+ if (ds == null)
{
- if (ssm.fromSeq == seq || ssm.fromSeq == ds)
- {
- codon = ssm.mapping.map.locateInTo(index, index);
- if (codon != null)
- {
- for (int i = 0; i < codon.length; i += 2)
- {
- results.addResult(ssm.mapping.to, codon[i], codon[i + 1]);
- }
- }
- }
- else if (ssm.mapping.to == seq || ssm.mapping.to == ds)
- {
- {
- codon = ssm.mapping.map.locateInFrom(index, index);
- if (codon != null)
- {
- for (int i = 0; i < codon.length; i += 2)
- {
- results.addResult(ssm.fromSeq, codon[i], codon[i + 1]);
- }
- }
- }
- }
+ ds = seq;
}
- }
-
- /**
- * Returns the DNA codon positions (base 1) for the given position (base 1) in
- * a mapped protein sequence, or null if no mapping is found.
- *
- * Intended for use in aligning cDNA to match aligned protein. Only the first
- * mapping found is returned, so not suitable for use if multiple protein
- * sequences are mapped to the same cDNA (but aligning cDNA as protein is
- * ill-defined for this case anyway).
- *
- * @param seq
- * the DNA dataset sequence
- * @param aaPos
- * residue position (base 1) in a protein sequence
- * @return
- */
- public int[] getDnaPosition(SequenceI seq, int aaPos)
- {
- /*
- * Adapted from markMappedRegion().
- */
- MapList ml = null;
- int i = 0;
for (SequenceToSequenceMapping ssm : mappings)
{
- if (ssm.fromSeq == seq)
+ if (ssm.covers(seq, true, true))
{
- ml = getdnaToProt()[i];
- break;
+ ssm.markMappedRegion(ds, index, results);
}
- i++;
}
- return ml == null ? null : ml.locateInFrom(aaPos, aaPos);
}
/**
}
return null;
}
+
+ /**
+ * Returns the first mapping found which is between the given dataset sequence
+ * and another, is a triplet mapping (3:1 or 1:3), and covers the full extent
+ * of both sequences involved
+ *
+ * @param seq
+ * @return
+ */
+ public SequenceToSequenceMapping getCoveringCodonMapping(SequenceI seq)
+ {
+ for (SequenceToSequenceMapping mapping : mappings)
+ {
+ if (mapping.getMapping().getMap().isTripletMap()
+ && mapping.covers(seq))
+ {
+ if (mapping.fromSeq == seq
+ && mapping.covers(mapping.getMapping().getTo()))
+ {
+ return mapping;
+ }
+ else if (mapping.getMapping().getTo() == seq
+ && mapping.covers(mapping.fromSeq))
+ {
+ return mapping;
+ }
+ }
+ }
+ return null;
+ }
}