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
84 public RotatableCanvas(AlignViewport av)
\r
89 public void setPoints(Vector points, int npoint)
\r
91 this.points = points;
\r
92 this.npoint = npoint;
\r
94 PaintRefresher.Register(this, av.alignment);
\r
96 prefsize = getPreferredSize();
\r
97 orig = new float[npoint][3];
\r
99 for (int i = 0; i < npoint; i++)
\r
101 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
102 for (int j = 0; j < 3; j++)
\r
104 orig[i][j] = sp.coord[j];
\r
107 //Initialize the matrices to identity
\r
109 for (int i = 0; i < 3; i++)
\r
111 for (int j = 0; j < 3; j++)
\r
115 idmat.addElement(i, j, 0);
\r
116 objmat.addElement(i, j, 0);
\r
117 rotmat.addElement(i, j, 0);
\r
121 idmat.addElement(i, j, 0);
\r
122 objmat.addElement(i, j, 0);
\r
123 rotmat.addElement(i, j, 0);
\r
128 axes = new float[3][3];
\r
134 scale = findScale();
\r
136 // System.out.println("Scale factor = " + scale);
\r
138 addMouseListener(this);
\r
139 addKeyListener(this);
\r
140 // if (getParent() != null) {
\r
141 // getParent().addKeyListener(this);
\r
143 addMouseMotionListener(this);
\r
146 // rubberband = new RubberbandRectangle(this);
\r
147 // rubberband.setActive(true);
\r
148 // rubberband.addListener(this);
\r
151 /* public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {
\r
152 redrawneeded = true;
\r
157 public void removeNotify() {
\r
158 controller.removeListener(this);
\r
159 super.removeNotify();
\r
162 public void initAxes()
\r
164 for (int i = 0; i < 3; i++)
\r
166 for (int j = 0; j < 3; j++)
\r
180 public void findWidth()
\r
182 max = new float[3];
\r
183 min = new float[3];
\r
185 max[0] = (float) - 1e30;
\r
186 max[1] = (float) - 1e30;
\r
187 max[2] = (float) - 1e30;
\r
189 min[0] = (float) 1e30;
\r
190 min[1] = (float) 1e30;
\r
191 min[2] = (float) 1e30;
\r
193 for (int i = 0; i < 3; i++)
\r
195 for (int j = 0; j < npoint; j++)
\r
197 SequencePoint sp = (SequencePoint) points.elementAt(j);
\r
198 if (sp.coord[i] >= max[i])
\r
200 max[i] = sp.coord[i];
\r
202 if (sp.coord[i] <= min[i])
\r
204 min[i] = sp.coord[i];
\r
209 // System.out.println("xmax " + max[0] + " min " + min[0]);
\r
210 //System.out.println("ymax " + max[1] + " min " + min[1]);
\r
211 //System.out.println("zmax " + max[2] + " min " + min[2]);
\r
213 width[0] = Math.abs(max[0] - min[0]);
\r
214 width[1] = Math.abs(max[1] - min[1]);
\r
215 width[2] = Math.abs(max[2] - min[2]);
\r
217 maxwidth = width[0];
\r
219 if (width[1] > width[0])
\r
221 maxwidth = width[1];
\r
223 if (width[2] > width[1])
\r
225 maxwidth = width[2];
\r
228 //System.out.println("Maxwidth = " + maxwidth);
\r
231 public float findScale()
\r
233 int dim, width, height;
\r
234 if (getSize().width != 0)
\r
236 width = getSize().width;
\r
237 height = getSize().height;
\r
241 width = prefsize.width;
\r
242 height = prefsize.height;
\r
245 if (width < height)
\r
254 return (float) (dim * scalefactor / (2 * maxwidth));
\r
257 public void findCentre()
\r
259 //Find centre coordinate
\r
262 centre[0] = (max[0] + min[0]) / 2;
\r
263 centre[1] = (max[1] + min[1]) / 2;
\r
264 centre[2] = (max[2] + min[2]) / 2;
\r
266 // System.out.println("Centre x " + centre[0]);
\r
267 //System.out.println("Centre y " + centre[1]);
\r
268 //System.out.println("Centre z " + centre[2]);
\r
271 public Dimension getPreferredSize()
\r
273 if (prefsize != null)
\r
279 return new Dimension(400, 400);
\r
283 public Dimension getMinimumSize()
\r
285 return getPreferredSize();
\r
288 public void paint(Graphics g)
\r
290 if (points == null)
\r
292 g.setFont(new Font("Verdana", Font.PLAIN, 18));
\r
293 g.drawString("Calculating PCA....", 20, getSize().height / 2);
\r
298 //Only create the image at the beginning -
\r
299 if ( (img == null) || (prefsize.width != getSize().width) ||
\r
300 (prefsize.height != getSize().height))
\r
302 prefsize.width = getSize().width;
\r
303 prefsize.height = getSize().height;
\r
305 scale = findScale();
\r
307 // System.out.println("New scale = " + scale);
\r
308 img = createImage(getSize().width, getSize().height);
\r
309 ig = img.getGraphics();
\r
313 drawBackground(ig, Color.black);
\r
315 if (drawAxes == true)
\r
320 g.drawImage(img, 0, 0, this);
\r
324 public void drawAxes(Graphics g)
\r
327 g.setColor(Color.yellow);
\r
328 for (int i = 0; i < 3; i++)
\r
330 g.drawLine(getSize().width / 2, getSize().height / 2,
\r
331 (int) (axes[i][0] * scale * max[0] + getSize().width / 2),
\r
332 (int) (axes[i][1] * scale * max[1] + getSize().height / 2));
\r
336 public void drawBackground(Graphics g, Color col)
\r
339 g.fillRect(0, 0, prefsize.width, prefsize.height);
\r
342 public void drawScene(Graphics g)
\r
344 boolean darker = false;
\r
346 int halfwidth = getSize().width / 2;
\r
347 int halfheight = getSize().height / 2;
\r
349 for (int i = 0; i < npoint; i++)
\r
351 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
352 int x = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
353 int y = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
354 float z = sp.coord[1] - centre[2];
\r
356 if (sp.sequence.getColor() == Color.black)
\r
358 g.setColor(Color.white);
\r
362 g.setColor(sp.sequence.getColor());
\r
365 if (av.getSelectionGroup() != null)
\r
367 if (av.getSelectionGroup().sequences.contains( ( (SequencePoint) points.
\r
368 elementAt(i)).sequence))
\r
370 g.setColor(Color.gray);
\r
375 g.setColor(g.getColor().darker());
\r
378 g.fillRect(x - 3, y - 3, 6, 6);
\r
379 g.setColor(Color.red);
\r
381 // //Now the rectangle
\r
382 // if (rectx2 != -1 && recty2 != -1) {
\r
383 // g.setColor(Color.white);
\r
385 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
\r
389 public Dimension minimumsize()
\r
394 public Dimension preferredsize()
\r
399 public void keyTyped(KeyEvent evt)
\r
402 public void keyReleased(KeyEvent evt)
\r
405 public void keyPressed(KeyEvent evt)
\r
408 if (evt.getKeyCode() == KeyEvent.VK_UP)
\r
410 scalefactor = (float) (scalefactor * 1.1);
\r
411 scale = findScale();
\r
413 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
\r
415 scalefactor = (float) (scalefactor * 0.9);
\r
416 scale = findScale();
\r
418 else if (evt.getKeyChar() == 's')
\r
420 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
421 if (rectx2 != -1 && recty2 != -1)
\r
423 rectSelect(rectx1, recty1, rectx2, recty2);
\r
430 public void printPoints()
\r
432 for (int i = 0; i < npoint; i++)
\r
434 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
435 Format.print(System.out, "%5d ", i);
\r
436 for (int j = 0; j < 3; j++)
\r
438 Format.print(System.out, "%13.3f ", sp.coord[j]);
\r
440 System.out.println();
\r
444 public void mouseClicked(MouseEvent evt)
\r
447 public void mouseEntered(MouseEvent evt)
\r
450 public void mouseExited(MouseEvent evt)
\r
453 public void mouseReleased(MouseEvent evt)
\r
456 public void mousePressed(MouseEvent evt)
\r
458 int x = evt.getX();
\r
459 int y = evt.getY();
\r
476 SequenceI found = findPoint(x, y);
\r
480 if (av.getSelectionGroup() != null)
\r
482 av.getSelectionGroup().addOrRemove(found, true);
\r
483 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
\r
484 PaintRefresher.Refresh(this, av.alignment);
\r
488 av.setSelectionGroup(new SequenceGroup());
\r
489 av.getSelectionGroup().addOrRemove(found, true);
\r
490 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
\r
497 // private void fireSequenceSelectionEvent(Selection sel) {
\r
498 // controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));
\r
501 public void mouseMoved(MouseEvent evt)
\r
503 // SequenceI found = findPoint(evt.getX(), evt.getY());
\r
506 public void mouseDragged(MouseEvent evt)
\r
510 //Check if this is a rectangle drawing drag
\r
511 if ( (evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
\r
513 // rectx2 = evt.getX();
\r
514 // recty2 = evt.getY();
\r
518 rotmat.setIdentity();
\r
520 rotmat.rotate( (float) (my - omy), 'x');
\r
521 rotmat.rotate( (float) (mx - omx), 'y');
\r
523 for (int i = 0; i < npoint; i++)
\r
525 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
526 sp.coord[0] -= centre[0];
\r
527 sp.coord[1] -= centre[1];
\r
528 sp.coord[2] -= centre[2];
\r
530 //Now apply the rotation matrix
\r
531 sp.coord = rotmat.vectorMultiply(sp.coord);
\r
533 //Now translate back again
\r
534 sp.coord[0] += centre[0];
\r
535 sp.coord[1] += centre[1];
\r
536 sp.coord[2] += centre[2];
\r
539 for (int i = 0; i < 3; i++)
\r
541 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
546 paint(this.getGraphics());
\r
551 public void rectSelect(int x1, int y1, int x2, int y2)
\r
553 boolean changedSel = false;
\r
554 for (int i = 0; i < npoint; i++)
\r
556 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
557 int tmp1 = (int) ( (sp.coord[0] - centre[0]) * scale +
\r
558 (float) getSize().width / 2.0);
\r
559 int tmp2 = (int) ( (sp.coord[1] - centre[1]) * scale +
\r
560 (float) getSize().height / 2.0);
\r
562 if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)
\r
566 if (!av.getSelectionGroup().sequences.contains(sp.sequence))
\r
568 av.getSelectionGroup().addSequence(sp.sequence, true);
\r
575 public SequenceI findPoint(int x, int y)
\r
578 int halfwidth = getSize().width / 2;
\r
579 int halfheight = getSize().height / 2;
\r
583 for (int i = 0; i < npoint; i++)
\r
586 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
587 int px = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
588 int py = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
590 if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)
\r
597 return ( (SequencePoint) points.elementAt(found)).sequence;
\r
604 /* public boolean handleRubberbandEvent(RubberbandEvent evt) {
\r
605 System.out.println("Rubberband handler called in RotatableCanvas with " +
\r
608 Rubberband rb = (Rubberband)evt.getSource();
\r
610 // Clear the current selection (instance variable)
\r
611 //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {
\r
612 // clearSelection();
\r
615 if (rb.getComponent() == this) {
\r
616 Rectangle bounds = evt.getBounds();
\r
617 rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);
\r
620 redrawneeded = true;
\r
621 paint(this.getGraphics());
\r