2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.appletgui;
23 import jalview.api.RotatableCanvasI;
24 import jalview.datamodel.SequenceGroup;
25 import jalview.datamodel.SequenceI;
26 import jalview.datamodel.SequencePoint;
27 import jalview.math.RotatableMatrix;
28 import jalview.util.Format;
29 import jalview.util.MessageManager;
30 import jalview.viewmodel.AlignmentViewport;
32 import java.awt.Color;
33 import java.awt.Dimension;
35 import java.awt.Graphics;
36 import java.awt.Image;
37 import awt2swing.Panel;
38 import java.awt.event.KeyEvent;
39 import java.awt.event.KeyListener;
40 import java.awt.event.MouseEvent;
41 import java.awt.event.MouseListener;
42 import java.awt.event.MouseMotionListener;
43 import java.util.Vector;
45 public class RotatableCanvas extends Panel implements MouseListener,
46 MouseMotionListener, KeyListener, RotatableCanvasI
48 RotatableMatrix idmat = new RotatableMatrix(3, 3);
50 RotatableMatrix objmat = new RotatableMatrix(3, 3);
52 RotatableMatrix rotmat = new RotatableMatrix(3, 3);
58 // RubberbandRectangle rubberband;
60 boolean drawAxes = true;
76 float centre[] = new float[3];
78 float width[] = new float[3];
80 float max[] = new float[3];
82 float min[] = new float[3];
112 float scalefactor = 1;
114 AlignmentViewport av;
116 boolean showLabels = false;
118 public RotatableCanvas(AlignmentViewport av)
123 public void showLabels(boolean b)
129 public void setPoints(Vector points, int npoint)
131 this.points = points;
132 this.npoint = npoint;
133 PaintRefresher.Register(this, av.getSequenceSetId());
135 prefsize = getPreferredSize();
136 orig = new float[npoint][3];
138 for (int i = 0; i < npoint; i++)
140 SequencePoint sp = (SequencePoint) points.elementAt(i);
141 for (int j = 0; j < 3; j++)
143 orig[i][j] = sp.coord[j];
146 // Initialize the matrices to identity
148 for (int i = 0; i < 3; i++)
150 for (int j = 0; j < 3; j++)
154 idmat.addElement(i, j, 0);
155 objmat.addElement(i, j, 0);
156 rotmat.addElement(i, j, 0);
160 idmat.addElement(i, j, 0);
161 objmat.addElement(i, j, 0);
162 rotmat.addElement(i, j, 0);
167 axes = new float[3][3];
175 // System.out.println("Scale factor = " + scale);
177 addMouseListener(this);
178 addKeyListener(this);
179 // if (getParent() != null) {
180 // getParent().addKeyListener(this);
182 addMouseMotionListener(this);
185 // rubberband = new RubberbandRectangle(this);
186 // rubberband.setActive(true);
187 // rubberband.addListener(this);
191 * public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {
192 * redrawneeded = true; repaint(); return true; }
194 * public void removeNotify() { controller.removeListener(this);
195 * super.removeNotify(); }
198 public void initAxes()
200 for (int i = 0; i < 3; i++)
202 for (int j = 0; j < 3; j++)
216 public void findWidth()
221 max[0] = (float) -1e30;
222 max[1] = (float) -1e30;
223 max[2] = (float) -1e30;
225 min[0] = (float) 1e30;
226 min[1] = (float) 1e30;
227 min[2] = (float) 1e30;
229 for (int i = 0; i < 3; i++)
231 for (int j = 0; j < npoint; j++)
233 SequencePoint sp = (SequencePoint) points.elementAt(j);
234 if (sp.coord[i] >= max[i])
236 max[i] = sp.coord[i];
238 if (sp.coord[i] <= min[i])
240 min[i] = sp.coord[i];
245 // System.out.println("xmax " + max[0] + " min " + min[0]);
246 // System.out.println("ymax " + max[1] + " min " + min[1]);
247 // System.out.println("zmax " + max[2] + " min " + min[2]);
249 width[0] = Math.abs(max[0] - min[0]);
250 width[1] = Math.abs(max[1] - min[1]);
251 width[2] = Math.abs(max[2] - min[2]);
255 if (width[1] > width[0])
259 if (width[2] > width[1])
264 // System.out.println("Maxwidth = " + maxwidth);
267 public float findScale()
269 int dim, width, height;
270 if (getSize().width != 0)
272 width = getSize().width;
273 height = getSize().height;
277 width = prefsize.width;
278 height = prefsize.height;
290 return dim * scalefactor / (2 * maxwidth);
293 public void findCentre()
295 // Find centre coordinate
298 centre[0] = (max[0] + min[0]) / 2;
299 centre[1] = (max[1] + min[1]) / 2;
300 centre[2] = (max[2] + min[2]) / 2;
302 // System.out.println("Centre x " + centre[0]);
303 // System.out.println("Centre y " + centre[1]);
304 // System.out.println("Centre z " + centre[2]);
307 public Dimension getPreferredSize()
309 if (prefsize != null)
315 return new Dimension(400, 400);
319 public Dimension getMinimumSize()
321 return getPreferredSize();
324 public void update(Graphics g)
329 public void PaintComponent(Graphics g)
333 g.setFont(new Font("Verdana", Font.PLAIN, 18));
334 awt2swing.Util.drawString(g, MessageManager.getString("label.calculating_pca")
335 + "....", 20, getSize().height / 2);
340 // Only create the image at the beginning -
341 if ((img == null) || (prefsize.width != getSize().width)
342 || (prefsize.height != getSize().height))
344 prefsize.width = getSize().width;
345 prefsize.height = getSize().height;
349 // System.out.println("New scale = " + scale);
350 img = createImage(getSize().width, getSize().height);
351 ig = img.getGraphics();
355 drawBackground(ig, Color.black);
357 if (drawAxes == true)
364 ig.setColor(Color.red);
365 awt2swing.Util.drawString(ig, tooltip, toolx, tooly);
368 g.drawImage(img, 0, 0, this);
372 public void drawAxes(Graphics g)
375 g.setColor(Color.yellow);
376 for (int i = 0; i < 3; i++)
378 g.drawLine(getSize().width / 2, getSize().height / 2,
379 (int) (axes[i][0] * scale * max[0] + getSize().width / 2),
380 (int) (axes[i][1] * scale * max[1] + getSize().height / 2));
384 public void drawBackground(Graphics g, Color col)
387 g.fillRect(0, 0, prefsize.width, prefsize.height);
390 public void drawScene(Graphics g)
392 // boolean darker = false;
394 int halfwidth = getSize().width / 2;
395 int halfheight = getSize().height / 2;
397 for (int i = 0; i < npoint; i++)
399 SequencePoint sp = (SequencePoint) points.elementAt(i);
400 int x = (int) ((sp.coord[0] - centre[0]) * scale) + halfwidth;
401 int y = (int) ((sp.coord[1] - centre[1]) * scale)
403 float z = sp.coord[1] - centre[2];
405 if (av.getSequenceColour(sp.sequence) == Color.black)
407 g.setColor(Color.white);
411 g.setColor(av.getSequenceColour(sp.sequence));
414 if (av.getSelectionGroup() != null)
416 if (av.getSelectionGroup().getSequences(null)
417 .contains(((SequencePoint) points.elementAt(i)).sequence))
419 g.setColor(Color.gray);
424 g.setColor(g.getColor().darker());
427 g.fillRect(x - 3, y - 3, 6, 6);
430 g.setColor(Color.red);
431 awt2swing.Util.drawString(g,
432 ((SequencePoint) points.elementAt(i)).sequence.getName(),
438 public Dimension minimumsize()
443 public Dimension preferredsize()
448 public void keyTyped(KeyEvent evt)
452 public void keyReleased(KeyEvent evt)
456 public void keyPressed(KeyEvent evt)
458 if (evt.getKeyCode() == KeyEvent.VK_UP)
460 scalefactor = (float) (scalefactor * 1.1);
463 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
465 scalefactor = (float) (scalefactor * 0.9);
468 else if (evt.getKeyChar() == 's')
470 System.err.println("DEBUG: Rectangle selection"); // log.debug
471 if (rectx2 != -1 && recty2 != -1)
473 rectSelect(rectx1, recty1, rectx2, recty2);
480 public void printPoints()
482 for (int i = 0; i < npoint; i++)
484 SequencePoint sp = (SequencePoint) points.elementAt(i);
485 Format.printLong(System.out, "%5d ", i);
486 for (int j = 0; j < 3; j++)
488 Format.printDouble(System.out, "%13.3f ", sp.coord[j]);
490 System.out.println();
494 public void mouseClicked(MouseEvent evt)
498 public void mouseEntered(MouseEvent evt)
502 public void mouseExited(MouseEvent evt)
506 public void mouseReleased(MouseEvent evt)
510 public void mousePressed(MouseEvent evt)
530 SequenceI found = findPoint(x, y);
534 // TODO: applet PCA is not associatable with multi-panels - only parent
536 if (av.getSelectionGroup() != null)
538 av.getSelectionGroup().addOrRemove(found, true);
539 av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
543 av.setSelectionGroup(new SequenceGroup());
544 av.getSelectionGroup().addOrRemove(found, true);
545 av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);
548 PaintRefresher.Refresh(this, av.getSequenceSetId());
554 public void mouseMoved(MouseEvent evt)
556 SequenceI found = findPoint(evt.getX(), evt.getY());
563 tooltip = found.getName();
570 public void mouseDragged(MouseEvent evt)
575 rotmat.setIdentity();
577 rotmat.rotate(my - omy, 'x');
578 rotmat.rotate(mx - omx, 'y');
580 for (int i = 0; i < npoint; i++)
582 SequencePoint sp = (SequencePoint) points.elementAt(i);
583 sp.coord[0] -= centre[0];
584 sp.coord[1] -= centre[1];
585 sp.coord[2] -= centre[2];
587 // Now apply the rotation matrix
588 sp.coord = rotmat.vectorMultiply(sp.coord);
590 // Now translate back again
591 sp.coord[0] += centre[0];
592 sp.coord[1] += centre[1];
593 sp.coord[2] += centre[2];
596 for (int i = 0; i < 3; i++)
598 axes[i] = rotmat.vectorMultiply(axes[i]);
603 paint(this.getGraphics());
606 public void rectSelect(int x1, int y1, int x2, int y2)
608 // boolean changedSel = false;
609 for (int i = 0; i < npoint; i++)
611 SequencePoint sp = (SequencePoint) points.elementAt(i);
612 int tmp1 = (int) ((sp.coord[0] - centre[0]) * scale + getSize().width / 2.0);
613 int tmp2 = (int) ((sp.coord[1] - centre[1]) * scale + getSize().height / 2.0);
615 if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)
619 if (!av.getSelectionGroup().getSequences(null)
620 .contains(sp.sequence))
622 av.getSelectionGroup().addSequence(sp.sequence, true);
629 public SequenceI findPoint(int x, int y)
632 int halfwidth = getSize().width / 2;
633 int halfheight = getSize().height / 2;
637 for (int i = 0; i < npoint; i++)
640 SequencePoint sp = (SequencePoint) points.elementAt(i);
641 int px = (int) ((sp.coord[0] - centre[0]) * scale)
643 int py = (int) ((sp.coord[1] - centre[1]) * scale)
646 if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)
653 return ((SequencePoint) points.elementAt(found)).sequence;