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
20 package jalview.appletgui;
\r
25 import java.awt.event.*;
\r
27 import jalview.datamodel.*;
\r
28 import jalview.math.*;
\r
29 import jalview.util.*;
\r
31 public class RotatableCanvas
\r
32 extends Panel implements MouseListener,
\r
33 MouseMotionListener,
\r
36 RotatableMatrix idmat = new RotatableMatrix(3, 3);
\r
37 RotatableMatrix objmat = new RotatableMatrix(3, 3);
\r
38 RotatableMatrix rotmat = new RotatableMatrix(3, 3);
\r
42 //RubberbandRectangle rubberband;
\r
44 boolean drawAxes = true;
\r
56 float centre[] = new float[3];
\r
57 float width[] = new float[3];
\r
59 float max[] = new float[3];
\r
60 float min[] = new float[3];
\r
82 float scalefactor = 1;
\r
85 boolean showLabels = false;
\r
87 public RotatableCanvas(AlignViewport av)
\r
92 public void showLabels(boolean b)
\r
98 public void setPoints(Vector points, int npoint)
\r
100 this.points = points;
\r
101 this.npoint = npoint;
\r
102 PaintRefresher.Register(this, av.alignment);
\r
104 prefsize = getPreferredSize();
\r
105 orig = new float[npoint][3];
\r
107 for (int i = 0; i < npoint; i++)
\r
109 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
110 for (int j = 0; j < 3; j++)
\r
112 orig[i][j] = sp.coord[j];
\r
115 //Initialize the matrices to identity
\r
117 for (int i = 0; i < 3; i++)
\r
119 for (int j = 0; j < 3; j++)
\r
123 idmat.addElement(i, j, 0);
\r
124 objmat.addElement(i, j, 0);
\r
125 rotmat.addElement(i, j, 0);
\r
129 idmat.addElement(i, j, 0);
\r
130 objmat.addElement(i, j, 0);
\r
131 rotmat.addElement(i, j, 0);
\r
136 axes = new float[3][3];
\r
142 scale = findScale();
\r
144 // System.out.println("Scale factor = " + scale);
\r
146 addMouseListener(this);
\r
147 addKeyListener(this);
\r
148 // if (getParent() != null) {
\r
149 // getParent().addKeyListener(this);
\r
151 addMouseMotionListener(this);
\r
154 // rubberband = new RubberbandRectangle(this);
\r
155 // rubberband.setActive(true);
\r
156 // rubberband.addListener(this);
\r
159 /* public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {
\r
160 redrawneeded = true;
\r
165 public void removeNotify() {
\r
166 controller.removeListener(this);
\r
167 super.removeNotify();
\r
170 public void initAxes()
\r
172 for (int i = 0; i < 3; i++)
\r
174 for (int j = 0; j < 3; j++)
\r
188 public void findWidth()
\r
190 max = new float[3];
\r
191 min = new float[3];
\r
193 max[0] = (float) - 1e30;
\r
194 max[1] = (float) - 1e30;
\r
195 max[2] = (float) - 1e30;
\r
197 min[0] = (float) 1e30;
\r
198 min[1] = (float) 1e30;
\r
199 min[2] = (float) 1e30;
\r
201 for (int i = 0; i < 3; i++)
\r
203 for (int j = 0; j < npoint; j++)
\r
205 SequencePoint sp = (SequencePoint) points.elementAt(j);
\r
206 if (sp.coord[i] >= max[i])
\r
208 max[i] = sp.coord[i];
\r
210 if (sp.coord[i] <= min[i])
\r
212 min[i] = sp.coord[i];
\r
217 // System.out.println("xmax " + max[0] + " min " + min[0]);
\r
218 //System.out.println("ymax " + max[1] + " min " + min[1]);
\r
219 //System.out.println("zmax " + max[2] + " min " + min[2]);
\r
221 width[0] = Math.abs(max[0] - min[0]);
\r
222 width[1] = Math.abs(max[1] - min[1]);
\r
223 width[2] = Math.abs(max[2] - min[2]);
\r
225 maxwidth = width[0];
\r
227 if (width[1] > width[0])
\r
229 maxwidth = width[1];
\r
231 if (width[2] > width[1])
\r
233 maxwidth = width[2];
\r
236 //System.out.println("Maxwidth = " + maxwidth);
\r
239 public float findScale()
\r
241 int dim, width, height;
\r
242 if (getSize().width != 0)
\r
244 width = getSize().width;
\r
245 height = getSize().height;
\r
249 width = prefsize.width;
\r
250 height = prefsize.height;
\r
253 if (width < height)
\r
262 return (float) (dim * scalefactor / (2 * maxwidth));
\r
265 public void findCentre()
\r
267 //Find centre coordinate
\r
270 centre[0] = (max[0] + min[0]) / 2;
\r
271 centre[1] = (max[1] + min[1]) / 2;
\r
272 centre[2] = (max[2] + min[2]) / 2;
\r
274 // System.out.println("Centre x " + centre[0]);
\r
275 //System.out.println("Centre y " + centre[1]);
\r
276 //System.out.println("Centre z " + centre[2]);
\r
279 public Dimension getPreferredSize()
\r
281 if (prefsize != null)
\r
287 return new Dimension(400, 400);
\r
291 public Dimension getMinimumSize()
\r
293 return getPreferredSize();
\r
296 public void update(Graphics g)
\r
300 public void paint(Graphics g)
\r
302 if (points == null)
\r
304 g.setFont(new Font("Verdana", Font.PLAIN, 18));
\r
305 g.drawString("Calculating PCA....", 20, getSize().height / 2);
\r
310 //Only create the image at the beginning -
\r
311 if ( (img == null) || (prefsize.width != getSize().width) ||
\r
312 (prefsize.height != getSize().height))
\r
314 prefsize.width = getSize().width;
\r
315 prefsize.height = getSize().height;
\r
317 scale = findScale();
\r
319 // System.out.println("New scale = " + scale);
\r
320 img = createImage(getSize().width, getSize().height);
\r
321 ig = img.getGraphics();
\r
325 drawBackground(ig, Color.black);
\r
327 if (drawAxes == true)
\r
334 ig.setColor(Color.red);
\r
335 ig.drawString(tooltip, toolx, tooly);
\r
338 g.drawImage(img, 0, 0, this);
\r
342 public void drawAxes(Graphics g)
\r
345 g.setColor(Color.yellow);
\r
346 for (int i = 0; i < 3; i++)
\r
348 g.drawLine(getSize().width / 2, getSize().height / 2,
\r
349 (int) (axes[i][0] * scale * max[0] + getSize().width / 2),
\r
350 (int) (axes[i][1] * scale * max[1] + getSize().height / 2));
\r
354 public void drawBackground(Graphics g, Color col)
\r
357 g.fillRect(0, 0, prefsize.width, prefsize.height);
\r
360 public void drawScene(Graphics g)
\r
362 //boolean darker = false;
\r
364 int halfwidth = getSize().width / 2;
\r
365 int halfheight = getSize().height / 2;
\r
367 for (int i = 0; i < npoint; i++)
\r
369 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
370 int x = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
371 int y = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
372 float z = sp.coord[1] - centre[2];
\r
374 if (sp.sequence.getColor() == Color.black)
\r
376 g.setColor(Color.white);
\r
380 g.setColor(sp.sequence.getColor());
\r
383 if (av.getSelectionGroup() != null)
\r
385 if (av.getSelectionGroup().sequences.contains( ( (SequencePoint) points.
\r
386 elementAt(i)).sequence))
\r
388 g.setColor(Color.gray);
\r
393 g.setColor(g.getColor().darker());
\r
396 g.fillRect(x - 3, y - 3, 6, 6);
\r
399 g.setColor(Color.red);
\r
400 g.drawString( ( (SequencePoint) points.elementAt(i)).sequence.
\r
407 public Dimension minimumsize()
\r
412 public Dimension preferredsize()
\r
417 public void keyTyped(KeyEvent evt)
\r
420 public void keyReleased(KeyEvent evt)
\r
423 public void keyPressed(KeyEvent evt)
\r
426 if (evt.getKeyCode() == KeyEvent.VK_UP)
\r
428 scalefactor = (float) (scalefactor * 1.1);
\r
429 scale = findScale();
\r
431 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
\r
433 scalefactor = (float) (scalefactor * 0.9);
\r
434 scale = findScale();
\r
436 else if (evt.getKeyChar() == 's')
\r
438 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
439 if (rectx2 != -1 && recty2 != -1)
\r
441 rectSelect(rectx1, recty1, rectx2, recty2);
\r
448 public void printPoints()
\r
450 for (int i = 0; i < npoint; i++)
\r
452 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
453 Format.print(System.out, "%5d ", i);
\r
454 for (int j = 0; j < 3; j++)
\r
456 Format.print(System.out, "%13.3f ", sp.coord[j]);
\r
458 System.out.println();
\r
462 public void mouseClicked(MouseEvent evt)
\r
465 public void mouseEntered(MouseEvent evt)
\r
468 public void mouseExited(MouseEvent evt)
\r
471 public void mouseReleased(MouseEvent evt)
\r
474 public void mousePressed(MouseEvent evt)
\r
476 int x = evt.getX();
\r
477 int y = evt.getY();
\r
494 SequenceI found = findPoint(x, y);
\r
498 if (av.getSelectionGroup() != null)
\r
500 av.getSelectionGroup().addOrRemove(found, true);
\r
501 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
\r
502 PaintRefresher.Refresh(this, av.alignment);
\r
506 av.setSelectionGroup(new SequenceGroup());
\r
507 av.getSelectionGroup().addOrRemove(found, true);
\r
508 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
\r
516 public void mouseMoved(MouseEvent evt)
\r
518 SequenceI found = findPoint(evt.getX(), evt.getY());
\r
523 tooltip = found.getName();
\r
524 toolx = evt.getX();
\r
525 tooly = evt.getY();
\r
530 public void mouseDragged(MouseEvent evt)
\r
535 rotmat.setIdentity();
\r
537 rotmat.rotate( (float) (my - omy), 'x');
\r
538 rotmat.rotate( (float) (mx - omx), 'y');
\r
540 for (int i = 0; i < npoint; i++)
\r
542 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
543 sp.coord[0] -= centre[0];
\r
544 sp.coord[1] -= centre[1];
\r
545 sp.coord[2] -= centre[2];
\r
547 //Now apply the rotation matrix
\r
548 sp.coord = rotmat.vectorMultiply(sp.coord);
\r
550 //Now translate back again
\r
551 sp.coord[0] += centre[0];
\r
552 sp.coord[1] += centre[1];
\r
553 sp.coord[2] += centre[2];
\r
556 for (int i = 0; i < 3; i++)
\r
558 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
563 paint(this.getGraphics());
\r
566 public void rectSelect(int x1, int y1, int x2, int y2)
\r
568 //boolean changedSel = false;
\r
569 for (int i = 0; i < npoint; i++)
\r
571 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
572 int tmp1 = (int) ( (sp.coord[0] - centre[0]) * scale +
\r
573 (float) getSize().width / 2.0);
\r
574 int tmp2 = (int) ( (sp.coord[1] - centre[1]) * scale +
\r
575 (float) getSize().height / 2.0);
\r
577 if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)
\r
581 if (!av.getSelectionGroup().sequences.contains(sp.sequence))
\r
583 av.getSelectionGroup().addSequence(sp.sequence, true);
\r
590 public SequenceI findPoint(int x, int y)
\r
593 int halfwidth = getSize().width / 2;
\r
594 int halfheight = getSize().height / 2;
\r
598 for (int i = 0; i < npoint; i++)
\r
601 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
602 int px = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
603 int py = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
605 if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)
\r
612 return ( (SequencePoint) points.elementAt(found)).sequence;
\r