2 * Jalview - A Sequence Alignment Editor and Viewer
3 * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21 import jalview.datamodel.*;
23 import jalview.math.*;
26 import java.awt.event.*;
39 public class RotatableCanvas extends JPanel implements MouseListener,
40 MouseMotionListener, KeyListener
42 RotatableMatrix idmat = new RotatableMatrix(3, 3);
43 RotatableMatrix objmat = new RotatableMatrix(3, 3);
44 RotatableMatrix rotmat = new RotatableMatrix(3, 3);
46 //RubberbandRectangle rubberband;
47 boolean drawAxes = true;
55 float[] centre = new float[3];
56 float[] width = new float[3];
57 float[] max = new float[3];
58 float[] min = new float[3];
73 float scalefactor = 1;
75 boolean showLabels = false;
76 Color bgColour = Color.black;
78 // Controller controller;
79 public RotatableCanvas(AlignViewport av)
84 public void showLabels(boolean b)
90 public void setPoints(Vector points, int npoint)
94 ToolTipManager.sharedInstance().registerComponent(this);
95 ToolTipManager.sharedInstance().setInitialDelay(0);
96 ToolTipManager.sharedInstance().setDismissDelay(10000);
97 PaintRefresher.Register(this, av.alignment);
99 prefsize = getPreferredSize();
100 orig = new float[npoint][3];
102 for (int i = 0; i < npoint; i++)
104 SequencePoint sp = (SequencePoint) points.elementAt(i);
106 for (int j = 0; j < 3; j++)
108 orig[i][j] = sp.coord[j];
112 //Initialize the matrices to identity
113 for (int i = 0; i < 3; i++)
115 for (int j = 0; j < 3; j++)
119 idmat.addElement(i, j, 0);
120 objmat.addElement(i, j, 0);
121 rotmat.addElement(i, j, 0);
125 idmat.addElement(i, j, 0);
126 objmat.addElement(i, j, 0);
127 rotmat.addElement(i, j, 0);
132 axes = new float[3][3];
140 addMouseListener(this);
141 addKeyListener(this);
143 addMouseMotionListener(this);
147 public void initAxes()
149 for (int i = 0; i < 3; i++)
151 for (int j = 0; j < 3; j++)
168 public void findWidth()
173 max[0] = (float) -1e30;
174 max[1] = (float) -1e30;
175 max[2] = (float) -1e30;
177 min[0] = (float) 1e30;
178 min[1] = (float) 1e30;
179 min[2] = (float) 1e30;
181 for (int i = 0; i < 3; i++)
183 for (int j = 0; j < npoint; j++)
185 SequencePoint sp = (SequencePoint) points.elementAt(j);
187 if (sp.coord[i] >= max[i])
189 max[i] = sp.coord[i];
192 if (sp.coord[i] <= min[i])
194 min[i] = sp.coord[i];
199 // System.out.println("xmax " + max[0] + " min " + min[0]);
200 //System.out.println("ymax " + max[1] + " min " + min[1]);
201 //System.out.println("zmax " + max[2] + " min " + min[2]);
202 width[0] = Math.abs(max[0] - min[0]);
203 width[1] = Math.abs(max[1] - min[1]);
204 width[2] = Math.abs(max[2] - min[2]);
208 if (width[1] > width[0])
213 if (width[2] > width[1])
218 //System.out.println("Maxwidth = " + maxwidth);
224 * @return DOCUMENT ME!
226 public float findScale()
235 height = getHeight();
239 width = prefsize.width;
240 height = prefsize.height;
252 return (float) ((dim * scalefactor) / (2 * maxwidth));
258 public void findCentre()
260 //Find centre coordinate
263 centre[0] = (max[0] + min[0]) / 2;
264 centre[1] = (max[1] + min[1]) / 2;
265 centre[2] = (max[2] + min[2]) / 2;
267 // System.out.println("Centre x " + centre[0]);
268 //System.out.println("Centre y " + centre[1]);
269 //System.out.println("Centre z " + centre[2]);
275 * @return DOCUMENT ME!
277 public Dimension getPreferredSize()
279 if (prefsize != null)
285 return new Dimension(400, 400);
292 * @return DOCUMENT ME!
294 public Dimension getMinimumSize()
296 return getPreferredSize();
302 * @param g DOCUMENT ME!
304 public void paintComponent(Graphics g1)
307 Graphics2D g = (Graphics2D) g1;
309 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
310 RenderingHints.VALUE_ANTIALIAS_ON);
313 g.setFont(new Font("Verdana", Font.PLAIN, 18));
314 g.drawString("Calculating PCA....", 20, getHeight()/2);
318 //Only create the image at the beginning -
319 if ( (img == null) || (prefsize.width != getWidth()) ||
320 (prefsize.height != getHeight()))
322 prefsize.width = getWidth();
323 prefsize.height = getHeight();
327 // System.out.println("New scale = " + scale);
328 img = createImage(getWidth(), getHeight());
329 ig = img.getGraphics();
333 drawBackground(ig, bgColour);
336 if (drawAxes == true)
341 g.drawImage(img, 0, 0, this);
348 * @param g DOCUMENT ME!
350 public void drawAxes(Graphics g)
353 g.setColor(Color.yellow);
355 for (int i = 0; i < 3; i++)
357 g.drawLine(getWidth() / 2, getHeight() / 2,
358 (int) ((axes[i][0] * scale * max[0]) + (getWidth() / 2)),
359 (int) ((axes[i][1] * scale * max[1]) + (getHeight() / 2)));
366 * @param g DOCUMENT ME!
367 * @param col DOCUMENT ME!
369 public void drawBackground(Graphics g, Color col)
372 g.fillRect(0, 0, prefsize.width, prefsize.height);
378 * @param g DOCUMENT ME!
380 public void drawScene(Graphics g1)
383 Graphics2D g = (Graphics2D) g1;
385 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
386 RenderingHints.VALUE_ANTIALIAS_ON);
389 int halfwidth = getWidth() / 2;
390 int halfheight = getHeight() / 2;
392 for (int i = 0; i < npoint; i++)
394 SequencePoint sp = (SequencePoint) points.elementAt(i);
395 int x = (int) ((float) (sp.coord[0] - centre[0]) * scale) +
397 int y = (int) ((float) (sp.coord[1] - centre[1]) * scale) +
399 float z = sp.coord[1] - centre[2];
401 if (sp.sequence.getColor() == Color.black)
403 g.setColor(Color.white);
407 g.setColor(sp.sequence.getColor());
410 if (av.getSelectionGroup() != null)
412 if (av.getSelectionGroup().getSequences(false).contains(
413 ((SequencePoint) points.elementAt(i)).sequence))
415 g.setColor(Color.gray);
421 g.setColor(g.getColor().darker());
424 g.fillRect(x - 3, y - 3, 6, 6);
427 g.setColor(Color.red);
428 g.drawString( ( (SequencePoint) points.elementAt(i)).sequence.
434 // //Now the rectangle
435 // if (rectx2 != -1 && recty2 != -1) {
436 // g.setColor(Color.white);
438 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
445 * @return DOCUMENT ME!
447 public Dimension minimumsize()
455 * @return DOCUMENT ME!
457 public Dimension preferredsize()
465 * @param evt DOCUMENT ME!
467 public void keyTyped(KeyEvent evt)
474 * @param evt DOCUMENT ME!
476 public void keyReleased(KeyEvent evt)
483 * @param evt DOCUMENT ME!
485 public void keyPressed(KeyEvent evt)
487 if (evt.getKeyCode() == KeyEvent.VK_UP)
489 scalefactor = (float) (scalefactor * 1.1);
492 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
494 scalefactor = (float) (scalefactor * 0.9);
497 else if (evt.getKeyChar() == 's')
499 System.err.println("DEBUG: Rectangle selection"); // log.debug
501 if ((rectx2 != -1) && (recty2 != -1))
503 rectSelect(rectx1, recty1, rectx2, recty2);
514 * @param evt DOCUMENT ME!
516 public void mouseClicked(MouseEvent evt)
523 * @param evt DOCUMENT ME!
525 public void mouseEntered(MouseEvent evt)
532 * @param evt DOCUMENT ME!
534 public void mouseExited(MouseEvent evt)
541 * @param evt DOCUMENT ME!
543 public void mouseReleased(MouseEvent evt)
550 * @param evt DOCUMENT ME!
552 public void mousePressed(MouseEvent evt)
572 SequenceI found = findPoint(x, y);
576 if (av.getSelectionGroup() != null)
578 av.getSelectionGroup().addOrRemove(found, true);
579 PaintRefresher.Refresh(this, av.alignment);
583 av.setSelectionGroup(new SequenceGroup());
584 av.getSelectionGroup().addOrRemove(found, true);
585 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
592 // private void fireSequenceSelectionEvent(Selection sel) {
593 // controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));
595 public void mouseMoved(MouseEvent evt)
597 SequenceI found = findPoint(evt.getX(), evt.getY());
601 this.setToolTipText(found.getName());
605 this.setToolTipText(null);
612 * @param evt DOCUMENT ME!
614 public void mouseDragged(MouseEvent evt)
619 //Check if this is a rectangle drawing drag
620 if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
622 // rectx2 = evt.getX();
623 // recty2 = evt.getY();
627 rotmat.setIdentity();
629 rotmat.rotate((float) (my - omy), 'x');
630 rotmat.rotate((float) (mx - omx), 'y');
632 for (int i = 0; i < npoint; i++)
634 SequencePoint sp = (SequencePoint) points.elementAt(i);
635 sp.coord[0] -= centre[0];
636 sp.coord[1] -= centre[1];
637 sp.coord[2] -= centre[2];
639 //Now apply the rotation matrix
640 sp.coord = rotmat.vectorMultiply(sp.coord);
642 //Now translate back again
643 sp.coord[0] += centre[0];
644 sp.coord[1] += centre[1];
645 sp.coord[2] += centre[2];
648 for (int i = 0; i < 3; i++)
650 axes[i] = rotmat.vectorMultiply(axes[i]);
656 paint(this.getGraphics());
663 * @param x1 DOCUMENT ME!
664 * @param y1 DOCUMENT ME!
665 * @param x2 DOCUMENT ME!
666 * @param y2 DOCUMENT ME!
668 public void rectSelect(int x1, int y1, int x2, int y2)
670 for (int i = 0; i < npoint; i++)
672 SequencePoint sp = (SequencePoint) points.elementAt(i);
673 int tmp1 = (int) (((sp.coord[0] - centre[0]) * scale) +
674 ((float) getWidth() / 2.0));
675 int tmp2 = (int) (((sp.coord[1] - centre[1]) * scale) +
676 ((float) getHeight() / 2.0));
678 if ((tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2))
682 if (!av.getSelectionGroup().getSequences(false).contains(sp.sequence))
684 av.getSelectionGroup().addSequence(sp.sequence, true);
691 // fireSequenceSelectionEvent(av.getSelection());
698 * @param x DOCUMENT ME!
699 * @param y DOCUMENT ME!
701 * @return DOCUMENT ME!
703 public SequenceI findPoint(int x, int y)
705 int halfwidth = getWidth() / 2;
706 int halfheight = getHeight() / 2;
710 for (int i = 0; i < npoint; i++)
712 SequencePoint sp = (SequencePoint) points.elementAt(i);
713 int px = (int) ((float) (sp.coord[0] - centre[0]) * scale) +
715 int py = (int) ((float) (sp.coord[1] - centre[1]) * scale) +
718 if ((Math.abs(px - x) < 3) && (Math.abs(py - y) < 3))
726 return ((SequencePoint) points.elementAt(found)).sequence;
734 /* public boolean handleRubberbandEvent(RubberbandEvent evt) {
735 System.out.println("Rubberband handler called in RotatableCanvas with " +
738 Rubberband rb = (Rubberband)evt.getSource();
740 // Clear the current selection (instance variable)
741 //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {
745 if (rb.getComponent() == this) {
746 Rectangle bounds = evt.getBounds();
747 rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);
751 paint(this.getGraphics());