JAL-1066 - T-Coffee color scheme + signature change on findColour method
[jalview.git] / src / jalview / schemes / ResidueColourScheme.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3  * Copyright (C) 2011 J Procter, AM Waterhouse, 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.schemes;
19
20 import jalview.analysis.AAFrequency;
21 import jalview.analysis.Conservation;
22
23 import java.awt.Color;
24 import java.util.Hashtable;
25
26 /**
27  * DOCUMENT ME!
28  * 
29  * @author $author$
30  * @version $Revision$
31  */
32 public class ResidueColourScheme implements ColourSchemeI
33 {
34
35   boolean conservationColouring = false;
36
37   Color[] colors = null;
38
39   int threshold = 0;
40
41   /* Set when threshold colouring to either pid_gaps or pid_nogaps */
42   protected String ignoreGaps = AAFrequency.PID_GAPS;
43
44   /** Consenus as a hashtable array */
45   Hashtable[] consensus;
46
47   /** Conservation string as a char array */
48   char[] conservation;
49
50   int conservationLength = 0;
51
52   /** DOCUMENT ME!! */
53   int inc = 30;
54
55   /**
56    * Creates a new ResidueColourScheme object.
57    * 
58    * @param colors
59    *          DOCUMENT ME!
60    * @param threshold
61    *          DOCUMENT ME!
62    */
63   public ResidueColourScheme(Color[] colours, int threshold)
64   {
65     this.colors = colours;
66     this.threshold = threshold;
67   }
68
69   /**
70    * Creates a new ResidueColourScheme object.
71    */
72   public ResidueColourScheme()
73   {
74   }
75
76   /**
77    * Find a colour without an index in a sequence
78    */
79   public Color findColour(char c)
80   {
81     return colors == null ? Color.white
82             : colors[ResidueProperties.aaIndex[c]];
83   }
84
85   @Override
86   public Color findColour(char c, int j, int sequenceIndex)
87   {
88     Color currentColour;
89
90     if ((threshold == 0) || aboveThreshold(c, j))
91     {
92       currentColour = colors[ResidueProperties.aaIndex[c]];
93     }
94     else
95     {
96       currentColour = Color.white;
97     }
98
99     if (conservationColouring)
100     {
101       currentColour = applyConservation(currentColour, j);
102     }
103
104     return currentColour;
105   }
106
107   /**
108    * Get the percentage threshold for this colour scheme
109    * 
110    * @return Returns the percentage threshold
111    */
112   public int getThreshold()
113   {
114     return threshold;
115   }
116
117   /**
118    * DOCUMENT ME!
119    * 
120    * @param ct
121    *          DOCUMENT ME!
122    */
123   public void setThreshold(int ct, boolean ignoreGaps)
124   {
125     threshold = ct;
126     if (ignoreGaps)
127     {
128       this.ignoreGaps = AAFrequency.PID_NOGAPS;
129     }
130     else
131     {
132       this.ignoreGaps = AAFrequency.PID_GAPS;
133     }
134   }
135
136   /**
137    * DOCUMENT ME!
138    * 
139    * @param s
140    *          DOCUMENT ME!
141    * @param j
142    *          DOCUMENT ME!
143    * 
144    * @return DOCUMENT ME!
145    */
146   public boolean aboveThreshold(char c, int j)
147   {
148     if ('a' <= c && c <= 'z')
149     {
150       // TO UPPERCASE !!!
151       // Faster than toUpperCase
152       c -= ('a' - 'A');
153     }
154
155     if (consensus == null || consensus.length < j || consensus[j] == null)
156     {
157       return false;
158     }
159
160     if ((((Integer) consensus[j].get(AAFrequency.MAXCOUNT)).intValue() != -1)
161             && consensus[j].contains(String.valueOf(c)))
162     {
163       if (((Float) consensus[j].get(ignoreGaps)).floatValue() >= threshold)
164       {
165         return true;
166       }
167     }
168
169     return false;
170   }
171
172   public boolean conservationApplied()
173   {
174     return conservationColouring;
175   }
176
177   public void setConservationInc(int i)
178   {
179     inc = i;
180   }
181
182   public int getConservationInc()
183   {
184     return inc;
185   }
186
187   /**
188    * DOCUMENT ME!
189    * 
190    * @param consensus
191    *          DOCUMENT ME!
192    */
193   public void setConsensus(Hashtable[] consensus)
194   {
195     if (consensus == null)
196     {
197       return;
198     }
199
200     this.consensus = consensus;
201   }
202
203   public void setConservation(Conservation cons)
204   {
205     if (cons == null)
206     {
207       conservationColouring = false;
208       conservation = null;
209     }
210     else
211     {
212       conservationColouring = true;
213       int i, iSize = cons.getConsSequence().getLength();
214       conservation = new char[iSize];
215       for (i = 0; i < iSize; i++)
216       {
217         conservation[i] = cons.getConsSequence().getCharAt(i);
218       }
219       conservationLength = conservation.length;
220     }
221
222   }
223
224   /**
225    * DOCUMENT ME!
226    * 
227    * @param s
228    *          DOCUMENT ME!
229    * @param i
230    *          DOCUMENT ME!
231    * 
232    * @return DOCUMENT ME!
233    */
234
235   Color applyConservation(Color currentColour, int i)
236   {
237
238     if ((conservationLength > i) && (conservation[i] != '*')
239             && (conservation[i] != '+'))
240     {
241       if (jalview.util.Comparison.isGap(conservation[i]))
242       {
243         currentColour = Color.white;
244       }
245       else
246       {
247         float t = 11 - (conservation[i] - '0');
248         if (t == 0)
249         {
250           return Color.white;
251         }
252
253         int red = currentColour.getRed();
254         int green = currentColour.getGreen();
255         int blue = currentColour.getBlue();
256
257         int dr = 255 - red;
258         int dg = 255 - green;
259         int db = 255 - blue;
260
261         dr *= t / 10f;
262         dg *= t / 10f;
263         db *= t / 10f;
264
265         red += (inc / 20f) * dr;
266         green += (inc / 20f) * dg;
267         blue += (inc / 20f) * db;
268
269         if (red > 255 || green > 255 || blue > 255)
270         {
271           currentColour = Color.white;
272         }
273         else
274         {
275           currentColour = new Color(red, green, blue);
276         }
277       }
278     }
279     return currentColour;
280   }
281
282 }