{
return dataset;
}
+
+ /**
+ * Answers true if the supplied alignment has the same number of sequences,
+ * and they are of equivalent length, ignoring gaps. Alignments should be of
+ * the same type (protein/nucleotide) or different types with 3:1 length
+ * scaling.
+ *
+ * @param al
+ */
+ @Override
+ public boolean isMappableTo(AlignmentI al)
+ {
+ int thisCodonScale = this.isNucleotide() ? 1 : 3;
+ int thatCodonScale = al.isNucleotide() ? 1 : 3;
+ if (this == al || this.getHeight() != al.getHeight())
+ {
+ return false;
+ }
+
+ // TODO: match sequence ids, allow different sequence ordering?
+ // TODO: allow for stop/start codons?
+ // TODO: exclude introns
+ int i = 0;
+ for (SequenceI seq : this.getSequences())
+ {
+ final int thisSequenceDnaLength = seq.getDatasetSequence()
+ .getLength() * thisCodonScale;
+ final int thatSequenceDnaLength = al.getSequenceAt(i)
+ .getDatasetSequence().getLength()
+ * thatCodonScale;
+ if (thisSequenceDnaLength != thatSequenceDnaLength)
+ {
+ return false;
+ }
+ i++;
+ }
+ return true;
+ }
+
+ /**
+ * Align this alignment the same as the given one. If both of the same type
+ * (nucleotide/protein) then align both identically. If this is nucleotide and
+ * the other is protein, make 3 gaps for each gap in the protein sequences. If
+ * this is protein and the other is nucleotide, insert a gap for each 3 gaps
+ * (or part thereof) between nucleotide bases. The two alignments should be
+ * compatible in height and lengths, but if not, then discrepancies will be
+ * ignored with unpredictable results.
+ *
+ * @param al
+ * @throws UnsupportedOperation
+ * if alignment of protein from cDNA is requested (not yet
+ * implemented)
+ */
+ @Override
+ public void alignAs(AlignmentI al)
+ {
+ boolean thisIsNucleotide = this.isNucleotide();
+ boolean thatIsProtein = !al.isNucleotide();
+ if (!thatIsProtein && !thisIsNucleotide)
+ {
+ throw new UnsupportedOperationException(
+ "Alignment of protein from cDNA not implemented");
+ }
+ char thisGapChar = this.getGapCharacter();
+ char thatGapChar = al.getGapCharacter();
+ String gap = thisIsNucleotide && thatIsProtein ? String
+ .valueOf(new char[]
+ { thisGapChar, thisGapChar, thisGapChar }) : String
+ .valueOf(thisGapChar);
+ int ratio = thisIsNucleotide && thatIsProtein ? 3 : 1;
+ int i = 0;
+ for (SequenceI seq : this.getSequences())
+ {
+ SequenceI other = al.getSequenceAt(i++);
+ if (other == null)
+ {
+ continue;
+ }
+ char[] thisDs = seq.getDatasetSequence().getSequence();
+ char[] thatDs = other.getSequence();
+ StringBuilder thisAligned = new StringBuilder(2 * thisDs.length);
+ int thisDsPosition = 0;
+ for (char thatChar : thatDs)
+ {
+ if (thatChar == thatGapChar)
+ {
+ /*
+ * Add (equivalent of) a gap
+ */
+ thisAligned.append(gap);
+ }
+ else
+ {
+ /*
+ * Add (equivalent of) a residue
+ */
+ for (int j = 0; j < ratio && thisDsPosition < thisDs.length; j++)
+ {
+ thisAligned.append(thisDs[thisDsPosition++]);
+ }
+ }
+ }
+ /*
+ * Include any 'extra' residues (there shouldn't be).
+ */
+ while (thisDsPosition < thisDs.length)
+ {
+ thisAligned.append(thisDs[thisDsPosition++]);
+ }
+ seq.setSequence(new String(thisAligned));
+ }
+ }
}