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().getSequences(false).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
425 if (evt.getKeyCode() == KeyEvent.VK_UP)
\r
427 scalefactor = (float) (scalefactor * 1.1);
\r
428 scale = findScale();
\r
430 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
\r
432 scalefactor = (float) (scalefactor * 0.9);
\r
433 scale = findScale();
\r
435 else if (evt.getKeyChar() == 's')
\r
437 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
438 if (rectx2 != -1 && recty2 != -1)
\r
440 rectSelect(rectx1, recty1, rectx2, recty2);
\r
447 public void printPoints()
\r
449 for (int i = 0; i < npoint; i++)
\r
451 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
452 Format.print(System.out, "%5d ", i);
\r
453 for (int j = 0; j < 3; j++)
\r
455 Format.print(System.out, "%13.3f ", sp.coord[j]);
\r
457 System.out.println();
\r
461 public void mouseClicked(MouseEvent evt)
\r
464 public void mouseEntered(MouseEvent evt)
\r
467 public void mouseExited(MouseEvent evt)
\r
470 public void mouseReleased(MouseEvent evt)
\r
473 public void mousePressed(MouseEvent evt)
\r
475 int x = evt.getX();
\r
476 int y = evt.getY();
\r
493 SequenceI found = findPoint(x, y);
\r
497 if (av.getSelectionGroup() != null)
\r
499 av.getSelectionGroup().addOrRemove(found, true);
\r
500 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
\r
501 PaintRefresher.Refresh(this, av.alignment);
\r
505 av.setSelectionGroup(new SequenceGroup());
\r
506 av.getSelectionGroup().addOrRemove(found, true);
\r
507 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
\r
515 public void mouseMoved(MouseEvent evt)
\r
517 SequenceI found = findPoint(evt.getX(), evt.getY());
\r
522 tooltip = found.getName();
\r
523 toolx = evt.getX();
\r
524 tooly = evt.getY();
\r
529 public void mouseDragged(MouseEvent evt)
\r
534 rotmat.setIdentity();
\r
536 rotmat.rotate( (float) (my - omy), 'x');
\r
537 rotmat.rotate( (float) (mx - omx), 'y');
\r
539 for (int i = 0; i < npoint; i++)
\r
541 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
542 sp.coord[0] -= centre[0];
\r
543 sp.coord[1] -= centre[1];
\r
544 sp.coord[2] -= centre[2];
\r
546 //Now apply the rotation matrix
\r
547 sp.coord = rotmat.vectorMultiply(sp.coord);
\r
549 //Now translate back again
\r
550 sp.coord[0] += centre[0];
\r
551 sp.coord[1] += centre[1];
\r
552 sp.coord[2] += centre[2];
\r
555 for (int i = 0; i < 3; i++)
\r
557 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
562 paint(this.getGraphics());
\r
565 public void rectSelect(int x1, int y1, int x2, int y2)
\r
567 //boolean changedSel = false;
\r
568 for (int i = 0; i < npoint; i++)
\r
570 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
571 int tmp1 = (int) ( (sp.coord[0] - centre[0]) * scale +
\r
572 (float) getSize().width / 2.0);
\r
573 int tmp2 = (int) ( (sp.coord[1] - centre[1]) * scale +
\r
574 (float) getSize().height / 2.0);
\r
576 if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)
\r
580 if (!av.getSelectionGroup().getSequences(false).contains(sp.sequence))
\r
582 av.getSelectionGroup().addSequence(sp.sequence, true);
\r
589 public SequenceI findPoint(int x, int y)
\r
592 int halfwidth = getSize().width / 2;
\r
593 int halfheight = getSize().height / 2;
\r
597 for (int i = 0; i < npoint; i++)
\r
600 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
601 int px = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
602 int py = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
604 if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)
\r
611 return ( (SequencePoint) points.elementAt(found)).sequence;
\r