SequenceFeature display added
[jalview.git] / src / MCview / rotCanvas.java
1 package MCview;\r
2 \r
3 import java.awt.*;\r
4 import java.awt.event.*;\r
5 import java.util.*;\r
6 import java.io.*;\r
7 import javax.swing.*;\r
8 \r
9 public class rotCanvas extends JPanel implements KeyListener,\r
10                                                  MouseListener,\r
11                                                  MouseMotionListener {\r
12   MCMatrix  idmat  = new MCMatrix(3,3);\r
13   MCMatrix  objmat = new MCMatrix(3,3);\r
14 \r
15   boolean redrawneeded =true;\r
16 \r
17   int omx = 0;\r
18   int mx = 0;\r
19   int omy = 0;\r
20   int my = 0;\r
21 \r
22   public PDBfile pdb;\r
23 \r
24   int bsize;\r
25 \r
26   Image img;\r
27   Graphics ig;\r
28 \r
29   Dimension prefsize;\r
30 \r
31   float centre[] = new float[3];\r
32   float width[]  = new float[3];\r
33 \r
34   float maxwidth;\r
35   float scale;\r
36 \r
37   String inStr;\r
38   String inType;\r
39 \r
40   boolean depthcue   = true;\r
41   boolean wire       = false;\r
42   boolean bymolecule = false;\r
43   boolean zbuffer    = true;\r
44 \r
45   boolean dragging;\r
46 \r
47   int xstart;\r
48   int xend;\r
49   int ystart;\r
50   int yend;\r
51   int xmid;\r
52   int ymid;\r
53 \r
54   Font font = new Font("Helvetica",Font.PLAIN,10);\r
55 \r
56   public rotCanvas(PDBfile pdb) throws IOException {\r
57 \r
58     this.pdb      = pdb;\r
59     this.prefsize = new Dimension( getWidth(), getHeight());\r
60 \r
61     //Initialize the matrices to identity\r
62 \r
63     for (int i = 0; i < 3; i++) {\r
64       for (int j = 0; j < 3 ; j++) {\r
65         if (i != j) {\r
66           idmat.addElement(i,j,0);\r
67           objmat.addElement(i,j,0);\r
68         } else {\r
69           idmat.addElement(i,j,1);\r
70           objmat.addElement(i,j,1);\r
71         }\r
72       }\r
73     }\r
74 \r
75     addMouseMotionListener(this);\r
76     addMouseListener(this);\r
77     addKeyListener(this);\r
78 \r
79     addPDBfile();\r
80     ToolTipManager.sharedInstance().registerComponent(this);\r
81 \r
82   }\r
83 \r
84   public void addPDBfile() {\r
85     findCentre();\r
86     findWidth();\r
87 \r
88     scale = findScale();\r
89 \r
90     System.out.println("Scale factor = " + scale);\r
91   }\r
92 \r
93   public void deleteBonds() {\r
94     scale     = 0;\r
95     maxwidth  = 0;\r
96 \r
97     width[0] = 0;\r
98     width[1] = 0;\r
99     width[2] = 0;\r
100 \r
101     centre[0] = 0;\r
102     centre[1] = 0;\r
103     centre[2] = 0;\r
104 \r
105     for (int i=0; i < pdb.chains.size(); i++) {\r
106       ((PDBChain)pdb.chains.elementAt(i)).bonds = null;\r
107     }\r
108   }\r
109 \r
110   public void findWidth() {\r
111     float max[] = new float[3];\r
112     float min[] = new float[3];\r
113 \r
114     max[0] = (float)-1e30;\r
115     max[1] = (float)-1e30;\r
116     max[2] = (float)-1e30;\r
117 \r
118     min[0] = (float)1e30;\r
119     min[1] = (float)1e30;\r
120     min[2] = (float)1e30;\r
121 \r
122     for (int ii=0; ii < pdb.chains.size(); ii++) {\r
123       if (((PDBChain)pdb.chains.elementAt(ii)).isVisible) {\r
124 \r
125         Vector bonds = ((PDBChain)pdb.chains.elementAt(ii)).bonds;\r
126 \r
127         for (int i = 0; i < bonds.size(); i++) {\r
128           Bond tmp = (Bond)bonds.elementAt(i);\r
129 \r
130           if (tmp.start[0] >= max[0])\r
131             max[0] = tmp.start[0];\r
132           if (tmp.start[1] >= max[1])\r
133             max[1] = tmp.start[1];\r
134           if (tmp.start[2] >= max[2])\r
135             max[2] = tmp.start[2];\r
136           if (tmp.start[0] <= min[0])\r
137             min[0] = tmp.start[0];\r
138           if (tmp.start[1] <= min[1])\r
139             min[1] = tmp.start[1];\r
140           if (tmp.start[2] <= min[2])\r
141             min[2] = tmp.start[2];\r
142 \r
143           if (tmp.end[0] >= max[0])\r
144             max[0] = tmp.end[0];\r
145           if (tmp.end[1] >= max[1])\r
146             max[1] = tmp.end[1];\r
147           if (tmp.end[2] >= max[2])\r
148             max[2] = tmp.end[2];\r
149           if (tmp.end[0] <= min[0])\r
150             min[0] = tmp.end[0];\r
151           if (tmp.end[1] <= min[1])\r
152             min[1] = tmp.end[1];\r
153           if (tmp.end[2] <= min[2])\r
154             min[2] = tmp.end[2];\r
155         }\r
156       }\r
157     }\r
158 \r
159     System.out.println("xmax " + max[0] + " min " + min[0]);\r
160     System.out.println("ymax " + max[1] + " min " + min[1]);\r
161     System.out.println("zmax " + max[2] + " min " + min[2]);\r
162 \r
163     width[0] = (float)Math.abs(max[0] - min[0]);\r
164     width[1] = (float)Math.abs(max[1] - min[1]);\r
165     width[2] = (float)Math.abs(max[2] - min[2]);\r
166 \r
167     maxwidth = width[0];\r
168 \r
169     if (width[1] > width[0])\r
170       maxwidth = width[1];\r
171     if (width[2] > width[1])\r
172       maxwidth = width[2];\r
173 \r
174     System.out.println("Maxwidth = " + maxwidth);\r
175   }\r
176 \r
177   public float findScale() {\r
178     int dim, width, height;\r
179 \r
180     if ( getWidth() != 0) {\r
181       width  = getWidth();\r
182       height = getHeight();\r
183 \r
184     } else {\r
185       width  = prefsize.width;\r
186       height = prefsize.height;\r
187     }\r
188 \r
189     if (width < height) {\r
190       dim = width;\r
191     } else {\r
192       dim = height;\r
193     }\r
194 \r
195     return (float)(dim/(1.5d*maxwidth));\r
196   }\r
197 \r
198 \r
199 \r
200   public void findCentre() {\r
201     float xtot = 0;\r
202     float ytot = 0;\r
203     float ztot = 0;\r
204 \r
205     int bsize  = 0;\r
206     //Find centre coordinate\r
207 \r
208     for (int ii = 0; ii < pdb.chains.size() ; ii++) {\r
209       if (((PDBChain)pdb.chains.elementAt(ii)).isVisible) {\r
210 \r
211         Vector bonds = ((PDBChain)pdb.chains.elementAt(ii)).bonds;\r
212 \r
213         bsize += bonds.size();\r
214 \r
215         for (int i = 0; i < bonds.size(); i++) {\r
216 \r
217           xtot = xtot + ((Bond)bonds.elementAt(i)).start[0] +\r
218                  ((Bond)bonds.elementAt(i)).end[0];\r
219 \r
220           ytot = ytot + ((Bond)bonds.elementAt(i)).start[1] +\r
221                  ((Bond)bonds.elementAt(i)).end[1];\r
222 \r
223           ztot = ztot + ((Bond)bonds.elementAt(i)).start[2] +\r
224                  ((Bond)bonds.elementAt(i)).end[2];\r
225         }\r
226       }\r
227     }\r
228 \r
229     centre[0] = xtot / (2 * (float)bsize);\r
230     centre[1] = ytot / (2 * (float)bsize);\r
231     centre[2] = ztot / (2 * (float)bsize);\r
232   }\r
233 \r
234   public void paintComponent(Graphics g) {\r
235     //Only create the image at the beginning -\r
236     //this saves much memory usage\r
237     if ((img == null) || (prefsize.width != getWidth()) || (prefsize.height != getHeight())) {\r
238       prefsize.width  = getWidth();\r
239       prefsize.height = getHeight();\r
240 \r
241       scale = findScale();\r
242       img   = createImage(prefsize.width,prefsize.height);\r
243       ig    = img.getGraphics();\r
244 \r
245       redrawneeded = true;\r
246     }\r
247 \r
248     if (redrawneeded == true) {\r
249       drawBackground(ig,Color.black);\r
250       drawScene(ig);\r
251       redrawneeded = false;\r
252     } else {\r
253       ig = img.getGraphics();\r
254     }\r
255 \r
256     g.drawImage(img,0,0,this);\r
257   }\r
258 \r
259   public void drawBackground(Graphics g, Color col) {\r
260     g.setColor(col);\r
261     g.fillRect(0,0,prefsize.width,prefsize.height);\r
262   }\r
263 \r
264 \r
265   public void drawScene(Graphics g) {\r
266     // Sort the bonds by z coord\r
267 \r
268     Vector bonds = new Vector();\r
269 \r
270 \r
271     for (int ii = 0; ii < pdb.chains.size() ; ii++) {\r
272       if (((PDBChain)pdb.chains.elementAt(ii)).isVisible) {\r
273 \r
274         Vector tmp = ((PDBChain)pdb.chains.elementAt(ii)).bonds;\r
275 \r
276         for (int i=0; i < tmp.size(); i++) {\r
277           bonds.addElement(tmp.elementAt(i));\r
278         }\r
279       }\r
280     }\r
281 \r
282     if (zbuffer) {\r
283       Zsort.Zsort(bonds);\r
284     }\r
285 \r
286     for (int i = 0; i < bonds.size(); i++) {\r
287       Bond tmpBond = (Bond)bonds.elementAt(i);\r
288 \r
289       xstart = (int)((tmpBond.start[0] - centre[0])*scale + getWidth()/2);\r
290       ystart = (int)((tmpBond.start[1] - centre[1])*scale + getHeight()/2);\r
291 \r
292       xend = (int)((tmpBond.end[0] - centre[0])*scale + getWidth()/2);\r
293       yend = (int)((tmpBond.end[1] - centre[1])*scale + getHeight()/2);\r
294 \r
295       xmid = (xend+xstart)/2;\r
296       ymid = (yend+ystart)/2;\r
297 \r
298 \r
299       if (depthcue && !bymolecule) {\r
300 \r
301         if (tmpBond.start[2] < (centre[2] - maxwidth/6))  {\r
302           g.setColor(tmpBond.startCol.darker().darker());\r
303           drawLine(g,xstart,ystart,xmid,ymid);\r
304 \r
305           g.setColor(tmpBond.endCol.darker().darker());\r
306           drawLine(g,xmid,ymid,xend,yend);\r
307         } else if (tmpBond.start[2] < (centre[2]+maxwidth/6)) {\r
308           g.setColor(tmpBond.startCol.darker());\r
309           drawLine(g,xstart,ystart,xmid,ymid);\r
310 \r
311           g.setColor(tmpBond.endCol.darker());\r
312           drawLine(g,xmid,ymid,xend,yend);\r
313         } else {\r
314           g.setColor(tmpBond.startCol);\r
315           drawLine(g,xstart,ystart,xmid,ymid);\r
316 \r
317           g.setColor(tmpBond.endCol);\r
318           drawLine(g,xmid,ymid,xend,yend);\r
319         }\r
320       } else if (depthcue && bymolecule) {\r
321         if (tmpBond.start[2] < (centre[2] - maxwidth/6))  {\r
322           g.setColor(Color.green.darker().darker());\r
323           drawLine(g,xstart,ystart,xend,yend);\r
324 \r
325         } else if (tmpBond.start[2] < (centre[2]+maxwidth/6)) {\r
326           g.setColor(Color.green.darker());\r
327           drawLine(g,xstart,ystart,xend,yend);\r
328 \r
329         } else {\r
330           g.setColor(Color.green);\r
331           drawLine(g,xstart,ystart,xend,yend);\r
332 \r
333         }\r
334       } else if (!depthcue && !bymolecule) {\r
335         g.setColor(tmpBond.startCol);\r
336         drawLine(g,xstart,ystart,xmid,ymid);\r
337         g.setColor(tmpBond.endCol);\r
338         drawLine(g,xmid,ymid,xend,yend);\r
339 \r
340       } else {\r
341         drawLine(g,xstart,ystart,xend,yend);\r
342       }\r
343     }\r
344   }\r
345 \r
346   public void drawLine(Graphics g, int x1, int y1, int x2, int y2) {\r
347     if (!wire) {\r
348 \r
349       if (((float)Math.abs(y2-y1)/(float)Math.abs(x2-x1)) < 0.5) {\r
350 \r
351         g.drawLine(x1,y1,x2,y2);\r
352         g.drawLine(x1+1,y1+1,x2+1,y2+1);\r
353         g.drawLine(x1,y1-1,x2,y2-1);\r
354       } else {\r
355         g.setColor(g.getColor().brighter());\r
356         g.drawLine(x1,y1,x2,y2);\r
357         g.drawLine(x1+1,y1,x2+1,y2);\r
358         g.drawLine(x1-1,y1,x2-1,y2);\r
359 \r
360       }\r
361     } else {\r
362       g.drawLine(x1,y1,x2,y2);\r
363     }\r
364   }\r
365 \r
366   public Dimension minimumsize() {\r
367     return prefsize;\r
368   }\r
369   public Dimension preferredsize() {\r
370     return prefsize;\r
371   }\r
372 \r
373   public void keyTyped(KeyEvent evt) { }\r
374   public void keyReleased(KeyEvent evt) { }\r
375   public void keyPressed(KeyEvent evt) {\r
376     int key = evt.getKeyChar();\r
377 \r
378     if (evt.getKeyCode() == KeyEvent.VK_UP) {\r
379       scale        = (float)(scale * 1.1);\r
380       redrawneeded = true;\r
381       repaint();\r
382 \r
383     } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) {\r
384       scale        = (float)(scale * 0.9);\r
385       redrawneeded = true;\r
386       repaint();\r
387 \r
388     } else if (key == 'w') {\r
389 \r
390       wire = !wire;\r
391       System.out.println("wireframe " + wire);\r
392       redrawneeded = true;\r
393       repaint();\r
394 \r
395     } else if (key == 'd') {\r
396       depthcue = !depthcue;\r
397       System.out.println("Depth cueing is " + depthcue);\r
398       redrawneeded = true;\r
399       repaint();\r
400 \r
401     } else if (key == 'm') {\r
402       bymolecule = !bymolecule;\r
403       System.out.println("Bymolecule is " + bymolecule);\r
404       redrawneeded = true;\r
405       repaint();\r
406 \r
407     } else if (key == 'z') {\r
408       zbuffer = !zbuffer;\r
409       System.out.println("Z buffering is " + zbuffer);\r
410       redrawneeded = true;\r
411       repaint();\r
412 \r
413     } else if (key == 'c') {\r
414       bymolecule = false;\r
415       pdb.setChainColours();\r
416       System.out.println("Colouring by chain");\r
417       redrawneeded = true;\r
418       repaint();\r
419 \r
420     } else if (key == 'h') {\r
421       bymolecule = false;\r
422       pdb.setHydrophobicityColours();\r
423       System.out.println("Colouring by hydrophobicity");\r
424       redrawneeded = true;\r
425       repaint();\r
426 \r
427     } else if (key == 'q') {\r
428       bymolecule = false;\r
429       pdb.setChargeColours();\r
430       System.out.println("Colouring charges and cysteines");\r
431       redrawneeded = true;\r
432       repaint();\r
433 \r
434     }\r
435     return;\r
436   }\r
437 \r
438   public void mousePressed(MouseEvent e)\r
439   {\r
440 \r
441       mx = e.getX();\r
442       my = e.getY();\r
443       omx = mx;\r
444       omy = my;\r
445       dragging = false;\r
446 }\r
447 \r
448   public void mouseMoved(MouseEvent e)\r
449   {\r
450     myAtom fatom = null;\r
451     for (int ii = 0; ii < pdb.chains.size(); ii++)\r
452     {\r
453 \r
454       PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);\r
455       if (chain.isVisible)\r
456       {\r
457         Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;\r
458         for (int i = 0; i < bonds.size(); i++)\r
459         {\r
460           Bond tmpBond = (Bond) bonds.elementAt(i);\r
461           int truex = (int) ( (tmpBond.start[0] - centre[0]) * scale +\r
462                              getWidth() / 2);\r
463           if (Math.abs(truex - e.getX()) <= 2)\r
464           {\r
465             int truey = (int) ( (tmpBond.start[1] - centre[1]) * scale +\r
466                                getHeight() / 2);\r
467             if (Math.abs(truey - e.getY()) <= 2)\r
468               fatom = tmpBond.at1;\r
469           }\r
470         }\r
471       }\r
472     }\r
473     if(fatom!=null)\r
474      {\r
475        this.setToolTipText(fatom.resName);\r
476        System.out.println(fatom.resName);\r
477      }\r
478      else\r
479         this.setToolTipText(null);\r
480   }\r
481 \r
482   public void mouseClicked(MouseEvent e) { }\r
483   public void mouseEntered(MouseEvent e) { }\r
484   public void mouseExited(MouseEvent e) { }\r
485 \r
486   public void mouseDragged(MouseEvent evt) {\r
487     int x = evt.getX();\r
488     int y = evt.getY();\r
489     mx = x;\r
490     my = y;\r
491 \r
492     MCMatrix objmat = new MCMatrix(3,3);\r
493     objmat.setIdentity();\r
494 \r
495     if ((evt.getModifiers()  & Event.META_MASK) != 0) {\r
496       objmat.rotatez((float)((mx-omx)));\r
497     } else {\r
498       objmat.rotatex((float)((my-omy)));\r
499       objmat.rotatey((float)((omx-mx)));\r
500     }\r
501 \r
502     //Alter the bonds\r
503     for (int ii = 0; ii < pdb.chains.size() ; ii++) {\r
504       Vector bonds = ((PDBChain)pdb.chains.elementAt(ii)).bonds;\r
505 \r
506       for (int i = 0; i < bonds.size(); i++) {\r
507 \r
508         Bond tmpBond = (Bond)bonds.elementAt(i);\r
509 \r
510         //Translate the bond so the centre is 0,0,0\r
511         tmpBond.translate(-centre[0],-centre[1],-centre[2]);\r
512 \r
513         //Now apply the rotation matrix\r
514         tmpBond.start = objmat.vectorMultiply(tmpBond.start);\r
515         tmpBond.end   = objmat.vectorMultiply(tmpBond.end);\r
516 \r
517         //Now translate back again\r
518         tmpBond.translate(centre[0],centre[1],centre[2]);\r
519       }\r
520     }\r
521 \r
522     objmat = null;\r
523 \r
524     omx    = mx;\r
525     omy    = my;\r
526 \r
527     redrawneeded = true;\r
528 \r
529     paint(this.getGraphics());\r
530 \r
531     dragging = true;\r
532     return;\r
533   }\r
534 \r
535   public void mouseReleased(MouseEvent evt) {\r
536     int x = evt.getX();\r
537     int y = evt.getY();\r
538 \r
539     if (!dragging) {\r
540       myAtom tmp = findAtom(x,y);\r
541     }\r
542     drawLabels();\r
543     return;\r
544   }\r
545 \r
546   public void drawLabels() {\r
547     redrawneeded = true;\r
548     paint(this.getGraphics());\r
549 \r
550     for (int ii = 0; ii < pdb.chains.size() ; ii++) {\r
551 \r
552       PDBChain chain = (PDBChain)pdb.chains.elementAt(ii);\r
553 \r
554       if (chain.isVisible) {\r
555 \r
556         Vector bonds = ((PDBChain)pdb.chains.elementAt(ii)).bonds;\r
557 \r
558         for (int i = 0; i < bonds.size(); i++) {\r
559           Bond tmpBond = (Bond)bonds.elementAt(i);\r
560 \r
561           if (tmpBond.at1.isSelected) {\r
562             labelAtom(img.getGraphics(),tmpBond,1);\r
563           }\r
564 \r
565           if (tmpBond.at2.isSelected) {\r
566             labelAtom(img.getGraphics(),tmpBond,2);\r
567           }\r
568 \r
569         }\r
570       }\r
571     }\r
572 \r
573     this.getGraphics().drawImage(img,0,0,this);\r
574 \r
575     dragging = false;\r
576 \r
577   }\r
578 \r
579   public void labelAtom(Graphics g,Bond b, int n) {\r
580 \r
581     g.setFont(font);\r
582 \r
583     if (n ==1) {\r
584 \r
585       int xstart = (int)((b.start[0] - centre[0])*scale + getWidth()/2);\r
586       int ystart = (int)((b.start[1] - centre[1])*scale + getHeight()/2);\r
587 \r
588       g.setColor(Color.red);\r
589       g.drawString(b.at1.resName + "-" + b.at1.resNumber,xstart,ystart);\r
590     }\r
591 \r
592     if (n ==2) {\r
593 \r
594       int xstart = (int)((b.end[0] - centre[0])*scale + getWidth()/2);\r
595       int ystart = (int)((b.end[1] - centre[1])*scale + getHeight()/2);\r
596 \r
597       g.setColor(Color.red);\r
598       g.drawString(b.at2.resName + "-" + b.at2.resNumber,xstart,ystart);\r
599     }\r
600   }\r
601 \r
602 \r
603   public myAtom findAtom(int x, int y) {\r
604     myAtom fatom = null;\r
605 \r
606     int foundchain = -1;\r
607 \r
608     for (int ii = 0; ii < pdb.chains.size() ; ii++) {\r
609 \r
610       PDBChain chain = (PDBChain)pdb.chains.elementAt(ii);\r
611 \r
612       if (chain.isVisible) {\r
613 \r
614         Vector bonds = ((PDBChain)pdb.chains.elementAt(ii)).bonds;\r
615 \r
616         for (int i = 0; i < bonds.size(); i++) {\r
617           Bond tmpBond = (Bond)bonds.elementAt(i);\r
618 \r
619           int truex = (int)((tmpBond.start[0] - centre[0])*scale + getWidth()/2);\r
620 \r
621           if (Math.abs(truex - x) <= 2) {\r
622 \r
623             int truey = (int)((tmpBond.start[1] - centre[1])*scale + getHeight()/2);\r
624 \r
625             if (Math.abs(truey - y) <= 2) {\r
626 \r
627               System.out.println("Found match");\r
628               System.out.println(x + " " + y);\r
629               System.out.println(truex + " " + truey);\r
630               System.out.println(tmpBond.start[0] + " " + tmpBond.start[1]);\r
631               System.out.println("Atom 1 = " + tmpBond.at1.resName + " " +\r
632                                  tmpBond.at1.resNumber + " " + tmpBond.at1.chain);\r
633               fatom = tmpBond.at1;\r
634               fatom.isSelected = !fatom.isSelected;\r
635               foundchain = ii;\r
636             }\r
637           }\r
638         }\r
639       }\r
640 \r
641       if (fatom != null) //)&& chain.ds != null)\r
642       {\r
643         chain = (PDBChain)pdb.chains.elementAt(foundchain);\r
644         // SMJS TODO\r
645         // int tmp = chain.ds.seqstart + fatom.resNumber - chain.offset;\r
646         // int pos = chain.ds.findIndex(tmp);\r
647         // System.out.println("Found seq " + chain.ds.name + " "  + tmp + " " + pos);\r
648       }\r
649 \r
650     }\r
651     return fatom;\r
652   }\r
653 \r
654   public void update(Graphics g) {\r
655     paint(g);\r
656   }\r
657 \r
658 }\r