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 (points == null)
\r
298 g.setFont(new Font("Verdana", Font.PLAIN, 18));
\r
299 g.drawString("Calculating PCA....", 20, getSize().height / 2);
\r
304 //Only create the image at the beginning -
\r
305 if ( (img == null) || (prefsize.width != getSize().width) ||
\r
306 (prefsize.height != getSize().height))
\r
308 prefsize.width = getSize().width;
\r
309 prefsize.height = getSize().height;
\r
311 scale = findScale();
\r
313 // System.out.println("New scale = " + scale);
\r
314 img = createImage(getSize().width, getSize().height);
\r
315 ig = img.getGraphics();
\r
319 drawBackground(ig, Color.black);
\r
321 if (drawAxes == true)
\r
326 g.drawImage(img, 0, 0, this);
\r
330 public void drawAxes(Graphics g)
\r
333 g.setColor(Color.yellow);
\r
334 for (int i = 0; i < 3; i++)
\r
336 g.drawLine(getSize().width / 2, getSize().height / 2,
\r
337 (int) (axes[i][0] * scale * max[0] + getSize().width / 2),
\r
338 (int) (axes[i][1] * scale * max[1] + getSize().height / 2));
\r
342 public void drawBackground(Graphics g, Color col)
\r
345 g.fillRect(0, 0, prefsize.width, prefsize.height);
\r
348 public void drawScene(Graphics g)
\r
350 //boolean darker = false;
\r
352 int halfwidth = getSize().width / 2;
\r
353 int halfheight = getSize().height / 2;
\r
355 for (int i = 0; i < npoint; i++)
\r
357 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
358 int x = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
359 int y = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
360 float z = sp.coord[1] - centre[2];
\r
362 if (sp.sequence.getColor() == Color.black)
\r
364 g.setColor(Color.white);
\r
368 g.setColor(sp.sequence.getColor());
\r
371 if (av.getSelectionGroup() != null)
\r
373 if (av.getSelectionGroup().sequences.contains( ( (SequencePoint) points.
\r
374 elementAt(i)).sequence))
\r
376 g.setColor(Color.gray);
\r
381 g.setColor(g.getColor().darker());
\r
384 g.fillRect(x - 3, y - 3, 6, 6);
\r
387 g.setColor(Color.red);
\r
388 g.drawString( ( (SequencePoint) points.elementAt(i)).sequence.
\r
394 // //Now the rectangle
\r
395 // if (rectx2 != -1 && recty2 != -1) {
\r
396 // g.setColor(Color.white);
\r
398 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
\r
402 public Dimension minimumsize()
\r
407 public Dimension preferredsize()
\r
412 public void keyTyped(KeyEvent evt)
\r
415 public void keyReleased(KeyEvent evt)
\r
418 public void keyPressed(KeyEvent evt)
\r
421 if (evt.getKeyCode() == KeyEvent.VK_UP)
\r
423 scalefactor = (float) (scalefactor * 1.1);
\r
424 scale = findScale();
\r
426 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
\r
428 scalefactor = (float) (scalefactor * 0.9);
\r
429 scale = findScale();
\r
431 else if (evt.getKeyChar() == 's')
\r
433 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
434 if (rectx2 != -1 && recty2 != -1)
\r
436 rectSelect(rectx1, recty1, rectx2, recty2);
\r
443 public void printPoints()
\r
445 for (int i = 0; i < npoint; i++)
\r
447 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
448 Format.print(System.out, "%5d ", i);
\r
449 for (int j = 0; j < 3; j++)
\r
451 Format.print(System.out, "%13.3f ", sp.coord[j]);
\r
453 System.out.println();
\r
457 public void mouseClicked(MouseEvent evt)
\r
460 public void mouseEntered(MouseEvent evt)
\r
463 public void mouseExited(MouseEvent evt)
\r
466 public void mouseReleased(MouseEvent evt)
\r
469 public void mousePressed(MouseEvent evt)
\r
471 int x = evt.getX();
\r
472 int y = evt.getY();
\r
489 SequenceI found = findPoint(x, y);
\r
493 if (av.getSelectionGroup() != null)
\r
495 av.getSelectionGroup().addOrRemove(found, true);
\r
496 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
\r
497 PaintRefresher.Refresh(this, av.alignment);
\r
501 av.setSelectionGroup(new SequenceGroup());
\r
502 av.getSelectionGroup().addOrRemove(found, true);
\r
503 av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);
\r
510 // private void fireSequenceSelectionEvent(Selection sel) {
\r
511 // controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));
\r
514 public void mouseMoved(MouseEvent evt)
\r
516 // SequenceI found = findPoint(evt.getX(), evt.getY());
\r
519 public void mouseDragged(MouseEvent evt)
\r
523 //Check if this is a rectangle drawing drag
\r
524 if ( (evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
\r
526 // rectx2 = evt.getX();
\r
527 // recty2 = evt.getY();
\r
531 rotmat.setIdentity();
\r
533 rotmat.rotate( (float) (my - omy), 'x');
\r
534 rotmat.rotate( (float) (mx - omx), 'y');
\r
536 for (int i = 0; i < npoint; i++)
\r
538 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
539 sp.coord[0] -= centre[0];
\r
540 sp.coord[1] -= centre[1];
\r
541 sp.coord[2] -= centre[2];
\r
543 //Now apply the rotation matrix
\r
544 sp.coord = rotmat.vectorMultiply(sp.coord);
\r
546 //Now translate back again
\r
547 sp.coord[0] += centre[0];
\r
548 sp.coord[1] += centre[1];
\r
549 sp.coord[2] += centre[2];
\r
552 for (int i = 0; i < 3; i++)
\r
554 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
559 paint(this.getGraphics());
\r
564 public void rectSelect(int x1, int y1, int x2, int y2)
\r
566 //boolean changedSel = false;
\r
567 for (int i = 0; i < npoint; i++)
\r
569 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
570 int tmp1 = (int) ( (sp.coord[0] - centre[0]) * scale +
\r
571 (float) getSize().width / 2.0);
\r
572 int tmp2 = (int) ( (sp.coord[1] - centre[1]) * scale +
\r
573 (float) getSize().height / 2.0);
\r
575 if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)
\r
579 if (!av.getSelectionGroup().sequences.contains(sp.sequence))
\r
581 av.getSelectionGroup().addSequence(sp.sequence, true);
\r
588 public SequenceI findPoint(int x, int y)
\r
591 int halfwidth = getSize().width / 2;
\r
592 int halfheight = getSize().height / 2;
\r
596 for (int i = 0; i < npoint; i++)
\r
599 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
600 int px = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
601 int py = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
603 if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)
\r
610 return ( (SequencePoint) points.elementAt(found)).sequence;
\r
617 /* public boolean handleRubberbandEvent(RubberbandEvent evt) {
\r
618 System.out.println("Rubberband handler called in RotatableCanvas with " +
\r
621 Rubberband rb = (Rubberband)evt.getSource();
\r
623 // Clear the current selection (instance variable)
\r
624 //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {
\r
625 // clearSelection();
\r
628 if (rb.getComponent() == this) {
\r
629 Rectangle bounds = evt.getBounds();
\r
630 rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);
\r
633 redrawneeded = true;
\r
634 paint(this.getGraphics());
\r