patch to fix occasional arrayoutofbounds exception when working with hidden columns...
[jalview.git] / src / jalview / schemes / ResidueColourScheme.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.schemes;
20
21 import java.util.*;
22
23 import java.awt.*;
24
25 import jalview.analysis.*;
26
27 /**
28  * DOCUMENT ME!
29  * 
30  * @author $author$
31  * @version $Revision$
32  */
33 public class ResidueColourScheme implements ColourSchemeI
34 {
35
36   boolean conservationColouring = false;
37
38   Color[] colors;
39
40   int threshold = 0;
41
42   /* Set when threshold colouring to either pid_gaps or pid_nogaps */
43   protected String ignoreGaps = AAFrequency.PID_GAPS;
44
45   /** Consenus as a hashtable array */
46   Hashtable[] consensus;
47
48   /** Conservation string as a char array */
49   char[] conservation;
50
51   int conservationLength = 0;
52
53   /** DOCUMENT ME!! */
54   int inc = 30;
55
56   /**
57    * Creates a new ResidueColourScheme object.
58    * 
59    * @param colors
60    *                DOCUMENT ME!
61    * @param threshold
62    *                DOCUMENT ME!
63    */
64   public ResidueColourScheme(Color[] colours, int threshold)
65   {
66     this.colors = colours;
67     this.threshold = threshold;
68   }
69
70   /**
71    * Creates a new ResidueColourScheme object.
72    */
73   public ResidueColourScheme()
74   {
75   }
76
77   /**
78    * Find a colour without an index in a sequence
79    */
80   public Color findColour(char c)
81   {
82     return colors[ResidueProperties.aaIndex[c]];
83   }
84
85   public Color findColour(char c, int j)
86   {
87     Color currentColour;
88
89     if ((threshold == 0) || aboveThreshold(c, j))
90     {
91       currentColour = colors[ResidueProperties.aaIndex[c]];
92     }
93     else
94     {
95       currentColour = Color.white;
96     }
97
98     if (conservationColouring)
99     {
100       currentColour = applyConservation(currentColour, j);
101     }
102
103     return currentColour;
104   }
105
106   /**
107    * Get the percentage threshold for this colour scheme
108    * 
109    * @return Returns the percentage threshold
110    */
111   public int getThreshold()
112   {
113     return threshold;
114   }
115
116   /**
117    * DOCUMENT ME!
118    * 
119    * @param ct
120    *                DOCUMENT ME!
121    */
122   public void setThreshold(int ct, boolean ignoreGaps)
123   {
124     threshold = ct;
125     if (ignoreGaps)
126     {
127       this.ignoreGaps = AAFrequency.PID_NOGAPS;
128     }
129     else
130     {
131       this.ignoreGaps = AAFrequency.PID_GAPS;
132     }
133   }
134
135   /**
136    * DOCUMENT ME!
137    * 
138    * @param s
139    *                DOCUMENT ME!
140    * @param j
141    *                DOCUMENT ME!
142    * 
143    * @return DOCUMENT ME!
144    */
145   public boolean aboveThreshold(char c, int j)
146   {
147     if ('a' <= c && c <= 'z')
148     {
149       // TO UPPERCASE !!!
150       // Faster than toUpperCase
151       c -= ('a' - 'A');
152     }
153
154     if (consensus == null || consensus.length < j || consensus[j] == null)
155     {
156       return false;
157     }
158
159     if ((((Integer) consensus[j].get(AAFrequency.MAXCOUNT)).intValue() != -1)
160             && consensus[j].contains(String.valueOf(c)))
161     {
162       if (((Float) consensus[j].get(ignoreGaps)).floatValue() >= threshold)
163       {
164         return true;
165       }
166     }
167
168     return false;
169   }
170
171   public boolean conservationApplied()
172   {
173     return conservationColouring;
174   }
175
176   public void setConservationInc(int i)
177   {
178     inc = i;
179   }
180
181   public int getConservationInc()
182   {
183     return inc;
184   }
185
186   /**
187    * DOCUMENT ME!
188    * 
189    * @param consensus
190    *                DOCUMENT ME!
191    */
192   public void setConsensus(Hashtable[] consensus)
193   {
194     if (consensus == null)
195     {
196       return;
197     }
198
199     this.consensus = consensus;
200   }
201
202   public void setConservation(Conservation cons)
203   {
204     if (cons == null)
205     {
206       conservationColouring = false;
207       conservation = null;
208     }
209     else
210     {
211       conservationColouring = true;
212       int i, iSize = cons.getConsSequence().getLength();
213       conservation = new char[iSize];
214       for (i = 0; i < iSize; i++)
215       {
216         conservation[i] = cons.getConsSequence().getCharAt(i);
217       }
218       conservationLength = conservation.length;
219     }
220
221   }
222
223   /**
224    * DOCUMENT ME!
225    * 
226    * @param s
227    *                DOCUMENT ME!
228    * @param i
229    *                DOCUMENT ME!
230    * 
231    * @return DOCUMENT ME!
232    */
233
234   Color applyConservation(Color currentColour, int i)
235   {
236
237     if ((conservationLength > i) && (conservation[i] != '*')
238             && (conservation[i] != '+'))
239     {
240       if (jalview.util.Comparison.isGap(conservation[i]))
241       {
242         currentColour = Color.white;
243       }
244       else
245       {
246         float t = 11 - (conservation[i] - '0');
247         if (t == 0)
248         {
249           return Color.white;
250         }
251
252         int red = currentColour.getRed();
253         int green = currentColour.getGreen();
254         int blue = currentColour.getBlue();
255
256         int dr = 255 - red;
257         int dg = 255 - green;
258         int db = 255 - blue;
259
260         dr *= t / 10f;
261         dg *= t / 10f;
262         db *= t / 10f;
263
264         red += (inc / 20f) * dr;
265         green += (inc / 20f) * dg;
266         blue += (inc / 20f) * db;
267
268         if (red > 255 || green > 255 || blue > 255)
269         {
270           currentColour = Color.white;
271         }
272         else
273         {
274           currentColour = new Color(red, green, blue);
275         }
276       }
277     }
278     return currentColour;
279   }
280
281 }