Remove redundancy in Eclipse
[jalview.git] / src / jalview / appletgui / RotatableCanvas.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\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
9  *\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
14  *\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
18  */\r
19 \r
20 package jalview.appletgui;\r
21 \r
22 import java.util.*;\r
23 \r
24 import java.awt.*;\r
25 import java.awt.event.*;\r
26 \r
27 import jalview.datamodel.*;\r
28 import jalview.math.*;\r
29 import jalview.util.*;\r
30 \r
31 public class RotatableCanvas\r
32     extends Panel implements MouseListener,\r
33     MouseMotionListener,\r
34     KeyListener\r
35 {\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
39 \r
40   //RubberbandRectangle rubberband;\r
41 \r
42   boolean drawAxes = true;\r
43 \r
44   int omx = 0;\r
45   int mx = 0;\r
46   int omy = 0;\r
47   int my = 0;\r
48 \r
49   Image img;\r
50   Graphics ig;\r
51 \r
52   Dimension prefsize;\r
53 \r
54   float centre[] = new float[3];\r
55   float width[] = new float[3];\r
56 \r
57   float max[] = new float[3];\r
58   float min[] = new float[3];\r
59 \r
60   float maxwidth;\r
61   float scale;\r
62 \r
63   int npoint;\r
64 \r
65   Vector points;\r
66   float[][] orig;\r
67   float[][] axes;\r
68 \r
69   int startx;\r
70   int starty;\r
71 \r
72   int lastx;\r
73   int lasty;\r
74 \r
75   int rectx1;\r
76   int recty1;\r
77   int rectx2;\r
78   int recty2;\r
79 \r
80   float scalefactor = 1;\r
81 \r
82   AlignViewport av;\r
83   boolean showLabels = false;\r
84 \r
85   public RotatableCanvas(AlignViewport av)\r
86   {\r
87     this.av = av;\r
88   }\r
89 \r
90   public void showLabels(boolean b)\r
91   {\r
92     showLabels = b;\r
93     repaint();\r
94   }\r
95 \r
96   public void setPoints(Vector points, int npoint)\r
97   {\r
98     this.points = points;\r
99     this.npoint = npoint;\r
100     PaintRefresher.Register(this, av.alignment);\r
101 \r
102     prefsize = getPreferredSize();\r
103     orig = new float[npoint][3];\r
104 \r
105     for (int i = 0; i < npoint; i++)\r
106     {\r
107       SequencePoint sp = (SequencePoint) points.elementAt(i);\r
108       for (int j = 0; j < 3; j++)\r
109       {\r
110         orig[i][j] = sp.coord[j];\r
111       }\r
112     }\r
113     //Initialize the matrices to identity\r
114 \r
115     for (int i = 0; i < 3; i++)\r
116     {\r
117       for (int j = 0; j < 3; j++)\r
118       {\r
119         if (i != j)\r
120         {\r
121           idmat.addElement(i, j, 0);\r
122           objmat.addElement(i, j, 0);\r
123           rotmat.addElement(i, j, 0);\r
124         }\r
125         else\r
126         {\r
127           idmat.addElement(i, j, 0);\r
128           objmat.addElement(i, j, 0);\r
129           rotmat.addElement(i, j, 0);\r
130         }\r
131       }\r
132     }\r
133 \r
134     axes = new float[3][3];\r
135     initAxes();\r
136 \r
137     findCentre();\r
138     findWidth();\r
139 \r
140     scale = findScale();\r
141 \r
142     //    System.out.println("Scale factor = " + scale);\r
143 \r
144     addMouseListener(this);\r
145     addKeyListener(this);\r
146     // if (getParent() != null) {\r
147     //   getParent().addKeyListener(this);\r
148     //}\r
149     addMouseMotionListener(this);\r
150 \r
151     // Add rubberband\r
152     //   rubberband  = new RubberbandRectangle(this);\r
153     //  rubberband.setActive(true);\r
154     //   rubberband.addListener(this);\r
155   }\r
156 \r
157   /* public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {\r
158      redrawneeded = true;\r
159      repaint();\r
160      return true;\r
161    }\r
162 \r
163    public void removeNotify() {\r
164      controller.removeListener(this);\r
165      super.removeNotify();\r
166    }*/\r
167 \r
168   public void initAxes()\r
169   {\r
170     for (int i = 0; i < 3; i++)\r
171     {\r
172       for (int j = 0; j < 3; j++)\r
173       {\r
174         if (i != j)\r
175         {\r
176           axes[i][j] = 0;\r
177         }\r
178         else\r
179         {\r
180           axes[i][j] = 1;\r
181         }\r
182       }\r
183     }\r
184   }\r
185 \r
186   public void findWidth()\r
187   {\r
188     max = new float[3];\r
189     min = new float[3];\r
190 \r
191     max[0] = (float) - 1e30;\r
192     max[1] = (float) - 1e30;\r
193     max[2] = (float) - 1e30;\r
194 \r
195     min[0] = (float) 1e30;\r
196     min[1] = (float) 1e30;\r
197     min[2] = (float) 1e30;\r
198 \r
199     for (int i = 0; i < 3; i++)\r
200     {\r
201       for (int j = 0; j < npoint; j++)\r
202       {\r
203         SequencePoint sp = (SequencePoint) points.elementAt(j);\r
204         if (sp.coord[i] >= max[i])\r
205         {\r
206           max[i] = sp.coord[i];\r
207         }\r
208         if (sp.coord[i] <= min[i])\r
209         {\r
210           min[i] = sp.coord[i];\r
211         }\r
212       }\r
213     }\r
214 \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
218 \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
222 \r
223     maxwidth = width[0];\r
224 \r
225     if (width[1] > width[0])\r
226     {\r
227       maxwidth = width[1];\r
228     }\r
229     if (width[2] > width[1])\r
230     {\r
231       maxwidth = width[2];\r
232     }\r
233 \r
234     //System.out.println("Maxwidth = " + maxwidth);\r
235   }\r
236 \r
237   public float findScale()\r
238   {\r
239     int dim, width, height;\r
240     if (getSize().width != 0)\r
241     {\r
242       width = getSize().width;\r
243       height = getSize().height;\r
244     }\r
245     else\r
246     {\r
247       width = prefsize.width;\r
248       height = prefsize.height;\r
249     }\r
250 \r
251     if (width < height)\r
252     {\r
253       dim = width;\r
254     }\r
255     else\r
256     {\r
257       dim = height;\r
258     }\r
259 \r
260     return (float) (dim * scalefactor / (2 * maxwidth));\r
261   }\r
262 \r
263   public void findCentre()\r
264   {\r
265     //Find centre coordinate\r
266     findWidth();\r
267 \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
271 \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
275   }\r
276 \r
277   public Dimension getPreferredSize()\r
278   {\r
279     if (prefsize != null)\r
280     {\r
281       return prefsize;\r
282     }\r
283     else\r
284     {\r
285       return new Dimension(400, 400);\r
286     }\r
287   }\r
288 \r
289   public Dimension getMinimumSize()\r
290   {\r
291     return getPreferredSize();\r
292   }\r
293 \r
294   public void paint(Graphics g)\r
295   {\r
296     if (points == null)\r
297     {\r
298       g.setFont(new Font("Verdana", Font.PLAIN, 18));\r
299       g.drawString("Calculating PCA....", 20, getSize().height / 2);\r
300     }\r
301     else\r
302     {\r
303 \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
307       {\r
308         prefsize.width = getSize().width;\r
309         prefsize.height = getSize().height;\r
310 \r
311         scale = findScale();\r
312 \r
313         //      System.out.println("New scale = " + scale);\r
314         img = createImage(getSize().width, getSize().height);\r
315         ig = img.getGraphics();\r
316 \r
317       }\r
318 \r
319       drawBackground(ig, Color.black);\r
320       drawScene(ig);\r
321       if (drawAxes == true)\r
322       {\r
323         drawAxes(ig);\r
324       }\r
325 \r
326       g.drawImage(img, 0, 0, this);\r
327     }\r
328   }\r
329 \r
330   public void drawAxes(Graphics g)\r
331   {\r
332 \r
333     g.setColor(Color.yellow);\r
334     for (int i = 0; i < 3; i++)\r
335     {\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
339     }\r
340   }\r
341 \r
342   public void drawBackground(Graphics g, Color col)\r
343   {\r
344     g.setColor(col);\r
345     g.fillRect(0, 0, prefsize.width, prefsize.height);\r
346   }\r
347 \r
348   public void drawScene(Graphics g)\r
349   {\r
350     //boolean darker = false;\r
351 \r
352     int halfwidth = getSize().width / 2;\r
353     int halfheight = getSize().height / 2;\r
354 \r
355     for (int i = 0; i < npoint; i++)\r
356     {\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
361 \r
362       if (sp.sequence.getColor() == Color.black)\r
363       {\r
364         g.setColor(Color.white);\r
365       }\r
366       else\r
367       {\r
368         g.setColor(sp.sequence.getColor());\r
369       }\r
370 \r
371       if (av.getSelectionGroup() != null)\r
372       {\r
373         if (av.getSelectionGroup().sequences.contains( ( (SequencePoint) points.\r
374             elementAt(i)).sequence))\r
375         {\r
376           g.setColor(Color.gray);\r
377         }\r
378       }\r
379       if (z < 0)\r
380       {\r
381         g.setColor(g.getColor().darker());\r
382       }\r
383 \r
384       g.fillRect(x - 3, y - 3, 6, 6);\r
385       if (showLabels)\r
386       {\r
387         g.setColor(Color.red);\r
388         g.drawString( ( (SequencePoint) points.elementAt(i)).sequence.\r
389                      getName(),\r
390                      x - 3, y - 4);\r
391       }\r
392 \r
393     }\r
394 //    //Now the rectangle\r
395 //    if (rectx2 != -1 && recty2 != -1) {\r
396 //      g.setColor(Color.white);\r
397 //\r
398 //      g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);\r
399 //    }\r
400   }\r
401 \r
402   public Dimension minimumsize()\r
403   {\r
404     return prefsize;\r
405   }\r
406 \r
407   public Dimension preferredsize()\r
408   {\r
409     return prefsize;\r
410   }\r
411 \r
412   public void keyTyped(KeyEvent evt)\r
413   {}\r
414 \r
415   public void keyReleased(KeyEvent evt)\r
416   {}\r
417 \r
418   public void keyPressed(KeyEvent evt)\r
419   {\r
420     requestFocus();\r
421     if (evt.getKeyCode() == KeyEvent.VK_UP)\r
422     {\r
423       scalefactor = (float) (scalefactor * 1.1);\r
424       scale = findScale();\r
425     }\r
426     else if (evt.getKeyCode() == KeyEvent.VK_DOWN)\r
427     {\r
428       scalefactor = (float) (scalefactor * 0.9);\r
429       scale = findScale();\r
430     }\r
431     else if (evt.getKeyChar() == 's')\r
432     {\r
433       System.err.println("DEBUG: Rectangle selection"); // log.debug\r
434       if (rectx2 != -1 && recty2 != -1)\r
435       {\r
436         rectSelect(rectx1, recty1, rectx2, recty2);\r
437 \r
438       }\r
439     }\r
440     repaint();\r
441   }\r
442 \r
443   public void printPoints()\r
444   {\r
445     for (int i = 0; i < npoint; i++)\r
446     {\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
450       {\r
451         Format.print(System.out, "%13.3f  ", sp.coord[j]);\r
452       }\r
453       System.out.println();\r
454     }\r
455   }\r
456 \r
457   public void mouseClicked(MouseEvent evt)\r
458   {}\r
459 \r
460   public void mouseEntered(MouseEvent evt)\r
461   {}\r
462 \r
463   public void mouseExited(MouseEvent evt)\r
464   {}\r
465 \r
466   public void mouseReleased(MouseEvent evt)\r
467   {}\r
468 \r
469   public void mousePressed(MouseEvent evt)\r
470   {\r
471     int x = evt.getX();\r
472     int y = evt.getY();\r
473 \r
474     mx = x;\r
475     my = y;\r
476 \r
477     omx = mx;\r
478     omy = my;\r
479 \r
480     startx = x;\r
481     starty = y;\r
482 \r
483     rectx1 = x;\r
484     recty1 = y;\r
485 \r
486     rectx2 = -1;\r
487     recty2 = -1;\r
488 \r
489     SequenceI found = findPoint(x, y);\r
490 \r
491     if (found != null)\r
492     {\r
493       if (av.getSelectionGroup() != null)\r
494       {\r
495         av.getSelectionGroup().addOrRemove(found, true);\r
496         av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);\r
497         PaintRefresher.Refresh(this, av.alignment);\r
498       }\r
499       else\r
500       {\r
501         av.setSelectionGroup(new SequenceGroup());\r
502         av.getSelectionGroup().addOrRemove(found, true);\r
503         av.getSelectionGroup().setEndRes(av.alignment.getWidth()-1);\r
504 \r
505       }\r
506     }\r
507     repaint();\r
508   }\r
509 \r
510   // private void fireSequenceSelectionEvent(Selection sel) {\r
511   //   controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));\r
512   //}\r
513 \r
514   public void mouseMoved(MouseEvent evt)\r
515   {\r
516     // SequenceI found = findPoint(evt.getX(), evt.getY());\r
517   }\r
518 \r
519   public void mouseDragged(MouseEvent evt)\r
520   {\r
521     mx = evt.getX();\r
522     my = evt.getY();\r
523     //Check if this is a rectangle drawing drag\r
524     if ( (evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0)\r
525     {\r
526 //      rectx2 = evt.getX();\r
527 //      recty2 = evt.getY();\r
528     }\r
529     else\r
530     {\r
531       rotmat.setIdentity();\r
532 \r
533       rotmat.rotate( (float) (my - omy), 'x');\r
534       rotmat.rotate( (float) (mx - omx), 'y');\r
535 \r
536       for (int i = 0; i < npoint; i++)\r
537       {\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
542 \r
543         //Now apply the rotation matrix\r
544         sp.coord = rotmat.vectorMultiply(sp.coord);\r
545 \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
550       }\r
551 \r
552       for (int i = 0; i < 3; i++)\r
553       {\r
554         axes[i] = rotmat.vectorMultiply(axes[i]);\r
555       }\r
556       omx = mx;\r
557       omy = my;\r
558 \r
559       paint(this.getGraphics());\r
560     }\r
561 \r
562   }\r
563 \r
564   public void rectSelect(int x1, int y1, int x2, int y2)\r
565   {\r
566     //boolean changedSel = false;\r
567     for (int i = 0; i < npoint; i++)\r
568     {\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
574 \r
575       if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)\r
576       {\r
577         if (av != null)\r
578         {\r
579           if (!av.getSelectionGroup().sequences.contains(sp.sequence))\r
580           {\r
581             av.getSelectionGroup().addSequence(sp.sequence, true);\r
582           }\r
583         }\r
584       }\r
585     }\r
586   }\r
587 \r
588   public SequenceI findPoint(int x, int y)\r
589   {\r
590 \r
591     int halfwidth = getSize().width / 2;\r
592     int halfheight = getSize().height / 2;\r
593 \r
594     int found = -1;\r
595 \r
596     for (int i = 0; i < npoint; i++)\r
597     {\r
598 \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
602 \r
603       if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)\r
604       {\r
605         found = i;\r
606       }\r
607     }\r
608     if (found != -1)\r
609     {\r
610       return ( (SequencePoint) points.elementAt(found)).sequence;\r
611     }\r
612     else\r
613     {\r
614       return null;\r
615     }\r
616   }\r
617   /*  public boolean handleRubberbandEvent(RubberbandEvent evt) {\r
618       System.out.println("Rubberband handler called in RotatableCanvas with " +\r
619                          evt.getBounds());\r
620 \r
621       Rubberband rb = (Rubberband)evt.getSource();\r
622 \r
623       // Clear the current selection (instance variable)\r
624       //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {\r
625       //   clearSelection();\r
626       //}\r
627 \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
631       }\r
632 \r
633       redrawneeded = true;\r
634       paint(this.getGraphics());\r
635 \r
636       return true;\r
637     }*/\r
638 \r
639 }\r