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