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
35 //RubberbandListener,
\r
36 //SequenceSelectionListener
\r
38 RotatableMatrix idmat = new RotatableMatrix(3, 3);
\r
39 RotatableMatrix objmat = new RotatableMatrix(3, 3);
\r
40 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 // Controller controller;
\r
88 public RotatableCanvas(AlignViewport av,
\r
89 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 //Only create the image at the beginning -
\r
291 if ( (img == null) || (prefsize.width != getSize().width) ||
\r
292 (prefsize.height != getSize().height))
\r
294 prefsize.width = getSize().width;
\r
295 prefsize.height = getSize().height;
\r
297 scale = findScale();
\r
299 // System.out.println("New scale = " + scale);
\r
300 img = createImage(getSize().width, getSize().height);
\r
301 ig = img.getGraphics();
\r
305 drawBackground(ig, Color.black);
\r
307 if (drawAxes == true)
\r
312 g.drawImage(img, 0, 0, this);
\r
315 public void drawAxes(Graphics g)
\r
318 g.setColor(Color.yellow);
\r
319 for (int i = 0; i < 3; i++)
\r
321 g.drawLine(getSize().width / 2, getSize().height / 2,
\r
322 (int) (axes[i][0] * scale * max[0] + getSize().width / 2),
\r
323 (int) (axes[i][1] * scale * max[1] + getSize().height / 2));
\r
327 public void drawBackground(Graphics g, Color col)
\r
330 g.fillRect(0, 0, prefsize.width, prefsize.height);
\r
333 public void drawScene(Graphics g)
\r
335 boolean darker = false;
\r
337 int halfwidth = getSize().width / 2;
\r
338 int halfheight = getSize().height / 2;
\r
340 for (int i = 0; i < npoint; i++)
\r
342 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
343 int x = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
344 int y = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
345 float z = sp.coord[1] - centre[2];
\r
347 if (sp.sequence.getColor() == Color.black)
\r
349 g.setColor(Color.white);
\r
353 g.setColor(sp.sequence.getColor());
\r
356 if (av.getSelectionGroup() != null)
\r
358 if (av.getSelectionGroup().sequences.contains( ( (SequencePoint) points.
\r
359 elementAt(i)).sequence))
\r
361 g.setColor(Color.gray);
\r
366 g.setColor(g.getColor().darker());
\r
369 g.fillRect(x - 3, y - 3, 6, 6);
\r
370 g.setColor(Color.red);
\r
372 // //Now the rectangle
\r
373 // if (rectx2 != -1 && recty2 != -1) {
\r
374 // g.setColor(Color.white);
\r
376 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
\r
380 public Dimension minimumsize()
\r
385 public Dimension preferredsize()
\r
390 public void keyTyped(KeyEvent evt)
\r
393 public void keyReleased(KeyEvent evt)
\r
396 public void keyPressed(KeyEvent evt)
\r
399 if (evt.getKeyCode() == KeyEvent.VK_UP)
\r
401 scalefactor = (float) (scalefactor * 1.1);
\r
402 scale = findScale();
\r
404 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
\r
406 scalefactor = (float) (scalefactor * 0.9);
\r
407 scale = findScale();
\r
409 else if (evt.getKeyChar() == 's')
\r
411 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
412 if (rectx2 != -1 && recty2 != -1)
\r
414 rectSelect(rectx1, recty1, rectx2, recty2);
\r
421 public void printPoints()
\r
423 for (int i = 0; i < npoint; i++)
\r
425 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
426 Format.print(System.out, "%5d ", i);
\r
427 for (int j = 0; j < 3; j++)
\r
429 Format.print(System.out, "%13.3f ", sp.coord[j]);
\r
431 System.out.println();
\r
435 public void mouseClicked(MouseEvent evt)
\r
438 public void mouseEntered(MouseEvent evt)
\r
441 public void mouseExited(MouseEvent evt)
\r
444 public void mouseReleased(MouseEvent evt)
\r
447 public void mousePressed(MouseEvent evt)
\r
449 int x = evt.getX();
\r
450 int y = evt.getY();
\r
467 SequenceI found = findPoint(x, y);
\r
471 if (av.getSelectionGroup() != null)
\r
473 av.getSelectionGroup().addOrRemove(found, true);
\r
474 PaintRefresher.Refresh(this, av.alignment);
\r
478 av.setSelectionGroup(new SequenceGroup());
\r
479 av.getSelectionGroup().addOrRemove(found, true);
\r
480 av.getSelectionGroup().setEndRes(av.alignment.getWidth());
\r
487 // private void fireSequenceSelectionEvent(Selection sel) {
\r
488 // controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));
\r
491 public void mouseMoved(MouseEvent evt)
\r
493 // SequenceI found = findPoint(evt.getX(), evt.getY());
\r
496 public void mouseDragged(MouseEvent evt)
\r
500 //Check if this is a rectangle drawing drag
\r
501 if ( (evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)
\r
503 // rectx2 = evt.getX();
\r
504 // recty2 = evt.getY();
\r
508 rotmat.setIdentity();
\r
510 rotmat.rotate( (float) (my - omy), 'x');
\r
511 rotmat.rotate( (float) (mx - omx), 'y');
\r
513 for (int i = 0; i < npoint; i++)
\r
515 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
516 sp.coord[0] -= centre[0];
\r
517 sp.coord[1] -= centre[1];
\r
518 sp.coord[2] -= centre[2];
\r
520 //Now apply the rotation matrix
\r
521 sp.coord = rotmat.vectorMultiply(sp.coord);
\r
523 //Now translate back again
\r
524 sp.coord[0] += centre[0];
\r
525 sp.coord[1] += centre[1];
\r
526 sp.coord[2] += centre[2];
\r
529 for (int i = 0; i < 3; i++)
\r
531 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
536 paint(this.getGraphics());
\r
541 public void rectSelect(int x1, int y1, int x2, int y2)
\r
543 boolean changedSel = false;
\r
544 for (int i = 0; i < npoint; i++)
\r
546 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
547 int tmp1 = (int) ( (sp.coord[0] - centre[0]) * scale +
\r
548 (float) getSize().width / 2.0);
\r
549 int tmp2 = (int) ( (sp.coord[1] - centre[1]) * scale +
\r
550 (float) getSize().height / 2.0);
\r
552 if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)
\r
556 if (!av.getSelectionGroup().sequences.contains(sp.sequence))
\r
558 av.getSelectionGroup().addSequence(sp.sequence, true);
\r
565 public SequenceI findPoint(int x, int y)
\r
568 int halfwidth = getSize().width / 2;
\r
569 int halfheight = getSize().height / 2;
\r
573 for (int i = 0; i < npoint; i++)
\r
576 SequencePoint sp = (SequencePoint) points.elementAt(i);
\r
577 int px = (int) ( (float) (sp.coord[0] - centre[0]) * scale) + halfwidth;
\r
578 int py = (int) ( (float) (sp.coord[1] - centre[1]) * scale) + halfheight;
\r
580 if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)
\r
587 return ( (SequencePoint) points.elementAt(found)).sequence;
\r
594 /* public boolean handleRubberbandEvent(RubberbandEvent evt) {
\r
595 System.out.println("Rubberband handler called in RotatableCanvas with " +
\r
598 Rubberband rb = (Rubberband)evt.getSource();
\r
600 // Clear the current selection (instance variable)
\r
601 //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {
\r
602 // clearSelection();
\r
605 if (rb.getComponent() == this) {
\r
606 Rectangle bounds = evt.getBounds();
\r
607 rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);
\r
610 redrawneeded = true;
\r
611 paint(this.getGraphics());
\r