applied LGPLv3 and source code formatting.
[vamsas.git] / src / uk / ac / vamsas / objects / utils / Mapping.java
1 /*\r
2  * This file is part of the Vamsas Client version 0.1. \r
3  * Copyright 2009 by Jim Procter, Iain Milne, Pierre Marguerite, \r
4  *  Andrew Waterhouse and Dominik Lindner.\r
5  * \r
6  * Earlier versions have also been incorporated into Jalview version 2.4 \r
7  * since 2008, and TOPALi version 2 since 2007.\r
8  * \r
9  * The Vamsas Client is free software: you can redistribute it and/or modify\r
10  * it under the terms of the GNU Lesser General Public License as published by\r
11  * the Free Software Foundation, either version 3 of the License, or\r
12  * (at your option) any later version.\r
13  *  \r
14  * The Vamsas Client is distributed in the hope that it will be useful,\r
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
17  * GNU Lesser General Public License for more details.\r
18  * \r
19  * You should have received a copy of the GNU Lesser General Public License\r
20  * along with the Vamsas Client.  If not, see <http://www.gnu.org/licenses/>.\r
21  */\r
22 package uk.ac.vamsas.objects.utils;\r
23 \r
24 /*\r
25  * This code was originated from\r
26  * Jalview - A Sequence Alignment Editor and Viewer\r
27  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
28  *\r
29  * This program is free software; you can redistribute it and/or\r
30  * modify it under the terms of the GNU General Public License\r
31  * as published by the Free Software Foundation; either version 2\r
32  * of the License, or (at your option) any later version.\r
33  *\r
34  * This program is distributed in the hope that it will be useful,\r
35  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
36  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
37  * GNU General Public License for more details.\r
38  *\r
39  * You should have received a copy of the GNU General Public License\r
40  * along with this program; if not, write to the Free Software\r
41  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
42  */\r
43 \r
44 import java.util.Vector;\r
45 \r
46 public class Mapping {\r
47   /**\r
48    * Contains the start-end pairs mapping from the associated sequence to the\r
49    * sequence in the database coordinate system it also takes care of step\r
50    * difference between coordinate systems\r
51    */\r
52   MapList map = null;\r
53 \r
54   /**\r
55    * The seuqence that map maps the associated seuqence to (if any). SequenceI\r
56    * to = null;\r
57    */\r
58   public Mapping(MapList map) {\r
59     super();\r
60     this.map = map;\r
61   }\r
62 \r
63   /*\r
64    * public Mapping(SequenceI to, MapList map) { this(map); this.to = to; }\r
65    */\r
66   /**\r
67    * create a new mapping from\r
68    * \r
69    * (in Jalview) param to was the destination sequence being mapped\r
70    * \r
71    * @param local\r
72    *          int[] {start,end,start,end} series on associated sequence\r
73    * @param mapped\r
74    *          int[] {start,end,...} ranges on the reference frame being mapped\r
75    *          to\r
76    * @param i\r
77    *          step size on associated sequence\r
78    * @param j\r
79    *          step size on mapped frame\r
80    */\r
81   public Mapping(// SequenceI to,\r
82       int[] local, int[] mapped, int i, int j) {\r
83     this(new MapList(local, mapped, i, j));\r
84   }\r
85 \r
86   /**\r
87    * create a duplicate (and independent) mapping object with the same reference\r
88    * to any SequenceI being mapped to.\r
89    * \r
90    * @param map2\r
91    */\r
92   public Mapping(Mapping map2) {\r
93     if (map2 != this && map2 != null) {\r
94       if (map2.map != null) {\r
95         map = new MapList(map2.map);\r
96       }\r
97     }\r
98   }\r
99 \r
100   /**\r
101    * @return the map\r
102    */\r
103   public MapList getMap() {\r
104     return map;\r
105   }\r
106 \r
107   /**\r
108    * @param map\r
109    *          the map to set\r
110    */\r
111   public void setMap(MapList map) {\r
112     this.map = map;\r
113   }\r
114 \r
115   /**\r
116    * Equals that compares both the to references and MapList mappings.\r
117    * \r
118    * @param other\r
119    * @return\r
120    */\r
121   public boolean equals(Mapping other) {\r
122     if (other == null)\r
123       return false;\r
124     if (other == this)\r
125       return true;\r
126     if ((map != null && other.map == null)\r
127         || (map == null && other.map != null))\r
128       return false;\r
129     if (map.equals(other.map))\r
130       return true;\r
131     return false;\r
132   }\r
133 \r
134   /**\r
135    * get the 'initial' position in the associated sequence for a position in the\r
136    * mapped reference frame\r
137    * \r
138    * @param mpos\r
139    * @return\r
140    */\r
141   public int getPosition(int mpos) {\r
142     if (map != null) {\r
143       int[] mp = map.shiftTo(mpos);\r
144       if (mp != null) {\r
145         return mp[0];\r
146       }\r
147     }\r
148     return mpos;\r
149   }\r
150 \r
151   /**\r
152    * gets boundary in direction of mapping\r
153    * \r
154    * @param position\r
155    *          in mapped reference frame\r
156    * @return int{start, end} positions in associated sequence (in direction of\r
157    *         mapped word)\r
158    */\r
159   public int[] getWord(int mpos) {\r
160     if (map != null) {\r
161       return map.getToWord(mpos);\r
162     }\r
163     return null;\r
164   }\r
165 \r
166   /**\r
167    * width of mapped unit in associated sequence\r
168    * \r
169    */\r
170   public int getWidth() {\r
171     if (map != null) {\r
172       return map.getFromRatio();\r
173     }\r
174     return 1;\r
175   }\r
176 \r
177   /**\r
178    * width of unit in mapped reference frame\r
179    * \r
180    * @return\r
181    */\r
182   public int getMappedWidth() {\r
183     if (map != null) {\r
184       return map.getToRatio();\r
185     }\r
186     return 1;\r
187   }\r
188 \r
189   /**\r
190    * get mapped position in the associated reference frame for position pos in\r
191    * the associated sequence.\r
192    * \r
193    * @param pos\r
194    * @return\r
195    */\r
196   public int getMappedPosition(int pos) {\r
197     if (map != null) {\r
198       int[] mp = map.shiftFrom(pos);\r
199       if (mp != null) {\r
200         return mp[0];\r
201       }\r
202     }\r
203     return pos;\r
204   }\r
205 \r
206   public int[] getMappedWord(int pos) {\r
207     if (map != null) {\r
208       int[] mp = map.shiftFrom(pos);\r
209       if (mp != null) {\r
210         return new int[] { mp[0], mp[0] + mp[2] * (map.getToRatio() - 1) };\r
211       }\r
212     }\r
213     return null;\r
214   }\r
215 \r
216   /**\r
217    * locates the region of feature f in the associated (local) sequence's\r
218    * reference frame\r
219    * \r
220    * @param f\r
221    * @return int[] { start1, end1, ... starti, endi } for the corresponding\r
222    *         interval in local reference frame\r
223    */\r
224   public int[] locateFeature(int begin, int end) {\r
225     if (true) { // f.getBegin()!=f.getEnd()) {\r
226       if (map != null) {\r
227         int[] frange = map.locateInFrom(begin, end); // f.getBegin(),\r
228                                                      // f.getEnd());\r
229         /*\r
230          * left in as an example as to how this is used in Jalview\r
231          * SequenceFeature[] vf = new SequenceFeature[frange.length / 2]; for\r
232          * (int i = 0, v = 0; i < frange.length; i += 2, v++) { vf[v] = new\r
233          * SequenceFeature(f); vf[v].setBegin(frange[i]); vf[v].setEnd(frange[i\r
234          * + 1]); if (frange.length > 2) vf[v].setDescription(f.getDescription()\r
235          * + "\nPart " + v); }\r
236          */\r
237         return frange;\r
238       }\r
239     }\r
240     // give up and just return the interval unchanged - this might not be the\r
241     // correct behaviour\r
242     return new int[] { begin, end };\r
243   }\r
244 \r
245   /**\r
246    * return a series of contigs on the associated sequence corresponding to the\r
247    * from,to interval on the mapped reference frame\r
248    * \r
249    * @param from\r
250    * @param to\r
251    * @return int[] { from_i, to_i for i=1 to n contiguous regions in the\r
252    *         associated sequence}\r
253    */\r
254   public int[] locateRange(int from, int to) {\r
255     if (map != null) {\r
256       if (from <= to) {\r
257         from = (map.getToLowest() < from) ? from : map.getToLowest();\r
258         to = (map.getToHighest() > to) ? to : map.getToHighest();\r
259         if (from > to)\r
260           return null;\r
261       } else {\r
262         from = (map.getToHighest() > from) ? from : map.getToHighest();\r
263         to = (map.getToLowest() < to) ? to : map.getToLowest();\r
264         if (from < to)\r
265           return null;\r
266       }\r
267       return map.locateInFrom(from, to);\r
268     }\r
269     return new int[] { from, to };\r
270   }\r
271 \r
272   /**\r
273    * return a series of mapped contigs mapped from a range on the associated\r
274    * sequence\r
275    * \r
276    * @param from\r
277    * @param to\r
278    * @return\r
279    */\r
280   public int[] locateMappedRange(int from, int to) {\r
281     if (map != null) {\r
282 \r
283       if (from <= to) {\r
284         from = (map.getFromLowest() < from) ? from : map.getFromLowest();\r
285         to = (map.getFromHighest() > to) ? to : map.getFromHighest();\r
286         if (from > to)\r
287           return null;\r
288       } else {\r
289         from = (map.getFromHighest() > from) ? from : map.getFromHighest();\r
290         to = (map.getFromLowest() < to) ? to : map.getFromLowest();\r
291         if (from < to)\r
292           return null;\r
293       }\r
294       return map.locateInTo(from, to);\r
295     }\r
296     return new int[] { from, to };\r
297   }\r
298 \r
299   /**\r
300    * return a new mapping object with a maplist modifed to only map the visible\r
301    * regions defined by viscontigs.\r
302    * \r
303    * @param viscontigs\r
304    * @return\r
305    */\r
306   public Mapping intersectVisContigs(int[] viscontigs) {\r
307     Mapping copy = new Mapping(this);\r
308     if (map != null) {\r
309       Vector toRange = new Vector();\r
310       Vector fromRange = new Vector();\r
311       for (int vc = 0; vc < viscontigs.length; vc += 2) {\r
312         // find a mapped range in this visible region\r
313         int[] mpr = locateMappedRange(1 + viscontigs[vc],\r
314             viscontigs[vc + 1] - 1);\r
315         if (mpr != null) {\r
316           for (int m = 0; m < mpr.length; m += 2) {\r
317             toRange.addElement(new int[] { mpr[m], mpr[m + 1] });\r
318             int[] xpos = locateRange(mpr[m], mpr[m + 1]);\r
319             for (int x = 0; x < xpos.length; x += 2) {\r
320               fromRange.addElement(new int[] { xpos[x], xpos[x + 1] });\r
321             }\r
322           }\r
323         }\r
324       }\r
325       int[] from = new int[fromRange.size() * 2];\r
326       int[] to = new int[toRange.size() * 2];\r
327       int[] r;\r
328       for (int f = 0, fSize = fromRange.size(); f < fSize; f++) {\r
329         r = (int[]) fromRange.elementAt(f);\r
330         from[f * 2] = r[0];\r
331         from[f * 2 + 1] = r[1];\r
332       }\r
333       for (int f = 0, fSize = toRange.size(); f < fSize; f++) {\r
334         r = (int[]) toRange.elementAt(f);\r
335         to[f * 2] = r[0];\r
336         to[f * 2 + 1] = r[1];\r
337       }\r
338       copy.setMap(new MapList(from, to, map.getFromRatio(), map.getToRatio()));\r
339     }\r
340     return copy;\r
341   }\r
342 \r
343   public static void main(String[] args) {\r
344     /**\r
345      * trite test of the intersectVisContigs method for a simple DNA -> Protein\r
346      * exon map and a range of visContigs\r
347      */\r
348     MapList fk = new MapList(new int[] { 1, 6, 8, 13, 15, 23 }, new int[] { 1,\r
349         7 }, 3, 1);\r
350     Mapping m = new Mapping(fk);\r
351     Mapping m_1 = m.intersectVisContigs(new int[] { fk.getFromLowest(),\r
352         fk.getFromHighest() });\r
353     Mapping m_2 = m.intersectVisContigs(new int[] { 1, 7, 11, 20 });\r
354     System.out.println("" + m_1.map.getFromRanges());\r
355     // this test was for debugging purposes only - it should run without\r
356     // exceptions, but the\r
357     // integrity of the mapping was checked using an interactive debugger rather\r
358     // than programmatically.\r
359   }\r
360 }\r