X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Frenderer%2FAnnotationRenderer.java;h=b5dac0d50f95fb5daf98ac5379724f0bea3d6697;hb=eb3e681d6e82ccdd5d312d1981dfb306e7f479f0;hp=9a0081f3394c5bc4e3b16fcbd5f2c55706b38dd9;hpb=8ea26cfd5ef46f5f5e15a4e0e2b0a20dfa8204f6;p=jalview.git diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index 9a0081f..b5dac0d 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -28,11 +28,15 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; +import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.image.ImageObserver; import java.util.BitSet; import java.util.Hashtable; +import org.jfree.graphics2d.svg.SVGGraphics2D; +import org.jibble.epsgraphics.EpsGraphics2D; + import jalview.analysis.AAFrequency; import jalview.analysis.CodingUtils; import jalview.analysis.Rna; @@ -91,6 +95,10 @@ public class AnnotationRenderer private boolean av_ignoreGapsConsensus; + private boolean renderingVectors = false; + + private boolean glyphLineDrawn = false; + /** * attributes set from AwtRenderPanelI */ @@ -167,7 +175,6 @@ public class AnnotationRenderer 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; @@ -177,11 +184,19 @@ public class AnnotationRenderer : row_annotations[column - 1].secondaryStructure; boolean diffupstream = sCol == 0 || row_annotations[sCol - 1] == null - || dc != row_annotations[sCol - 1].secondaryStructure; + || dc != row_annotations[sCol - 1].secondaryStructure + || !validEnd; boolean diffdownstream = !validRes || !validEnd || row_annotations[column] == null || dc != row_annotations[column].secondaryStructure; + if (diffupstream || diffdownstream) + { + // draw glyphline under arrow + drawGlyphLine(g, lastSSX, x, y, iconOffset); + } + g.setColor(STEM_COLOUR); + if (column > 0 && Rna.isClosingParenthesis(dc)) { if (diffupstream) @@ -194,7 +209,8 @@ public class AnnotationRenderer */ fillPolygon(g, new int[] { lastSSX + 5, lastSSX + 5, lastSSX }, new int[] - { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, + { y + iconOffset + 1, y + 13 + iconOffset, + y + 7 + iconOffset }, 3); x1 += 5; } @@ -212,9 +228,10 @@ public class AnnotationRenderer * if annotation ending with an opeing base pair half of the stem, * display a forward arrow */ - fillPolygon(g, new int[] { x2 - 5, x2 - 5, x2 }, + fillPolygon(g, new int[] { x2 - 6, x2 - 6, x2 - 1 }, new int[] - { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset }, + { y + iconOffset + 1, y + 13 + iconOffset, + y + 7 + iconOffset }, 3); x2 -= 5; } @@ -224,7 +241,8 @@ public class AnnotationRenderer } } // draw arrow body - fillRect(g, x1, y + 4 + iconOffset, x2 - x1, 7); + unsetAntialias(g); + fillRect(g, x1, y + 4 + iconOffset, x2 - x1, 6); } void drawNotCanonicalAnnot(Graphics g, Color nonCanColor, @@ -243,7 +261,8 @@ public class AnnotationRenderer : row_annotations[column - 1].displayCharacter; boolean diffupstream = sCol == 0 || row_annotations[sCol - 1] == null - || !dc.equals(row_annotations[sCol - 1].displayCharacter); + || !dc.equals(row_annotations[sCol - 1].displayCharacter) + || !validEnd; boolean diffdownstream = !validRes || !validEnd || row_annotations[column] == null || !dc.equals(row_annotations[column].displayCharacter); @@ -254,8 +273,7 @@ public class AnnotationRenderer if (diffupstream || diffdownstream) { // draw glyphline under arrow - this.drawGlyphLine(g, row_annotations, lastSSX, x, y, iconOffset, - startRes, column, validRes, validEnd); + drawGlyphLine(g, lastSSX, x, y, iconOffset); } g.setColor(nonCanColor); if (column > 0 && Rna.isClosingParenthesis(dc)) @@ -297,7 +315,7 @@ public class AnnotationRenderer } // draw arrow body unsetAntialias(g); - fillRect(g, x1 - 1, y + 4 + iconOffset, x2 - x1 + 1, 6); + fillRect(g, x1, y + 4 + iconOffset, x2 - x1, 6); } // public void updateFromAnnotationPanel(FontMetrics annotFM, AlignViewportI @@ -460,16 +478,11 @@ public class AnnotationRenderer AlignViewportI av, Graphics g, int activeRow, int startRes, int endRes) { - Graphics2D g2d = (Graphics2D) g; - /* - if (Cache.getDefault("ANTI_ALIAS", true)) + if (g instanceof EpsGraphics2D || g instanceof SVGGraphics2D) { - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, - RenderingHints.VALUE_STROKE_PURE); + this.setVectorRendering(true); } - */ + Graphics2D g2d = (Graphics2D) g; long stime = System.currentTimeMillis(); boolean usedFaded = false; @@ -616,9 +629,13 @@ public class AnnotationRenderer * * continue; } */ + // first pass sets up state for drawing continuation from left-hand // column // of startRes + + // flag used for vector rendition + this.glyphLineDrawn = false; x = (startRes == 0) ? 0 : -1; while (x < endRes - startRes) { @@ -905,13 +922,17 @@ public class AnnotationRenderer // temp = x; break; default: - unsetAntialias(g); - g.setColor(GLYPHLINE_COLOR); - g.fillRect(lastSSX, y + 6 + iconOffset, - (x * charWidth) - lastSSX, 2); - g.drawRect(lastSSX, y + 6 + iconOffset, - (x * charWidth) - lastSSX - 1, 2); - // temp = x; + if (isVectorRendering()) + { + // draw single full width glyphline + drawGlyphLine(g, lastSSX, endRes - x, y, iconOffset); + // disable more glyph lines + this.glyphLineDrawn = true; + } + else + { + drawGlyphLine(g, lastSSX, x, y, iconOffset); + } break; } } @@ -1042,8 +1063,17 @@ public class AnnotationRenderer x, y, iconOffset, startRes, column, validRes, validEnd); break; default: - drawGlyphLine(g, row_annotations, lastSSX, x, y, iconOffset, - startRes, column, validRes, validEnd); + if (isVectorRendering()) + { + // draw single full width glyphline + drawGlyphLine(g, lastSSX, endRes - x, y, iconOffset); + // disable more glyph lines + this.glyphLineDrawn = true; + } + else + { + drawGlyphLine(g, lastSSX, x, y, iconOffset); + } break; } } @@ -1170,7 +1200,7 @@ public class AnnotationRenderer public static final Color GLYPHLINE_COLOR = Color.gray; - public static final Color SHEET_COLOUR = Color.green.darker(); + public static final Color SHEET_COLOUR = Color.green; public static final Color HELIX_COLOUR = Color.red; @@ -1178,15 +1208,17 @@ public class AnnotationRenderer // private Color sdNOTCANONICAL_COLOUR; - 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, int lastSSX, int x, int y, int iconOffset) { + if (glyphLineDrawn) + { + // if we've drawn a single long glyphline for an export, don't draw the + // bits + return; + } unsetAntialias(g); g.setColor(GLYPHLINE_COLOR); g.fillRect(lastSSX, y + 6 + iconOffset, (x * charWidth) - lastSSX, 2); - g.drawRect(lastSSX, y + 6 + iconOffset, (x * charWidth) - lastSSX - 1, - 2); } void drawSheetAnnot(Graphics g, Annotation[] row, @@ -1198,8 +1230,8 @@ public class AnnotationRenderer || row[column].secondaryStructure != 'E') { // draw the glyphline underneath - drawGlyphLine(g, row, lastSSX, x, y, iconOffset, startRes, column, - validRes, validEnd); + drawGlyphLine(g, lastSSX, x, y, iconOffset); + g.setColor(SHEET_COLOUR); fillRect(g, lastSSX, y + 4 + iconOffset, (x * charWidth) - lastSSX - 4, 6); @@ -1215,7 +1247,8 @@ public class AnnotationRenderer else { g.setColor(SHEET_COLOUR); - fillRect(g, lastSSX, y + 4 + iconOffset, x * charWidth - lastSSX, 6); + fillRect(g, lastSSX, y + 4 + iconOffset, (x * charWidth) - lastSSX, + 6); } } @@ -1223,29 +1256,29 @@ public class AnnotationRenderer int y, int iconOffset, int startRes, int column, boolean validRes, boolean validEnd) { - g.setColor(HELIX_COLOUR); - int sCol = (lastSSX / charWidth) + hiddenColumns.visibleToAbsoluteColumn(startRes); int x1 = lastSSX; int x2 = (x * charWidth); - y--; - - if (USE_FILL_ROUND_RECT) + if (USE_FILL_ROUND_RECT || isVectorRendering()) { + // draw glyph line behind helix (visible in EPS or SVG output) + drawGlyphLine(g, lastSSX, x, y, iconOffset); + + g.setColor(HELIX_COLOUR); + setAntialias(g); int ofs = charWidth / 2; // Off by 1 offset when drawing rects and ovals // to offscreen image on the MAC - fillRoundRect(g, lastSSX, y + 4 + iconOffset, x2 - x1 - 1, 8, 8, 8); + fillRoundRect(g, lastSSX, y + 3 + iconOffset, x2 - x1 - 1, 8, 8, 8); if (sCol == 0 || row[sCol - 1] == null || row[sCol - 1].secondaryStructure != 'H') { } else { - // g.setColor(Color.orange); - fillRoundRect(g, lastSSX, y + 4 + iconOffset, x2 - x1 - ofs, 8, 0, + fillRoundRect(g, lastSSX, y + 3 + iconOffset, x2 - x1 - ofs, 8, 0, 0); } if (!validRes || row[column] == null @@ -1255,31 +1288,38 @@ public class AnnotationRenderer } else { - // g.setColor(Color.magenta); - fillRoundRect(g, lastSSX + ofs, y + 4 + iconOffset, x2 - x1 - ofs, + fillRoundRect(g, lastSSX + ofs, y + 3 + iconOffset, x2 - x1 - ofs, 8, 0, 0); - } return; } - if (sCol == 0 || row[sCol - 1] == null - || row[sCol - 1].secondaryStructure != 'H') + boolean leftEnd = sCol == 0 || row[sCol - 1] == null + || row[sCol - 1].secondaryStructure != 'H'; + boolean rightEnd = !validRes || row[column] == null + || row[column].secondaryStructure != 'H'; + + if (leftEnd || rightEnd) + { + drawGlyphLine(g, lastSSX, x, y, iconOffset); + } + g.setColor(HELIX_COLOUR); + + if (leftEnd) { - fillArc(g, lastSSX, y + 4 + iconOffset, charWidth, 8, 90, 180); + fillArc(g, lastSSX, y + 3 + iconOffset, charWidth, 8, 90, 180); x1 += charWidth / 2; } - if (!validRes || row[column] == null - || row[column].secondaryStructure != 'H') + if (rightEnd) { - fillArc(g, (x * charWidth) - charWidth - 1, y + 4 + iconOffset, - charWidth, 8, 270, 180); + fillArc(g, ((x - 1) * charWidth), y + 3 + iconOffset, charWidth, 8, + 270, 180); x2 -= charWidth / 2; } - fillRect(g, x1, y + 4 + iconOffset, x2 - x1, 8); + fillRect(g, x1, y + 3 + iconOffset, x2 - x1, 8); } void drawLineGraph(Graphics g, AlignmentAnnotation _aa, @@ -1290,6 +1330,13 @@ public class AnnotationRenderer { return; } + Stroke roundStroke = new BasicStroke(1, BasicStroke.CAP_ROUND, + BasicStroke.JOIN_ROUND); + Stroke squareStroke = new BasicStroke(1, BasicStroke.CAP_SQUARE, + BasicStroke.JOIN_MITER); + Graphics2D g2d = (Graphics2D) g; + Stroke prevStroke = g2d.getStroke(); + g2d.setStroke(roundStroke); int x = 0; @@ -1315,9 +1362,9 @@ public class AnnotationRenderer y2 = y - (int) ((0 - min / range) * graphHeight); } - setAntialias(g); g.setColor(Color.gray); - g.drawLine(x - charWidth, y2, (eRes - sRes + 1) * charWidth, y2); + drawLine(g, squareStroke, x * charWidth - charWidth, y2, + (eRes - sRes) * charWidth, y2); eRes = Math.min(eRes, aa_annotations.length); @@ -1359,7 +1406,7 @@ public class AnnotationRenderer // standalone value y1 = y - (int) (((aa_annotations[column].value - min) / range) * graphHeight); - g.drawLine(x * charWidth + charWidth / 4, y1, + drawLine(g, x * charWidth + charWidth / 4, y1, x * charWidth + 3 * charWidth / 4, y1); x++; continue; @@ -1376,7 +1423,7 @@ public class AnnotationRenderer y2 = y - (int) (((aa_annotations[column].value - min) / range) * graphHeight); - g.drawLine(x * charWidth - charWidth / 2, y1, + drawLine(g, (x - 1) * charWidth + charWidth / 2, y1, x * charWidth + charWidth / 2, y2); x++; } @@ -1385,14 +1432,14 @@ public class AnnotationRenderer { g.setColor(_aa.threshold.colour); Graphics2D g2 = (Graphics2D) g; - g2.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, + Stroke s = new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, 3f, new float[] - { 5f, 3f }, 0f)); + { 5f, 3f }, 0f); y2 = (int) (y - ((_aa.threshold.value - min) / range) * graphHeight); - g.drawLine(0, y2, (eRes - sRes) * charWidth, y2); - g2.setStroke(new BasicStroke()); + drawLine(g, s, 0, y2, (eRes - sRes) * charWidth, y2); } + g2d.setStroke(prevStroke); } @SuppressWarnings("unused") @@ -1419,7 +1466,7 @@ public class AnnotationRenderer g.setColor(Color.gray); - g.drawLine(x, y2, (eRes - sRes) * charWidth, y2); + drawLine(g, x, y2, (eRes - sRes) * charWidth, y2); int column; int aaMax = aa_annotations.length - 1; @@ -1618,15 +1665,13 @@ public class AnnotationRenderer if (_aa.threshold != null) { g.setColor(_aa.threshold.colour); - Graphics2D g2 = (Graphics2D) g; - g2.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, + Stroke s = new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, 3f, new float[] - { 5f, 3f }, 0f)); + { 5f, 3f }, 0f); y2 = (int) (y - ((_aa.threshold.value - min) / range) * _aa.graphHeight); - g.drawLine(0, y2, (eRes - sRes) * charWidth, y2); - g2.setStroke(new BasicStroke()); + drawLine(g, s, 0, y2, (eRes - sRes) * charWidth, y2); } } @@ -1793,40 +1838,59 @@ public class AnnotationRenderer } } - private static void fillPolygon(Graphics g, int[] xpoints, int[] ypoints, - int n) + private void fillPolygon(Graphics g, int[] xpoints, int[] ypoints, int n) { - unsetAntialias(g); - g.fillPolygon(xpoints, ypoints, n); setAntialias(g); g.fillPolygon(xpoints, ypoints, n); - g.drawPolygon(xpoints, ypoints, n); } - private static void fillRect(Graphics g, int a, int b, int c, int d) + /* + private void fillRect(Graphics g, int a, int b, int c, int d) { + fillRect(g, false, a, b, c, d); + }*/ + + private void fillRect(Graphics g, int a, int b, int c, int d) + { + unsetAntialias(g); g.fillRect(a, b, c, d); - g.drawRect(a, b, c, d); } - private static void fillRoundRect(Graphics g, int a, int b, int c, int d, - int e, int f) + private void fillRoundRect(Graphics g, int a, int b, int c, int d, int e, + int f) { setAntialias(g); g.fillRoundRect(a, b, c, d, e, f); - g.drawRoundRect(a, b, c, d, e, f); } - private static void fillArc(Graphics g, int a, int b, int c, int d, int e, - int f) + private void fillArc(Graphics g, int a, int b, int c, int d, int e, int f) { setAntialias(g); g.fillArc(a, b, c, d, e, f); - g.drawArc(a, b, c, d, e, f); } - private static void setAntialias(Graphics g) + private void drawLine(Graphics g, Stroke s, int a, int b, int c, int d) { + Graphics2D g2d = (Graphics2D) g; + Stroke p = g2d.getStroke(); + g2d.setStroke(s); + drawLine(g, a, b, c, d); + g2d.setStroke(p); + } + + private void drawLine(Graphics g, int a, int b, int c, int d) + { + setAntialias(g); + g.drawLine(a, b, c, d); + } + + private void setAntialias(Graphics g) + { + if (isVectorRendering()) + { + // no need to antialias vector drawings + return; + } if (Cache.getDefault("ANTI_ALIAS", true)) { Graphics2D g2d = (Graphics2D) g; @@ -1835,10 +1899,25 @@ public class AnnotationRenderer } } - private static void unsetAntialias(Graphics g) + private void unsetAntialias(Graphics g) { + if (isVectorRendering()) + { + // no need to antialias vector drawings + return; + } Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); } + + public void setVectorRendering(boolean b) + { + renderingVectors = b; + } + + public boolean isVectorRendering() + { + return renderingVectors; + } }