JAL-4045 - don't apply distribution dependent scale factor to the axis lines!
[jalview.git] / src / jalview / gui / RotatableCanvas.java
index 2053f94..ef0b2aa 100755 (executable)
  */
 package jalview.gui;
 
-import jalview.api.RotatableCanvasI;
-import jalview.datamodel.Point;
-import jalview.datamodel.SequenceGroup;
-import jalview.datamodel.SequenceI;
-import jalview.datamodel.SequencePoint;
-import jalview.math.RotatableMatrix;
-import jalview.math.RotatableMatrix.Axis;
-import jalview.util.MessageManager;
-import jalview.viewmodel.AlignmentViewport;
-
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Font;
@@ -52,13 +42,24 @@ import java.util.List;
 import javax.swing.JPanel;
 import javax.swing.ToolTipManager;
 
+import jalview.api.RotatableCanvasI;
+import jalview.datamodel.Point;
+import jalview.datamodel.SequenceGroup;
+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;
+
 /**
  * Models a Panel on which a set of points, and optionally x/y/z axes, can be
  * drawn, and rotated or zoomed with the mouse
  */
-public class RotatableCanvas extends JPanel implements MouseListener,
-        MouseMotionListener, KeyListener, RotatableCanvasI,
-        MouseWheelListener
+public class RotatableCanvas extends JPanel
+        implements MouseListener, MouseMotionListener, KeyListener,
+        RotatableCanvasI, MouseWheelListener
 {
   private static final float ZOOM_OUT = 0.9f;
 
@@ -103,7 +104,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
    * half the available width or height (whichever is less); increase this
    * factor to zoom in, decrease it to zoom out
    */
-  float scaleFactor;
+  private float scaleFactor;
 
   int npoint;
 
@@ -115,7 +116,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
   /*
    * x, y, z axis end points (PCA dimension values)
    */
-  Point[] axisEndPoints;
+  private Point[] axisEndPoints;
 
   // fields for 'select rectangle' (JAL-1124)
   // int rectx1;
@@ -127,11 +128,11 @@ public class RotatableCanvas extends JPanel implements MouseListener,
 
   AlignmentPanel ap;
 
-  boolean showLabels;
+  private boolean showLabels;
 
-  Color bgColour;
+  private Color bgColour;
 
-  boolean applyToAllViews;
+  private boolean applyToAllViews;
 
   /**
    * Constructor
@@ -142,10 +143,10 @@ public class RotatableCanvas extends JPanel implements MouseListener,
   {
     this.av = panel.av;
     this.ap = panel;
-    axisEndPoints = new Point[DIMS];
-    showLabels = false;
-    applyToAllViews = false;
-    bgColour = Color.BLACK;
+    setAxisEndPoints(new Point[DIMS]);
+    setShowLabels(false);
+    setApplyToAllViews(false);
+    setBgColour(Color.BLACK);
     resetAxes();
 
     ToolTipManager.sharedInstance().registerComponent(this);
@@ -162,7 +163,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
    */
   public void showLabels(boolean show)
   {
-    showLabels = show;
+    setShowLabels(show);
     repaint();
   }
 
@@ -175,7 +176,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
 
     findWidths();
 
-    scaleFactor = 1f;
+    setScaleFactor(1f);
   }
 
   /**
@@ -184,9 +185,9 @@ public class RotatableCanvas extends JPanel implements MouseListener,
    */
   protected void resetAxes()
   {
-    axisEndPoints[0] = new Point(1f, 0f, 0f);
-    axisEndPoints[1] = new Point(0f, 1f, 0f);
-    axisEndPoints[2] = new Point(0f, 0f, 1f);
+    getAxisEndPoints()[0] = new Point(1f, 0f, 0f);
+    getAxisEndPoints()[1] = new Point(0f, 1f, 0f);
+    getAxisEndPoints()[2] = new Point(0f, 0f, 1f);
   }
 
   /**
@@ -197,15 +198,15 @@ public class RotatableCanvas extends JPanel implements MouseListener,
   {
     float[] max = new float[DIMS];
     float[] min = new float[DIMS];
-    
+
     max[0] = -Float.MAX_VALUE;
     max[1] = -Float.MAX_VALUE;
     max[2] = -Float.MAX_VALUE;
-    
+
     min[0] = Float.MAX_VALUE;
     min[1] = Float.MAX_VALUE;
     min[2] = Float.MAX_VALUE;
-    
+
     for (SequencePoint sp : sequencePoints)
     {
       max[0] = Math.max(max[0], sp.coord.x);
@@ -215,7 +216,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
       min[1] = Math.min(min[1], sp.coord.y);
       min[2] = Math.min(min[2], sp.coord.z);
     }
-    
+
     seqMin = min;
     seqMax = max;
   }
@@ -286,7 +287,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
         ig = img.getGraphics();
       }
 
-      drawBackground(ig, bgColour);
+      drawBackground(ig);
       drawScene(ig);
 
       if (drawAxes)
@@ -321,28 +322,27 @@ public class RotatableCanvas extends JPanel implements MouseListener,
 
     int midX = getWidth() / 2;
     int midY = getHeight() / 2;
-    float maxWidth = Math.max(Math.abs(seqMax[0] - seqMin[0]),
-            Math.abs(seqMax[1] - seqMin[1]));
+    // float maxWidth = Math.max(Math.abs(seqMax[0] - seqMin[0]),
+    // Math.abs(seqMax[1] - seqMin[1]));
     int pix = Math.min(getWidth(), getHeight());
-    float scaleBy = pix * scaleFactor / (2f * maxWidth);
+    float scaleBy = pix * getScaleFactor() / (2f);
 
     for (int i = 0; i < DIMS; i++)
     {
       g.drawLine(midX, midY,
-              midX + (int) (axisEndPoints[i].x * scaleBy * seqMax[0]),
-              midY + (int) (axisEndPoints[i].y * scaleBy * seqMax[1]));
+              midX + (int) (getAxisEndPoints()[i].x * scaleBy * 0.25),
+              midY + (int) (getAxisEndPoints()[i].y * scaleBy * 0.25));
     }
   }
 
   /**
-   * Fills the background with the specified colour
+   * Fills the background with the currently configured background colour
    * 
    * @param g
-   * @param col
    */
