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