798dae0284665ab2678055a3c9c11f6b75277389
[jalviewjs.git] / unused / appletgui / RotatableCanvas.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)\r
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors\r
4  * \r
5  * This file is part of Jalview.\r
6  * \r
7  * Jalview is free software: you can redistribute it and/or\r
8  * modify it under the terms of the GNU General Public License \r
9  * as published by the Free Software Foundation, either version 3\r
10  * of the License, or (at your option) any later version.\r
11  *  \r
12  * Jalview is distributed in the hope that it will be useful, but \r
13  * WITHOUT ANY WARRANTY; without even the implied warranty \r
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
15  * PURPOSE.  See the GNU General Public License for more details.\r
16  * \r
17  * You should have received a copy of the GNU General Public License\r
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
19  * The Jalview Authors are detailed in the 'AUTHORS' file.\r
20  */\r
21 package jalview.appletgui;\r
22 \r
23 import jalview.api.RotatableCanvasI;\r
24 import jalview.datamodel.SequenceGroup;\r
25 import jalview.datamodel.SequenceI;\r
26 import jalview.datamodel.SequencePoint;\r
27 import jalview.math.RotatableMatrix;\r
28 import jalview.util.Format;\r
29 import jalview.util.MessageManager;\r
30 import jalview.viewmodel.AlignmentViewport;\r
31 \r
32 import java.awt.Color;\r
33 import java.awt.Dimension;\r
34 import java.awt.Font;\r
35 import java.awt.Graphics;\r
36 import java.awt.Image;\r
37 import javax.swing.JPanel;\r
38 import java.awt.event.KeyEvent;\r
39 import java.awt.event.KeyListener;\r
40 import java.awt.event.MouseEvent;\r
41 import java.awt.event.MouseListener;\r
42 import java.awt.event.MouseMotionListener;\r
43 import java.util.Vector;\r
44 \r
45 public class RotatableCanvas extends JPanel implements MouseListener,\r
46         MouseMotionListener, KeyListener, RotatableCanvasI\r
47 {\r
48   RotatableMatrix idmat = new RotatableMatrix(3, 3);\r
49 \r
50   RotatableMatrix objmat = new RotatableMatrix(3, 3);\r
51 \r
52   RotatableMatrix rotmat = new RotatableMatrix(3, 3);\r
53 \r
54   String tooltip;\r
55 \r
56   int toolx, tooly;\r
57 \r
58   // RubberbandRectangle rubberband;\r
59 \r
60   boolean drawAxes = true;\r
61 \r
62   int omx = 0;\r
63 \r
64   int mx = 0;\r
65 \r
66   int omy = 0;\r
67 \r
68   int my = 0;\r
69 \r
70   Image img;\r
71 \r
72   Graphics ig;\r
73 \r
74   Dimension prefsize;\r
75 \r
76   float centre[] = new float[3];\r
77 \r
78   float width[] = new float[3];\r
79 \r
80   float max[] = new float[3];\r
81 \r
82   float min[] = new float[3];\r
83 \r
84   float maxwidth;\r
85 \r
86   float scale;\r
87 \r
88   int npoint;\r
89 \r
90   Vector points;\r
91 \r
92   float[][] orig;\r
93 \r
94   float[][] axes;\r
95 \r
96   int startx;\r
97 \r
98   int starty;\r
99 \r
100   int lastx;\r
101 \r
102   int lasty;\r
103 \r
104   int rectx1;\r
105 \r
106   int recty1;\r
107 \r
108   int rectx2;\r
109 \r
110   int recty2;\r
111 \r
112   float scalefactor = 1;\r
113 \r
114   AlignmentViewport av;\r
115 \r
116   boolean showLabels = false;\r
117 \r
118   public RotatableCanvas(AlignmentViewport av)\r
119   {\r
120     this.av = av;\r
121   }\r
122 \r
123   public void showLabels(boolean b)\r
124   {\r
125     showLabels = b;\r
126     repaint();\r
127   }\r
128 \r
129   public void setPoints(Vector points, int npoint)\r
130   {\r
131     this.points = points;\r
132     this.npoint = npoint;\r
133     PaintRefresher.Register(this, av.getSequenceSetId());\r
134 \r
135     prefsize = getPreferredSize();\r
136     orig = new float[npoint][3];\r
137 \r
138     for (int i = 0; i < npoint; i++)\r
139     {\r
140       SequencePoint sp = (SequencePoint) points.elementAt(i);\r
141       for (int j = 0; j < 3; j++)\r
142       {\r
143         orig[i][j] = sp.coord[j];\r
144       }\r
145     }\r
146     // Initialize the matrices to identity\r
147 \r
148     for (int i = 0; i < 3; i++)\r
149     {\r
150       for (int j = 0; j < 3; j++)\r
151       {\r
152         if (i != j)\r
153         {\r
154           idmat.addElement(i, j, 0);\r
155           objmat.addElement(i, j, 0);\r
156           rotmat.addElement(i, j, 0);\r
157         }\r
158         else\r
159         {\r
160           idmat.addElement(i, j, 0);\r
161           objmat.addElement(i, j, 0);\r
162           rotmat.addElement(i, j, 0);\r
163         }\r
164       }\r
165     }\r
166 \r
167     axes = new float[3][3];\r
168     initAxes();\r
169 \r
170     findCentre();\r
171     findWidth();\r
172 \r
173     scale = findScale();\r
174 \r
175     // System.out.println("Scale factor = " + scale);\r
176 \r
177     addMouseListener(this);\r
178     addKeyListener(this);\r
179     // if (getParent() != null) {\r
180     // getParent().addKeyListener(this);\r
181     // }\r
182     addMouseMotionListener(this);\r
183 \r
184     // Add rubberband\r
185     // rubberband = new RubberbandRectangle(this);\r
186     // rubberband.setActive(true);\r
187     // rubberband.addListener(this);\r
188   }\r
189 \r
190   /*\r
191    * public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {\r
192    * redrawneeded = true; repaint(); return true; }\r
193    * \r
194    * public void removeNotify() { controller.removeListener(this);\r
195    * super.removeNotify(); }\r
196    */\r
197 \r
198   public void initAxes()\r
199   {\r
200     for (int i = 0; i < 3; i++)\r
201     {\r
202       for (int j = 0; j < 3; j++)\r
203       {\r
204         if (i != j)\r
205         {\r
206           axes[i][j] = 0;\r
207         }\r
208         else\r
209         {\r
210           axes[i][j] = 1;\r
211         }\r
212       }\r
213     }\r
214   }\r
215 \r
216   public void findWidth()\r
217   {\r
218     max = new float[3];\r
219     min = new float[3];\r
220 \r
221     max[0] = (float) -1e30;\r
222     max[1] = (float) -1e30;\r
223     max[2] = (float) -1e30;\r
224 \r
225     min[0] = (float) 1e30;\r
226     min[1] = (float) 1e30;\r
227     min[2] = (float) 1e30;\r
228 \r
229     for (int i = 0; i < 3; i++)\r
230     {\r
231       for (int j = 0; j < npoint; j++)\r
232       {\r
233         SequencePoint sp = (SequencePoint) points.elementAt(j);\r
234         if (sp.coord[i] >= max[i])\r
235         {\r
236           max[i] = sp.coord[i];\r
237         }\r
238         if (sp.coord[i] <= min[i])\r
239         {\r
240           min[i] = sp.coord[i];\r
241         }\r
242       }\r
243     }\r
244 \r
245     // System.out.println("xmax " + max[0] + " min " + min[0]);\r
246     // System.out.println("ymax " + max[1] + " min " + min[1]);\r
247     // System.out.println("zmax " + max[2] + " min " + min[2]);\r
248 \r
249     width[0] = Math.abs(max[0] - min[0]);\r
250     width[1] = Math.abs(max[1] - min[1]);\r
251     width[2] = Math.abs(max[2] - min[2]);\r
252 \r
253     maxwidth = width[0];\r
254 \r
255     if (width[1] > width[0])\r
256     {\r
257       maxwidth = width[1];\r
258     }\r
259     if (width[2] > width[1])\r
260     {\r
261       maxwidth = width[2];\r
262     }\r
263 \r
264     // System.out.println("Maxwidth = " + maxwidth);\r
265   }\r
266 \r
267   public float findScale()\r
268   {\r
269     int dim, width, height;\r
270     if (getSize().width != 0)\r
271     {\r
272       width = getSize().width;\r
273       height = getSize().height;\r
274     }\r
275     else\r
276     {\r
277       width = prefsize.width;\r
278       height = prefsize.height;\r
279     }\r
280 \r
281     if (width < height)\r
282     {\r
283       dim = width;\r
284     }\r
285     else\r
286     {\r
287       dim = height;\r
288     }\r
289 \r
290     return dim * scalefactor / (2 * maxwidth);\r
291   }\r
292 \r
293   public void findCentre()\r
294   {\r
295     // Find centre coordinate\r
296     findWidth();\r
297 \r
298     centre[0] = (max[0] + min[0]) / 2;\r
299     centre[1] = (max[1] + min[1]) / 2;\r
300     centre[2] = (max[2] + min[2]) / 2;\r
301 \r
302     // System.out.println("Centre x " + centre[0]);\r
303     // System.out.println("Centre y " + centre[1]);\r
304     // System.out.println("Centre z " + centre[2]);\r
305   }\r
306 \r
307   public Dimension getPreferredSize()\r
308   {\r
309     if (prefsize != null)\r
310     {\r
311       return prefsize;\r
312     }\r
313     else\r
314     {\r
315       return new Dimension(400, 400);\r
316     }\r
317   }\r
318 \r
319   public Dimension getMinimumSize()\r
320   {\r
321     return getPreferredSize();\r
322   }\r
323 \r
324   public void update(Graphics g)\r
325   {\r
326     paint(g);\r
327   }\r
328 \r
329   public void paint(Graphics g)\r
330   {\r
331     if (points == null)\r
332     {\r
333       g.setFont(new Font("Verdana", Font.PLAIN, 18));\r
334       g.drawString(MessageManager.getString("label.calculating_pca")\r
335               + "....", 20, getSize().height / 2);\r
336     }\r
337     else\r
338     {\r
339 \r
340       // Only create the image at the beginning -\r
341       if ((img == null) || (prefsize.width != getSize().width)\r
342               || (prefsize.height != getSize().height))\r
343       {\r
344         prefsize.width = getSize().width;\r
345         prefsize.height = getSize().height;\r
346 \r
347         scale = findScale();\r
348 \r
349         // System.out.println("New scale = " + scale);\r
350         img = createImage(getSize().width, getSize().height);\r
351         ig = img.getGraphics();\r
352 \r
353       }\r
354 \r
355       drawBackground(ig, Color.black);\r
356       drawScene(ig);\r
357       if (drawAxes == true)\r
358       {\r
359         drawAxes(ig);\r
360       }\r
361 \r
362       if (tooltip != null)\r
363       {\r
364         ig.setColor(Color.red);\r
365         ig.drawString(tooltip, toolx, tooly);\r
366       }\r
367 \r
368       g.drawImage(img, 0, 0, this);\r
369     }\r
370   }\r
371 \r
372   public void drawAxes(Graphics g)\r
373   {\r
374 \r
375     g.setColor(Color.yellow);\r
376     for (int i = 0; i < 3; i++)\r
377     {\r
378       g.drawLine(getSize().width / 2, getSize().height / 2,\r
379               (int) (axes[i][0] * scale * max[0] + getSize().width / 2),\r
380               (int) (axes[i][1] * scale * max[1] + getSize().height / 2));\r
381     }\r
382   }\r
383 \r
384   public void drawBackground(Graphics g, Color col)\r
385   {\r
386     g.setColor(col);\r
387     g.fillRect(0, 0, prefsize.width, prefsize.height);\r
388   }\r
389 \r
390   public void drawScene(Graphics g)\r
391   {\r
392     // boolean darker = false;\r
393 \r
394     int halfwidth = getSize().width / 2;\r
395     int halfheight = getSize().height / 2;\r
396 \r
397     for (int i = 0; i < npoint; i++)\r
398     {\r
399       SequencePoint sp = (SequencePoint) points.elementAt(i);\r
400       int x = (int) ((sp.coord[0] - centre[0]) * scale) + halfwidth;\r
401       int y = (int) ((sp.coord[1] - centre[1]) * scale)\r
402               + halfheight;\r
403       float z = sp.coord[1] - centre[2];\r
404 \r
405       if (av.getSequenceColour(sp.sequence) == Color.black)\r
406       {\r
407         g.setColor(Color.white);\r
408       }\r
409       else\r
410       {\r
411         g.setColor(av.getSequenceColour(sp.sequence));\r
412       }\r
413 \r
414       if (av.getSelectionGroup() != null)\r
415       {\r
416         if (av.getSelectionGroup().getSequences(null)\r
417                 .contains(((SequencePoint) points.elementAt(i)).sequence))\r
418         {\r
419           g.setColor(Color.gray);\r
420         }\r
421       }\r
422       if (z < 0)\r
423       {\r
424         g.setColor(g.getColor().darker());\r
425       }\r
426 \r
427       g.fillRect(x - 3, y - 3, 6, 6);\r
428       if (showLabels)\r
429       {\r
430         g.setColor(Color.red);\r
431         g.drawString(\r
432                 ((SequencePoint) points.elementAt(i)).sequence.getName(),\r
433                 x - 3, y - 4);\r
434       }\r
435     }\r
436   }\r
437 \r
438   public Dimension minimumsize()\r
439   {\r
440     return prefsize;\r
441   }\r
442 \r
443   public Dimension preferredsize()\r
444   {\r
445     return prefsize;\r
446   }\r
447 \r
448   public void keyTyped(KeyEvent evt)\r
449   {\r
450   }\r
451 \r
452   public void keyReleased(KeyEvent evt)\r
453   {\r
454   }\r
455 \r
456   public void keyPressed(KeyEvent evt)\r
457   {\r
458     if (evt.getKeyCode() == KeyEvent.VK_UP)\r
459     {\r
460       scalefactor = (float) (scalefactor * 1.1);\r
461       scale = findScale();\r
462     }\r
463     else if (evt.getKeyCode() == KeyEvent.VK_DOWN)\r
464     {\r
465       scalefactor = (float) (scalefactor * 0.9);\r
466       scale = findScale();\r
467     }\r
468     else if (evt.getKeyChar() == 's')\r
469     {\r
470       System.err.println("DEBUG: Rectangle selection"); // log.debug\r
471       if (rectx2 != -1 && recty2 != -1)\r
472       {\r
473         rectSelect(rectx1, recty1, rectx2, recty2);\r
474 \r
475       }\r
476     }\r
477     repaint();\r
478   }\r
479 \r
480   public void printPoints()\r
481   {\r
482     for (int i = 0; i < npoint; i++)\r
483     {\r
484       SequencePoint sp = (SequencePoint) points.elementAt(i);\r
485       Format.printLong(System.out, "%5d ", i);\r
486       for (int j = 0; j < 3; j++)\r
487       {\r
488         Format.printDouble(System.out, "%13.3f  ", sp.coord[j]);\r
489       }\r
490       System.out.println();\r
491     }\r
492   }\r
493 \r
494   public void mouseClicked(MouseEvent evt)\r
495   {\r
496   }\r
497 \r
498   public void mouseEntered(MouseEvent evt)\r
499   {\r
500   }\r
501 \r
502   public void mouseExited(MouseEvent evt)\r
503   {\r
504   }\r
505 \r
506   public void mouseReleased(MouseEvent evt)\r
507   {\r
508   }\r
509 \r
510   public void mousePressed(MouseEvent evt)\r
511   {\r
512     int x = evt.getX();\r
513     int y = evt.getY();\r
514 \r
515     mx = x;\r
516     my = y;\r
517 \r
518     omx = mx;\r
519     omy = my;\r
520 \r
521     startx = x;\r
522     starty = y;\r
523 \r
524     rectx1 = x;\r
525     recty1 = y;\r
526 \r
527     rectx2 = -1;\r
528     recty2 = -1;\r
529 \r
530     SequenceI found = findPoint(x, y);\r
531 \r
532     if (found != null)\r
533     {\r
534       // TODO: applet PCA is not associatable with multi-panels - only parent\r
535       // view\r
536       if (av.getSelectionGroup() != null)\r
537       {\r
538         av.getSelectionGroup().addOrRemove(found, true);\r
539         av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);\r
540       }\r
541       else\r
542       {\r
543         av.setSelectionGroup(new SequenceGroup());\r
544         av.getSelectionGroup().addOrRemove(found, true);\r
545         av.getSelectionGroup().setEndRes(av.getAlignment().getWidth() - 1);\r
546 \r
547       }\r
548       PaintRefresher.Refresh(this, av.getSequenceSetId());\r
549       av.sendSelection();\r
550     }\r
551     repaint();\r
552   }\r
553 \r
554   public void mouseMoved(MouseEvent evt)\r
555   {\r
556     SequenceI found = findPoint(evt.getX(), evt.getY());\r
557     if (found == null)\r
558     {\r
559       tooltip = null;\r
560     }\r
561     else\r
562     {\r
563       tooltip = found.getName();\r
564       toolx = evt.getX();\r
565       tooly = evt.getY();\r
566     }\r
567     repaint();\r
568   }\r
569 \r
570   public void mouseDragged(MouseEvent evt)\r
571   {\r
572     mx = evt.getX();\r
573     my = evt.getY();\r
574 \r
575     rotmat.setIdentity();\r
576 \r
577     rotmat.rotate(my - omy, 'x');\r
578     rotmat.rotate(mx - omx, 'y');\r
579 \r
580     for (int i = 0; i < npoint; i++)\r
581     {\r
582       SequencePoint sp = (SequencePoint) points.elementAt(i);\r
583       sp.coord[0] -= centre[0];\r
584       sp.coord[1] -= centre[1];\r
585       sp.coord[2] -= centre[2];\r
586 \r
587       // Now apply the rotation matrix\r
588       sp.coord = rotmat.vectorMultiply(sp.coord);\r
589 \r
590       // Now translate back again\r
591       sp.coord[0] += centre[0];\r
592       sp.coord[1] += centre[1];\r
593       sp.coord[2] += centre[2];\r
594     }\r
595 \r
596     for (int i = 0; i < 3; i++)\r
597     {\r
598       axes[i] = rotmat.vectorMultiply(axes[i]);\r
599     }\r
600     omx = mx;\r
601     omy = my;\r
602 \r
603     paint(this.getGraphics());\r
604   }\r
605 \r
606   public void rectSelect(int x1, int y1, int x2, int y2)\r
607   {\r
608     // boolean changedSel = false;\r
609     for (int i = 0; i < npoint; i++)\r
610     {\r
611       SequencePoint sp = (SequencePoint) points.elementAt(i);\r
612       int tmp1 = (int) ((sp.coord[0] - centre[0]) * scale + getSize().width / 2.0);\r
613       int tmp2 = (int) ((sp.coord[1] - centre[1]) * scale + getSize().height / 2.0);\r
614 \r
615       if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2)\r
616       {\r
617         if (av != null)\r
618         {\r
619           if (!av.getSelectionGroup().getSequences(null)\r
620                   .contains(sp.sequence))\r
621           {\r
622             av.getSelectionGroup().addSequence(sp.sequence, true);\r
623           }\r
624         }\r
625       }\r
626     }\r
627   }\r
628 \r
629   public SequenceI findPoint(int x, int y)\r
630   {\r
631 \r
632     int halfwidth = getSize().width / 2;\r
633     int halfheight = getSize().height / 2;\r
634 \r
635     int found = -1;\r
636 \r
637     for (int i = 0; i < npoint; i++)\r
638     {\r
639 \r
640       SequencePoint sp = (SequencePoint) points.elementAt(i);\r
641       int px = (int) ((sp.coord[0] - centre[0]) * scale)\r
642               + halfwidth;\r
643       int py = (int) ((sp.coord[1] - centre[1]) * scale)\r
644               + halfheight;\r
645 \r
646       if (Math.abs(px - x) < 3 && Math.abs(py - y) < 3)\r
647       {\r
648         found = i;\r
649       }\r
650     }\r
651     if (found != -1)\r
652     {\r
653       return ((SequencePoint) points.elementAt(found)).sequence;\r
654     }\r
655     else\r
656     {\r
657       return null;\r
658     }\r
659   }\r
660 \r
661 }\r