Jalview Imported Sources
[jalview.git] / src / jalview / gui / RotatableCanvas.java
1 package jalview.gui;\r
2 \r
3 import jalview.math.*;\r
4 import jalview.datamodel.*;\r
5 import jalview.util.*;\r
6 \r
7 import java.awt.*;\r
8 import java.awt.event.*;\r
9 import javax.swing.*;\r
10 import java.util.*;\r
11 \r
12 \r
13 public class RotatableCanvas extends JPanel implements MouseListener,\r
14                                                        MouseMotionListener,\r
15                                                        KeyListener\r
16                                                        //RubberbandListener,\r
17                                                        //SequenceSelectionListener\r
18 {\r
19   RotatableMatrix idmat  = new RotatableMatrix(3,3);\r
20   RotatableMatrix objmat = new RotatableMatrix(3,3);\r
21   RotatableMatrix rotmat = new RotatableMatrix(3,3);\r
22 \r
23   //RubberbandRectangle rubberband;\r
24 \r
25   boolean drawAxes = true;\r
26 \r
27   int omx = 0;\r
28   int mx = 0;\r
29   int omy = 0;\r
30   int my = 0;\r
31 \r
32   Image img;\r
33   Graphics ig;\r
34 \r
35   Dimension prefsize;\r
36 \r
37   float centre[] = new float[3];\r
38   float width[] = new float[3];\r
39 \r
40   float max[] = new float[3];\r
41   float min[] = new float[3];\r
42 \r
43   float maxwidth;\r
44   float scale;\r
45 \r
46   int npoint;\r
47 \r
48   Vector points;\r
49   float[][] orig;\r
50   float[][] axes;\r
51 \r
52   int startx;\r
53   int starty;\r
54 \r
55   int lastx;\r
56   int lasty;\r
57 \r
58   int rectx1;\r
59   int recty1;\r
60   int rectx2;\r
61   int recty2;\r
62 \r
63   float scalefactor = 1;\r
64 \r
65   AlignViewport av;\r
66 //  Controller    controller;\r
67 \r
68 \r
69   public RotatableCanvas(AlignViewport av,\r
70                           Vector points, int npoint) {\r
71     this.points = points;\r
72     this.npoint = npoint;\r
73     this.av = av;\r
74     ToolTipManager.sharedInstance().registerComponent(this);\r
75     PaintRefresher.Register(this);\r
76 //\r
77     prefsize = getPreferredSize();\r
78     orig = new float[npoint][3];\r
79 \r
80     for (int i=0; i < npoint; i++) {\r
81       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
82       for (int j=0; j < 3; j++) {\r
83         orig[i][j] = sp.coord[j];\r
84       }\r
85     }\r
86     //Initialize the matrices to identity\r
87 \r
88     for (int i = 0; i < 3; i++) {\r
89       for (int j = 0; j < 3 ; j++) {\r
90         if (i != j) {\r
91           idmat.addElement(i,j,0);\r
92           objmat.addElement(i,j,0);\r
93           rotmat.addElement(i,j,0);\r
94         } else {\r
95           idmat.addElement(i,j,0);\r
96           objmat.addElement(i,j,0);\r
97           rotmat.addElement(i,j,0);\r
98         }\r
99       }\r
100     }\r
101 \r
102     axes = new float[3][3];\r
103     initAxes();\r
104 \r
105     findCentre();\r
106     findWidth();\r
107 \r
108     scale = findScale();\r
109 \r
110     //    System.out.println("Scale factor = " + scale);\r
111 \r
112     addMouseListener(this);\r
113     addKeyListener(this);\r
114    // if (getParent() != null) {\r
115    //   getParent().addKeyListener(this);\r
116     //}\r
117     addMouseMotionListener(this);\r
118 \r
119     // Add rubberband\r
120  //   rubberband  = new RubberbandRectangle(this);\r
121   //  rubberband.setActive(true);\r
122  //   rubberband.addListener(this);\r
123   }\r
124 \r
125  /* public boolean handleSequenceSelectionEvent(SequenceSelectionEvent evt) {\r
126     redrawneeded = true;\r
127     repaint();\r
128     return true;\r
129   }\r
130 \r
131   public void removeNotify() {\r
132     controller.removeListener(this);\r
133     super.removeNotify();\r
134   }*/\r
135 \r
136   public void initAxes() {\r
137     for (int i = 0; i < 3; i++) {\r
138       for (int j=0; j < 3; j++) {\r
139         if (i != j) {\r
140           axes[i][j] = 0;\r
141         } else {\r
142           axes[i][j] = 1;\r
143         }\r
144       }\r
145     }\r
146   }\r
147 \r
148   public void findWidth() {\r
149     max = new float[3];\r
150     min = new float[3];\r
151 \r
152     max[0] = (float)-1e30;\r
153     max[1] = (float)-1e30;\r
154     max[2] = (float)-1e30;\r
155 \r
156     min[0] = (float)1e30;\r
157     min[1] = (float)1e30;\r
158     min[2] = (float)1e30;\r
159 \r
160     for (int i = 0; i < 3; i++) {\r
161       for (int j = 0; j < npoint; j++) {\r
162         SequencePoint sp = (SequencePoint)points.elementAt(j);\r
163         if (sp.coord[i] >= max[i]) {\r
164           max[i] = sp.coord[i];\r
165         }\r
166         if (sp.coord[i] <= min[i]) {\r
167           min[i] = sp.coord[i];\r
168         }\r
169       }\r
170     }\r
171 \r
172     //    System.out.println("xmax " + max[0] + " min " + min[0]);\r
173     //System.out.println("ymax " + max[1] + " min " + min[1]);\r
174     //System.out.println("zmax " + max[2] + " min " + min[2]);\r
175 \r
176     width[0] = Math.abs(max[0] - min[0]);\r
177     width[1] = Math.abs(max[1] - min[1]);\r
178     width[2] = Math.abs(max[2] - min[2]);\r
179 \r
180     maxwidth = width[0];\r
181 \r
182     if (width[1] > width[0])\r
183       maxwidth = width[1];\r
184     if (width[2] > width[1])\r
185       maxwidth = width[2];\r
186 \r
187     //System.out.println("Maxwidth = " + maxwidth);\r
188   }\r
189 \r
190   public float findScale() {\r
191     int dim, width, height;\r
192     if (getWidth() != 0) {\r
193       width = getWidth();\r
194       height = getHeight();\r
195     } else {\r
196       width = prefsize.width;\r
197       height = prefsize.height;\r
198     }\r
199 \r
200     if (width < height) {\r
201       dim = width;\r
202     } else {\r
203       dim = height;\r
204     }\r
205 \r
206     return (float)(dim*scalefactor/(2*maxwidth));\r
207   }\r
208 \r
209   public void findCentre() {\r
210     //Find centre coordinate\r
211     findWidth();\r
212 \r
213     centre[0] = (max[0] + min[0])/2;\r
214     centre[1] = (max[1] + min[1])/2;\r
215     centre[2] = (max[2] + min[2])/2;\r
216 \r
217     //    System.out.println("Centre x " + centre[0]);\r
218     //System.out.println("Centre y " + centre[1]);\r
219     //System.out.println("Centre z " + centre[2]);\r
220   }\r
221 \r
222   public Dimension getPreferredSize() {\r
223     if (prefsize != null) {\r
224       return prefsize;\r
225     } else {\r
226       return new Dimension(400,400);\r
227     }\r
228   }\r
229 \r
230   public Dimension getMinimumSize() {\r
231     return getPreferredSize();\r
232   }\r
233 \r
234   public void paintComponent(Graphics g) {\r
235     //Only create the image at the beginning -\r
236     if ((img == null) || (prefsize.width != getWidth()) || (prefsize.height != getHeight())) {\r
237       prefsize.width = getWidth();\r
238       prefsize.height = getHeight();\r
239 \r
240       scale = findScale();\r
241 \r
242       //      System.out.println("New scale = " + scale);\r
243       img = createImage(getWidth(),getHeight());\r
244       ig = img.getGraphics();\r
245 \r
246     }\r
247 \r
248 \r
249       drawBackground(ig,Color.black);\r
250       drawScene(ig);\r
251       if (drawAxes == true)\r
252       {\r
253         drawAxes(ig);\r
254       }\r
255 \r
256 \r
257     g.drawImage(img,0,0,this);\r
258   }\r
259 \r
260   public void drawAxes(Graphics g) {\r
261 \r
262     g.setColor(Color.yellow);\r
263     for (int i=0; i < 3 ; i++) {\r
264       g.drawLine(getWidth()/2,getHeight()/2,\r
265                  (int)(axes[i][0]*scale*max[0] + getWidth()/2),\r
266                  (int)(axes[i][1]*scale*max[1] + getHeight()/2));\r
267     }\r
268   }\r
269 \r
270   public void drawBackground(Graphics g, Color col) {\r
271     g.setColor(col);\r
272     g.fillRect(0,0,prefsize.width,prefsize.height);\r
273   }\r
274 \r
275 \r
276   public void drawScene(Graphics g) {\r
277     boolean darker = false;\r
278 \r
279     int halfwidth = getWidth()/2;\r
280     int halfheight = getHeight()/2;\r
281 \r
282     for (int i = 0; i < npoint; i++) {\r
283       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
284       int x = (int)((float)(sp.coord[0] - centre[0])*scale) + halfwidth;\r
285       int y = (int)((float)(sp.coord[1] - centre[1])*scale) + halfheight;\r
286       float z = sp.coord[1] - centre[2];\r
287       if (sp.sequence instanceof DrawableSequence) {\r
288         if (((DrawableSequence)sp.sequence).color == Color.black) {\r
289           g.setColor(Color.white);\r
290         } else {\r
291           g.setColor(((DrawableSequence)sp.sequence).color);\r
292         }\r
293       } else {\r
294         g.setColor(Color.red);\r
295       }\r
296       if (av != null) {\r
297         if (av.getSelection().contains(((SequencePoint)points.elementAt(i)).sequence)) {\r
298           g.setColor(Color.gray);\r
299         }\r
300       }\r
301       if (z < 0) {\r
302         g.setColor(g.getColor().darker());\r
303       }\r
304 \r
305       g.fillRect(x-3,y-3,6,6);\r
306       g.setColor(Color.red);\r
307     }\r
308 //    //Now the rectangle\r
309 //    if (rectx2 != -1 && recty2 != -1) {\r
310 //      g.setColor(Color.white);\r
311 //\r
312 //      g.drawRect(rectx1,recty1,rectx2-rectx1,recty2-recty1);\r
313 //    }\r
314   }\r
315 \r
316   public Dimension minimumsize() {\r
317     return prefsize;\r
318   }\r
319 \r
320   public Dimension preferredsize() {\r
321     return prefsize;\r
322   }\r
323 \r
324   public void keyTyped(KeyEvent evt) { }\r
325   public void keyReleased(KeyEvent evt) { }\r
326 \r
327   public void keyPressed(KeyEvent evt) {\r
328     requestFocus();\r
329     if (evt.getKeyCode() == KeyEvent.VK_UP) {\r
330       scalefactor = (float)(scalefactor * 1.1);\r
331       scale = findScale();\r
332     } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) {\r
333       scalefactor = (float)(scalefactor * 0.9);\r
334       scale = findScale();\r
335     } else if (evt.getKeyChar() == 's') {\r
336       System.out.println("Rectangle selection");\r
337       if (rectx2 != -1 && recty2 != -1) {\r
338         rectSelect(rectx1,recty1,rectx2,recty2);\r
339 \r
340       }\r
341     }\r
342     repaint();\r
343   }\r
344 \r
345   public void printPoints() {\r
346     for (int i=0; i < npoint; i++) {\r
347       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
348       Format.print(System.out,"%5d ", i);\r
349       for (int j=0; j < 3;j++) {\r
350         Format.print(System.out,"%13.3f  ",sp.coord[j]);\r
351       }\r
352       System.out.println();\r
353     }\r
354   }\r
355 \r
356   public void mouseClicked(MouseEvent evt) { }\r
357   public void mouseEntered(MouseEvent evt) { }\r
358   public void mouseExited(MouseEvent evt) { }\r
359   public void mouseReleased(MouseEvent evt) { }\r
360 \r
361   public void mousePressed(MouseEvent evt) {\r
362     int x = evt.getX();\r
363     int y = evt.getY();\r
364 \r
365     mx = x;\r
366     my = y;\r
367 \r
368     omx = mx;\r
369     omy = my;\r
370 \r
371     startx = x;\r
372     starty = y;\r
373 \r
374     rectx1 = x;\r
375     recty1 = y;\r
376 \r
377     rectx2 = -1;\r
378     recty2 = -1;\r
379 \r
380     SequenceI found = findPoint(x,y);\r
381 \r
382     if (found != null) {\r
383       if (av != null) {\r
384 \r
385         if (av.getSelection().contains(found)) {\r
386           av.getSelection().removeElement(found);\r
387         } else {\r
388           av.getSelection().addElement(found);\r
389         }\r
390         PaintRefresher.Refresh(this);\r
391       }\r
392     }\r
393     repaint();\r
394   }\r
395 \r
396  // private void fireSequenceSelectionEvent(Selection sel) {\r
397  //   controller.handleSequenceSelectionEvent(new SequenceSelectionEvent(this,sel));\r
398   //}\r
399 \r
400   public void mouseMoved(MouseEvent evt)\r
401   {\r
402    SequenceI found = findPoint(evt.getX(), evt.getY());\r
403    if (found != null)\r
404      this.setToolTipText(found.getName());\r
405    else\r
406      this.setToolTipText(null);\r
407  }\r
408 \r
409   public void mouseDragged(MouseEvent evt) {\r
410     mx = evt.getX();\r
411     my = evt.getY();\r
412     //Check if this is a rectangle drawing drag\r
413     if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0) {\r
414 //      rectx2 = evt.getX();\r
415 //      recty2 = evt.getY();\r
416     } else {\r
417       rotmat.setIdentity();\r
418 \r
419       rotmat.rotate((float)(my-omy),'x');\r
420       rotmat.rotate((float)(mx-omx),'y');\r
421 \r
422       for (int i = 0; i < npoint; i++) {\r
423         SequencePoint sp = (SequencePoint)points.elementAt(i);\r
424         sp.coord[0] -= centre[0];\r
425         sp.coord[1] -= centre[1];\r
426         sp.coord[2] -= centre[2];\r
427 \r
428         //Now apply the rotation matrix\r
429         sp.coord= rotmat.vectorMultiply(sp.coord);\r
430 \r
431         //Now translate back again\r
432         sp.coord[0] += centre[0];\r
433         sp.coord[1] += centre[1];\r
434         sp.coord[2] += centre[2];\r
435       }\r
436 \r
437       for (int i=0; i < 3; i++) {\r
438         axes[i] = rotmat.vectorMultiply(axes[i]);\r
439       }\r
440       omx = mx;\r
441       omy = my;\r
442 \r
443       paint(this.getGraphics());\r
444     }\r
445 \r
446   }\r
447 \r
448   public void rectSelect(int x1, int y1, int x2, int y2) {\r
449     boolean changedSel = false;\r
450     for (int i=0; i < npoint; i++) {\r
451       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
452       int tmp1 = (int)((sp.coord[0] - centre[0])*scale + (float)getWidth()/2.0);\r
453       int tmp2 = (int)((sp.coord[1] - centre[1])*scale + (float)getHeight()/2.0);\r
454 \r
455       if (tmp1 > x1 && tmp1 < x2 && tmp2 > y1 && tmp2 < y2) {\r
456         if (av != null) {\r
457           if (!av.getSelection().contains(sp.sequence)) {\r
458             changedSel = true;\r
459             av.getSelection().addElement(sp.sequence);\r
460           }\r
461         }\r
462       }\r
463     }\r
464    // if (changedSel) {\r
465    //    fireSequenceSelectionEvent(av.getSelection());\r
466    // }\r
467   }\r
468   public SequenceI findPoint(int x, int y) {\r
469 \r
470     int halfwidth = getWidth()/2;\r
471     int halfheight = getHeight()/2;\r
472 \r
473     int found = -1;\r
474 \r
475     for (int i=0; i < npoint; i++) {\r
476 \r
477       SequencePoint sp = (SequencePoint)points.elementAt(i);\r
478       int px = (int)((float)(sp.coord[0] - centre[0])*scale) + halfwidth;\r
479       int py = (int)((float)(sp.coord[1] - centre[1])*scale) + halfheight;\r
480 \r
481 \r
482       if (Math.abs(px-x)<3 && Math.abs(py - y) < 3 ) {\r
483         found = i;\r
484       }\r
485     }\r
486     if (found != -1) {\r
487       return ((SequencePoint)points.elementAt(found)).sequence;\r
488     } else {\r
489       return null;\r
490     }\r
491   }\r
492 /*  public boolean handleRubberbandEvent(RubberbandEvent evt) {\r
493     System.out.println("Rubberband handler called in RotatableCanvas with " +\r
494                        evt.getBounds());\r
495 \r
496     Rubberband rb = (Rubberband)evt.getSource();\r
497 \r
498     // Clear the current selection (instance variable)\r
499     //if ((rb.getModifiers() & Event.SHIFT_MASK) == 0) {\r
500     //   clearSelection();\r
501     //}\r
502 \r
503     if (rb.getComponent() == this) {\r
504       Rectangle bounds = evt.getBounds();\r
505       rectSelect(bounds.x,bounds.y,bounds.x+bounds.width,bounds.y+bounds.height);\r
506     }\r
507 \r
508     redrawneeded = true;\r
509     paint(this.getGraphics());\r
510 \r
511     return true;\r
512   }*/\r
513 \r
514 }\r