2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3 * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, 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/>.
18 package jalview.appletgui;
23 import java.awt.event.*;
25 import jalview.api.RotatableCanvasI;
26 import jalview.datamodel.*;
27 import jalview.math.*;
28 import jalview.util.*;
30 public class RotatableCanvas extends Panel implements MouseListener,
31 MouseMotionListener, KeyListener, RotatableCanvasI
33 RotatableMatrix idmat = new RotatableMatrix(3, 3);
35 RotatableMatrix objmat = new RotatableMatrix(3, 3);
37 RotatableMatrix rotmat = new RotatableMatrix(3, 3);
43 // 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;
101 boolean showLabels = false;
103 public RotatableCanvas(AlignViewport av)
108 public void showLabels(boolean b)
114 public void setPoints(Vector points, int npoint)
116 this.points = points;
117 this.npoint = npoint;
118 PaintRefresher.Register(this, av.getSequenceSetId());
120 prefsize = getPreferredSize();
121 orig = new float[npoint][3];
123 for (int i = 0; i < npoint; i++)
125 SequencePoint sp = (SequencePoint) points.elementAt(i);
126 for (int j = 0; j < 3; j++)
128 orig[i][j] = sp.coord[j];
131 // Initialize the matrices to identity
133 for (int i = 0; i < 3; i++)
135 for (int j = 0; j < 3; j++)
139 idmat.addElement(i, j, 0);
140 objmat.addElement(i, j, 0);
141 rotmat.addElement(i, j, 0);
145 idmat.addElement(i, j, 0);
146 objmat.addElement(i, j, 0);
147 rotmat.addElement(i, j, 0);
152 axes = new float[3][3];
160 // System.out.println("Scale factor = " + scale);
162 addMouseListener(this);
163 addKeyListener(this);
164 // if (getParent() != null) {
165 // getParent().addKeyListener(this);
167 addMouseMotionListener(this);
170 // rubberband = new RubberbandRectangle(this);
171 // rubberband.setActive(true);
172 // rubberband.addListener(this);
176 * public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {
177 * redrawneeded = true; repaint(); return true; }
179 * public void removeNotify() { controller.removeListener(this);
180 * super.removeNotify(); }
183 public void initAxes()
185 for (int i = 0; i < 3; i++)
187 for (int j = 0; j < 3; j++)
201 public void findWidth()
206 max[0] = (float) -1e30;
207 max[1] = (float) -1e30;
208 max[2] = (float) -1e30;
210 min[0] = (float) 1e30;
211 min[1] = (float) 1e30;
212 min[2] = (float) 1e30;
214 for (int i = 0; i < 3; i++)
216 for (int j = 0; j < npoint; j++)
218 SequencePoint sp = (SequencePoint) points.elementAt(j);
219 if (sp.coord[i] >= max[i])
221 max[i] = sp.coord[i];
223 if (sp.coord[i] <= min[i])
225 min[i] = sp.coord[i];
230 // System.out.println("xmax " + max[0] + " min " + min[0]);
231 // System.out.println("ymax " + max[1] + " min " + min[1]);
232 // System.out.println("zmax " + max[2] + " min " + min[2]);
234 width[0] = Math.abs(max[0] - min[0]);
235 width[1] = Math.abs(max[1] - min[1]);
236 width[2] = Math.abs(max[2] - min[2]);
240 if (width[1] > width[0])
244 if (width[2] > width[1])
249 // System.out.println("Maxwidth = " + maxwidth);
252 public float findScale()
254 int dim, width, height;
255 if (getSize().width != 0)
257 width = getSize().width;
258 height = getSize().height;
262 width = prefsize.width;
263 height = prefsize.height;
275 return (float) (dim * scalefactor / (2 * maxwidth));
278 public void findCentre()
280 // Find centre coordinate
283 centre[0] = (max[0] + min[0]) / 2;
284 centre[1] = (max[1] + min[1]) / 2;
285 centre[2] = (max[2] + min[2]) / 2;
287 // System.out.println("Centre x " + centre[0]);
288 // System.out.println("Centre y " + centre[1]);
289 // System.out.println("Centre z " + centre[2]);
292 public Dimension getPreferredSize()
294 if (prefsize != null)
300 return new Dimension(400, 400);
304 public Dimension getMinimumSize()
306 return getPreferredSize();
309 public void update(Graphics g)
314 public void paint(Graphics g)
318 g.setFont(new Font("Verdana", Font.PLAIN, 18));
319 g.drawString("Calculating PCA....", 20, getSize().height / 2);
324 // Only create the image at the beginning -
325 if ((img == null) || (prefsize.width != getSize().width)
326 || (prefsize.height != getSize().height))
328 prefsize.width = getSize().width;
329 prefsize.height = getSize().height;
333 // System.out.println("New scale = " + scale);
334 img = createImage(getSize().width, getSize().height);
335 ig = img.getGraphics();
339 drawBackground(ig, Color.black);
341 if (drawAxes == true)
348 ig.setColor(Color.red);
349 ig.drawString(tooltip, toolx, tooly);
352 g.drawImage(img, 0, 0, this);
356 public void drawAxes(Graphics g)
359 g.setColor(Color.yellow);
360 for (int i = 0; i < 3; i++)
362 g.drawLine(getSize().width / 2, getSize().height / 2,
363 (int) (axes[i][0] * scale * max[0] + getSize().width / 2),
364 (int) (axes[i][1] * scale * max[1] + getSize().height / 2));
368 public void drawBackground(Graphics g, Color col)
371 g.fillRect(0, 0, prefsize.width, prefsize.height);
374 public void drawScene(Graphics g)
376 // boolean darker = false;
378 int halfwidth = getSize().width / 2;
379 int halfheight = getSize().height / 2;
381 for (int i = 0; i < npoint; i++)
383 SequencePoint sp = (SequencePoint) points.elementAt(i);
384 int x = (int) ((float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
385 int y = (int) ((float) (sp.coord[1] - centre[1]) * scale)
387 float z = sp.coord[1] - centre[2];
389 if (av.getSequenceColour(sp.sequence) == Color.black)
391 g.setColor(Color.white);
395 g.setColor(av.getSequenceColour(sp.sequence));
398 if (av.getSelectionGroup() != null)
400 if (av.getSelectionGroup().getSequences(null)
401 .contains(((SequencePoint) points.elementAt(i)).sequence))
403 g.setColor(Color.gray);
408 g.setColor(g.getColor().darker());
411 g.fillRect(x - 3, y - 3, 6, 6);
414 g.setColor(Color.red);
416 ((SequencePoint) points.elementAt(i)).sequence.getName(),
422 public Dimension minimumsize()
427 public Dimension preferredsize()
432 public void keyTyped(KeyEvent evt)
436 public void keyReleased(KeyEvent evt)
440 public void keyPressed(KeyEvent evt)
442 if (evt.getKeyCode() == KeyEvent.VK_UP)
444 scalefactor = (float) (scalefactor * 1.1);
447 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
449 scalefactor = (float) (scalefactor * 0.9);
452 else if (evt.getKeyChar() == 's')
454 System.err.println("DEBUG: Rectangle selection"); // log.debug
455 if (rectx2 != -1 && recty2 != -1)
457 rectSelect(rectx1, recty1, rectx2, recty2);
464 public void printPoints()
466 for (int i = 0; i < npoint; i++)
468 SequencePoint sp = (SequencePoint) points.elementAt(i);
469 Format.print(System.out, "%5d ", i);
470 for (int j = 0; j < 3; j++)
472 Format.print(System.out, "%13.3f ", sp.coord[j]);
474 System.out.println();
478 public void mouseClicked(MouseEvent evt)
482 public void mouseEntered(MouseEvent evt)
486 public void mouseExited(MouseEvent evt)
490 public void mouseReleased(MouseEvent evt)
494 public void mousePressed(MouseEvent evt)
514 SequenceI found = findPoint(x, y);
518 // TODO: applet PCA is not associatable with multi-panels - only parent
520 if (av.getSelectionGroup() != null)
522 av.getSelectionGroup().addOrRemove(found, true);
523 av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
527 av.setSelectionGroup(new SequenceGroup());
528 av.getSelectionGroup().addOrRemove(found, true);
529 av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
532 PaintRefresher.Refresh(this, av.getSequenceSetId());
538 public void mouseMoved(MouseEvent evt)
540 SequenceI found = findPoint(evt.getX(), evt.getY());
547 tooltip = found.getName();
554 public void mouseDragged(MouseEvent evt)
559 rotmat.setIdentity();
561 rotmat.rotate((float) (my - omy), 'x');
562 rotmat.rotate((float) (mx - omx), 'y');
564 for (int i = 0; i < npoint; i++)
566 SequencePoint sp = (SequencePoint) points.elementAt(i);
567 sp.coord[0] -= centre[0];
568 sp.coord[1] -= centre[1];
569 sp.coord[2] -= centre[2];
571 // Now apply the rotation matrix
572 sp.coord = rotmat.vectorMultiply(sp.coord);
574 // Now translate back again
575 sp.coord[0] += centre[0];
576 sp.coord[1] += centre[1];
577 sp.coord[2] += centre[2];
580 for (int i = 0; i < 3; i++)
582 axes[i] = rotmat.vectorMultiply(axes[i]);
587 paint(this.getGraphics());
590 public void rectSelect(int x1, int y1, int x2, int y2)
592 // boolean changedSel = false;
593 for (int i = 0; i < npoint; i++)
595 SequencePoint sp = (SequencePoint) points.elementAt(i);
596 int tmp1 = (int) ((sp.coord[0] - centre[0]) * scale + (float) getSize().width / 2.0);
597 int tmp2 = (int) ((sp.coord[1] - centre[1]) * scale + (float) getSize().height / 2.0);
599 if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)
603 if (!av.getSelectionGroup().getSequences(null)
604 .contains(sp.sequence))
606 av.getSelectionGroup().addSequence(sp.sequence, true);
613 public SequenceI findPoint(int x, int y)
616 int halfwidth = getSize().width / 2;
617 int halfheight = getSize().height / 2;
621 for (int i = 0; i < npoint; i++)
624 SequencePoint sp = (SequencePoint) points.elementAt(i);
625 int px = (int) ((float) (sp.coord[0] - centre[0]) * scale)
627 int py = (int) ((float) (sp.coord[1] - centre[1]) * scale)
630 if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)
637 return ((SequencePoint) points.elementAt(found)).sequence;