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
100 PaintRefresher.Register(this, av.alignment);
\r
102 prefsize = getPreferredSize();
\r
103 orig = new float[npoint][3];
\r
105 for (int i = 0; i < npoint; i++)
\r
107 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
108 for (int j = 0; j < 3; j++)
\r
110 orig[i][j] = sp.coord[j];
\r
113 //Initialize the matrices to identity
\r
115 for (int i = 0; i < 3; i++)
\r
117 for (int j = 0; j < 3; j++)
\r
121 idmat.addElement(i, j, 0);
\r
122 objmat.addElement(i, j, 0);
\r
123 rotmat.addElement(i, j, 0);
\r
127 idmat.addElement(i, j, 0);
\r
128 objmat.addElement(i, j, 0);
\r
129 rotmat.addElement(i, j, 0);
\r
134 axes = new float[3][3];
\r
140 scale = findScale();
\r
142 // System.out.println("Scale factor = " + scale);
\r
144 addMouseListener(this);
\r
145 addKeyListener(this);
\r
146 // if (getParent() != null) {
\r
147 // getParent().addKeyListener(this);
\r
149 addMouseMotionListener(this);
\r
152 // rubberband = new RubberbandRectangle(this);
\r
153 // rubberband.setActive(true);
\r
154 // rubberband.addListener(this);
\r
157 /* public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {
\r
158 redrawneeded = true;
\r
163 public void removeNotify() {
\r
164 controller.removeListener(this);
\r
165 super.removeNotify();
\r
168 public void initAxes()
\r
170 for (int i = 0; i < 3; i++)
\r
172 for (int j = 0; j < 3; j++)
\r
186 public void findWidth()
\r
188 max = new float[3];
\r
189 min = new float[3];
\r
191 max[0] = (float) - 1e30;
\r
192 max[1] = (float) - 1e30;
\r
193 max[2] = (float) - 1e30;
\r
195 min[0] = (float) 1e30;
\r
196 min[1] = (float) 1e30;
\r
197 min[2] = (float) 1e30;
\r
199 for (int i = 0; i < 3; i++)
\r
201 for (int j = 0; j < npoint; j++)
\r
203 SequencePoint sp = (SequencePoint) points.elementAt(j);
\r
204 if (sp.coord[i] >= max[i])
\r
206 max[i] = sp.coord[i];
\r
208 if (sp.coord[i] <= min[i])
\r
210 min[i] = sp.coord[i];
\r
215 // System.out.println("xmax " + max[0] + " min " + min[0]);
\r
216 //System.out.println("ymax " + max[1] + " min " + min[1]);
\r
217 //System.out.println("zmax " + max[2] + " min " + min[2]);
\r
219 width[0] = Math.abs(max[0] - min[0]);
\r
220 width[1] = Math.abs(max[1] - min[1]);
\r
221 width[2] = Math.abs(max[2] - min[2]);
\r
223 maxwidth = width[0];
\r
225 if (width[1] > width[0])
\r
227 maxwidth = width[1];
\r
229 if (width[2] > width[1])
\r
231 maxwidth = width[2];
\r
234 //System.out.println("Maxwidth = " + maxwidth);
\r
237 public float findScale()
\r
239 int dim, width, height;
\r
240 if (getSize().width != 0)
\r
242 width = getSize().width;
\r
243 height = getSize().height;
\r
247 width = prefsize.width;
\r
248 height = prefsize.height;
\r
251 if (width < height)
\r
260 return (float) (dim * scalefactor / (2 * maxwidth));
\r
263 public void findCentre()
\r
265 //Find centre coordinate
\r
268 centre[0] = (max[0] + min[0]) / 2;
\r
269 centre[1] = (max[1] + min[1]) / 2;
\r
270 centre[2] = (max[2] + min[2]) / 2;
\r
272 // System.out.println("Centre x " + centre[0]);
\r
273 //System.out.println("Centre y " + centre[1]);
\r
274 //System.out.println("Centre z " + centre[2]);
\r
277 public Dimension getPreferredSize()
\r
279 if (prefsize != null)
\r
285 return new Dimension(400, 400);
\r
289 public Dimension getMinimumSize()
\r
291 return getPreferredSize();
\r
294 public void paint(Graphics g)
\r
296 if (!jalview.bin.JalviewLite.AWT1)
\r
298 MyGraphics.AntiAlias(g);
\r
301 if (points == null)
\r
303 g.setFont(new Font("Verdana", Font.PLAIN, 18));
\r
304 g.drawString("Calculating PCA....", 20, getSize().height / 2);
\r
309 //Only create the image at the beginning -
\r
310 if ( (img == null) || (prefsize.width != getSize().width) ||
\r
311 (prefsize.height != getSize().height))
\r
313 prefsize.width = getSize().width;
\r
314 prefsize.height = getSize().height;
\r
316 scale = findScale();
\r
318 // System.out.println("New scale = " + scale);
\r
319 img = createImage(getSize().width, getSize().height);
\r
320 ig = img.getGraphics();
\r
324 drawBackground(ig, Color.black);
\r
326 if (drawAxes == true)
\r
331 g.drawImage(img, 0, 0, this);
\r
335 public void drawAxes(Graphics g)
\r
338 g.setColor(Color.yellow);
\r
339 for (int i = 0; i < 3; i++)
\r
341 g.drawLine(getSize().width / 2, getSize().height / 2,
\r
342 (int) (axes[i][0] * scale * max[0] + getSize().width / 2),
\r
343 (int) (axes[i][1] * scale * max[1] + getSize().height / 2));
\r
347 public void drawBackground(Graphics g, Color col)
\r
350 g.fillRect(0, 0, prefsize.width, prefsize.height);
\r
353 public void drawScene(Graphics g)
\r
355 //boolean darker = false;
\r
357 int halfwidth = getSize().width / 2;
\r
358 int halfheight = getSize().height / 2;
\r
360 for (int i = 0; i < npoint; i++)
\r
362 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
363 int x = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
364 int y = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
365 float z = sp.coord[1] - centre[2];
\r
367 if (sp.sequence.getColor() == Color.black)
\r
369 g.setColor(Color.white);
\r
373 g.setColor(sp.sequence.getColor());
\r
376 if (av.getSelectionGroup() != null)
\r
378 if (av.getSelectionGroup().sequences.contains( ( (SequencePoint) points.
\r
379 elementAt(i)).sequence))
\r
381 g.setColor(Color.gray);
\r
386 g.setColor(g.getColor().darker());
\r
389 g.fillRect(x - 3, y - 3, 6, 6);
\r
392 g.setColor(Color.red);
\r
393 g.drawString( ( (SequencePoint) points.elementAt(i)).sequence.
\r
399 // //Now the rectangle
\r
400 // if (rectx2 != -1 && recty2 != -1) {
\r
401 // g.setColor(Color.white);
\r
403 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
\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
515 // private void fireSequenceSelectionEvent(Selection sel) {
\r
516 // controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));
\r
519 public void mouseMoved(MouseEvent evt)
\r
521 // SequenceI found = findPoint(evt.getX(), evt.getY());
\r
524 public void mouseDragged(MouseEvent evt)
\r
528 //Check if this is a rectangle drawing drag
\r
529 if ( (evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
\r
531 // rectx2 = evt.getX();
\r
532 // recty2 = evt.getY();
\r
536 rotmat.setIdentity();
\r
538 rotmat.rotate( (float) (my - omy), 'x');
\r
539 rotmat.rotate( (float) (mx - omx), 'y');
\r
541 for (int i = 0; i < npoint; i++)
\r
543 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
544 sp.coord[0] -= centre[0];
\r
545 sp.coord[1] -= centre[1];
\r
546 sp.coord[2] -= centre[2];
\r
548 //Now apply the rotation matrix
\r
549 sp.coord = rotmat.vectorMultiply(sp.coord);
\r
551 //Now translate back again
\r
552 sp.coord[0] += centre[0];
\r
553 sp.coord[1] += centre[1];
\r
554 sp.coord[2] += centre[2];
\r
557 for (int i = 0; i < 3; i++)
\r
559 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
564 paint(this.getGraphics());
\r
569 public void rectSelect(int x1, int y1, int x2, int y2)
\r
571 //boolean changedSel = false;
\r
572 for (int i = 0; i < npoint; i++)
\r
574 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
575 int tmp1 = (int) ( (sp.coord[0] - centre[0]) * scale +
\r
576 (float) getSize().width / 2.0);
\r
577 int tmp2 = (int) ( (sp.coord[1] - centre[1]) * scale +
\r
578 (float) getSize().height / 2.0);
\r
580 if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)
\r
584 if (!av.getSelectionGroup().sequences.contains(sp.sequence))
\r
586 av.getSelectionGroup().addSequence(sp.sequence, true);
\r
593 public SequenceI findPoint(int x, int y)
\r
596 int halfwidth = getSize().width / 2;
\r
597 int halfheight = getSize().height / 2;
\r
601 for (int i = 0; i < npoint; i++)
\r
604 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
605 int px = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
606 int py = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
608 if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)
\r
615 return ( (SequencePoint) points.elementAt(found)).sequence;
\r
622 /* public boolean handleRubberbandEvent(RubberbandEvent evt) {
\r
623 System.out.println("Rubberband handler called in RotatableCanvas with " +
\r
626 Rubberband rb = (Rubberband)evt.getSource();
\r
628 // Clear the current selection (instance variable)
\r
629 //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {
\r
630 // clearSelection();
\r
633 if (rb.getComponent() == this) {
\r
634 Rectangle bounds = evt.getBounds();
\r
635 rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);
\r
638 redrawneeded = true;
\r
639 paint(this.getGraphics());
\r