2 * Jalview - A Sequence Alignment Editor and Viewer
\r
3 * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
\r
5 * This program is free software; you can redistribute it and/or
\r
6 * modify it under the terms of the GNU General Public License
\r
7 * as published by the Free Software Foundation; either version 2
\r
8 * of the License, or (at your option) any later version.
\r
10 * This program is distributed in the hope that it will be useful,
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 * GNU General Public License for more details.
\r
15 * You should have received a copy of the GNU General Public License
\r
16 * along with this program; if not, write to the Free Software
\r
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
\r
19 package jalview.gui;
\r
21 import jalview.datamodel.*;
\r
23 import jalview.math.*;
\r
25 import jalview.util.*;
\r
28 import java.awt.event.*;
\r
32 import javax.swing.*;
\r
39 * @version $Revision$
\r
41 public class RotatableCanvas extends JPanel implements MouseListener,
\r
42 MouseMotionListener, KeyListener
\r
44 RotatableMatrix idmat = new RotatableMatrix(3, 3);
\r
45 RotatableMatrix objmat = new RotatableMatrix(3, 3);
\r
46 RotatableMatrix rotmat = new RotatableMatrix(3, 3);
\r
48 //RubberbandRectangle rubberband;
\r
49 boolean drawAxes = true;
\r
57 float[] centre = new float[3];
\r
58 float[] width = new float[3];
\r
59 float[] max = new float[3];
\r
60 float[] min = new float[3];
\r
75 float scalefactor = 1;
\r
77 boolean showLabels = false;
\r
78 Color bgColour = Color.black;
\r
80 // Controller controller;
\r
81 public RotatableCanvas(AlignViewport av)
\r
86 public void showLabels(boolean b)
\r
92 public void setPoints(Vector points, int npoint)
\r
94 this.points = points;
\r
95 this.npoint = npoint;
\r
96 ToolTipManager.sharedInstance().registerComponent(this);
\r
97 ToolTipManager.sharedInstance().setInitialDelay(0);
\r
98 ToolTipManager.sharedInstance().setDismissDelay(10000);
\r
99 PaintRefresher.Register(this, av.alignment);
\r
101 prefsize = getPreferredSize();
\r
102 orig = new float[npoint][3];
\r
104 for (int i = 0; i < npoint; i++)
\r
106 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
108 for (int j = 0; j < 3; j++)
\r
110 orig[i][j] = sp.coord[j];
\r
114 //Initialize the matrices to identity
\r
115 for (int i = 0; i < 3; i++)
\r
117 for (int j = 0; j < 3; j++)
\r
121 idmat.addElement(i, j, 0);
\r
122 objmat.addElement(i, j, 0);
\r
123 rotmat.addElement(i, j, 0);
\r
127 idmat.addElement(i, j, 0);
\r
128 objmat.addElement(i, j, 0);
\r
129 rotmat.addElement(i, j, 0);
\r
134 axes = new float[3][3];
\r
140 scale = findScale();
\r
142 addMouseListener(this);
\r
143 addKeyListener(this);
\r
145 addMouseMotionListener(this);
\r
149 public void initAxes()
\r
151 for (int i = 0; i < 3; i++)
\r
153 for (int j = 0; j < 3; j++)
\r
170 public void findWidth()
\r
172 max = new float[3];
\r
173 min = new float[3];
\r
175 max[0] = (float) -1e30;
\r
176 max[1] = (float) -1e30;
\r
177 max[2] = (float) -1e30;
\r
179 min[0] = (float) 1e30;
\r
180 min[1] = (float) 1e30;
\r
181 min[2] = (float) 1e30;
\r
183 for (int i = 0; i < 3; i++)
\r
185 for (int j = 0; j < npoint; j++)
\r
187 SequencePoint sp = (SequencePoint) points.elementAt(j);
\r
189 if (sp.coord[i] >= max[i])
\r
191 max[i] = sp.coord[i];
\r
194 if (sp.coord[i] <= min[i])
\r
196 min[i] = sp.coord[i];
\r
201 // System.out.println("xmax " + max[0] + " min " + min[0]);
\r
202 //System.out.println("ymax " + max[1] + " min " + min[1]);
\r
203 //System.out.println("zmax " + max[2] + " min " + min[2]);
\r
204 width[0] = Math.abs(max[0] - min[0]);
\r
205 width[1] = Math.abs(max[1] - min[1]);
\r
206 width[2] = Math.abs(max[2] - min[2]);
\r
208 maxwidth = width[0];
\r
210 if (width[1] > width[0])
\r
212 maxwidth = width[1];
\r
215 if (width[2] > width[1])
\r
217 maxwidth = width[2];
\r
220 //System.out.println("Maxwidth = " + maxwidth);
\r
226 * @return DOCUMENT ME!
\r
228 public float findScale()
\r
234 if (getWidth() != 0)
\r
236 width = getWidth();
\r
237 height = getHeight();
\r
241 width = prefsize.width;
\r
242 height = prefsize.height;
\r
245 if (width < height)
\r
254 return (float) ((dim * scalefactor) / (2 * maxwidth));
\r
260 public void findCentre()
\r
262 //Find centre coordinate
\r
265 centre[0] = (max[0] + min[0]) / 2;
\r
266 centre[1] = (max[1] + min[1]) / 2;
\r
267 centre[2] = (max[2] + min[2]) / 2;
\r
269 // System.out.println("Centre x " + centre[0]);
\r
270 //System.out.println("Centre y " + centre[1]);
\r
271 //System.out.println("Centre z " + centre[2]);
\r
277 * @return DOCUMENT ME!
\r
279 public Dimension getPreferredSize()
\r
281 if (prefsize != null)
\r
287 return new Dimension(400, 400);
\r
294 * @return DOCUMENT ME!
\r
296 public Dimension getMinimumSize()
\r
298 return getPreferredSize();
\r
304 * @param g DOCUMENT ME!
\r
306 public void paintComponent(Graphics g1)
\r
309 Graphics2D g = (Graphics2D) g1;
\r
311 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
\r
312 RenderingHints.VALUE_ANTIALIAS_ON);
\r
315 g.setFont(new Font("Verdana", Font.PLAIN, 18));
\r
316 g.drawString("Calculating PCA....", 20, getHeight()/2);
\r
320 //Only create the image at the beginning -
\r
321 if ( (img == null) || (prefsize.width != getWidth()) ||
\r
322 (prefsize.height != getHeight()))
\r
324 prefsize.width = getWidth();
\r
325 prefsize.height = getHeight();
\r
327 scale = findScale();
\r
329 // System.out.println("New scale = " + scale);
\r
330 img = createImage(getWidth(), getHeight());
\r
331 ig = img.getGraphics();
\r
335 drawBackground(ig, bgColour);
\r
338 if (drawAxes == true)
\r
343 g.drawImage(img, 0, 0, this);
\r
350 * @param g DOCUMENT ME!
\r
352 public void drawAxes(Graphics g)
\r
355 g.setColor(Color.yellow);
\r
357 for (int i = 0; i < 3; i++)
\r
359 g.drawLine(getWidth() / 2, getHeight() / 2,
\r
360 (int) ((axes[i][0] * scale * max[0]) + (getWidth() / 2)),
\r
361 (int) ((axes[i][1] * scale * max[1]) + (getHeight() / 2)));
\r
368 * @param g DOCUMENT ME!
\r
369 * @param col DOCUMENT ME!
\r
371 public void drawBackground(Graphics g, Color col)
\r
374 g.fillRect(0, 0, prefsize.width, prefsize.height);
\r
380 * @param g DOCUMENT ME!
\r
382 public void drawScene(Graphics g1)
\r
385 Graphics2D g = (Graphics2D) g1;
\r
387 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
\r
388 RenderingHints.VALUE_ANTIALIAS_ON);
\r
391 int halfwidth = getWidth() / 2;
\r
392 int halfheight = getHeight() / 2;
\r
394 for (int i = 0; i < npoint; i++)
\r
396 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
397 int x = (int) ((float) (sp.coord[0] - centre[0]) * scale) +
\r
399 int y = (int) ((float) (sp.coord[1] - centre[1]) * scale) +
\r
401 float z = sp.coord[1] - centre[2];
\r
403 if (sp.sequence.getColor() == Color.black)
\r
405 g.setColor(Color.white);
\r
409 g.setColor(sp.sequence.getColor());
\r
412 if (av.getSelectionGroup() != null)
\r
414 if (av.getSelectionGroup().sequences.contains(
\r
415 ((SequencePoint) points.elementAt(i)).sequence))
\r
417 g.setColor(Color.gray);
\r
423 g.setColor(g.getColor().darker());
\r
426 g.fillRect(x - 3, y - 3, 6, 6);
\r
429 g.setColor(Color.red);
\r
430 g.drawString( ( (SequencePoint) points.elementAt(i)).sequence.
\r
436 // //Now the rectangle
\r
437 // if (rectx2 != -1 && recty2 != -1) {
\r
438 // g.setColor(Color.white);
\r
440 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
\r
447 * @return DOCUMENT ME!
\r
449 public Dimension minimumsize()
\r
457 * @return DOCUMENT ME!
\r
459 public Dimension preferredsize()
\r
467 * @param evt DOCUMENT ME!
\r
469 public void keyTyped(KeyEvent evt)
\r
476 * @param evt DOCUMENT ME!
\r
478 public void keyReleased(KeyEvent evt)
\r
485 * @param evt DOCUMENT ME!
\r
487 public void keyPressed(KeyEvent evt)
\r
489 if (evt.getKeyCode() == KeyEvent.VK_UP)
\r
491 scalefactor = (float) (scalefactor * 1.1);
\r
492 scale = findScale();
\r
494 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
\r
496 scalefactor = (float) (scalefactor * 0.9);
\r
497 scale = findScale();
\r
499 else if (evt.getKeyChar() == 's')
\r
501 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
503 if ((rectx2 != -1) && (recty2 != -1))
\r
505 rectSelect(rectx1, recty1, rectx2, recty2);
\r
515 public void printPoints()
\r
517 for (int i = 0; i < npoint; i++)
\r
519 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
520 Format.print(System.out, "%5d ", i);
\r
522 for (int j = 0; j < 3; j++)
\r
524 Format.print(System.out, "%13.3f ", sp.coord[j]);
\r
527 System.out.println();
\r
534 * @param evt DOCUMENT ME!
\r
536 public void mouseClicked(MouseEvent evt)
\r
543 * @param evt DOCUMENT ME!
\r
545 public void mouseEntered(MouseEvent evt)
\r
552 * @param evt DOCUMENT ME!
\r
554 public void mouseExited(MouseEvent evt)
\r
561 * @param evt DOCUMENT ME!
\r
563 public void mouseReleased(MouseEvent evt)
\r
570 * @param evt DOCUMENT ME!
\r
572 public void mousePressed(MouseEvent evt)
\r
574 int x = evt.getX();
\r
575 int y = evt.getY();
\r
592 SequenceI found = findPoint(x, y);
\r
596 if (av.getSelectionGroup() != null)
\r
598 av.getSelectionGroup().addOrRemove(found, true);
\r
599 PaintRefresher.Refresh(this, av.alignment);
\r
603 av.setSelectionGroup(new SequenceGroup());
\r
604 av.getSelectionGroup().addOrRemove(found, true);
\r
605 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
\r
612 // private void fireSequenceSelectionEvent(Selection sel) {
\r
613 // controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));
\r
615 public void mouseMoved(MouseEvent evt)
\r
617 SequenceI found = findPoint(evt.getX(), evt.getY());
\r
621 this.setToolTipText(found.getName());
\r
625 this.setToolTipText(null);
\r
632 * @param evt DOCUMENT ME!
\r
634 public void mouseDragged(MouseEvent evt)
\r
639 //Check if this is a rectangle drawing drag
\r
640 if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
\r
642 // rectx2 = evt.getX();
\r
643 // recty2 = evt.getY();
\r
647 rotmat.setIdentity();
\r
649 rotmat.rotate((float) (my - omy), 'x');
\r
650 rotmat.rotate((float) (mx - omx), 'y');
\r
652 for (int i = 0; i < npoint; i++)
\r
654 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
655 sp.coord[0] -= centre[0];
\r
656 sp.coord[1] -= centre[1];
\r
657 sp.coord[2] -= centre[2];
\r
659 //Now apply the rotation matrix
\r
660 sp.coord = rotmat.vectorMultiply(sp.coord);
\r
662 //Now translate back again
\r
663 sp.coord[0] += centre[0];
\r
664 sp.coord[1] += centre[1];
\r
665 sp.coord[2] += centre[2];
\r
668 for (int i = 0; i < 3; i++)
\r
670 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
676 paint(this.getGraphics());
\r
683 * @param x1 DOCUMENT ME!
\r
684 * @param y1 DOCUMENT ME!
\r
685 * @param x2 DOCUMENT ME!
\r
686 * @param y2 DOCUMENT ME!
\r
688 public void rectSelect(int x1, int y1, int x2, int y2)
\r
690 boolean changedSel = false;
\r
692 for (int i = 0; i < npoint; i++)
\r
694 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
695 int tmp1 = (int) (((sp.coord[0] - centre[0]) * scale) +
\r
696 ((float) getWidth() / 2.0));
\r
697 int tmp2 = (int) (((sp.coord[1] - centre[1]) * scale) +
\r
698 ((float) getHeight() / 2.0));
\r
700 if ((tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2))
\r
704 if (!av.getSelectionGroup().sequences.contains(sp.sequence))
\r
707 av.getSelectionGroup().addSequence(sp.sequence, true);
\r
713 // if (changedSel) {
\r
714 // fireSequenceSelectionEvent(av.getSelection());
\r
721 * @param x DOCUMENT ME!
\r
722 * @param y DOCUMENT ME!
\r
724 * @return DOCUMENT ME!
\r
726 public SequenceI findPoint(int x, int y)
\r
728 int halfwidth = getWidth() / 2;
\r
729 int halfheight = getHeight() / 2;
\r
733 for (int i = 0; i < npoint; i++)
\r
735 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
736 int px = (int) ((float) (sp.coord[0] - centre[0]) * scale) +
\r
738 int py = (int) ((float) (sp.coord[1] - centre[1]) * scale) +
\r
741 if ((Math.abs(px - x) < 3) && (Math.abs(py - y) < 3))
\r
749 return ((SequencePoint) points.elementAt(found)).sequence;
\r
757 /* public boolean handleRubberbandEvent(RubberbandEvent evt) {
\r
758 System.out.println("Rubberband handler called in RotatableCanvas with " +
\r
761 Rubberband rb = (Rubberband)evt.getSource();
\r
763 // Clear the current selection (instance variable)
\r
764 //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {
\r
765 // clearSelection();
\r
768 if (rb.getComponent() == this) {
\r
769 Rectangle bounds = evt.getBounds();
\r
770 rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);
\r
773 redrawneeded = true;
\r
774 paint(this.getGraphics());
\r