2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
\r
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
\r
5 * This file is part of Jalview.
\r
7 * Jalview is free software: you can redistribute it and/or
\r
8 * modify it under the terms of the GNU General Public License
\r
9 * as published by the Free Software Foundation, either version 3
\r
10 * of the License, or (at your option) any later version.
\r
12 * Jalview is distributed in the hope that it will be useful, but
\r
13 * WITHOUT ANY WARRANTY; without even the implied warranty
\r
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
15 * PURPOSE. See the GNU General Public License for more details.
\r
17 * You should have received a copy of the GNU General Public License
\r
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
\r
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
\r
21 package jalview.appletgui;
\r
23 import jalview.api.RotatableCanvasI;
\r
24 import jalview.datamodel.SequenceGroup;
\r
25 import jalview.datamodel.SequenceI;
\r
26 import jalview.datamodel.SequencePoint;
\r
27 import jalview.math.RotatableMatrix;
\r
28 import jalview.util.Format;
\r
29 import jalview.util.MessageManager;
\r
30 import jalview.viewmodel.AlignmentViewport;
\r
32 import java.awt.Color;
\r
33 import java.awt.Dimension;
\r
34 import java.awt.Font;
\r
35 import java.awt.Graphics;
\r
36 import java.awt.Image;
\r
37 import javax.swing.JPanel;
\r
38 import java.awt.event.KeyEvent;
\r
39 import java.awt.event.KeyListener;
\r
40 import java.awt.event.MouseEvent;
\r
41 import java.awt.event.MouseListener;
\r
42 import java.awt.event.MouseMotionListener;
\r
43 import java.util.Vector;
\r
45 public class RotatableCanvas extends JPanel implements MouseListener,
\r
46 MouseMotionListener, KeyListener, RotatableCanvasI
\r
48 RotatableMatrix idmat = new RotatableMatrix(3, 3);
\r
50 RotatableMatrix objmat = new RotatableMatrix(3, 3);
\r
52 RotatableMatrix rotmat = new RotatableMatrix(3, 3);
\r
58 // RubberbandRectangle rubberband;
\r
60 boolean drawAxes = true;
\r
76 float centre[] = new float[3];
\r
78 float width[] = new float[3];
\r
80 float max[] = new float[3];
\r
82 float min[] = new float[3];
\r
112 float scalefactor = 1;
\r
114 AlignmentViewport av;
\r
116 boolean showLabels = false;
\r
118 public RotatableCanvas(AlignmentViewport av)
\r
123 public void showLabels(boolean b)
\r
129 public void setPoints(Vector points, int npoint)
\r
131 this.points = points;
\r
132 this.npoint = npoint;
\r
133 PaintRefresher.Register(this, av.getSequenceSetId());
\r
135 prefsize = getPreferredSize();
\r
136 orig = new float[npoint][3];
\r
138 for (int i = 0; i < npoint; i++)
\r
140 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
141 for (int j = 0; j < 3; j++)
\r
143 orig[i][j] = sp.coord[j];
\r
146 // Initialize the matrices to identity
\r
148 for (int i = 0; i < 3; i++)
\r
150 for (int j = 0; j < 3; j++)
\r
154 idmat.addElement(i, j, 0);
\r
155 objmat.addElement(i, j, 0);
\r
156 rotmat.addElement(i, j, 0);
\r
160 idmat.addElement(i, j, 0);
\r
161 objmat.addElement(i, j, 0);
\r
162 rotmat.addElement(i, j, 0);
\r
167 axes = new float[3][3];
\r
173 scale = findScale();
\r
175 // System.out.println("Scale factor = " + scale);
\r
177 addMouseListener(this);
\r
178 addKeyListener(this);
\r
179 // if (getParent() != null) {
\r
180 // getParent().addKeyListener(this);
\r
182 addMouseMotionListener(this);
\r
185 // rubberband = new RubberbandRectangle(this);
\r
186 // rubberband.setActive(true);
\r
187 // rubberband.addListener(this);
\r
191 * public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {
\r
192 * redrawneeded = true; repaint(); return true; }
\r
194 * public void removeNotify() { controller.removeListener(this);
\r
195 * super.removeNotify(); }
\r
198 public void initAxes()
\r
200 for (int i = 0; i < 3; i++)
\r
202 for (int j = 0; j < 3; j++)
\r
216 public void findWidth()
\r
218 max = new float[3];
\r
219 min = new float[3];
\r
221 max[0] = (float) -1e30;
\r
222 max[1] = (float) -1e30;
\r
223 max[2] = (float) -1e30;
\r
225 min[0] = (float) 1e30;
\r
226 min[1] = (float) 1e30;
\r
227 min[2] = (float) 1e30;
\r
229 for (int i = 0; i < 3; i++)
\r
231 for (int j = 0; j < npoint; j++)
\r
233 SequencePoint sp = (SequencePoint) points.elementAt(j);
\r
234 if (sp.coord[i] >= max[i])
\r
236 max[i] = sp.coord[i];
\r
238 if (sp.coord[i] <= min[i])
\r
240 min[i] = sp.coord[i];
\r
245 // System.out.println("xmax " + max[0] + " min " + min[0]);
\r
246 // System.out.println("ymax " + max[1] + " min " + min[1]);
\r
247 // System.out.println("zmax " + max[2] + " min " + min[2]);
\r
249 width[0] = Math.abs(max[0] - min[0]);
\r
250 width[1] = Math.abs(max[1] - min[1]);
\r
251 width[2] = Math.abs(max[2] - min[2]);
\r
253 maxwidth = width[0];
\r
255 if (width[1] > width[0])
\r
257 maxwidth = width[1];
\r
259 if (width[2] > width[1])
\r
261 maxwidth = width[2];
\r
264 // System.out.println("Maxwidth = " + maxwidth);
\r
267 public float findScale()
\r
269 int dim, width, height;
\r
270 if (getSize().width != 0)
\r
272 width = getSize().width;
\r
273 height = getSize().height;
\r
277 width = prefsize.width;
\r
278 height = prefsize.height;
\r
281 if (width < height)
\r
290 return dim * scalefactor / (2 * maxwidth);
\r
293 public void findCentre()
\r
295 // Find centre coordinate
\r
298 centre[0] = (max[0] + min[0]) / 2;
\r
299 centre[1] = (max[1] + min[1]) / 2;
\r
300 centre[2] = (max[2] + min[2]) / 2;
\r
302 // System.out.println("Centre x " + centre[0]);
\r
303 // System.out.println("Centre y " + centre[1]);
\r
304 // System.out.println("Centre z " + centre[2]);
\r
307 public Dimension getPreferredSize()
\r
309 if (prefsize != null)
\r
315 return new Dimension(400, 400);
\r
319 public Dimension getMinimumSize()
\r
321 return getPreferredSize();
\r
324 public void update(Graphics g)
\r
329 public void paint(Graphics g)
\r
331 if (points == null)
\r
333 g.setFont(new Font("Verdana", Font.PLAIN, 18));
\r
334 g.drawString(MessageManager.getString("label.calculating_pca")
\r
335 + "....", 20, getSize().height / 2);
\r
340 // Only create the image at the beginning -
\r
341 if ((img == null) || (prefsize.width != getSize().width)
\r
342 || (prefsize.height != getSize().height))
\r
344 prefsize.width = getSize().width;
\r
345 prefsize.height = getSize().height;
\r
347 scale = findScale();
\r
349 // System.out.println("New scale = " + scale);
\r
350 img = createImage(getSize().width, getSize().height);
\r
351 ig = img.getGraphics();
\r
355 drawBackground(ig, Color.black);
\r
357 if (drawAxes == true)
\r
362 if (tooltip != null)
\r
364 ig.setColor(Color.red);
\r
365 ig.drawString(tooltip, toolx, tooly);
\r
368 g.drawImage(img, 0, 0, this);
\r
372 public void drawAxes(Graphics g)
\r
375 g.setColor(Color.yellow);
\r
376 for (int i = 0; i < 3; i++)
\r
378 g.drawLine(getSize().width / 2, getSize().height / 2,
\r
379 (int) (axes[i][0] * scale * max[0] + getSize().width / 2),
\r
380 (int) (axes[i][1] * scale * max[1] + getSize().height / 2));
\r
384 public void drawBackground(Graphics g, Color col)
\r
387 g.fillRect(0, 0, prefsize.width, prefsize.height);
\r
390 public void drawScene(Graphics g)
\r
392 // boolean darker = false;
\r
394 int halfwidth = getSize().width / 2;
\r
395 int halfheight = getSize().height / 2;
\r
397 for (int i = 0; i < npoint; i++)
\r
399 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
400 int x = (int) ((sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
401 int y = (int) ((sp.coord[1] - centre[1]) * scale)
\r
403 float z = sp.coord[1] - centre[2];
\r
405 if (av.getSequenceColour(sp.sequence) == Color.black)
\r
407 g.setColor(Color.white);
\r
411 g.setColor(av.getSequenceColour(sp.sequence));
\r
414 if (av.getSelectionGroup() != null)
\r
416 if (av.getSelectionGroup().getSequences(null)
\r
417 .contains(((SequencePoint) points.elementAt(i)).sequence))
\r
419 g.setColor(Color.gray);
\r
424 g.setColor(g.getColor().darker());
\r
427 g.fillRect(x - 3, y - 3, 6, 6);
\r
430 g.setColor(Color.red);
\r
432 ((SequencePoint) points.elementAt(i)).sequence.getName(),
\r
438 public Dimension minimumsize()
\r
443 public Dimension preferredsize()
\r
448 public void keyTyped(KeyEvent evt)
\r
452 public void keyReleased(KeyEvent evt)
\r
456 public void keyPressed(KeyEvent evt)
\r
458 if (evt.getKeyCode() == KeyEvent.VK_UP)
\r
460 scalefactor = (float) (scalefactor * 1.1);
\r
461 scale = findScale();
\r
463 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
\r
465 scalefactor = (float) (scalefactor * 0.9);
\r
466 scale = findScale();
\r
468 else if (evt.getKeyChar() == 's')
\r
470 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
471 if (rectx2 != -1 && recty2 != -1)
\r
473 rectSelect(rectx1, recty1, rectx2, recty2);
\r
480 public void printPoints()
\r
482 for (int i = 0; i < npoint; i++)
\r
484 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
485 Format.printLong(System.out, "%5d ", i);
\r
486 for (int j = 0; j < 3; j++)
\r
488 Format.printDouble(System.out, "%13.3f ", sp.coord[j]);
\r
490 System.out.println();
\r
494 public void mouseClicked(MouseEvent evt)
\r
498 public void mouseEntered(MouseEvent evt)
\r
502 public void mouseExited(MouseEvent evt)
\r
506 public void mouseReleased(MouseEvent evt)
\r
510 public void mousePressed(MouseEvent evt)
\r
512 int x = evt.getX();
\r
513 int y = evt.getY();
\r
530 SequenceI found = findPoint(x, y);
\r
534 // TODO: applet PCA is not associatable with multi-panels - only parent
\r
536 if (av.getSelectionGroup() != null)
\r
538 av.getSelectionGroup().addOrRemove(found, true);
\r
539 av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
\r
543 av.setSelectionGroup(new SequenceGroup());
\r
544 av.getSelectionGroup().addOrRemove(found, true);
\r
545 av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
\r
548 PaintRefresher.Refresh(this, av.getSequenceSetId());
\r
549 av.sendSelection();
\r
554 public void mouseMoved(MouseEvent evt)
\r
556 SequenceI found = findPoint(evt.getX(), evt.getY());
\r
563 tooltip = found.getName();
\r
564 toolx = evt.getX();
\r
565 tooly = evt.getY();
\r
570 public void mouseDragged(MouseEvent evt)
\r
575 rotmat.setIdentity();
\r
577 rotmat.rotate(my - omy, 'x');
\r
578 rotmat.rotate(mx - omx, 'y');
\r
580 for (int i = 0; i < npoint; i++)
\r
582 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
583 sp.coord[0] -= centre[0];
\r
584 sp.coord[1] -= centre[1];
\r
585 sp.coord[2] -= centre[2];
\r
587 // Now apply the rotation matrix
\r
588 sp.coord = rotmat.vectorMultiply(sp.coord);
\r
590 // Now translate back again
\r
591 sp.coord[0] += centre[0];
\r
592 sp.coord[1] += centre[1];
\r
593 sp.coord[2] += centre[2];
\r
596 for (int i = 0; i < 3; i++)
\r
598 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
603 paint(this.getGraphics());
\r
606 public void rectSelect(int x1, int y1, int x2, int y2)
\r
608 // boolean changedSel = false;
\r
609 for (int i = 0; i < npoint; i++)
\r
611 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
612 int tmp1 = (int) ((sp.coord[0] - centre[0]) * scale + getSize().width / 2.0);
\r
613 int tmp2 = (int) ((sp.coord[1] - centre[1]) * scale + getSize().height / 2.0);
\r
615 if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)
\r
619 if (!av.getSelectionGroup().getSequences(null)
\r
620 .contains(sp.sequence))
\r
622 av.getSelectionGroup().addSequence(sp.sequence, true);
\r
629 public SequenceI findPoint(int x, int y)
\r
632 int halfwidth = getSize().width / 2;
\r
633 int halfheight = getSize().height / 2;
\r
637 for (int i = 0; i < npoint; i++)
\r
640 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
641 int px = (int) ((sp.coord[0] - centre[0]) * scale)
\r
643 int py = (int) ((sp.coord[1] - centre[1]) * scale)
\r
646 if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)
\r
653 return ((SequencePoint) points.elementAt(found)).sequence;
\r