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
22 import jalview.math.*;
\r
23 import jalview.datamodel.*;
\r
24 import jalview.util.*;
\r
27 import java.awt.event.*;
\r
31 public class RotatableCanvas extends Panel implements MouseListener,
\r
32 MouseMotionListener,
\r
34 //RubberbandListener,
\r
35 //SequenceSelectionListener
\r
37 RotatableMatrix idmat = new RotatableMatrix(3,3);
\r
38 RotatableMatrix objmat = new RotatableMatrix(3,3);
\r
39 RotatableMatrix rotmat = new RotatableMatrix(3,3);
\r
41 //RubberbandRectangle rubberband;
\r
43 boolean drawAxes = true;
\r
55 float centre[] = new float[3];
\r
56 float width[] = new float[3];
\r
58 float max[] = new float[3];
\r
59 float min[] = new float[3];
\r
81 float scalefactor = 1;
\r
84 // Controller controller;
\r
87 public RotatableCanvas(AlignViewport av,
\r
88 Vector points, int npoint) {
\r
89 this.points = points;
\r
90 this.npoint = npoint;
\r
92 PaintRefresher.Register(this);
\r
94 prefsize = getPreferredSize();
\r
95 orig = new float[npoint][3];
\r
97 for (int i=0; i < npoint; i++) {
\r
98 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
99 for (int j=0; j < 3; j++) {
\r
100 orig[i][j] = sp.coord[j];
\r
103 //Initialize the matrices to identity
\r
105 for (int i = 0; i < 3; i++) {
\r
106 for (int j = 0; j < 3 ; j++) {
\r
108 idmat.addElement(i,j,0);
\r
109 objmat.addElement(i,j,0);
\r
110 rotmat.addElement(i,j,0);
\r
112 idmat.addElement(i,j,0);
\r
113 objmat.addElement(i,j,0);
\r
114 rotmat.addElement(i,j,0);
\r
119 axes = new float[3][3];
\r
125 scale = findScale();
\r
127 // System.out.println("Scale factor = " + scale);
\r
129 addMouseListener(this);
\r
130 addKeyListener(this);
\r
131 // if (getParent() != null) {
\r
132 // getParent().addKeyListener(this);
\r
134 addMouseMotionListener(this);
\r
137 // rubberband = new RubberbandRectangle(this);
\r
138 // rubberband.setActive(true);
\r
139 // rubberband.addListener(this);
\r
142 /* public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {
\r
143 redrawneeded = true;
\r
148 public void removeNotify() {
\r
149 controller.removeListener(this);
\r
150 super.removeNotify();
\r
153 public void initAxes() {
\r
154 for (int i = 0; i < 3; i++) {
\r
155 for (int j=0; j < 3; j++) {
\r
165 public void findWidth() {
\r
166 max = new float[3];
\r
167 min = new float[3];
\r
169 max[0] = (float)-1e30;
\r
170 max[1] = (float)-1e30;
\r
171 max[2] = (float)-1e30;
\r
173 min[0] = (float)1e30;
\r
174 min[1] = (float)1e30;
\r
175 min[2] = (float)1e30;
\r
177 for (int i = 0; i < 3; i++) {
\r
178 for (int j = 0; j < npoint; j++) {
\r
179 SequencePoint sp = (SequencePoint)points.elementAt(j);
\r
180 if (sp.coord[i] >= max[i]) {
\r
181 max[i] = sp.coord[i];
\r
183 if (sp.coord[i] <= min[i]) {
\r
184 min[i] = sp.coord[i];
\r
189 // System.out.println("xmax " + max[0] + " min " + min[0]);
\r
190 //System.out.println("ymax " + max[1] + " min " + min[1]);
\r
191 //System.out.println("zmax " + max[2] + " min " + min[2]);
\r
193 width[0] = Math.abs(max[0] - min[0]);
\r
194 width[1] = Math.abs(max[1] - min[1]);
\r
195 width[2] = Math.abs(max[2] - min[2]);
\r
197 maxwidth = width[0];
\r
199 if (width[1] > width[0])
\r
200 maxwidth = width[1];
\r
201 if (width[2] > width[1])
\r
202 maxwidth = width[2];
\r
204 //System.out.println("Maxwidth = " + maxwidth);
\r
207 public float findScale() {
\r
208 int dim, width, height;
\r
209 if (getSize().width != 0) {
\r
210 width = getSize().width;
\r
211 height = getSize().height;
\r
213 width = prefsize.width;
\r
214 height = prefsize.height;
\r
217 if (width < height) {
\r
223 return (float)(dim*scalefactor/(2*maxwidth));
\r
226 public void findCentre() {
\r
227 //Find centre coordinate
\r
230 centre[0] = (max[0] + min[0])/2;
\r
231 centre[1] = (max[1] + min[1])/2;
\r
232 centre[2] = (max[2] + min[2])/2;
\r
234 // System.out.println("Centre x " + centre[0]);
\r
235 //System.out.println("Centre y " + centre[1]);
\r
236 //System.out.println("Centre z " + centre[2]);
\r
239 public Dimension getPreferredSize() {
\r
240 if (prefsize != null) {
\r
243 return new Dimension(400,400);
\r
247 public Dimension getMinimumSize() {
\r
248 return getPreferredSize();
\r
251 public void paint(Graphics g) {
\r
252 //Only create the image at the beginning -
\r
253 if ((img == null) || (prefsize.width != getSize().width) || (prefsize.height != getSize().height)) {
\r
254 prefsize.width = getSize().width;
\r
255 prefsize.height = getSize().height;
\r
257 scale = findScale();
\r
259 // System.out.println("New scale = " + scale);
\r
260 img = createImage(getSize().width,getSize().height);
\r
261 ig = img.getGraphics();
\r
266 drawBackground(ig,Color.black);
\r
268 if (drawAxes == true)
\r
274 g.drawImage(img,0,0,this);
\r
277 public void drawAxes(Graphics g) {
\r
279 g.setColor(Color.yellow);
\r
280 for (int i=0; i < 3 ; i++) {
\r
281 g.drawLine(getSize().width/2,getSize().height/2,
\r
282 (int)(axes[i][0]*scale*max[0] + getSize().width/2),
\r
283 (int)(axes[i][1]*scale*max[1] + getSize().height/2));
\r
287 public void drawBackground(Graphics g, Color col) {
\r
289 g.fillRect(0,0,prefsize.width,prefsize.height);
\r
293 public void drawScene(Graphics g) {
\r
294 boolean darker = false;
\r
296 int halfwidth = getSize().width/2;
\r
297 int halfheight = getSize().height/2;
\r
299 for (int i = 0; i < npoint; i++) {
\r
300 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
301 int x = (int)((float)(sp.coord[0] - centre[0])*scale) + halfwidth;
\r
302 int y = (int)((float)(sp.coord[1] - centre[1])*scale) + halfheight;
\r
303 float z = sp.coord[1] - centre[2];
\r
308 if (sp.sequence.getColor() == Color.black)
\r
309 g.setColor(Color.white);
\r
311 g.setColor(sp.sequence.getColor());
\r
314 if (av.getSelectionGroup() != null)
\r
316 if (av.getSelectionGroup().sequences.contains(((SequencePoint)points.elementAt(i)).sequence))
\r
317 g.setColor(Color.gray);
\r
320 g.setColor(g.getColor().darker());
\r
323 g.fillRect(x-3,y-3,6,6);
\r
324 g.setColor(Color.red);
\r
326 // //Now the rectangle
\r
327 // if (rectx2 != -1 && recty2 != -1) {
\r
328 // g.setColor(Color.white);
\r
330 // g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);
\r
334 public Dimension minimumsize() {
\r
338 public Dimension preferredsize() {
\r
342 public void keyTyped(KeyEvent evt) { }
\r
343 public void keyReleased(KeyEvent evt) { }
\r
345 public void keyPressed(KeyEvent evt) {
\r
347 if (evt.getKeyCode() == KeyEvent.VK_UP) {
\r
348 scalefactor = (float)(scalefactor * 1.1);
\r
349 scale = findScale();
\r
350 } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) {
\r
351 scalefactor = (float)(scalefactor * 0.9);
\r
352 scale = findScale();
\r
353 } else if (evt.getKeyChar() == 's') {
\r
354 System.err.println("DEBUG: Rectangle selection"); // log.debug
\r
355 if (rectx2 != -1 && recty2 != -1) {
\r
356 rectSelect(rectx1,recty1,rectx2,recty2);
\r
363 public void printPoints() {
\r
364 for (int i=0; i < npoint; i++) {
\r
365 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
366 Format.print(System.out,"%5d ", i);
\r
367 for (int j=0; j < 3;j++) {
\r
368 Format.print(System.out,"%13.3f ",sp.coord[j]);
\r
370 System.out.println();
\r
374 public void mouseClicked(MouseEvent evt) { }
\r
375 public void mouseEntered(MouseEvent evt) { }
\r
376 public void mouseExited(MouseEvent evt) { }
\r
377 public void mouseReleased(MouseEvent evt) { }
\r
379 public void mousePressed(MouseEvent evt) {
\r
380 int x = evt.getX();
\r
381 int y = evt.getY();
\r
398 SequenceI found = findPoint(x,y);
\r
402 if (av.getSelectionGroup() != null)
\r
404 av.getSelectionGroup().addOrRemove(found);
\r
405 PaintRefresher.Refresh(this);
\r
409 av.setSelectionGroup(new SequenceGroup());
\r
410 av.getSelectionGroup().addOrRemove(found);
\r
411 av.getSelectionGroup().setEndRes(av.alignment.getWidth());
\r
418 // private void fireSequenceSelectionEvent(Selection sel) {
\r
419 // controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));
\r
422 public void mouseMoved(MouseEvent evt)
\r
424 // SequenceI found = findPoint(evt.getX(), evt.getY());
\r
427 public void mouseDragged(MouseEvent evt) {
\r
430 //Check if this is a rectangle drawing drag
\r
431 if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0) {
\r
432 // rectx2 = evt.getX();
\r
433 // recty2 = evt.getY();
\r
435 rotmat.setIdentity();
\r
437 rotmat.rotate((float)(my-omy),'x');
\r
438 rotmat.rotate((float)(mx-omx),'y');
\r
440 for (int i = 0; i < npoint; i++) {
\r
441 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
442 sp.coord[0] -= centre[0];
\r
443 sp.coord[1] -= centre[1];
\r
444 sp.coord[2] -= centre[2];
\r
446 //Now apply the rotation matrix
\r
447 sp.coord= rotmat.vectorMultiply(sp.coord);
\r
449 //Now translate back again
\r
450 sp.coord[0] += centre[0];
\r
451 sp.coord[1] += centre[1];
\r
452 sp.coord[2] += centre[2];
\r
455 for (int i=0; i < 3; i++) {
\r
456 axes[i] = rotmat.vectorMultiply(axes[i]);
\r
461 paint(this.getGraphics());
\r
466 public void rectSelect(int x1, int y1, int x2, int y2) {
\r
467 boolean changedSel = false;
\r
468 for (int i=0; i < npoint; i++) {
\r
469 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
470 int tmp1 = (int)((sp.coord[0] - centre[0])*scale + (float)getSize().width/2.0);
\r
471 int tmp2 = (int)((sp.coord[1] - centre[1])*scale + (float)getSize().height/2.0);
\r
473 if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2) {
\r
475 if (!av.getSelectionGroup().sequences.contains(sp.sequence))
\r
478 av.getSelectionGroup().addSequence(sp.sequence);
\r
483 // if (changedSel) {
\r
484 // fireSequenceSelectionEvent(av.getSelection());
\r
487 public SequenceI findPoint(int x, int y) {
\r
489 int halfwidth = getSize().width/2;
\r
490 int halfheight = getSize().height/2;
\r
494 for (int i=0; i < npoint; i++) {
\r
496 SequencePoint sp = (SequencePoint)points.elementAt(i);
\r
497 int px = (int)((float)(sp.coord[0] - centre[0])*scale) + halfwidth;
\r
498 int py = (int)((float)(sp.coord[1] - centre[1])*scale) + halfheight;
\r
501 if (Math.abs(px-x)<3 && Math.abs(py - y) < 3 ) {
\r
506 return ((SequencePoint)points.elementAt(found)).sequence;
\r
511 /* public boolean handleRubberbandEvent(RubberbandEvent evt) {
\r
512 System.out.println("Rubberband handler called in RotatableCanvas with " +
\r
515 Rubberband rb = (Rubberband)evt.getSource();
\r
517 // Clear the current selection (instance variable)
\r
518 //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {
\r
519 // clearSelection();
\r
522 if (rb.getComponent() == this) {
\r
523 Rectangle bounds = evt.getBounds();
\r
524 rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);
\r
527 redrawneeded = true;
\r
528 paint(this.getGraphics());
\r