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