2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
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
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.api.RotatableCanvasI;
24 import jalview.datamodel.SequenceGroup;
25 import jalview.datamodel.SequenceI;
26 import jalview.datamodel.SequencePoint;
27 import jalview.math.RotatableMatrix;
28 import jalview.util.MessageManager;
29 import jalview.viewmodel.AlignmentViewport;
31 import java.awt.Color;
32 import java.awt.Dimension;
34 import java.awt.Graphics;
35 import java.awt.Graphics2D;
36 import java.awt.Image;
37 import java.awt.RenderingHints;
38 import java.awt.event.InputEvent;
39 import java.awt.event.KeyEvent;
40 import java.awt.event.KeyListener;
41 import java.awt.event.MouseEvent;
42 import java.awt.event.MouseListener;
43 import java.awt.event.MouseMotionListener;
44 import java.awt.event.MouseWheelEvent;
45 import java.awt.event.MouseWheelListener;
46 import java.util.Vector;
48 import javax.swing.JPanel;
49 import javax.swing.ToolTipManager;
57 public class RotatableCanvas extends JPanel implements MouseListener,
58 MouseMotionListener, KeyListener, RotatableCanvasI
60 RotatableMatrix idmat = new RotatableMatrix(3, 3);
62 RotatableMatrix objmat = new RotatableMatrix(3, 3);
64 RotatableMatrix rotmat = new RotatableMatrix(3, 3);
66 // RubberbandRectangle rubberband;
67 boolean drawAxes = true;
83 float[] centre = new float[3];
85 float[] width = new float[3];
87 float[] max = new float[3];
89 float[] min = new float[3];
119 float scalefactor = 1;
121 AlignmentViewport av;
125 boolean showLabels = false;
127 Color bgColour = Color.black;
129 boolean applyToAllViews = false;
131 // Controller controller;
132 public RotatableCanvas(AlignmentPanel ap)
137 addMouseWheelListener(new MouseWheelListener()
139 public void mouseWheelMoved(MouseWheelEvent e)
141 if (e.getWheelRotation() > 0)
143 scale = (float) (scale * 1.1);
149 scale = (float) (scale * 0.9);
157 public void showLabels(boolean b)
163 boolean first = true;
165 public void setPoints(Vector points, int npoint)
167 this.points = points;
168 this.npoint = npoint;
171 ToolTipManager.sharedInstance().registerComponent(this);
172 ToolTipManager.sharedInstance().setInitialDelay(0);
173 ToolTipManager.sharedInstance().setDismissDelay(10000);
175 prefsize = getPreferredSize();
176 orig = new float[npoint][3];
178 for (int i = 0; i < npoint; i++)
180 SequencePoint sp = (SequencePoint) points.elementAt(i);
182 for (int j = 0; j < 3; j++)
184 orig[i][j] = sp.coord[j];
188 // Initialize the matrices to identity
189 for (int i = 0; i < 3; i++)
191 for (int j = 0; j < 3; j++)
195 idmat.addElement(i, j, 0);
196 objmat.addElement(i, j, 0);
197 rotmat.addElement(i, j, 0);
201 idmat.addElement(i, j, 0);
202 objmat.addElement(i, j, 0);
203 rotmat.addElement(i, j, 0);
208 axes = new float[3][3];
218 addMouseListener(this);
220 addMouseMotionListener(this);
225 public void initAxes()
227 for (int i = 0; i < 3; i++)
229 for (int j = 0; j < 3; j++)
246 public void findWidth()
251 max[0] = (float) -1e30;
252 max[1] = (float) -1e30;
253 max[2] = (float) -1e30;
255 min[0] = (float) 1e30;
256 min[1] = (float) 1e30;
257 min[2] = (float) 1e30;
259 for (int i = 0; i < 3; i++)
261 for (int j = 0; j < npoint; j++)
263 SequencePoint sp = (SequencePoint) points.elementAt(j);
265 if (sp.coord[i] >= max[i])
267 max[i] = sp.coord[i];
270 if (sp.coord[i] <= min[i])
272 min[i] = sp.coord[i];
277 // System.out.println("xmax " + max[0] + " min " + min[0]);
278 // System.out.println("ymax " + max[1] + " min " + min[1]);
279 // System.out.println("zmax " + max[2] + " min " + min[2]);
280 width[0] = Math.abs(max[0] - min[0]);
281 width[1] = Math.abs(max[1] - min[1]);
282 width[2] = Math.abs(max[2] - min[2]);
286 if (width[1] > width[0])
291 if (width[2] > width[1])
296 // System.out.println("Maxwidth = " + maxwidth);
302 * @return DOCUMENT ME!
304 public float findScale()
313 height = getHeight();
317 width = prefsize.width;
318 height = prefsize.height;
330 return (float) ((dim * scalefactor) / (2 * maxwidth));
336 public void findCentre()
338 // Find centre coordinate
341 centre[0] = (max[0] + min[0]) / 2;
342 centre[1] = (max[1] + min[1]) / 2;
343 centre[2] = (max[2] + min[2]) / 2;
345 // System.out.println("Centre x " + centre[0]);
346 // System.out.println("Centre y " + centre[1]);
347 // System.out.println("Centre z " + centre[2]);
353 * @return DOCUMENT ME!
355 public Dimension getPreferredSize()
357 if (prefsize != null)
363 return new Dimension(400, 400);
370 * @return DOCUMENT ME!
372 public Dimension getMinimumSize()
374 return getPreferredSize();
383 public void paintComponent(Graphics g1)
386 Graphics2D g = (Graphics2D) g1;
388 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
389 RenderingHints.VALUE_ANTIALIAS_ON);
392 g.setFont(new Font("Verdana", Font.PLAIN, 18));
394 MessageManager.getString("label.calculating_pca") + "....",
395 20, getHeight() / 2);
399 // Only create the image at the beginning -
400 if ((img == null) || (prefsize.width != getWidth())
401 || (prefsize.height != getHeight()))
403 prefsize.width = getWidth();
404 prefsize.height = getHeight();
408 // System.out.println("New scale = " + scale);
409 img = createImage(getWidth(), getHeight());
410 ig = img.getGraphics();
413 drawBackground(ig, bgColour);
416 if (drawAxes == true)
421 g.drawImage(img, 0, 0, this);
431 public void drawAxes(Graphics g)
434 g.setColor(Color.yellow);
436 for (int i = 0; i < 3; i++)
438 g.drawLine(getWidth() / 2, getHeight() / 2,
439 (int) ((axes[i][0] * scale * max[0]) + (getWidth() / 2)),
440 (int) ((axes[i][1] * scale * max[1]) + (getHeight() / 2)));
452 public void drawBackground(Graphics g, Color col)
455 g.fillRect(0, 0, prefsize.width, prefsize.height);
464 public void drawScene(Graphics g1)
467 Graphics2D g = (Graphics2D) g1;
469 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
470 RenderingHints.VALUE_ANTIALIAS_ON);
472 int halfwidth = getWidth() / 2;
473 int halfheight = getHeight() / 2;
475 for (int i = 0; i < npoint; i++)
477 SequencePoint sp = (SequencePoint) points.elementAt(i);
478 int x = (int) ((float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
479 int y = (int) ((float) (sp.coord[1] - centre[1]) * scale)
481 float z = sp.coord[1] - centre[2];
483 if (av.getSequenceColour(sp.sequence) == Color.black)
485 g.setColor(Color.white);
489 g.setColor(av.getSequenceColour(sp.sequence));
492 if (av.getSelectionGroup() != null)
494 if (av.getSelectionGroup().getSequences(null)
495 .contains(((SequencePoint) points.elementAt(i)).sequence))
497 g.setColor(Color.gray);
503 g.setColor(g.getColor().darker());
506 g.fillRect(x - 3, y - 3, 6, 6);
509 g.setColor(Color.red);
511 ((SequencePoint) points.elementAt(i)).sequence.getName(),
516 // //Now the rectangle
517 // if (rectx2 != -1 && recty2 != -1) {
518 // g.setColor(Color.white);
520 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
527 * @return DOCUMENT ME!
529 public Dimension minimumsize()
537 * @return DOCUMENT ME!
539 public Dimension preferredsize()
550 public void keyTyped(KeyEvent evt)
560 public void keyReleased(KeyEvent evt)
570 public void keyPressed(KeyEvent evt)
572 if (evt.getKeyCode() == KeyEvent.VK_UP)
574 scalefactor = (float) (scalefactor * 1.1);
577 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
579 scalefactor = (float) (scalefactor * 0.9);
582 else if (evt.getKeyChar() == 's')
584 System.err.println("DEBUG: Rectangle selection"); // log.debug
586 if ((rectx2 != -1) && (recty2 != -1))
588 rectSelect(rectx1, recty1, rectx2, recty2);
601 public void mouseClicked(MouseEvent evt)
611 public void mouseEntered(MouseEvent evt)
621 public void mouseExited(MouseEvent evt)
631 public void mouseReleased(MouseEvent evt)
641 public void mousePressed(MouseEvent evt)
661 SequenceI found = findPoint(x, y);
665 AlignmentPanel[] aps = getAssociatedPanels();
667 for (int a = 0; a < aps.length; a++)
669 if (aps[a].av.getSelectionGroup() != null)
671 aps[a].av.getSelectionGroup().addOrRemove(found, true);
675 aps[a].av.setSelectionGroup(new SequenceGroup());
676 aps[a].av.getSelectionGroup().addOrRemove(found, true);
677 aps[a].av.getSelectionGroup()
678 .setEndRes(aps[a].av.getAlignment().getWidth() - 1);
681 PaintRefresher.Refresh(this, av.getSequenceSetId());
682 // canonical selection is sent to other listeners
689 // private void fireSequenceSelectionEvent(Selection sel) {
690 // controller.handleSequenceSelectionEvent(new
691 // SequenceSelectionEvent(this,sel));
693 public void mouseMoved(MouseEvent evt)
695 SequenceI found = findPoint(evt.getX(), evt.getY());
699 this.setToolTipText(found.getName());
703 this.setToolTipText(null);
713 public void mouseDragged(MouseEvent evt)
718 // Check if this is a rectangle drawing drag
719 if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
721 // rectx2 = evt.getX();
722 // recty2 = evt.getY();
726 rotmat.setIdentity();
728 rotmat.rotate((float) (my - omy), 'x');
729 rotmat.rotate((float) (mx - omx), 'y');
731 for (int i = 0; i < npoint; i++)
733 SequencePoint sp = (SequencePoint) points.elementAt(i);
734 sp.coord[0] -= centre[0];
735 sp.coord[1] -= centre[1];
736 sp.coord[2] -= centre[2];
738 // Now apply the rotation matrix
739 sp.coord = rotmat.vectorMultiply(sp.coord);
741 // Now translate back again
742 sp.coord[0] += centre[0];
743 sp.coord[1] += centre[1];
744 sp.coord[2] += centre[2];
747 for (int i = 0; i < 3; i++)
749 axes[i] = rotmat.vectorMultiply(axes[i]);
755 paint(this.getGraphics());
771 public void rectSelect(int x1, int y1, int x2, int y2)
773 for (int i = 0; i < npoint; i++)
775 SequencePoint sp = (SequencePoint) points.elementAt(i);
776 int tmp1 = (int) (((sp.coord[0] - centre[0]) * scale)
777 + ((float) getWidth() / 2.0));
778 int tmp2 = (int) (((sp.coord[1] - centre[1]) * scale)
779 + ((float) getHeight() / 2.0));
781 if ((tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2))
785 if (!av.getSelectionGroup().getSequences(null)
786 .contains(sp.sequence))
788 av.getSelectionGroup().addSequence(sp.sequence, true);
795 // fireSequenceSelectionEvent(av.getSelection());
807 * @return DOCUMENT ME!
809 public SequenceI findPoint(int x, int y)
811 int halfwidth = getWidth() / 2;
812 int halfheight = getHeight() / 2;
816 for (int i = 0; i < npoint; i++)
818 SequencePoint sp = (SequencePoint) points.elementAt(i);
819 int px = (int) ((float) (sp.coord[0] - centre[0]) * scale)
821 int py = (int) ((float) (sp.coord[1] - centre[1]) * scale)
824 if ((Math.abs(px - x) < 3) && (Math.abs(py - y) < 3))
832 return ((SequencePoint) points.elementAt(found)).sequence;
840 AlignmentPanel[] getAssociatedPanels()
844 return PaintRefresher.getAssociatedPanels(av.getSequenceSetId());
848 return new AlignmentPanel[] { ap };
854 * @return x,y,z positions of point s (index into points) under current
857 public double[] getPointPosition(int s)
859 double pts[] = new double[3];
860 float[] p = ((SequencePoint) points.elementAt(s)).coord;