-  public void drawBackground(Graphics g, Color col)
+  public void drawBackground(Graphics g)
   {
-    g.setColor(col);
+    g.setColor(getBgColour());
     g.fillRect(0, 0, prefSize.width, prefSize.height);
   }
 
@@ -365,7 +365,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     float xWidth = Math.abs(seqMax[0] - seqMin[0]);
     float yWidth = Math.abs(seqMax[1] - seqMin[1]);
     float maxWidth = Math.max(xWidth, yWidth);
-    float scaleBy = pix * scaleFactor / (2f * maxWidth);
+    float scaleBy = pix * getScaleFactor() / (2f * maxWidth);
 
     float[] centre = getCentre();
 
@@ -385,19 +385,19 @@ public class RotatableCanvas extends JPanel implements MouseListener,
       int y = (int) ((sp.coord.y - centre[1]) * scaleBy) + halfheight;
       g.fillRect(x - 3, y - 3, 6, 6);
 
-      if (showLabels)
+      if (isShowLabels())
       {
         g.setColor(Color.red);
         g.drawString(sp.getSequence().getName(), x - 3, y - 4);
       }
     }
-    if (showLabels)
+    if (isShowLabels())
     {
       g.setColor(AXIS_COLOUR);
       int midX = getWidth() / 2;
       int midY = getHeight() / 2;
       Iterator<String> axes = AXES.iterator();
-      for (Point p : axisEndPoints)
+      for (Point p : getAxisEndPoints())
       {
         int x = midX + (int) (p.x * scaleBy * seqMax[0]);
         int y = midY + (int) (p.y * scaleBy * seqMax[1]);
@@ -436,9 +436,20 @@ public class RotatableCanvas extends JPanel implements MouseListener,
         sequenceColour = Color.gray;
       }
     }
-    if (sp.coord.z < 0f)
+
+    /*
+     * graduate brighter for point in front of centre, darker if behind centre
+     */
+    float zCentre = (seqMin[2] + seqMax[2]) / 2f;
+    if (sp.coord.z > zCentre)
+    {
+      sequenceColour = ColorUtils.getGraduatedColour(sp.coord.z, 0,
+              sequenceColour, seqMax[2], sequenceColour.brighter());
+    }
+    else if (sp.coord.z < zCentre)
     {
-      sequenceColour = sequenceColour.darker();
+      sequenceColour = ColorUtils.getGraduatedColour(sp.coord.z, seqMin[2],
+              sequenceColour.darker(), 0, sequenceColour);
     }
 
     return sequenceColour;
