1 package jalview.renderer.seqfeatures;
3 import jalview.datamodel.SequenceFeature;
4 import jalview.datamodel.SequenceI;
6 import java.awt.AlphaComposite;
8 import java.awt.FontMetrics;
9 import java.awt.Graphics;
10 import java.awt.Graphics2D;
11 import java.awt.image.BufferedImage;
13 public class FeatureRenderer extends
14 jalview.viewmodel.seqfeatures.FeatureRendererModel
21 boolean offscreenRender = false;
23 protected SequenceI lastSeq;
29 int av_charHeight, av_charWidth;
31 boolean av_validCharWidth, av_isShowSeqFeatureHeight;
33 protected void updateAvConfig()
35 av_charHeight = av.getCharHeight();
36 av_charWidth = av.getCharWidth();
37 av_validCharWidth = av.isValidCharWidth();
38 av_isShowSeqFeatureHeight = av.isShowSequenceFeaturesHeight();
41 void renderFeature(Graphics g, SequenceI seq, int fstart, int fend,
42 Color featureColour, int start, int end, int y1)
45 if (((fstart <= end) && (fend >= start)))
48 { // fix for if the feature we have starts before the sequence start,
49 fstart = start; // but the feature end is still valid!!
56 int pady = (y1 + av_charHeight) - av_charHeight / 5;
57 for (i = fstart; i <= fend; i++)
61 if (jalview.util.Comparison.isGap(s))
66 g.setColor(featureColour);
68 g.fillRect((i - start) * av_charWidth, y1, av_charWidth,
71 if (offscreenRender || !av_validCharWidth)
76 g.setColor(Color.white);
77 charOffset = (av_charWidth - fm.charWidth(s)) / 2;
78 g.drawString(String.valueOf(s), charOffset
79 + (av_charWidth * (i - start)), pady);
85 void renderScoreFeature(Graphics g, SequenceI seq, int fstart, int fend,
86 Color featureColour, int start, int end, int y1, byte[] bs)
89 if (((fstart <= end) && (fend >= start)))
92 { // fix for if the feature we have starts before the sequence start,
93 fstart = start; // but the feature end is still valid!!
100 int pady = (y1 + av_charHeight) - av_charHeight / 5;
101 int ystrt = 0, yend = av_charHeight;
104 // signed - zero is always middle of residue line.
107 yend = av_charHeight * (128 - bs[1]) / 512;
108 ystrt = av_charHeight - yend / 2;
112 ystrt = av_charHeight / 2;
113 yend = av_charHeight * (bs[1] - 128) / 512;
118 yend = av_charHeight * bs[1] / 255;
119 ystrt = av_charHeight - yend;
122 for (i = fstart; i <= fend; i++)
124 s = seq.getCharAt(i);
126 if (jalview.util.Comparison.isGap(s))
131 g.setColor(featureColour);
132 int x = (i - start) * av_charWidth;
133 g.drawRect(x, y1, av_charWidth, av_charHeight);
134 g.fillRect(x, y1 + ystrt, av_charWidth, yend);
136 if (offscreenRender || !av_validCharWidth)
141 g.setColor(Color.black);
142 charOffset = (av_charWidth - fm.charWidth(s)) / 2;
143 g.drawString(String.valueOf(s), charOffset
144 + (av_charWidth * (i - start)), pady);
150 BufferedImage offscreenImage;
152 public Color findFeatureColour(Color initialCol, SequenceI seq, int res)
154 return new Color(findFeatureColour(initialCol.getRGB(), seq, res));
158 * This is used by the Molecule Viewer and Overview to get the accurate
159 * colourof the rendered sequence
161 public synchronized int findFeatureColour(int initialCol, final SequenceI seq,
164 if (!av.isShowSequenceFeatures())
169 SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures();
173 lastSequenceFeatures = sequenceFeatures;
174 if (lastSequenceFeatures != null)
176 sfSize = lastSequenceFeatures.length;
181 if (lastSequenceFeatures != sequenceFeatures)
183 lastSequenceFeatures = sequenceFeatures;
184 if (lastSequenceFeatures != null)
186 sfSize = lastSequenceFeatures.length;
191 if (lastSequenceFeatures == null || sfSize == 0)
196 if (jalview.util.Comparison.isGap(lastSeq.getCharAt(column)))
198 return Color.white.getRGB();
201 // Only bother making an offscreen image if transparency is applied
202 if (transparency != 1.0f && offscreenImage == null)
204 offscreenImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
207 currentColour = null;
208 // TODO: non-threadsafe - each rendering thread needs its own instance of
209 // the feature renderer - or this should be synchronized.
210 offscreenRender = true;
212 if (offscreenImage != null)
214 offscreenImage.setRGB(0, 0, initialCol);
215 drawSequence(offscreenImage.getGraphics(), lastSeq, column, column, 0);
217 return offscreenImage.getRGB(0, 0);
221 drawSequence(null, lastSeq, lastSeq.findPosition(column), -1, -1);
223 if (currentColour == null)
229 return ((Integer) currentColour).intValue();
235 private volatile SequenceFeature[] lastSequenceFeatures;
245 public synchronized void drawSequence(Graphics g, final SequenceI seq,
246 int start, int end, int y1)
248 SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures();
249 if (sequenceFeatures == null || sequenceFeatures.length == 0)
256 fm = g.getFontMetrics();
261 if (lastSeq == null || seq != lastSeq
262 || sequenceFeatures != lastSequenceFeatures)
265 lastSequenceFeatures = sequenceFeatures;
268 if (transparency != 1 && g != null)
270 Graphics2D g2 = (Graphics2D) g;
271 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
275 if (!offscreenRender)
277 spos = lastSeq.findPosition(start);
278 epos = lastSeq.findPosition(end);
281 sfSize = lastSequenceFeatures.length;
283 for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++)
285 type = renderOrder[renderIndex];
287 if (type == null || !showFeatureOfType(type))
292 // loop through all features in sequence to find
293 // current feature to render
294 for (sfindex = 0; sfindex < sfSize; sfindex++)
296 if (!lastSequenceFeatures[sfindex].type.equals(type))
301 if (featureGroups != null
302 && lastSequenceFeatures[sfindex].featureGroup != null
303 && lastSequenceFeatures[sfindex].featureGroup.length() != 0
305 .containsKey(lastSequenceFeatures[sfindex].featureGroup)
308 lastSequenceFeatures[sfindex].featureGroup)
315 && (lastSequenceFeatures[sfindex].getBegin() > epos || lastSequenceFeatures[sfindex]
321 if (offscreenRender && offscreenImage == null)
323 if (lastSequenceFeatures[sfindex].begin <= start
324 && lastSequenceFeatures[sfindex].end >= start)
326 // this is passed out to the overview and other sequence renderers
327 // (e.g. molecule viewer) to get displayed colour for rendered
329 currentColour = new Integer(
331 lastSequenceFeatures[sfindex]).getRGB());
332 // used to be retreived from av.featuresDisplayed
333 // currentColour = av.featuresDisplayed
334 // .get(sequenceFeatures[sfindex].type);
338 else if (lastSequenceFeatures[sfindex].type
339 .equals("disulfide bond"))
342 renderFeature(g, seq,
343 seq.findIndex(lastSequenceFeatures[sfindex].begin) - 1,
344 seq.findIndex(lastSequenceFeatures[sfindex].begin) - 1,
345 getColour(lastSequenceFeatures[sfindex])
346 // new Color(((Integer) av.featuresDisplayed
347 // .get(sequenceFeatures[sfindex].type)).intValue())
349 renderFeature(g, seq,
350 seq.findIndex(lastSequenceFeatures[sfindex].end) - 1,
351 seq.findIndex(lastSequenceFeatures[sfindex].end) - 1,
352 getColour(lastSequenceFeatures[sfindex])
353 // new Color(((Integer) av.featuresDisplayed
354 // .get(sequenceFeatures[sfindex].type)).intValue())
358 else if (showFeature(lastSequenceFeatures[sfindex]))
360 if (av_isShowSeqFeatureHeight
361 && lastSequenceFeatures[sfindex].score != Float.NaN)
363 renderScoreFeature(g, seq,
364 seq.findIndex(lastSequenceFeatures[sfindex].begin) - 1,
365 seq.findIndex(lastSequenceFeatures[sfindex].end) - 1,
366 getColour(lastSequenceFeatures[sfindex]), start, end,
367 y1, normaliseScore(lastSequenceFeatures[sfindex]));
371 renderFeature(g, seq,
372 seq.findIndex(lastSequenceFeatures[sfindex].begin) - 1,
373 seq.findIndex(lastSequenceFeatures[sfindex].end) - 1,
374 getColour(lastSequenceFeatures[sfindex]), start, end,
383 if (transparency != 1.0f && g != null && transparencyAvailable)
385 Graphics2D g2 = (Graphics2D) g;
386 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
391 boolean transparencyAvailable = true;
393 protected void setTransparencyAvailable(boolean isTransparencyAvailable)
395 transparencyAvailable = isTransparencyAvailable;
399 public boolean isTransparencyAvailable()
401 return transparencyAvailable;
405 * Called when alignment in associated view has new/modified features to
406 * discover and display.
409 public void featuresAdded()