X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Frenderer%2FAnnotationRenderer.java;h=4dd91da3bb91c7b5a3d354b61aa433ff180cf504;hb=f8a36759f4a0736882bbb2ea681fe56678c20c71;hp=2d8428901eb68fd1c0cd7bb283eaef6ced0f301d;hpb=6a951ef313becea88861eb3f48c244be82da1ca0;p=jalview.git diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index 2d84289..4dd91da 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -22,13 +22,19 @@ package jalview.renderer; import jalview.analysis.AAFrequency; import jalview.analysis.CodingUtils; +import jalview.analysis.Rna; import jalview.analysis.StructureFrequency; import jalview.api.AlignViewportI; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.ProfilesI; import jalview.schemes.ColourSchemeI; +import jalview.schemes.NucleotideColourScheme; import jalview.schemes.ResidueProperties; +import jalview.schemes.ZappoColourScheme; +import jalview.util.Platform; import java.awt.BasicStroke; import java.awt.Color; @@ -37,14 +43,11 @@ import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; -import java.awt.font.LineMetrics; import java.awt.geom.AffineTransform; import java.awt.image.ImageObserver; import java.util.BitSet; import java.util.Hashtable; -import com.stevesoft.pat.Regex; - public class AnnotationRenderer { private static final int UPPER_TO_LOWER = 'a' - 'A'; // 32 @@ -58,95 +61,24 @@ public class AnnotationRenderer */ private final boolean debugRedraw; - public AnnotationRenderer() - { - this(false); - } - - /** - * Create a new annotation Renderer - * - * @param debugRedraw - * flag indicating if timing and redraw parameter info should be - * output - */ - public AnnotationRenderer(boolean debugRedraw) - { - this.debugRedraw = debugRedraw; - } - - public void drawStemAnnot(Graphics g, Annotation[] row_annotations, - int lastSSX, int x, int y, int iconOffset, int startRes, - int column, boolean validRes, boolean validEnd) - { - g.setColor(STEM_COLOUR); - int sCol = (lastSSX / charWidth) + startRes; - int x1 = lastSSX; - int x2 = (x * charWidth); - Regex closeparen = new Regex("(\\))"); - - char dc = (column == 0 || row_annotations[column - 1] == null) ? ' ' - : row_annotations[column - 1].secondaryStructure; - - boolean diffupstream = sCol == 0 || row_annotations[sCol - 1] == null - || dc != row_annotations[sCol - 1].secondaryStructure; - boolean diffdownstream = !validRes || !validEnd - || row_annotations[column] == null - || dc != row_annotations[column].secondaryStructure; - // System.out.println("Column "+column+" diff up: "+diffupstream+" down:"+diffdownstream); - // If a closing base pair half of the stem, display a backward arrow - if (column > 0 && ResidueProperties.isCloseParenRNA(dc)) - { - - if (diffupstream) - // if (validRes && column>1 && row_annotations[column-2]!=null && - // dc.equals(row_annotations[column-2].displayCharacter)) - { - g.fillPolygon(new int[] { lastSSX + 5, lastSSX + 5, lastSSX }, - new int[] { y + iconOffset, y + 14 + iconOffset, - y + 8 + iconOffset }, 3); - x1 += 5; - } - if (diffdownstream) - { - x2 -= 1; - } - } - else - { - - // display a forward arrow - if (diffdownstream) - { - g.fillPolygon(new int[] { x2 - 5, x2 - 5, x2 }, new int[] { - y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, 3); - x2 -= 5; - } - if (diffupstream) - { - x1 += 1; - } - } - // draw arrow body - g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 7); - } - private int charWidth, endRes, charHeight; private boolean validCharWidth, hasHiddenColumns; private FontMetrics fm; - private final boolean MAC = jalview.util.Platform.isAMac(); + private final boolean MAC = Platform.isAMac(); boolean av_renderHistogram = true, av_renderProfile = true, av_normaliseProfile = false; - ColourSchemeI profcolour = null; + ResidueShaderI profcolour = null; private ColumnSelection columnSelection; - private Hashtable[] hconsensus; + private HiddenColumns hiddenColumns; + + private ProfilesI hconsensus; private Hashtable[] complementConsensus; @@ -195,7 +127,100 @@ public class AnnotationRenderer */ private boolean canClip = false; - public void drawNotCanonicalAnnot(Graphics g, Color nonCanColor, + public AnnotationRenderer() + { + this(false); + } + + /** + * Create a new annotation Renderer + * + * @param debugRedraw + * flag indicating if timing and redraw parameter info should be + * output + */ + public AnnotationRenderer(boolean debugRedraw) + { + this.debugRedraw = debugRedraw; + } + + /** + * Remove any references and resources when this object is no longer required + */ + public void dispose() + { + hconsensus = null; + complementConsensus = null; + hStrucConsensus = null; + fadedImage = null; + annotationPanel = null; + } + + void drawStemAnnot(Graphics g, Annotation[] row_annotations, int lastSSX, + int x, int y, int iconOffset, int startRes, int column, + boolean validRes, boolean validEnd) + { + g.setColor(STEM_COLOUR); + int sCol = (lastSSX / charWidth) + + hiddenColumns.visibleToAbsoluteColumn(startRes); + int x1 = lastSSX; + int x2 = (x * charWidth); + + char dc = (column == 0 || row_annotations[column - 1] == null) ? ' ' + : row_annotations[column - 1].secondaryStructure; + + boolean diffupstream = sCol == 0 || row_annotations[sCol - 1] == null + || dc != row_annotations[sCol - 1].secondaryStructure; + boolean diffdownstream = !validRes || !validEnd + || row_annotations[column] == null + || dc != row_annotations[column].secondaryStructure; + + if (column > 0 && Rna.isClosingParenthesis(dc)) + { + if (diffupstream) + // if (validRes && column>1 && row_annotations[column-2]!=null && + // dc.equals(row_annotations[column-2].displayCharacter)) + { + /* + * if new annotation with a closing base pair half of the stem, + * display a backward arrow + */ + g.fillPolygon(new int[] { lastSSX + 5, lastSSX + 5, lastSSX }, + new int[] + { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, + 3); + x1 += 5; + } + if (diffdownstream) + { + x2 -= 1; + } + } + else + { + // display a forward arrow + if (diffdownstream) + { + /* + * if annotation ending with an opeing base pair half of the stem, + * display a forward arrow + */ + g.fillPolygon(new int[] { x2 - 5, x2 - 5, x2 }, + new int[] + { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, + 3); + x2 -= 5; + } + if (diffupstream) + { + x1 += 1; + } + } + // draw arrow body + g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 7); + } + + void drawNotCanonicalAnnot(Graphics g, Color nonCanColor, Annotation[] row_annotations, int lastSSX, int x, int y, int iconOffset, int startRes, int column, boolean validRes, boolean validEnd) @@ -203,10 +228,10 @@ public class AnnotationRenderer // System.out.println(nonCanColor); g.setColor(nonCanColor); - int sCol = (lastSSX / charWidth) + startRes; + int sCol = (lastSSX / charWidth) + + hiddenColumns.visibleToAbsoluteColumn(startRes); int x1 = lastSSX; int x2 = (x * charWidth); - Regex closeparen = new Regex("}|]|<|[a-z]"); String dc = (column == 0 || row_annotations[column - 1] == null) ? "" : row_annotations[column - 1].displayCharacter; @@ -216,10 +241,10 @@ public class AnnotationRenderer boolean diffdownstream = !validRes || !validEnd || row_annotations[column] == null || !dc.equals(row_annotations[column].displayCharacter); - // System.out.println("Column "+column+" diff up: "+diffupstream+" down:"+diffdownstream); + // System.out.println("Column "+column+" diff up: "+diffupstream+" + // down:"+diffdownstream); // If a closing base pair half of the stem, display a backward arrow - if (column > 0 && closeparen.search(dc))// closeletter_b.search(dc)||closeletter_c.search(dc)||closeletter_d.search(dc)||closecrochet.search(dc)) - // ) + if (column > 0 && Rna.isClosingParenthesis(dc)) { if (diffupstream) @@ -227,8 +252,9 @@ public class AnnotationRenderer // dc.equals(row_annotations[column-2].displayCharacter)) { g.fillPolygon(new int[] { lastSSX + 5, lastSSX + 5, lastSSX }, - new int[] { y + iconOffset, y + 14 + iconOffset, - y + 8 + iconOffset }, 3); + new int[] + { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, + 3); x1 += 5; } if (diffdownstream) @@ -242,8 +268,10 @@ public class AnnotationRenderer // display a forward arrow if (diffdownstream) { - g.fillPolygon(new int[] { x2 - 5, x2 - 5, x2 }, new int[] { - y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, 3); + g.fillPolygon(new int[] { x2 - 5, x2 - 5, x2 }, + new int[] + { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, + 3); x2 -= 5; } if (diffupstream) @@ -290,22 +318,28 @@ public class AnnotationRenderer public void updateFromAlignViewport(AlignViewportI av) { charWidth = av.getCharWidth(); - endRes = av.getEndRes(); + endRes = av.getRanges().getEndRes(); charHeight = av.getCharHeight(); hasHiddenColumns = av.hasHiddenColumns(); validCharWidth = av.isValidCharWidth(); av_renderHistogram = av.isShowConsensusHistogram(); av_renderProfile = av.isShowSequenceLogo(); av_normaliseProfile = av.isNormaliseSequenceLogo(); - profcolour = av.getGlobalColourScheme(); - if (profcolour == null) + profcolour = av.getResidueShading(); + if (profcolour == null || profcolour.getColourScheme() == null) { - // Set the default colour for sequence logo if the alignnent has no - // colourscheme set - profcolour = av.getAlignment().isNucleotide() ? new jalview.schemes.NucleotideColourScheme() - : new jalview.schemes.ZappoColourScheme(); + /* + * Use default colour for sequence logo if + * the alignment has no colourscheme set + * (would like to use user preference but n/a for applet) + */ + ColourSchemeI col = av.getAlignment().isNucleotide() + ? new NucleotideColourScheme() + : new ZappoColourScheme(); + profcolour = new ResidueShader(col); } columnSelection = av.getColumnSelection(); + hiddenColumns = av.getAlignment().getHiddenColumns(); hconsensus = av.getSequenceConsensusHash(); complementConsensus = av.getComplementConsensusHash(); hStrucConsensus = av.getRnaStructureConsensusHash(); @@ -321,15 +355,14 @@ public class AnnotationRenderer * @param column * @return */ - public int[] getProfileFor(AlignmentAnnotation aa, int column) + int[] getProfileFor(AlignmentAnnotation aa, int column) { // TODO : consider refactoring the global alignment calculation // properties/rendering attributes as a global 'alignment group' which holds // all vis settings for the alignment as a whole rather than a subset // - if (aa.autoCalculated - && (aa.label.startsWith("Consensus") || aa.label - .startsWith("cDNA Consensus"))) + if (aa.autoCalculated && (aa.label.startsWith("Consensus") + || aa.label.startsWith("cDNA Consensus"))) { boolean forComplement = aa.label.startsWith("cDNA Consensus"); if (aa.groupRef != null && aa.groupRef.consensusData != null @@ -337,7 +370,7 @@ public class AnnotationRenderer { // TODO? group consensus for cDNA complement return AAFrequency.extractProfile( - aa.groupRef.consensusData[column], + aa.groupRef.consensusData.get(column), aa.groupRef.getIgnoreGapsConsensus()); } // TODO extend annotation row to enable dynamic and static profile data to @@ -346,12 +379,12 @@ public class AnnotationRenderer { if (forComplement) { - return AAFrequency.extractCdnaProfile( - complementConsensus[column], av_ignoreGapsConsensus); + return AAFrequency.extractCdnaProfile(complementConsensus[column], + av_ignoreGapsConsensus); } else { - return AAFrequency.extractProfile(hconsensus[column], + return AAFrequency.extractProfile(hconsensus.get(column), av_ignoreGapsConsensus); } } @@ -437,7 +470,8 @@ public class AnnotationRenderer .getAlignmentStrucConsensusAnnotation(); final AlignmentAnnotation complementConsensusAnnot = av .getComplementConsensusAnnotation(); - boolean renderHistogram = true, renderProfile = true, normaliseProfile = false, isRNA = rna; + boolean renderHistogram = true, renderProfile = true, + normaliseProfile = false, isRNA = rna; BitSet graphGroupDrawn = new BitSet(); int charOffset = 0; // offset for a label @@ -488,8 +522,8 @@ public class AnnotationRenderer lastSS = ' '; lastSSX = 0; - if (!useClip - || ((y - charHeight) < visHeight && (y + row.height + charHeight * 2) >= sOffset)) + if (!useClip || ((y - charHeight) < visHeight + && (y + row.height + charHeight * 2) >= sOffset)) {// if_in_visible_region if (!clipst) { @@ -529,8 +563,8 @@ public class AnnotationRenderer { y += charHeight; usedFaded = true; - g.drawImage(fadedImage, 0, y - row.height, imgWidth, y, 0, y - - row.height, imgWidth, y, annotationPanel); + g.drawImage(fadedImage, 0, y - row.height, imgWidth, y, 0, + y - row.height, imgWidth, y, annotationPanel); g.setColor(Color.black); // g.drawString("Calculating "+aa[i].label+"....",20, y-row.height/2); @@ -567,7 +601,7 @@ public class AnnotationRenderer { if (hasHiddenColumns) { - column = columnSelection.adjustForHiddenColumns(startRes + x); + column = hiddenColumns.visibleToAbsoluteColumn(startRes + x); if (column > row_annotations.length - 1) { break; @@ -588,7 +622,8 @@ public class AnnotationRenderer { validRes = true; } - final String displayChar = validRes ? row_annotations[column].displayCharacter + final String displayChar = validRes + ? row_annotations[column].displayCharacter : null; if (x > -1) { @@ -598,7 +633,7 @@ public class AnnotationRenderer if (columnSelection != null) { - if (columnSelection.isSelected(column)) + if (columnSelection.contains(column)) { g.fillRect(x * charWidth, y, charWidth, charHeight); } @@ -617,7 +652,8 @@ public class AnnotationRenderer if (validCharWidth && validRes && displayChar != null && (displayChar.length() > 0)) { - + Graphics2D gg = ((Graphics2D) g); + AffineTransform t = gg.getTransform(); fmWidth = fm.charsWidth(displayChar.toCharArray(), 0, displayChar.length()); if (/* centreColLabels || */scaleColLabel) @@ -633,8 +669,9 @@ public class AnnotationRenderer // scale only if the current font isn't already small enough fmScaling = charWidth; fmScaling /= fmWidth; - g.setFont(ofont.deriveFont(AffineTransform - .getScaleInstance(fmScaling, 1.0))); + gg.setFont(ofont); + gg.transform( + AffineTransform.getScaleInstance(fmScaling, 1.0)); // and update the label's width to reflect the scaling. fmWidth = charWidth; } @@ -649,28 +686,29 @@ public class AnnotationRenderer if (row_annotations[column].colour == null) { - g.setColor(Color.black); + gg.setColor(Color.black); } else { - g.setColor(row_annotations[column].colour); + gg.setColor(row_annotations[column].colour); } if (column == 0 || row.graph > 0) { - g.drawString(displayChar, (x * charWidth) + charOffset, y - + iconOffset); + gg.drawString(displayChar, (x * charWidth) + charOffset, + y + iconOffset); } - else if (row_annotations[column - 1] == null - || (labelAllCols - || !displayChar - .equals(row_annotations[column - 1].displayCharacter) || (displayChar - .length() < 2 && row_annotations[column].secondaryStructure == ' '))) + else if (row_annotations[column - 1] == null || (labelAllCols + || !displayChar.equals( + row_annotations[column - 1].displayCharacter) + || (displayChar.length() < 2 + && row_annotations[column].secondaryStructure == ' '))) { - g.drawString(displayChar, x * charWidth + charOffset, y - + iconOffset); + gg.drawString(displayChar, x * charWidth + charOffset, + y + iconOffset); } g.setFont(ofont); + gg.setTransform(t); } } if (row.hasIcons) @@ -732,7 +770,8 @@ public class AnnotationRenderer { int nb_annot = x - temp; - // System.out.println("\t type :"+lastSS+"\t x :"+x+"\t nbre annot :"+nb_annot); + // System.out.println("\t type :"+lastSS+"\t x :"+x+"\t nbre + // annot :"+nb_annot); switch (lastSS) { case '(': // Stem case for RNA secondary structure @@ -750,7 +789,7 @@ public class AnnotationRenderer validEnd); break; } - + // no break if isRNA - falls through to drawNotCanonicalAnnot! case 'E': if (!isRNA) { @@ -759,6 +798,7 @@ public class AnnotationRenderer validEnd); break; } + // no break if isRNA - fall through to drawNotCanonicalAnnot! case '{': case '}': @@ -825,8 +865,8 @@ public class AnnotationRenderer break; default: g.setColor(Color.gray); - g.fillRect(lastSSX, y + 6 + iconOffset, (x * charWidth) - - lastSSX, 2); + g.fillRect(lastSSX, y + 6 + iconOffset, + (x * charWidth) - lastSSX, 2); temp = x; break; } @@ -866,7 +906,6 @@ public class AnnotationRenderer { validRes = true; } - // x ++; if (row.hasIcons) @@ -881,6 +920,7 @@ public class AnnotationRenderer startRes, column, validRes, validEnd); break; } + // no break if isRNA - fall through to drawNotCanonicalAnnot! case 'E': if (!isRNA) @@ -889,6 +929,7 @@ public class AnnotationRenderer startRes, column, validRes, validEnd); break; } + // no break if isRNA - fall through to drawNotCanonicalAnnot! case '(': case ')': // Stem case for RNA secondary structure @@ -1024,7 +1065,7 @@ public class AnnotationRenderer { clipend = true; } - }// end if_in_visible_region + } // end if_in_visible_region if (row.graph > 0 && row.hasText) { y += charHeight; @@ -1041,13 +1082,13 @@ public class AnnotationRenderer { if (clipst) { - System.err.println("Start clip at : " + yfrom + " (index " + f_i - + ")"); + System.err.println( + "Start clip at : " + yfrom + " (index " + f_i + ")"); } if (clipend) { - System.err.println("End clip at : " + yto + " (index " + f_to - + ")"); + System.err.println( + "End clip at : " + yto + " (index " + f_to + ")"); } } ; @@ -1069,45 +1110,49 @@ public class AnnotationRenderer private Color sdNOTCANONICAL_COLOUR; - public void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX, - int x, int y, int iconOffset, int startRes, int column, - boolean validRes, boolean validEnd) + void drawGlyphLine(Graphics g, Annotation[] row, int lastSSX, int x, + int y, int iconOffset, int startRes, int column, boolean validRes, + boolean validEnd) { g.setColor(GLYPHLINE_COLOR); g.fillRect(lastSSX, y + 6 + iconOffset, (x * charWidth) - lastSSX, 2); } - public void drawSheetAnnot(Graphics g, Annotation[] row, + void drawSheetAnnot(Graphics g, Annotation[] row, - int lastSSX, int x, int y, int iconOffset, int startRes, int column, - boolean validRes, boolean validEnd) + int lastSSX, int x, int y, int iconOffset, int startRes, + int column, boolean validRes, boolean validEnd) { g.setColor(SHEET_COLOUR); if (!validEnd || !validRes || row == null || row[column] == null || row[column].secondaryStructure != 'E') { - g.fillRect(lastSSX, y + 4 + iconOffset, - (x * charWidth) - lastSSX - 4, 7); - g.fillPolygon(new int[] { (x * charWidth) - 4, (x * charWidth) - 4, - (x * charWidth) }, new int[] { y + iconOffset, - y + 14 + iconOffset, y + 7 + iconOffset }, 3); + g.fillRect(lastSSX, y + 4 + iconOffset, (x * charWidth) - lastSSX - 4, + 7); + g.fillPolygon( + new int[] + { (x * charWidth) - 4, (x * charWidth) - 4, (x * charWidth) }, + new int[] + { y + iconOffset, y + 14 + iconOffset, y + 7 + iconOffset }, + 3); } else { - g.fillRect(lastSSX, y + 4 + iconOffset, - (x + 1) * charWidth - lastSSX, 7); + g.fillRect(lastSSX, y + 4 + iconOffset, (x + 1) * charWidth - lastSSX, + 7); } } - public void drawHelixAnnot(Graphics g, Annotation[] row, int lastSSX, - int x, int y, int iconOffset, int startRes, int column, - boolean validRes, boolean validEnd) + void drawHelixAnnot(Graphics g, Annotation[] row, int lastSSX, int x, + int y, int iconOffset, int startRes, int column, boolean validRes, + boolean validEnd) { g.setColor(HELIX_COLOUR); - int sCol = (lastSSX / charWidth) + startRes; + int sCol = (lastSSX / charWidth) + + hiddenColumns.visibleToAbsoluteColumn(startRes); int x1 = lastSSX; int x2 = (x * charWidth); @@ -1135,8 +1180,8 @@ public class AnnotationRenderer else { // g.setColor(Color.magenta); - g.fillRoundRect(lastSSX + ofs, y + 4 + iconOffset, x2 - x1 - ofs - + 1, 8, 0, 0); + g.fillRoundRect(lastSSX + ofs, y + 4 + iconOffset, + x2 - x1 - ofs + 1, 8, 0, 0); } @@ -1161,9 +1206,9 @@ public class AnnotationRenderer g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8); } - public void drawLineGraph(Graphics g, AlignmentAnnotation _aa, - Annotation[] aa_annotations, int sRes, int eRes, int y, - float min, float max, int graphHeight) + void drawLineGraph(Graphics g, AlignmentAnnotation _aa, + Annotation[] aa_annotations, int sRes, int eRes, int y, float min, + float max, int graphHeight) { if (sRes > aa_annotations.length) { @@ -1207,7 +1252,7 @@ public class AnnotationRenderer column = sRes + x; if (hasHiddenColumns) { - column = columnSelection.adjustForHiddenColumns(column); + column = hiddenColumns.visibleToAbsoluteColumn(column); } if (column > aaMax) @@ -1231,13 +1276,13 @@ public class AnnotationRenderer g.setColor(aa_annotations[column].colour); } - y1 = y - - (int) (((aa_annotations[column - 1].value - min) / range) * graphHeight); - y2 = y - - (int) (((aa_annotations[column].value - min) / range) * graphHeight); + y1 = y - (int) (((aa_annotations[column - 1].value - min) / range) + * graphHeight); + y2 = y - (int) (((aa_annotations[column].value - min) / range) + * graphHeight); - g.drawLine(x * charWidth - charWidth / 2, y1, x * charWidth - + charWidth / 2, y2); + g.drawLine(x * charWidth - charWidth / 2, y1, + x * charWidth + charWidth / 2, y2); x++; } @@ -1246,7 +1291,8 @@ public class AnnotationRenderer g.setColor(_aa.threshold.colour); Graphics2D g2 = (Graphics2D) g; g2.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, - BasicStroke.JOIN_ROUND, 3f, new float[] { 5f, 3f }, 0f)); + BasicStroke.JOIN_ROUND, 3f, new float[] + { 5f, 3f }, 0f)); y2 = (int) (y - ((_aa.threshold.value - min) / range) * graphHeight); g.drawLine(0, y2, (eRes - sRes) * charWidth, y2); @@ -1254,7 +1300,8 @@ public class AnnotationRenderer } } - public void drawBarGraph(Graphics g, AlignmentAnnotation _aa, + @SuppressWarnings("unused") + void drawBarGraph(Graphics g, AlignmentAnnotation _aa, Annotation[] aa_annotations, int sRes, int eRes, float min, float max, int y, boolean renderHistogram, boolean renderProfile, boolean normaliseProfile) @@ -1286,7 +1333,7 @@ public class AnnotationRenderer column = sRes + x; if (hasHiddenColumns) { - column = columnSelection.adjustForHiddenColumns(column); + column = hiddenColumns.visibleToAbsoluteColumn(column); } if (column > aaMax) @@ -1308,8 +1355,8 @@ public class AnnotationRenderer g.setColor(aa_annotations[column].colour); } - y1 = y - - (int) (((aa_annotations[column].value - min) / (range)) * _aa.graphHeight); + y1 = y - (int) (((aa_annotations[column].value - min) / (range)) + * _aa.graphHeight); if (renderHistogram) { @@ -1338,62 +1385,58 @@ public class AnnotationRenderer boolean isCdnaProfile = profl[0] == AlignmentAnnotation.CDNA_PROFILE; float ht = normaliseProfile ? y - _aa.graphHeight : y1; double htn = normaliseProfile ? _aa.graphHeight : (y2 - y1);// aa.graphHeight; - double hght; - float wdth; - double ht2 = 0; - char[] dc; /** * Render a single base for a sequence profile, a base pair for * structure profile, and a triplet for a cdna profile */ - dc = new char[isStructureProfile ? 2 : (isCdnaProfile ? 3 : 1)]; + char[] dc = new char[isStructureProfile ? 2 + : (isCdnaProfile ? 3 : 1)]; + + // lm is not necessary - we can just use fm - could be off by no more + // than 0.5 px + // LineMetrics lm = g.getFontMetrics(ofont).getLineMetrics("Q", g); + // System.out.println(asc + " " + dec + " " + (asc - lm.getAscent()) + // + " " + (dec - lm.getDescent())); + + double asc = fm.getAscent(); + double dec = fm.getDescent(); + double fht = fm.getHeight(); - LineMetrics lm = g.getFontMetrics(ofont).getLineMetrics("Q", g); double scale = 1f / (normaliseProfile ? profl[2] : 100f); - float ofontHeight = 1f / lm.getAscent();// magnify to fill box - double scl = 0.0; + // float ofontHeight = 1f / fm.getAscent();// magnify to fill box /* * Traverse the character(s)/percentage data in the array */ - int c = 3; - int valuesProcessed = 0; + + float ht2 = ht; + // profl[1] is the number of values in the profile - while (valuesProcessed < profl[1]) + for (int i = 0, c = 3, last = profl[1]; i < last; i++) { + + String s; if (isStructureProfile) { // todo can we encode a structure pair as an int, like codons? dc[0] = (char) profl[c++]; dc[1] = (char) profl[c++]; + s = new String(dc); } else if (isCdnaProfile) { - dc = CodingUtils.decodeCodon(profl[c++]); + CodingUtils.decodeCodon2(profl[c++], dc); + s = new String(dc); } else { dc[0] = (char) profl[c++]; + s = new String(dc); } - - wdth = charWidth; - wdth /= fm.charsWidth(dc, 0, dc.length); - - ht += scl; // next profl[] position is profile % for the character(s) - scl = htn * scale * profl[c++]; - lm = ofont.getLineMetrics(dc, 0, 1, g.getFontMetrics() - .getFontRenderContext()); - g.setFont(ofont.deriveFont(AffineTransform.getScaleInstance( - wdth, scl / lm.getAscent()))); - lm = g.getFontMetrics().getLineMetrics(dc, 0, 1, g); - - // Debug - render boxes around characters - // g.setColor(Color.red); - // g.drawRect(x*av.charWidth, (int)ht, av.charWidth, - // (int)(scl)); - // g.setColor(profcolour.findColour(dc[0]).darker()); + + double newHeight = htn * scale * profl[c++]; /* * Set character colour as per alignment colour scheme; use the @@ -1403,7 +1446,7 @@ public class AnnotationRenderer if (isCdnaProfile) { final String codonTranslation = ResidueProperties - .codonTranslate(new String(dc)); + .codonTranslate(s); colour = profcolour.findColour(codonTranslation.charAt(0), column, null); } @@ -1413,11 +1456,43 @@ public class AnnotationRenderer } g.setColor(colour == Color.white ? Color.lightGray : colour); - hght = (ht + (scl - lm.getDescent() - lm.getBaselineOffsets()[lm - .getBaselineIndex()])); + // Debug - render boxes around characters + // g.setColor(Color.red); + // g.drawRect(x*av.charWidth, (int)ht, av.charWidth, + // (int)(scl)); + // g.setColor(profcolour.findColour(dc[0]).darker()); - g.drawChars(dc, 0, dc.length, x * charWidth, (int) hght); - valuesProcessed++; + double sx = 1f * charWidth / fm.charsWidth(dc, 0, dc.length); + double sy = newHeight / asc; + double newAsc = asc * sy; + double newDec = dec * sy; + // it is not necessary to recalculated lm for the new font. + // note: lm.getBaselineOffsets()[lm.getBaselineIndex()]) must be 0 + // by definition. Was: + // int hght = (int) (ht + (newAsc - newDec - lm.getBaselineOffsets()[lm.getBaselineIndex()])); + + // original: + + if (/** @j2sNative false && */ true) { + int hght = (int) (ht + (newAsc - newDec)); // Q: why " - newDec " ? (0,0) is on the font baseline, I think + Font font = ofont.deriveFont(AffineTransform.getScaleInstance(sx, sy)); + g.setFont(font); + g.drawChars(dc, 0, dc.length, x * charWidth, hght); + ht += newHeight; + } else { + // SwingJS does not implement font.deriveFont() + // this is off by a very small amount. + int hght2 = (int) (ht2 + newAsc); + Graphics2D gg = (Graphics2D) g.create(); + gg.setFont(ofont); + gg.transform(AffineTransform.getScaleInstance(sx, sy)); + //System.out.println("sx " + sx + " sy " + sy + " " + hght + " " + lm.getDescent() + " " + dec + " " + newDec + " " + lm.getAscent() + " " + asc + " " + newAsc); + gg.drawString(s, (int) (x * charWidth / sx), + (int) (hght2 / sy)); + gg.dispose(); + ht2 += newHeight; + } + } g.setFont(ofont); } @@ -1429,10 +1504,11 @@ public class AnnotationRenderer g.setColor(_aa.threshold.colour); Graphics2D g2 = (Graphics2D) g; g2.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, - BasicStroke.JOIN_ROUND, 3f, new float[] { 5f, 3f }, 0f)); + BasicStroke.JOIN_ROUND, 3f, new float[] + { 5f, 3f }, 0f)); - y2 = (int) (y - ((_aa.threshold.value - min) / range) - * _aa.graphHeight); + y2 = (int) (y + - ((_aa.threshold.value - min) / range) * _aa.graphHeight); g.drawLine(0, y2, (eRes - sRes) * charWidth, y2); g2.setStroke(new BasicStroke()); }