@@ -463,18 +474,41 @@ public class RotatableCanvas extends JPanel implements MouseListener,
   public void keyPressed(KeyEvent evt)
   {
     int keyCode = evt.getKeyCode();
+    boolean shiftDown = evt.isShiftDown();
 
     if (keyCode == KeyEvent.VK_UP)
     {
-      zoom(ZOOM_IN);
+      if (shiftDown)
+      {
+        rotate(0f, -1f);
+      }
+      else
+      {
+        zoom(ZOOM_IN);
+      }
     }
     else if (keyCode == KeyEvent.VK_DOWN)
     {
-      zoom(ZOOM_OUT);
+      if (shiftDown)
+      {
+        rotate(0f, 1f);
+      }
+      else
+      {
+        zoom(ZOOM_OUT);
+      }
+    }
+    else if (shiftDown && keyCode == KeyEvent.VK_LEFT)
+    {
+      rotate(1f, 0f);
+    }
+    else if (shiftDown && keyCode == KeyEvent.VK_RIGHT)
+    {
+      rotate(-1f, 0f);
     }
     else if (evt.getKeyChar() == 's')
     {
-      // Cache.log.warn("DEBUG: Rectangle selection");
+      // Cache.warn("DEBUG: Rectangle selection");
       // todo not yet enabled as rectx2, recty2 are always -1
       // need to set them in mouseDragged; JAL-1124
       // if ((rectx2 != -1) && (recty2 != -1))
@@ -491,7 +525,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
   {
     if (factor > 0f)
     {
-      scaleFactor *= factor;
+      setScaleFactor(getScaleFactor() * factor);
     }
   }
 
@@ -596,7 +630,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     int yDelta = yPos - mouseY;
 
     // Check if this is a rectangle drawing drag
-    if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
+    if ((evt.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0)
     {
       // rectx2 = evt.getX();
       // recty2 = evt.getY();
@@ -665,7 +699,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
 
       // Now translate back again
       sp.translate(centre[0], centre[1], centre[2]);
-      
+
       zMin = Math.min(zMin, sp.coord.z);
       zMax = Math.max(zMax, sp.coord.z);
     }
@@ -678,7 +712,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
      */
     for (int i = 0; i < DIMS; i++)
     {
-      axisEndPoints[i] = rotmat.vectorMultiply(axisEndPoints[i]);
+      getAxisEndPoints()[i] = rotmat.vectorMultiply(getAxisEndPoints()[i]);
     }
   }
 
@@ -714,9 +748,9 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     for (int i = 0; i < npoint; i++)
     {
       SequencePoint sp = sequencePoints.get(i);
-      int tmp1 = (int) (((sp.coord.x - centre[0]) * scaleFactor)
+      int tmp1 = (int) (((sp.coord.x - centre[0]) * getScaleFactor())
               + (getWidth() / 2.0));
-      int tmp2 = (int) (((sp.coord.y - centre[1]) * scaleFactor)
+      int tmp2 = (int) (((sp.coord.y - centre[1]) * getScaleFactor())
               + (getHeight() / 2.0));
 
       if ((tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2))
@@ -724,8 +758,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
         if (av != null)
         {
           SequenceI sequence = sp.getSequence();
-          if (!av.getSelectionGroup().getSequences(null)
-                  .contains(sequence))
+          if (!av.getSelectionGroup().getSequences(null).contains(sequence))
           {
             av.getSelectionGroup().addSequence(sequence, true);
           }
@@ -753,17 +786,15 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     float xWidth = Math.abs(seqMax[0] - seqMin[0]);
     float yWidth = Math.abs(seqMax[1] - seqMin[1]);
     float maxWidth = Math.max(xWidth, yWidth);
-    float scaleBy = pix * scaleFactor / (2f * maxWidth);
+    float scaleBy = pix * getScaleFactor() / (2f * maxWidth);
 
     float[] centre = getCentre();
 
     for (int i = 0; i < npoint; i++)
     {
       SequencePoint sp = sequencePoints.get(i);
-      int px = (int) ((sp.coord.x - centre[0]) * scaleBy)
-              + halfwidth;
-      int py = (int) ((sp.coord.y - centre[1]) * scaleBy)
-              + halfheight;
+      int px = (int) ((sp.coord.x - centre[0]) * scaleBy) + halfwidth;
+      int py = (int) ((sp.coord.y - centre[1]) * scaleBy) + halfheight;
 
       if ((Math.abs(px - x) < NEARBY) && (Math.abs(py - y) < NEARBY))
       {
@@ -790,7 +821,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
    */
   AlignmentPanel[] getAssociatedPanels()
   {
-    if (applyToAllViews)
+    if (isApplyToAllViews())
     {
       return PaintRefresher.getAssociatedPanels(av.getSequenceSetId());
     }
@@ -802,7 +833,7 @@ public class RotatableCanvas extends JPanel implements MouseListener,
 
   public Color getBackgroundColour()
   {
-    return bgColour;
+    return getBgColour();
   }
 
   /**
@@ -860,4 +891,54 @@ public class RotatableCanvas extends JPanel implements MouseListener,
     seqMin = min;
     seqMax = max;
   }
+
+  public float getScaleFactor()
+  {
+    return scaleFactor;
+  }
+
+  public void setScaleFactor(float scaleFactor)
+  {
+    this.scaleFactor = scaleFactor;
+  }
+
+  public boolean isShowLabels()
+  {
+    return showLabels;
+  }
+
+  public void setShowLabels(boolean showLabels)
+  {
+    this.showLabels = showLabels;
+  }
+
+  public boolean isApplyToAllViews()
+  {
+    return applyToAllViews;
+  }
+
+  public void setApplyToAllViews(boolean applyToAllViews)
+  {
+    this.applyToAllViews = applyToAllViews;
+  }
+
+  public Point[] getAxisEndPoints()
+  {
+    return axisEndPoints;
+  }
+
+  public void setAxisEndPoints(Point[] axisEndPoints)
+  {
+    this.axisEndPoints = axisEndPoints;
+  }
+
+  public Color getBgColour()
+  {
+    return bgColour;
+  }
+
+  public void setBgColour(Color bgColour)
+  {
+    this.bgColour = bgColour;
+  }
 }