Merge remote-tracking branch 'origin/develop' into
[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 jalview.util.MapList;
24
25 import java.util.Vector;
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 sequence that map maps the associated sequence 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   @Override
115   public boolean equals(Object o)
116   {
117     if (o == null || !(o instanceof Mapping))
118     {
119       return false;
120     }
121     Mapping other = (Mapping) o;
122     if (other == this)
123     {
124       return true;
125     }
126     if (other.to != to)
127     {
128       return false;
129     }
130     if ((map != null && other.map == null)
131             || (map == null && other.map != null))
132     {
133       return false;
134     }
135     if (map.equals(other.map))
136     {
137       return true;
138     }
139     return false;
140   }
141
142   /**
143    * get the 'initial' position in the associated sequence for a position in the
144    * mapped reference frame
145    * 
146    * @param mpos
147    * @return
148    */
149   public int getPosition(int mpos)
150   {
151     if (map != null)
152     {
153       int[] mp = map.shiftTo(mpos);
154       if (mp != null)
155       {
156         return mp[0];
157       }
158     }
159     return mpos;
160   }
161
162   /**
163    * gets boundary in direction of mapping
164    * 
165    * @param position
166    *          in mapped reference frame
167    * @return int{start, end} positions in associated sequence (in direction of
168    *         mapped word)
169    */
170   public int[] getWord(int mpos)
171   {
172     if (map != null)
173     {
174       return map.getToWord(mpos);
175     }
176     return null;
177   }
178
179   /**
180    * width of mapped unit in associated sequence
181    * 
182    */
183   public int getWidth()
184   {
185     if (map != null)
186     {
187       return map.getFromRatio();
188     }
189     return 1;
190   }
191
192   /**
193    * width of unit in mapped reference frame
194    * 
195    * @return
196    */
197   public int getMappedWidth()
198   {
199     if (map != null)
200     {
201       return map.getToRatio();
202     }
203     return 1;
204   }
205
206   /**
207    * get mapped position in the associated reference frame for position pos in
208    * the associated sequence.
209    * 
210    * @param pos
211    * @return
212    */
213   public int getMappedPosition(int pos)
214   {
215     if (map != null)
216     {
217       int[] mp = map.shiftFrom(pos);
218       if (mp != null)
219       {
220         return mp[0];
221       }
222     }
223     return pos;
224   }
225
226   public int[] getMappedWord(int pos)
227   {
228     if (map != null)
229     {
230       int[] mp = map.shiftFrom(pos);
231       if (mp != null)
232       {
233         return new int[]
234         { mp[0], mp[0] + mp[2] * (map.getToRatio() - 1) };
235       }
236     }
237     return null;
238   }
239
240   /**
241    * locates the region of feature f in the associated sequence's reference
242    * frame
243    * 
244    * @param f
245    * @return one or more features corresponding to f
246    */
247   public SequenceFeature[] locateFeature(SequenceFeature f)
248   {
249     if (true)
250     { // f.getBegin()!=f.getEnd()) {
251       if (map != null)
252       {
253         int[] frange = map.locateInFrom(f.getBegin(), f.getEnd());
254         if (frange == null)
255         {
256           // JBPNote - this isprobably not the right thing to doJBPHack
257           return null;
258         }
259         SequenceFeature[] vf = new SequenceFeature[frange.length / 2];
260         for (int i = 0, v = 0; i < frange.length; i += 2, v++)
261         {
262           vf[v] = new SequenceFeature(f);
263           vf[v].setBegin(frange[i]);
264           vf[v].setEnd(frange[i + 1]);
265           if (frange.length > 2)
266           {
267             vf[v].setDescription(f.getDescription() + "\nPart " + (v + 1));
268           }
269         }
270         return vf;
271       }
272     }
273     if (false) // else
274     {
275       int[] word = getWord(f.getBegin());
276       if (word[0] < word[1])
277       {
278         f.setBegin(word[0]);
279       }
280       else
281       {
282         f.setBegin(word[1]);
283       }
284       word = getWord(f.getEnd());
285       if (word[0] > word[1])
286       {
287         f.setEnd(word[0]);
288       }
289       else
290       {
291         f.setEnd(word[1]);
292       }
293     }
294     // give up and just return the feature.
295     return new SequenceFeature[]
296     { f };
297   }
298
299   /**
300    * return a series of contigs on the associated sequence corresponding to the
301    * from,to interval on the mapped reference frame
302    * 
303    * @param from
304    * @param to
305    * @return int[] { from_i, to_i for i=1 to n contiguous regions in the
306    *         associated sequence}
307    */
308   public int[] locateRange(int from, int to)
309   {
310     if (map != null)
311     {
312       if (from <= to)
313       {
314         from = (map.getToLowest() < from) ? from : map.getToLowest();
315         to = (map.getToHighest() > to) ? to : map.getToHighest();
316         if (from > to)
317         {
318           return null;
319         }
320       }
321       else
322       {
323         from = (map.getToHighest() > from) ? from : map.getToHighest();
324         to = (map.getToLowest() < to) ? to : map.getToLowest();
325         if (from < to)
326         {
327           return null;
328         }
329       }
330       return map.locateInFrom(from, to);
331     }
332     return new int[]
333     { from, to };
334   }
335
336   /**
337    * return a series of mapped contigs mapped from a range on the associated
338    * sequence
339    * 
340    * @param from
341    * @param to
342    * @return
343    */
344   public int[] locateMappedRange(int from, int to)
345   {
346     if (map != null)
347     {
348
349       if (from <= to)
350       {
351         from = (map.getFromLowest() < from) ? from : map.getFromLowest();
352         to = (map.getFromHighest() > to) ? to : map.getFromHighest();
353         if (from > to)
354         {
355           return null;
356         }
357       }
358       else
359       {
360         from = (map.getFromHighest() > from) ? from : map.getFromHighest();
361         to = (map.getFromLowest() < to) ? to : map.getFromLowest();
362         if (from < to)
363         {
364           return null;
365         }
366       }
367       return map.locateInTo(from, to);
368     }
369     return new int[]
370     { from, to };
371   }
372
373   /**
374    * return a new mapping object with a maplist modifed to only map the visible
375    * regions defined by viscontigs.
376    * 
377    * @param viscontigs
378    * @return
379    */
380   public Mapping intersectVisContigs(int[] viscontigs)
381   {
382     Mapping copy = new Mapping(this);
383     if (map != null)
384     {
385       int vpos = 0;
386       int apos = 0;
387       Vector toRange = new Vector();
388       Vector fromRange = new Vector();
389       for (int vc = 0; vc < viscontigs.length; vc += 2)
390       {
391         // find a mapped range in this visible region
392         int[] mpr = locateMappedRange(1 + viscontigs[vc],
393                 viscontigs[vc + 1] - 1);
394         if (mpr != null)
395         {
396           for (int m = 0; m < mpr.length; m += 2)
397           {
398             toRange.addElement(new int[]
399             { mpr[m], mpr[m + 1] });
400             int[] xpos = locateRange(mpr[m], mpr[m + 1]);
401             for (int x = 0; x < xpos.length; x += 2)
402             {
403               fromRange.addElement(new int[]
404               { xpos[x], xpos[x + 1] });
405             }
406           }
407         }
408       }
409       int[] from = new int[fromRange.size() * 2];
410       int[] to = new int[toRange.size() * 2];
411       int[] r;
412       for (int f = 0, fSize = fromRange.size(); f < fSize; f++)
413       {
414         r = (int[]) fromRange.elementAt(f);
415         from[f * 2] = r[0];
416         from[f * 2 + 1] = r[1];
417       }
418       for (int f = 0, fSize = toRange.size(); f < fSize; f++)
419       {
420         r = (int[]) toRange.elementAt(f);
421         to[f * 2] = r[0];
422         to[f * 2 + 1] = r[1];
423       }
424       copy.setMap(new MapList(from, to, map.getFromRatio(), map
425               .getToRatio()));
426     }
427     return copy;
428   }
429
430   public static void main(String[] args)
431   {
432     /**
433      * trite test of the intersectVisContigs method for a simple DNA -> Protein
434      * exon map and a range of visContigs
435      */
436     MapList fk = new MapList(new int[]
437     { 1, 6, 8, 13, 15, 23 }, new int[]
438     { 1, 7 }, 3, 1);
439     Mapping m = new Mapping(fk);
440     Mapping m_1 = m.intersectVisContigs(new int[]
441     { fk.getFromLowest(), fk.getFromHighest() });
442     Mapping m_2 = m.intersectVisContigs(new int[]
443     { 1, 7, 11, 20 });
444     System.out.println("" + m_1.map.getFromRanges());
445
446   }
447
448   /**
449    * get the sequence being mapped to - if any
450    * 
451    * @return null or a dataset sequence
452    */
453   public SequenceI getTo()
454   {
455     return to;
456   }
457
458   /**
459    * set the dataset sequence being mapped to if any
460    * 
461    * @param tto
462    */
463   public void setTo(SequenceI tto)
464   {
465     to = tto;
466   }
467
468   /*
469    * (non-Javadoc)
470    * 
471    * @see java.lang.Object#finalize()
472    */
473   protected void finalize() throws Throwable
474   {
475     map = null;
476     to = null;
477     super.finalize();
478   }
479
480 }