From: gmungoc Date: Mon, 30 Apr 2018 09:43:17 +0000 (+0100) Subject: JAL-2965 graduated sequence point colour from back to front X-Git-Tag: Release_2_11_1_0~78^2~9^2~11 X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=37651a9d177de05ff938276071c16ba95ac44c73 JAL-2965 graduated sequence point colour from back to front --- diff --git a/src/jalview/gui/RotatableCanvas.java b/src/jalview/gui/RotatableCanvas.java index 6fabd95..615b403 100755 --- a/src/jalview/gui/RotatableCanvas.java +++ b/src/jalview/gui/RotatableCanvas.java @@ -27,6 +27,7 @@ import jalview.datamodel.SequenceI; import jalview.datamodel.SequencePoint; import jalview.math.RotatableMatrix; import jalview.math.RotatableMatrix.Axis; +import jalview.util.ColorUtils; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; @@ -160,9 +161,14 @@ public class RotatableCanvas extends JPanel implements MouseListener, } - public void showLabels(boolean b) + /** + * Refreshes the display with labels shown (or not) + * + * @param show + */ + public void showLabels(boolean show) { - showLabels = b; + showLabels = show; repaint(); } @@ -204,7 +210,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * Resets axes to the initial state: x-axis to the right, y-axis up, z-axis to * back (so obscured in a 2-D display) */ - public void resetAxes() + protected void resetAxes() { axisEndPoints[0] = new Point(1f, 0f, 0f); axisEndPoints[1] = new Point(0f, 1f, 0f); @@ -216,7 +222,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * sequence point, and also the min-max range (width) for each dimension, and * the maximum width for all dimensions */ - public void findWidth() + protected void findWidth() { max = new float[DIMS]; min = new float[DIMS]; @@ -251,7 +257,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * * @return DOCUMENT ME! */ - public float findScale() + protected float findScale() { int dim; int w; @@ -283,7 +289,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, /** * Computes and saves the position of the centre of the view */ - public void findCentre() + protected void findCentre() { findWidth(); @@ -434,26 +440,8 @@ public class RotatableCanvas extends JPanel implements MouseListener, * gray if sequence is currently selected */ SequencePoint sp = points.elementAt(i); - SequenceI sequence = sp.getSequence(); - Color sequenceColour = av.getSequenceColour(sequence); - g.setColor( - sequenceColour == Color.black ? Color.white : sequenceColour); - if (av.getSelectionGroup() != null) - { - if (av.getSelectionGroup().getSequences(null) - .contains(sequence)) - { - g.setColor(Color.gray); - } - } - - /* - * dim sequence points 'at the back' - */ - if (sp.coord.z < centre.z) - { - g.setColor(g.getColor().darker()); - } + Color sequenceColour = getSequencePointColour(sp); + g.setColor(sequenceColour); int halfwidth = getWidth() / 2; int halfheight = getHeight() / 2; @@ -464,7 +452,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, if (showLabels) { g.setColor(Color.red); - g.drawString(sequence.getName(), x - 3, y - 4); + g.drawString(sp.getSequence().getName(), x - 3, y - 4); } } @@ -476,6 +464,40 @@ public class RotatableCanvas extends JPanel implements MouseListener, // } } + /** + * Determines the colour to use when drawing a sequence point. The colour is + * taken from the sequence id, with black converted to white, and then + * graduated from darker (at the back) to brighter (at the front) based on the + * z-axis coordinate of the point. + * + * @param sp + * @return + */ + protected Color getSequencePointColour(SequencePoint sp) + { + SequenceI sequence = sp.getSequence(); + Color sequenceColour = av.getSequenceColour(sequence); + if (sequenceColour == Color.black) + { + sequenceColour = Color.white; + } + if (av.getSelectionGroup() != null) + { + if (av.getSelectionGroup().getSequences(null).contains(sequence)) + { + sequenceColour = Color.gray; + } + } + + /* + * graduate from front (brighter) to back (darker) + */ + sequenceColour = ColorUtils.getGraduatedColour(sp.coord.z, min[2], + max[2], sequenceColour); + + return sequenceColour; + } + @Override public void keyTyped(KeyEvent evt) { @@ -691,7 +713,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param x2 * @param y2 */ - public void rectSelect(int x1, int y1, int x2, int y2) + protected void rectSelect(int x1, int y1, int x2, int y2) { for (int i = 0; i < npoint; i++) { @@ -725,7 +747,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * * @return */ - public SequenceI findSequenceAtPoint(int x, int y) + protected SequenceI findSequenceAtPoint(int x, int y) { int halfwidth = getWidth() / 2; int halfheight = getHeight() / 2; diff --git a/src/jalview/util/ColorUtils.java b/src/jalview/util/ColorUtils.java index 60129fb..16ff259 100644 --- a/src/jalview/util/ColorUtils.java +++ b/src/jalview/util/ColorUtils.java @@ -31,6 +31,9 @@ import java.util.Random; public class ColorUtils { + // constant borrowed from java.awt.Color + private static final float FACTOR = 0.7f; + private static final int MAX_CACHE_SIZE = 1729; /* * a cache for colours generated from text strings @@ -372,4 +375,63 @@ public class ColorUtils return col; } + + /** + * Generates a colour that is interpolated between + * colour.darker() and colour.brighter() in + * proportion as value is between min and + * max. Note that the 'neutral point' (unchanged colour) is + * closer to 'brighter' than to 'darker'as this is a geometric range. + * + * @param value + * @param min + * @param max + * @param colour + * @return + */ + public static Color getGraduatedColour(float value, float min, float max, + Color colour) + { + /* + * this computes the equivalent of + * getGraduatedColour(value, min, colour.darker(), max, colour.brighter()) + * but avoiding object creation except for the return value + */ + if (value < min) + { + value = min; + } + if (value > max) + { + value = max; + } + + int r = colour.getRed(); + int g = colour.getGreen(); + int b = colour.getBlue(); + + /* + * rgb for colour.darker(): + */ + float minR = r * FACTOR; + float minG = g * FACTOR; + float minB = b * FACTOR; + + /* + * rgb for colour.brighter(): + */ + float maxR = Math.min(255f, r / FACTOR); + float maxG = Math.min(255f, g / FACTOR); + float maxB = Math.min(255f, b / FACTOR); + + /* + * interpolation + */ + float p = (value - min) / (max - min); + int newR = (int) (minR + p * (maxR - minR)); + int newG = (int) (minG + p * (maxG - minG)); + int newB = (int) (minB + p * (maxB - minB)); + + return new Color(newR, newG, newB, colour.getAlpha()); + } } diff --git a/test/jalview/util/ColorUtilsTest.java b/test/jalview/util/ColorUtilsTest.java index fa4091f..0acd806 100644 --- a/test/jalview/util/ColorUtilsTest.java +++ b/test/jalview/util/ColorUtilsTest.java @@ -243,4 +243,48 @@ public class ColorUtilsTest assertEquals(new Color(184, 184, 184), ColorUtils.createColourFromName("HELLO HELLO HELLO ")); } + + /** + * Tests for the method that returns a colour graduated between darker() and + * brighter() + */ + @Test(groups = { "Functional" }) + public void testGetGraduatedColour_darkerToBrighter() + { + final Color colour = new Color(180, 200, 220); + + /* + * value half-way between min and max does _not_ mean colour unchanged + * darker (*.7) is (126, 140, 154) + * brighter (*1/.7) is (255, 255, 255) + * midway is (190, 197, 204) + */ + Color col = ColorUtils.getGraduatedColour(20f, 10f, 30f, colour); + assertEquals(190, col.getRed()); + assertEquals(197, col.getGreen()); + assertEquals(204, col.getBlue()); + + // minValue (or less) returns colour.darker() + // - or would do if Color.darker calculated better! + col = ColorUtils.getGraduatedColour(10f, 10f, 30f, colour); + assertEquals(col, new Color(126, 140, 154)); + // Color.darker computes 125.999999 and rounds down! + assertEquals(new Color(125, 140, 154), colour.darker()); + col = ColorUtils.getGraduatedColour(-10f, 10f, 30f, colour); + assertEquals(new Color(126, 140, 154), col); + + // maxValue (or more) returns colour.brighter() + col = ColorUtils.getGraduatedColour(30f, 10f, 30f, colour); + assertEquals(colour.brighter(), col); + col = ColorUtils.getGraduatedColour(40f, 10f, 30f, colour); + assertEquals(colour.brighter(), col); + + /* + * 'linear' mid-point between 0.7 and 1/0.7 is 1.057 + * so the ' + */ + Color c = new Color(200, 200, 200); + col = ColorUtils.getGraduatedColour(106f, 0f, 200f, c); + assertEquals(c, col); + } }