+ }\r
+\r
+ private static Annotation getCodonAnnotation(int[] is, Annotation[] annotations)\r
+ { \r
+ // Have a look at all the codon positions for annotation and put the first\r
+ // one found into the translated annotation pos.\r
+ for (int p=0; p<3; p++)\r
+ {\r
+ if (annotations[is[p]]!=null)\r
+ {\r
+ return new Annotation(annotations[is[p]]);\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Translate a na sequence\r
+ * \r
+ * @param selection sequence displayed under viscontigs visible columns\r
+ * @param seqstring ORF read in some global alignment reference frame\r
+ * @param viscontigs mapping from global reference frame to visible seqstring ORF read\r
+ * @param codons Definition of global ORF alignment reference frame\r
+ * @param gapCharacter\r
+ * @param newSeq\r
+ * @return sequence ready to be added to alignment.\r
+ */\r
+ public static SequenceI translateCodingRegion(SequenceI selection,\r
+ String seqstring, int[] viscontigs, AlignedCodonFrame codons,\r
+ char gapCharacter, DBRefEntry product)\r
+ {\r
+ ShiftList vismapping = new ShiftList(); // map from viscontigs to seqstring\r
+ // intervals\r
+ int vc, scontigs[] = new int[viscontigs.length];\r
+ int npos = 0;\r
+ for (vc = 0; vc < viscontigs.length; vc += 2)\r
+ {\r
+ vismapping.addShift(npos, viscontigs[vc]);\r
+ scontigs[vc] = npos;\r
+ npos += viscontigs[vc + 1];\r
+ scontigs[vc + 1] = npos;\r
+ }\r
+\r
+ StringBuffer protein = new StringBuffer();\r
+ String seq = seqstring.replace('U', 'T');\r
+ char codon[] = new char[3];\r
+ int cdp[] = new int[3], rf = 0, lastnpos = 0, nend;\r
+ int aspos = 0;\r
+ int resSize = 0;\r
+ for (npos = 0, nend = seq.length(); npos < nend; npos++)\r
+ {\r
+ if (!jalview.util.Comparison.isGap(seq.charAt(npos)))\r
+ {\r
+ cdp[rf] = npos; // store position\r
+ codon[rf++] = seq.charAt(npos); // store base\r
+ }\r
+ // filled an RF yet ?\r
+ if (rf == 3)\r
+ {\r
+ String aa = ResidueProperties.codonTranslate(new String(codon));\r
+ rf = 0;\r
+ if (aa == null)\r
+ aa = String.valueOf(gapCharacter);\r
+ else\r
+ {\r
+ if (aa.equals("STOP"))\r
+ {\r
+ aa = "X";\r
+ }\r
+ resSize++;\r
+ }\r
+ // insert/delete gaps prior to this codon - if necessary\r
+ boolean findpos = true;\r
+ while (findpos)\r
+ {\r
+ // first ensure that the codons array is long enough.\r
+ codons.checkCodonFrameWidth(aspos);\r
+ // now check to see if we place the aa at the current aspos in the\r
+ // protein alignment\r
+ switch (Dna.compare_codonpos(cdp, codons.codons[aspos]))\r
+ {\r
+ case -1:\r
+ codons.insertAAGap(aspos, gapCharacter);\r
+ findpos = false;\r
+ break;\r
+ case +1:\r
+ // this aa appears after the aligned codons at aspos, so prefix it\r
+ // with a gap\r
+ aa = "" + gapCharacter + aa;\r
+ aspos++;\r
+ //if (aspos >= codons.aaWidth)\r
+ // codons.aaWidth = aspos + 1;\r
+ break; // check the next position for alignment\r
+ case 0:\r
+ // codon aligns at aspos position.\r
+ findpos = false;\r
+ }\r
+ }\r
+ // codon aligns with all other sequence residues found at aspos\r
+ protein.append(aa);\r
+ lastnpos = npos;\r
+ if (codons.codons[aspos] == null)\r
+ {\r
+ // mark this column as aligning to this aligned reading frame\r
+ codons.codons[aspos] = new int[]\r
+ { cdp[0], cdp[1], cdp[2] };\r
+ }\r
+ aspos++;\r
+ if (aspos >= codons.aaWidth)\r
+ codons.aaWidth = aspos + 1;\r
+ }\r
+ }\r
+ if (resSize > 0)\r
+ {\r
+ SequenceI newseq = new Sequence(selection.getName(), protein\r
+ .toString());\r
+ if (rf != 0)\r
+ {\r
+ jalview.bin.Cache.log\r
+ .debug("trimming contigs for incomplete terminal codon.");\r
+ // map and trim contigs to ORF region\r
+ vc = scontigs.length - 1;\r
+ lastnpos = vismapping.shift(lastnpos); // place npos in context of\r
+ // whole dna alignment (rather\r
+ // than visible contigs)\r
+ // incomplete ORF could be broken over one or two visible contig\r
+ // intervals.\r
+ while (vc >= 0 && scontigs[vc] > lastnpos)\r
+ {\r
+ if (vc > 0 && scontigs[vc - 1] > lastnpos)\r
+ {\r
+ vc -= 2;\r
+ }\r
+ else\r
+ {\r
+ // correct last interval in list.\r
+ scontigs[vc] = lastnpos;\r
+ }\r
+ }\r
+\r
+ if (vc > 0 && (vc + 1) < scontigs.length)\r
+ {\r
+ // truncate map list to just vc elements\r
+ int t[] = new int[vc + 1];\r
+ System.arraycopy(scontigs, 0, t, 0, vc + 1);\r
+ scontigs = t;\r
+ }\r
+ if (vc <= 0)\r
+ scontigs = null;\r
+ }\r
+ if (scontigs != null)\r
+ {\r
+ npos = 0;\r
+ // Find sequence position for scontigs positions on the nucleotide\r
+ // sequence string we were passed.\r
+ for (vc = 0; vc < viscontigs.length; vc += 2)\r
+ {\r
+ scontigs[vc] = selection.findPosition(scontigs[vc]); // not from 1!\r
+ npos += viscontigs[vc];\r
+ scontigs[vc + 1] = selection\r
+ .findPosition(npos + scontigs[vc + 1]); // exclusive\r
+ if (scontigs[vc + 1] == selection.getEnd())\r
+ break;\r
+ }\r
+ // trim trailing empty intervals.\r
+ if ((vc + 2) < scontigs.length)\r
+ {\r
+ int t[] = new int[vc + 2];\r
+ System.arraycopy(scontigs, 0, t, 0, vc + 2);\r
+ scontigs = t;\r
+ }\r
+ MapList map = new MapList(scontigs, new int[]\r
+ { 1, resSize }, 3, 1);\r
+ // update newseq as if it was generated as mapping from product\r
+ \r
+ if (product != null)\r
+ {\r
+ newseq.setName(product.getSource() + "|"\r
+ + product.getAccessionId());\r
+ if (product.getMap() != null)\r
+ {\r
+ //Mapping mp = product.getMap();\r
+ //newseq.setStart(mp.getPosition(scontigs[0]));\r
+ //newseq.setEnd(mp\r
+ // .getPosition(scontigs[scontigs.length - 1]));\r
+ }\r
+ }\r
+ transferCodedFeatures(selection, newseq, map, null, null);\r
+ SequenceI rseq = newseq.deriveSequence(); // construct a dataset\r
+ // sequence for our new\r
+ // peptide, regardless.\r
+ // store a mapping (this actually stores a mapping between the dataset\r
+ // sequences for the two sequences\r
+ codons.addMap(selection, rseq, map);\r
+ return rseq;\r
+ }\r
+ }\r
+ // register the mapping somehow\r
+ // \r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Given a peptide newly translated from a dna sequence, copy over and set any\r
+ * features on the peptide from the DNA. If featureTypes is null, all features\r
+ * on the dna sequence are searched (rather than just the displayed ones), and\r
+ * similarly for featureGroups.\r
+ * \r
+ * @param dna\r
+ * @param pep\r
+ * @param map\r
+ * @param featureTypes\r
+ * hash who's keys are the displayed feature type strings\r
+ * @param featureGroups\r
+ * hash where keys are feature groups and values are Boolean objects\r
+ * indicating if they are displayed.\r
+ */\r
+ private static void transferCodedFeatures(SequenceI dna, SequenceI pep,\r
+ MapList map, Hashtable featureTypes, Hashtable featureGroups)\r
+ {\r
+ SequenceFeature[] sf = dna.getDatasetSequence().getSequenceFeatures();\r
+ Boolean fgstate;\r
+ jalview.datamodel.DBRefEntry[] dnarefs = jalview.util.DBRefUtils\r
+ .selectRefs(dna.getDBRef(),\r
+ jalview.datamodel.DBRefSource.DNACODINGDBS);\r
+ if (dnarefs != null)\r
+ {\r
+ // intersect with pep\r
+ for (int d = 0; d < dnarefs.length; d++)\r
+ {\r
+ Mapping mp = dnarefs[d].getMap();\r
+ if (mp != null)\r
+ {\r
+ }\r
+ }\r
+ }\r
+ if (sf != null)\r
+ {\r
+ for (int f = 0; f < sf.length; f++)\r
+ {\r
+ fgstate = (featureGroups == null) ? null : ((Boolean) featureGroups\r
+ .get(sf[f].featureGroup));\r
+ if ((featureTypes == null || featureTypes.containsKey(sf[f]\r
+ .getType()))\r
+ && (fgstate == null || fgstate.booleanValue()))\r
+ {\r
+ if (FeatureProperties.isCodingFeature(null, sf[f].getType()))\r
+ {\r
+ // if (map.intersectsFrom(sf[f].begin, sf[f].end))\r
+ {\r
+\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r