f66df316f8d31fa7f1927a3fcf4fc593f6787006
[vamsas.git] / src / uk / ac / vamsas / objects / utils / Range.java
1 package uk.ac.vamsas.objects.utils;\r
2 \r
3 import java.util.Vector;\r
4 \r
5 import uk.ac.vamsas.objects.core.Local;\r
6 import uk.ac.vamsas.objects.core.MapType;\r
7 import uk.ac.vamsas.objects.core.Mapped;\r
8 import uk.ac.vamsas.objects.core.RangeType;\r
9 import uk.ac.vamsas.objects.core.Seg;\r
10 \r
11 /**\r
12  * Utilities for working with RangeType and MapType objects.\r
13  * Derived from bitter experience.\r
14  * @author JimP\r
15  *\r
16  */\r
17 public class Range {\r
18 \r
19   /**\r
20    * get start<end range of segment, adjusting for inclusivity flag and\r
21    * polarity.\r
22    *\r
23    * @param visSeg\r
24    * @param ensureDirection when true - always ensure start is less than end.\r
25    * @return int[] { start, end, direction} where direction==1 for range running from end to start.\r
26    */\r
27   public static int[] getSegRange(Seg visSeg, boolean ensureDirection)\r
28   {\r
29     boolean incl = visSeg.getInclusive();\r
30     // adjust for inclusive flag.\r
31     int pol = (visSeg.getStart() <= visSeg.getEnd()) ? 1 : -1; // polarity of\r
32     // region.\r
33     int start = visSeg.getStart() + (incl ? 0 : pol);\r
34     int end = visSeg.getEnd() + (incl ? 0 : -pol);\r
35     if (ensureDirection && pol == -1)\r
36     {\r
37       // jalview doesn't deal with inverted ranges, yet.\r
38       int t = end;\r
39       end = start;\r
40       start = t;\r
41     }\r
42     return new int[]\r
43         {\r
44         start, end, pol < 0 ? 1 : 0};\r
45   }\r
46 \r
47   /**\r
48    * get real bounds of a RangeType's specification. start and end are an\r
49    * inclusive range within which all segments and positions lie.\r
50    * TODO: refactor to vamsas utils\r
51    * @param dseta\r
52    * @return int[] { start, end}\r
53    */\r
54   public static int[] getBounds(RangeType dseta)\r
55   {\r
56     if (dseta != null)\r
57     {\r
58       int[] se = null;\r
59       if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)\r
60       {\r
61         throw new Error("Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");\r
62       }\r
63       if (dseta.getSegCount() > 0)\r
64       {\r
65         se = getSegRange(dseta.getSeg(0), true);\r
66         for (int s = 1, sSize = dseta.getSegCount(); s < sSize; s++)\r
67         {\r
68           int nse[] = getSegRange(dseta.getSeg(s), true);\r
69           if (se[0] > nse[0])\r
70           {\r
71             se[0] = nse[0];\r
72           }\r
73           if (se[1] < nse[1])\r
74           {\r
75             se[1] = nse[1];\r
76           }\r
77         }\r
78       }\r
79       if (dseta.getPosCount() > 0)\r
80       {\r
81         // could do a polarity for pos range too. and pass back indication of discontinuities.\r
82         int pos = dseta.getPos(0).getI();\r
83         se = new int[]\r
84             {\r
85             pos, pos};\r
86         for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)\r
87         {\r
88           pos = dseta.getPos(p).getI();\r
89           if (se[0] > pos)\r
90           {\r
91             se[0] = pos;\r
92           }\r
93           if (se[1] < pos)\r
94           {\r
95             se[1] = pos;\r
96           }\r
97         }\r
98       }\r
99       return se;\r
100     }\r
101     return null;\r
102   }\r
103 \r
104   /**\r
105    * map from a rangeType's internal frame to the referenced object's coordinate frame.\r
106    * @param dseta\r
107    * @return int [] { ref(pos)...} for all pos in rangeType's frame.\r
108    */\r
109   public static int[] getMapping(RangeType dseta)\r
110   {\r
111     Vector posList = new Vector();\r
112     if (dseta != null)\r
113     {\r
114       int[] se = null;\r
115       if (dseta.getSegCount() > 0 && dseta.getPosCount() > 0)\r
116       {\r
117         throw new Error("Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");\r
118       }\r
119       if (dseta.getSegCount() > 0)\r
120       {\r
121         for (int s = 0, sSize = dseta.getSegCount(); s < sSize; s++)\r
122         {\r
123           se = getSegRange(dseta.getSeg(s), false);\r
124           int se_end = se[1 - se[2]] + (se[2] == 0 ? 1 : -1);\r
125           for (int p = se[se[2]]; p != se_end; p += se[2] == 0 ? 1 : -1)\r
126           {\r
127             posList.add(new Integer(p));\r
128           }\r
129         }\r
130       }\r
131       else if (dseta.getPosCount() > 0)\r
132       {\r
133         int pos = dseta.getPos(0).getI();\r
134 \r
135         for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++)\r
136         {\r
137           pos = dseta.getPos(p).getI();\r
138           posList.add(new Integer(pos));\r
139         }\r
140       }\r
141     }\r
142     if (posList != null && posList.size() > 0)\r
143     {\r
144       int[] range = new int[posList.size()];\r
145       for (int i = 0; i < range.length; i++)\r
146       {\r
147         range[i] = ( (Integer) posList.elementAt(i)).intValue();\r
148       }\r
149       posList.clear();\r
150       return range;\r
151     }\r
152     return null;\r
153   }\r
154 \r
155   public static int[] getIntervals(RangeType range)\r
156   {\r
157     int[] intervals=null;\r
158     Vector posList = new Vector();\r
159     if (range != null)\r
160     {\r
161       int[] se = null;\r
162       if (range.getSegCount() > 0 && range.getPosCount() > 0)\r
163       {\r
164         throw new Error("Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!");\r
165 }\r
166       if (range.getSegCount() > 0)\r
167       {\r
168         for (int s = 0, sSize = range.getSegCount(); s < sSize; s++)\r
169         {\r
170           se = getSegRange(range.getSeg(s), false);\r
171           posList.addElement(new Integer(se[0]));\r
172           posList.addElement(new Integer(se[1]));\r
173         }\r
174       }\r
175       else if (range.getPosCount() > 0)\r
176       {\r
177         int pos = range.getPos(0).getI();\r
178         for (int p = 0, pSize = range.getPosCount(); p < pSize; p++)\r
179         {\r
180           pos = range.getPos(p).getI();\r
181           posList.add(new Integer(pos));\r
182           posList.add(new Integer(pos));\r
183         }\r
184       }\r
185     }\r
186     if (posList != null && posList.size() > 0)\r
187     {\r
188       intervals=new int[posList.size()];\r
189       java.util.Enumeration e = posList.elements();\r
190       int i=0;\r
191       while (e.hasMoreElements())\r
192       {\r
193         intervals[i++] = ((Integer)e.nextElement()).intValue();\r
194       }\r
195     }\r
196     return intervals;\r
197   }\r
198   /**\r
199    * initialise a range type object from a set of start/end inclusive intervals\r
200    * @param mrt\r
201    * @param range\r
202    */\r
203   public static void initRangeType(RangeType mrt, int[] range)\r
204   {\r
205     for (int i=0; i<range.length; i+=2)\r
206     {\r
207       Seg vSeg = new Seg();\r
208       vSeg.setStart(range[i]);\r
209       vSeg.setEnd(range[i+1]);\r
210       vSeg.setInclusive(true);\r
211       mrt.addSeg(vSeg);\r
212     }\r
213   }\r
214 \r
215   /**\r
216    * \r
217    * @param maprange where the from range is the local mapped range, and the to range is the 'mapped' range in the MapRangeType\r
218    * @param default unit for local\r
219    * @param default unit for mapped\r
220    * @return MapList\r
221    */\r
222   public static MapList parsemapType(MapType maprange, int localu, int mappedu)\r
223   {\r
224     MapList ml = null;\r
225     int[] localRange = getIntervals(maprange.getLocal());\r
226     int[] mappedRange = getIntervals(maprange.getMapped());\r
227     long lu = maprange.getLocal().hasUnit() ? maprange.getLocal().getUnit() : localu;\r
228     long mu = maprange.getMapped().hasUnit() ? maprange.getMapped().getUnit() : mappedu;\r
229     ml = new MapList(localRange, mappedRange, (int)lu, (int)mu);\r
230     return ml;\r
231   }\r
232   /**\r
233    * Parse map with default units of 1,1\r
234    * @param map\r
235    * @return MapList representing map\r
236    */\r
237   public static MapList parsemapType(MapType map)\r
238   {\r
239     return parsemapType(map, 1, 1); \r
240   }\r
241 \r
242   /**\r
243    * initialise a MapType object from a MapList object.\r
244    * @param maprange\r
245    * @param ml\r
246    * @param setUnits\r
247    */\r
248   public static void initMapType(MapType maprange, MapList ml, boolean setUnits)\r
249   {\r
250     initMapType(maprange, ml, setUnits, false);\r
251   }\r
252   /**\r
253    * \r
254    * @param maprange\r
255    * @param ml\r
256    * @param setUnits\r
257    * @param reverse - reverse MapList mapping for Local and Mapped ranges and units \r
258    */\r
259   public static void initMapType(MapType maprange, MapList ml, boolean setUnits, boolean reverse)\r
260   {\r
261     maprange.setLocal(new Local());\r
262     maprange.setMapped(new Mapped());\r
263     if (!reverse)\r
264       {\r
265       initRangeType(maprange.getLocal(), ml.getFromRanges());\r
266       initRangeType(maprange.getMapped(), ml.getToRanges());\r
267       } else {\r
268         initRangeType(maprange.getLocal(), ml.getToRanges());\r
269         initRangeType(maprange.getMapped(), ml.getFromRanges());\r
270       }\r
271     if (setUnits)\r
272     {\r
273       if (!reverse)\r
274       { \r
275         maprange.getLocal().setUnit(ml.getFromRatio());\r
276         maprange.getMapped().setUnit(ml.getToRatio());\r
277       } else {\r
278         maprange.getLocal().setUnit(ml.getToRatio());\r
279         maprange.getMapped().setUnit(ml.getFromRatio());\r
280       }\r
281     }\r
282   }\r
283 \r
284 }