2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5)
3 * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
23 import java.awt.event.*;
26 import jalview.datamodel.*;
27 import jalview.math.*;
35 public class RotatableCanvas extends JPanel implements MouseListener,
36 MouseMotionListener, KeyListener
38 RotatableMatrix idmat = new RotatableMatrix(3, 3);
40 RotatableMatrix objmat = new RotatableMatrix(3, 3);
42 RotatableMatrix rotmat = new RotatableMatrix(3, 3);
44 // RubberbandRectangle rubberband;
45 boolean drawAxes = true;
61 float[] centre = new float[3];
63 float[] width = new float[3];
65 float[] max = new float[3];
67 float[] min = new float[3];
97 float scalefactor = 1;
103 boolean showLabels = false;
105 Color bgColour = Color.black;
107 boolean applyToAllViews = false;
109 // Controller controller;
110 public RotatableCanvas(AlignmentPanel ap)
115 addMouseWheelListener(new MouseWheelListener()
117 public void mouseWheelMoved(MouseWheelEvent e)
119 if (e.getWheelRotation() > 0)
121 scale = (float) (scale * 1.1);
127 scale = (float) (scale * 0.9);
135 public void showLabels(boolean b)
141 public void setPoints(Vector points, int npoint)
143 this.points = points;
144 this.npoint = npoint;
145 ToolTipManager.sharedInstance().registerComponent(this);
146 ToolTipManager.sharedInstance().setInitialDelay(0);
147 ToolTipManager.sharedInstance().setDismissDelay(10000);
149 prefsize = getPreferredSize();
150 orig = new float[npoint][3];
152 for (int i = 0; i < npoint; i++)
154 SequencePoint sp = (SequencePoint) points.elementAt(i);
156 for (int j = 0; j < 3; j++)
158 orig[i][j] = sp.coord[j];
162 // Initialize the matrices to identity
163 for (int i = 0; i < 3; i++)
165 for (int j = 0; j < 3; j++)
169 idmat.addElement(i, j, 0);
170 objmat.addElement(i, j, 0);
171 rotmat.addElement(i, j, 0);
175 idmat.addElement(i, j, 0);
176 objmat.addElement(i, j, 0);
177 rotmat.addElement(i, j, 0);
182 axes = new float[3][3];
190 addMouseListener(this);
192 addMouseMotionListener(this);
196 public void initAxes()
198 for (int i = 0; i < 3; i++)
200 for (int j = 0; j < 3; j++)
217 public void findWidth()
222 max[0] = (float) -1e30;
223 max[1] = (float) -1e30;
224 max[2] = (float) -1e30;
226 min[0] = (float) 1e30;
227 min[1] = (float) 1e30;
228 min[2] = (float) 1e30;
230 for (int i = 0; i < 3; i++)
232 for (int j = 0; j < npoint; j++)
234 SequencePoint sp = (SequencePoint) points.elementAt(j);
236 if (sp.coord[i] >= max[i])
238 max[i] = sp.coord[i];
241 if (sp.coord[i] <= min[i])
243 min[i] = sp.coord[i];
248 // System.out.println("xmax " + max[0] + " min " + min[0]);
249 // System.out.println("ymax " + max[1] + " min " + min[1]);
250 // System.out.println("zmax " + max[2] + " min " + min[2]);
251 width[0] = Math.abs(max[0] - min[0]);
252 width[1] = Math.abs(max[1] - min[1]);
253 width[2] = Math.abs(max[2] - min[2]);
257 if (width[1] > width[0])
262 if (width[2] > width[1])
267 // System.out.println("Maxwidth = " + maxwidth);
273 * @return DOCUMENT ME!
275 public float findScale()
284 height = getHeight();
288 width = prefsize.width;
289 height = prefsize.height;
301 return (float) ((dim * scalefactor) / (2 * maxwidth));
307 public void findCentre()
309 // Find centre coordinate
312 centre[0] = (max[0] + min[0]) / 2;
313 centre[1] = (max[1] + min[1]) / 2;
314 centre[2] = (max[2] + min[2]) / 2;
316 // System.out.println("Centre x " + centre[0]);
317 // System.out.println("Centre y " + centre[1]);
318 // System.out.println("Centre z " + centre[2]);
324 * @return DOCUMENT ME!
326 public Dimension getPreferredSize()
328 if (prefsize != null)
334 return new Dimension(400, 400);
341 * @return DOCUMENT ME!
343 public Dimension getMinimumSize()
345 return getPreferredSize();
354 public void paintComponent(Graphics g1)
357 Graphics2D g = (Graphics2D) g1;
359 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
360 RenderingHints.VALUE_ANTIALIAS_ON);
363 g.setFont(new Font("Verdana", Font.PLAIN, 18));
364 g.drawString("Calculating PCA....", 20, getHeight() / 2);
368 // Only create the image at the beginning -
369 if ((img == null) || (prefsize.width != getWidth())
370 || (prefsize.height != getHeight()))
372 prefsize.width = getWidth();
373 prefsize.height = getHeight();
377 // System.out.println("New scale = " + scale);
378 img = createImage(getWidth(), getHeight());
379 ig = img.getGraphics();
382 drawBackground(ig, bgColour);
385 if (drawAxes == true)
390 g.drawImage(img, 0, 0, this);
400 public void drawAxes(Graphics g)
403 g.setColor(Color.yellow);
405 for (int i = 0; i < 3; i++)
407 g.drawLine(getWidth() / 2, getHeight() / 2, (int) ((axes[i][0]
408 * scale * max[0]) + (getWidth() / 2)), (int) ((axes[i][1]
409 * scale * max[1]) + (getHeight() / 2)));
421 public void drawBackground(Graphics g, Color col)
424 g.fillRect(0, 0, prefsize.width, prefsize.height);
433 public void drawScene(Graphics g1)
436 Graphics2D g = (Graphics2D) g1;
438 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
439 RenderingHints.VALUE_ANTIALIAS_ON);
441 int halfwidth = getWidth() / 2;
442 int halfheight = getHeight() / 2;
444 for (int i = 0; i < npoint; i++)
446 SequencePoint sp = (SequencePoint) points.elementAt(i);
447 int x = (int) ((float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
448 int y = (int) ((float) (sp.coord[1] - centre[1]) * scale)
450 float z = sp.coord[1] - centre[2];
452 if (av.getSequenceColour(sp.sequence) == Color.black)
454 g.setColor(Color.white);
458 g.setColor(av.getSequenceColour(sp.sequence));
461 if (av.getSelectionGroup() != null)
463 if (av.getSelectionGroup().getSequences(null).contains(
464 ((SequencePoint) points.elementAt(i)).sequence))
466 g.setColor(Color.gray);
472 g.setColor(g.getColor().darker());
475 g.fillRect(x - 3, y - 3, 6, 6);
478 g.setColor(Color.red);
479 g.drawString(((SequencePoint) points.elementAt(i)).sequence
480 .getName(), x - 3, y - 4);
484 // //Now the rectangle
485 // if (rectx2 != -1 && recty2 != -1) {
486 // g.setColor(Color.white);
488 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
495 * @return DOCUMENT ME!
497 public Dimension minimumsize()
505 * @return DOCUMENT ME!
507 public Dimension preferredsize()
518 public void keyTyped(KeyEvent evt)
528 public void keyReleased(KeyEvent evt)
538 public void keyPressed(KeyEvent evt)
540 if (evt.getKeyCode() == KeyEvent.VK_UP)
542 scalefactor = (float) (scalefactor * 1.1);
545 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
547 scalefactor = (float) (scalefactor * 0.9);
550 else if (evt.getKeyChar() == 's')
552 System.err.println("DEBUG: Rectangle selection"); // log.debug
554 if ((rectx2 != -1) && (recty2 != -1))
556 rectSelect(rectx1, recty1, rectx2, recty2);
569 public void mouseClicked(MouseEvent evt)
579 public void mouseEntered(MouseEvent evt)
589 public void mouseExited(MouseEvent evt)
599 public void mouseReleased(MouseEvent evt)
609 public void mousePressed(MouseEvent evt)
629 SequenceI found = findPoint(x, y);
633 AlignmentPanel[] aps = getAssociatedPanels();
635 for (int a = 0; a < aps.length; a++)
637 if (aps[a].av.getSelectionGroup() != null)
639 aps[a].av.getSelectionGroup().addOrRemove(found, true);
643 aps[a].av.setSelectionGroup(new SequenceGroup());
644 aps[a].av.getSelectionGroup().addOrRemove(found, true);
645 aps[a].av.getSelectionGroup().setEndRes(
646 aps[a].av.alignment.getWidth() - 1);
649 PaintRefresher.Refresh(this, av.getSequenceSetId());
650 // canonical selection is sent to other listeners
657 // private void fireSequenceSelectionEvent(Selection sel) {
658 // controller.handleSequenceSelectionEvent(new
659 // SequenceSelectionEvent(this,sel));
661 public void mouseMoved(MouseEvent evt)
663 SequenceI found = findPoint(evt.getX(), evt.getY());
667 this.setToolTipText(found.getName());
671 this.setToolTipText(null);
681 public void mouseDragged(MouseEvent evt)
686 // Check if this is a rectangle drawing drag
687 if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
689 // rectx2 = evt.getX();
690 // recty2 = evt.getY();
694 rotmat.setIdentity();
696 rotmat.rotate((float) (my - omy), 'x');
697 rotmat.rotate((float) (mx - omx), 'y');
699 for (int i = 0; i < npoint; i++)
701 SequencePoint sp = (SequencePoint) points.elementAt(i);
702 sp.coord[0] -= centre[0];
703 sp.coord[1] -= centre[1];
704 sp.coord[2] -= centre[2];
706 // Now apply the rotation matrix
707 sp.coord = rotmat.vectorMultiply(sp.coord);
709 // Now translate back again
710 sp.coord[0] += centre[0];
711 sp.coord[1] += centre[1];
712 sp.coord[2] += centre[2];
715 for (int i = 0; i < 3; i++)
717 axes[i] = rotmat.vectorMultiply(axes[i]);
723 paint(this.getGraphics());
739 public void rectSelect(int x1, int y1, int x2, int y2)
741 for (int i = 0; i < npoint; i++)
743 SequencePoint sp = (SequencePoint) points.elementAt(i);
744 int tmp1 = (int) (((sp.coord[0] - centre[0]) * scale) + ((float) getWidth() / 2.0));
745 int tmp2 = (int) (((sp.coord[1] - centre[1]) * scale) + ((float) getHeight() / 2.0));
747 if ((tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2))
751 if (!av.getSelectionGroup().getSequences(null).contains(
754 av.getSelectionGroup().addSequence(sp.sequence, true);
761 // fireSequenceSelectionEvent(av.getSelection());
773 * @return DOCUMENT ME!
775 public SequenceI findPoint(int x, int y)
777 int halfwidth = getWidth() / 2;
778 int halfheight = getHeight() / 2;
782 for (int i = 0; i < npoint; i++)
784 SequencePoint sp = (SequencePoint) points.elementAt(i);
785 int px = (int) ((float) (sp.coord[0] - centre[0]) * scale)
787 int py = (int) ((float) (sp.coord[1] - centre[1]) * scale)
790 if ((Math.abs(px - x) < 3) && (Math.abs(py - y) < 3))
798 return ((SequencePoint) points.elementAt(found)).sequence;
806 AlignmentPanel[] getAssociatedPanels()
810 return PaintRefresher.getAssociatedPanels(av.getSequenceSetId());
814 return new AlignmentPanel[]