cb87719bc3cd9f810b7900c40537fa54fa17ca25
[jalview.git] / src / jalview / datamodel / Mapping.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview 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 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.datamodel;
22
23 import java.util.Vector;
24
25 import jalview.util.MapList;
26
27 public class Mapping
28 {
29   /**
30    * Contains the start-end pairs mapping from the associated sequence to the
31    * sequence in the database coordinate system it also takes care of step
32    * difference between coordinate systems
33    */
34   MapList map = null;
35
36   /**
37    * The seuqence that map maps the associated seuqence to (if any).
38    */
39   SequenceI to = null;
40
41   public Mapping(MapList map)
42   {
43     super();
44     this.map = map;
45   }
46
47   public Mapping(SequenceI to, MapList map)
48   {
49     this(map);
50     this.to = to;
51   }
52
53   /**
54    * create a new mapping from
55    * 
56    * @param to
57    *          the sequence being mapped
58    * @param exon
59    *          int[] {start,end,start,end} series on associated sequence
60    * @param is
61    *          int[] {start,end,...} ranges on the reference frame being mapped
62    *          to
63    * @param i
64    *          step size on associated sequence
65    * @param j
66    *          step size on mapped frame
67    */
68   public Mapping(SequenceI to, int[] exon, int[] is, int i, int j)
69   {
70     this(to, new MapList(exon, is, i, j));
71   }
72
73   /**
74    * create a duplicate (and independent) mapping object with the same reference
75    * to any SequenceI being mapped to.
76    * 
77    * @param map2
78    */
79   public Mapping(Mapping map2)
80   {
81     if (map2 != this && map2 != null)
82     {
83       if (map2.map != null)
84       {
85         map = new MapList(map2.map);
86       }
87       to = map2.to;
88     }
89   }
90
91   /**
92    * @return the map
93    */
94   public MapList getMap()
95   {
96     return map;
97   }
98
99   /**
100    * @param map
101    *          the map to set
102    */
103   public void setMap(MapList map)
104   {
105     this.map = map;
106   }
107
108   /**
109    * Equals that compares both the to references and MapList mappings.
110    * 
111    * @param other
112    * @return
113    */
114   public boolean equals(Mapping other)
115   {
116     if (other == null)
117       return false;
118     if (other == this)
119       return true;
120     if (other.to != to)
121       return false;
122     if ((map != null && other.map == null)
123             || (map == null && other.map != null))
124       return false;
125     if (map.equals(other.map))
126       return true;
127     return false;
128   }
129
130   /**
131    * get the 'initial' position in the associated sequence for a position in the
132    * mapped reference frame
133    * 
134    * @param mpos
135    * @return
136    */
137   public int getPosition(int mpos)
138   {
139     if (map != null)
140     {
141       int[] mp = map.shiftTo(mpos);
142       if (mp != null)
143       {
144         return mp[0];
145       }
146     }
147     return mpos;
148   }
149
150   /**
151    * gets boundary in direction of mapping
152    * 
153    * @param position
154    *          in mapped reference frame
155    * @return int{start, end} positions in associated sequence (in direction of
156    *         mapped word)
157    */
158   public int[] getWord(int mpos)
159   {
160     if (map != null)
161     {
162       return map.getToWord(mpos);
163     }
164     return null;
165   }
166
167   /**
168    * width of mapped unit in associated sequence
169    * 
170    */
171   public int getWidth()
172   {
173     if (map != null)
174     {
175       return map.getFromRatio();
176     }
177     return 1;
178   }
179
180   /**
181    * width of unit in mapped reference frame
182    * 
183    * @return
184    */
185   public int getMappedWidth()
186   {
187     if (map != null)
188     {
189       return map.getToRatio();
190     }
191     return 1;
192   }
193
194   /**
195    * get mapped position in the associated reference frame for position pos in
196    * the associated sequence.
197    * 
198    * @param pos
199    * @return
200    */
201   public int getMappedPosition(int pos)
202   {
203     if (map != null)
204     {
205       int[] mp = map.shiftFrom(pos);
206       if (mp != null)
207       {
208         return mp[0];
209       }
210     }
211     return pos;
212   }
213
214   public int[] getMappedWord(int pos)
215   {
216     if (map != null)
217     {
218       int[] mp = map.shiftFrom(pos);
219       if (mp != null)
220       {
221         return new int[]
222         { mp[0], mp[0] + mp[2] * (map.getToRatio() - 1) };
223       }
224     }
225     return null;
226   }
227
228   /**
229    * locates the region of feature f in the associated sequence's reference
230    * frame
231    * 
232    * @param f
233    * @return one or more features corresponding to f
234    */
235   public SequenceFeature[] locateFeature(SequenceFeature f)
236   {
237     if (true)
238     { // f.getBegin()!=f.getEnd()) {
239       if (map != null)
240       {
241         int[] frange = map.locateInFrom(f.getBegin(), f.getEnd());
242         if (frange == null)
243         {
244           // JBPNote - this isprobably not the right thing to doJBPHack
245           return null;
246         }
247         SequenceFeature[] vf = new SequenceFeature[frange.length / 2];
248         for (int i = 0, v = 0; i < frange.length; i += 2, v++)
249         {
250           vf[v] = new SequenceFeature(f);
251           vf[v].setBegin(frange[i]);
252           vf[v].setEnd(frange[i + 1]);
253           if (frange.length > 2)
254             vf[v].setDescription(f.getDescription() + "\nPart " + (v + 1));
255         }
256         return vf;
257       }
258     }
259     if (false) // else
260     {
261       int[] word = getWord(f.getBegin());
262       if (word[0] < word[1])
263       {
264         f.setBegin(word[0]);
265       }
266       else
267       {
268         f.setBegin(word[1]);
269       }
270       word = getWord(f.getEnd());
271       if (word[0] > word[1])
272       {
273         f.setEnd(word[0]);
274       }
275       else
276       {
277         f.setEnd(word[1]);
278       }
279     }
280     // give up and just return the feature.
281     return new SequenceFeature[]
282     { f };
283   }
284
285   /**
286    * return a series of contigs on the associated sequence corresponding to the
287    * from,to interval on the mapped reference frame
288    * 
289    * @param from
290    * @param to
291    * @return int[] { from_i, to_i for i=1 to n contiguous regions in the
292    *         associated sequence}
293    */
294   public int[] locateRange(int from, int to)
295   {
296     if (map != null)
297     {
298       if (from <= to)
299       {
300         from = (map.getToLowest() < from) ? from : map.getToLowest();
301         to = (map.getToHighest() > to) ? to : map.getToHighest();
302         if (from > to)
303           return null;
304       }
305       else
306       {
307         from = (map.getToHighest() > from) ? from : map.getToHighest();
308         to = (map.getToLowest() < to) ? to : map.getToLowest();
309         if (from < to)
310           return null;
311       }
312       return map.locateInFrom(from, to);
313     }
314     return new int[]
315     { from, to };
316   }
317
318   /**
319    * return a series of mapped contigs mapped from a range on the associated
320    * sequence
321    * 
322    * @param from
323    * @param to
324    * @return
325    */
326   public int[] locateMappedRange(int from, int to)
327   {
328     if (map != null)
329     {
330
331       if (from <= to)
332       {
333         from = (map.getFromLowest() < from) ? from : map.getFromLowest();
334         to = (map.getFromHighest() > to) ? to : map.getFromHighest();
335         if (from > to)
336           return null;
337       }
338       else
339       {
340         from = (map.getFromHighest() > from) ? from : map.getFromHighest();
341         to = (map.getFromLowest() < to) ? to : map.getFromLowest();
342         if (from < to)
343           return null;
344       }
345       return map.locateInTo(from, to);
346     }
347     return new int[]
348     { from, to };
349   }
350
351   /**
352    * return a new mapping object with a maplist modifed to only map the visible
353    * regions defined by viscontigs.
354    * 
355    * @param viscontigs
356    * @return
357    */
358   public Mapping intersectVisContigs(int[] viscontigs)
359   {
360     Mapping copy = new Mapping(this);
361     if (map != null)
362     {
363       int vpos = 0;
364       int apos = 0;
365       Vector toRange = new Vector();
366       Vector fromRange = new Vector();
367       for (int vc = 0; vc < viscontigs.length; vc += 2)
368       {
369         // find a mapped range in this visible region
370         int[] mpr = locateMappedRange(1 + viscontigs[vc],
371                 viscontigs[vc + 1] - 1);
372         if (mpr != null)
373         {
374           for (int m = 0; m < mpr.length; m += 2)
375           {
376             toRange.addElement(new int[]
377             { mpr[m], mpr[m + 1] });
378             int[] xpos = locateRange(mpr[m], mpr[m + 1]);
379             for (int x = 0; x < xpos.length; x += 2)
380             {
381               fromRange.addElement(new int[]
382               { xpos[x], xpos[x + 1] });
383             }
384           }
385         }
386       }
387       int[] from = new int[fromRange.size() * 2];
388       int[] to = new int[toRange.size() * 2];
389       int[] r;
390       for (int f = 0, fSize = fromRange.size(); f < fSize; f++)
391       {
392         r = (int[]) fromRange.elementAt(f);
393         from[f * 2] = r[0];
394         from[f * 2 + 1] = r[1];
395       }
396       for (int f = 0, fSize = toRange.size(); f < fSize; f++)
397       {
398         r = (int[]) toRange.elementAt(f);
399         to[f * 2] = r[0];
400         to[f * 2 + 1] = r[1];
401       }
402       copy.setMap(new MapList(from, to, map.getFromRatio(), map
403               .getToRatio()));
404     }
405     return copy;
406   }
407
408   public static void main(String[] args)
409   {
410     /**
411      * trite test of the intersectVisContigs method for a simple DNA -> Protein
412      * exon map and a range of visContigs
413      */
414     MapList fk = new MapList(new int[]
415     { 1, 6, 8, 13, 15, 23 }, new int[]
416     { 1, 7 }, 3, 1);
417     Mapping m = new Mapping(fk);
418     Mapping m_1 = m.intersectVisContigs(new int[]
419     { fk.getFromLowest(), fk.getFromHighest() });
420     Mapping m_2 = m.intersectVisContigs(new int[]
421     { 1, 7, 11, 20 });
422     System.out.println("" + m_1.map.getFromRanges());
423
424   }
425
426   /**
427    * get the sequence being mapped to - if any
428    * 
429    * @return null or a dataset sequence
430    */
431   public SequenceI getTo()
432   {
433     return to;
434   }
435
436   /**
437    * set the dataset sequence being mapped to if any
438    * 
439    * @param tto
440    */
441   public void setTo(SequenceI tto)
442   {
443     to = tto;
444   }
445
446   /*
447    * (non-Javadoc)
448    * 
449    * @see java.lang.Object#finalize()
450    */
451   protected void finalize() throws Throwable
452   {
453     map = null;
454     to = null;
455     super.finalize();
456   }
457
458 }