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
40 //RubberbandRectangle rubberband;
\r
42 boolean drawAxes = true;
\r
54 float centre[] = new float[3];
\r
55 float width[] = new float[3];
\r
57 float max[] = new float[3];
\r
58 float min[] = new float[3];
\r
80 float scalefactor = 1;
\r
83 boolean showLabels = false;
\r
85 public RotatableCanvas(AlignViewport av)
\r
90 public void showLabels(boolean b)
\r
96 public void setPoints(Vector points, int npoint)
\r
98 this.points = points;
\r
99 this.npoint = npoint;
\r
101 PaintRefresher.Register(this, av.alignment);
\r
103 prefsize = getPreferredSize();
\r
104 orig = new float[npoint][3];
\r
106 for (int i = 0; i < npoint; i++)
\r
108 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
109 for (int j = 0; j < 3; j++)
\r
111 orig[i][j] = sp.coord[j];
\r
114 //Initialize the matrices to identity
\r
116 for (int i = 0; i < 3; i++)
\r
118 for (int j = 0; j < 3; j++)
\r
122 idmat.addElement(i, j, 0);
\r
123 objmat.addElement(i, j, 0);
\r
124 rotmat.addElement(i, j, 0);
\r
128 idmat.addElement(i, j, 0);
\r
129 objmat.addElement(i, j, 0);
\r
130 rotmat.addElement(i, j, 0);
\r
135 axes = new float[3][3];
\r
141 scale = findScale();
\r
143 // System.out.println("Scale factor = " + scale);
\r
145 addMouseListener(this);
\r
146 addKeyListener(this);
\r
147 // if (getParent() != null) {
\r
148 // getParent().addKeyListener(this);
\r
150 addMouseMotionListener(this);
\r
153 // rubberband = new RubberbandRectangle(this);
\r
154 // rubberband.setActive(true);
\r
155 // rubberband.addListener(this);
\r
158 /* public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {
\r
159 redrawneeded = true;
\r
164 public void removeNotify() {
\r
165 controller.removeListener(this);
\r
166 super.removeNotify();
\r
169 public void initAxes()
\r
171 for (int i = 0; i < 3; i++)
\r
173 for (int j = 0; j < 3; j++)
\r
187 public void findWidth()
\r
189 max = new float[3];
\r
190 min = new float[3];
\r
192 max[0] = (float) - 1e30;
\r
193 max[1] = (float) - 1e30;
\r
194 max[2] = (float) - 1e30;
\r
196 min[0] = (float) 1e30;
\r
197 min[1] = (float) 1e30;
\r
198 min[2] = (float) 1e30;
\r
200 for (int i = 0; i < 3; i++)
\r
202 for (int j = 0; j < npoint; j++)
\r
204 SequencePoint sp = (SequencePoint) points.elementAt(j);
\r
205 if (sp.coord[i] >= max[i])
\r
207 max[i] = sp.coord[i];
\r
209 if (sp.coord[i] <= min[i])
\r
211 min[i] = sp.coord[i];
\r
216 // System.out.println("xmax " + max[0] + " min " + min[0]);
\r
217 //System.out.println("ymax " + max[1] + " min " + min[1]);
\r
218 //System.out.println("zmax " + max[2] + " min " + min[2]);
\r
220 width[0] = Math.abs(max[0] - min[0]);
\r
221 width[1] = Math.abs(max[1] - min[1]);
\r
222 width[2] = Math.abs(max[2] - min[2]);
\r
224 maxwidth = width[0];
\r
226 if (width[1] > width[0])
\r
228 maxwidth = width[1];
\r
230 if (width[2] > width[1])
\r
232 maxwidth = width[2];
\r
235 //System.out.println("Maxwidth = " + maxwidth);
\r
238 public float findScale()
\r
240 int dim, width, height;
\r
241 if (getSize().width != 0)
\r
243 width = getSize().width;
\r
244 height = getSize().height;
\r
248 width = prefsize.width;
\r
249 height = prefsize.height;
\r
252 if (width < height)
\r
261 return (float) (dim * scalefactor / (2 * maxwidth));
\r
264 public void findCentre()
\r
266 //Find centre coordinate
\r
269 centre[0] = (max[0] + min[0]) / 2;
\r
270 centre[1] = (max[1] + min[1]) / 2;
\r
271 centre[2] = (max[2] + min[2]) / 2;
\r
273 // System.out.println("Centre x " + centre[0]);
\r
274 //System.out.println("Centre y " + centre[1]);
\r
275 //System.out.println("Centre z " + centre[2]);
\r
278 public Dimension getPreferredSize()
\r
280 if (prefsize != null)
\r
286 return new Dimension(400, 400);
\r
290 public Dimension getMinimumSize()
\r
292 return getPreferredSize();
\r
295 public void paint(Graphics g)
\r
297 if (points == null)
\r
299 g.setFont(new Font("Verdana", Font.PLAIN, 18));
\r
300 g.drawString("Calculating PCA....", 20, getSize().height / 2);
\r
305 //Only create the image at the beginning -
\r
306 if ( (img == null) || (prefsize.width != getSize().width) ||
\r
307 (prefsize.height != getSize().height))
\r
309 prefsize.width = getSize().width;
\r
310 prefsize.height = getSize().height;
\r
312 scale = findScale();
\r
314 // System.out.println("New scale = " + scale);
\r
315 img = createImage(getSize().width, getSize().height);
\r
316 ig = img.getGraphics();
\r
320 drawBackground(ig, Color.black);
\r
322 if (drawAxes == true)
\r
327 g.drawImage(img, 0, 0, this);
\r
331 public void drawAxes(Graphics g)
\r
334 g.setColor(Color.yellow);
\r
335 for (int i = 0; i < 3; i++)
\r
337 g.drawLine(getSize().width / 2, getSize().height / 2,
\r
338 (int) (axes[i][0] * scale * max[0] + getSize().width / 2),
\r
339 (int) (axes[i][1] * scale * max[1] + getSize().height / 2));
\r
343 public void drawBackground(Graphics g, Color col)
\r
346 g.fillRect(0, 0, prefsize.width, prefsize.height);
\r
349 public void drawScene(Graphics g)
\r
351 boolean darker = false;
\r
353 int halfwidth = getSize().width / 2;
\r
354 int halfheight = getSize().height / 2;
\r
356 for (int i = 0; i < npoint; i++)
\r
358 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
359 int x = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
360 int y = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
361 float z = sp.coord[1] - centre[2];
\r
363 if (sp.sequence.getColor() == Color.black)
\r
365 g.setColor(Color.white);
\r
369 g.setColor(sp.sequence.getColor());
\r
372 if (av.getSelectionGroup() != null)
\r
374 if (av.getSelectionGroup().sequences.contains( ( (SequencePoint) points.
\r
375 elementAt(i)).sequence))
\r
377 g.setColor(Color.gray);
\r
382 g.setColor(g.getColor().darker());
\r
385 g.fillRect(x - 3, y - 3, 6, 6);
\r
388 g.setColor(Color.red);
\r
389 g.drawString( ( (SequencePoint) points.elementAt(i)).sequence.
\r
395 // //Now the rectangle
\r
396 // if (rectx2 != -1 && recty2 != -1) {
\r
397 // g.setColor(Color.white);
\r
399 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
\r
403 public Dimension minimumsize()
\r
408 public Dimension preferredsize()
\r
413 public void keyTyped(KeyEvent evt)
\r
416 public void keyReleased(KeyEvent evt)
\r
419 public void keyPressed(KeyEvent evt)
\r
422 if (evt.getKeyCode() == KeyEvent.VK_UP)
\r
424 scalefactor = (float) (scalefactor * 1.1);
\r
425 scale = findScale();
\r
427 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
\r
429 scalefactor = (float) (scalefactor * 0.9);
\r
430 scale = findScale();
\r
432 else if (evt.getKeyChar() == 's')
\r
434 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
435 if (rectx2 != -1 && recty2 != -1)
\r
437 rectSelect(rectx1, recty1, rectx2, recty2);
\r
444 public void printPoints()
\r
446 for (int i = 0; i < npoint; i++)
\r
448 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
449 Format.print(System.out, "%5d ", i);
\r
450 for (int j = 0; j < 3; j++)
\r
452 Format.print(System.out, "%13.3f ", sp.coord[j]);
\r
454 System.out.println();
\r
458 public void mouseClicked(MouseEvent evt)
\r
461 public void mouseEntered(MouseEvent evt)
\r
464 public void mouseExited(MouseEvent evt)
\r
467 public void mouseReleased(MouseEvent evt)
\r
470 public void mousePressed(MouseEvent evt)
\r
472 int x = evt.getX();
\r
473 int y = evt.getY();
\r
490 SequenceI found = findPoint(x, y);
\r
494 if (av.getSelectionGroup() != null)
\r
496 av.getSelectionGroup().addOrRemove(found, true);
\r
497 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
\r
498 PaintRefresher.Refresh(this, av.alignment);
\r
502 av.setSelectionGroup(new SequenceGroup());
\r
503 av.getSelectionGroup().addOrRemove(found, true);
\r
504 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
\r
511 // private void fireSequenceSelectionEvent(Selection sel) {
\r
512 // controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));
\r
515 public void mouseMoved(MouseEvent evt)
\r
517 // SequenceI found = findPoint(evt.getX(), evt.getY());
\r
520 public void mouseDragged(MouseEvent evt)
\r
524 //Check if this is a rectangle drawing drag
\r
525 if ( (evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
\r
527 // rectx2 = evt.getX();
\r
528 // recty2 = evt.getY();
\r
532 rotmat.setIdentity();
\r
534 rotmat.rotate( (float) (my - omy), 'x');
\r
535 rotmat.rotate( (float) (mx - omx), 'y');
\r
537 for (int i = 0; i < npoint; i++)
\r
539 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
540 sp.coord[0] -= centre[0];
\r
541 sp.coord[1] -= centre[1];
\r
542 sp.coord[2] -= centre[2];
\r
544 //Now apply the rotation matrix
\r
545 sp.coord = rotmat.vectorMultiply(sp.coord);
\r
547 //Now translate back again
\r
548 sp.coord[0] += centre[0];
\r
549 sp.coord[1] += centre[1];
\r
550 sp.coord[2] += centre[2];
\r
553 for (int i = 0; i < 3; i++)
\r
555 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
560 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().sequences.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
618 /* public boolean handleRubberbandEvent(RubberbandEvent evt) {
\r
619 System.out.println("Rubberband handler called in RotatableCanvas with " +
\r
622 Rubberband rb = (Rubberband)evt.getSource();
\r
624 // Clear the current selection (instance variable)
\r
625 //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {
\r
626 // clearSelection();
\r
629 if (rb.getComponent() == this) {
\r
630 Rectangle bounds = evt.getBounds();
\r
631 rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);
\r
634 redrawneeded = true;
\r
635 paint(this.getGraphics());
\r