formatting
[jalview.git] / src / MCview / AppletPDBCanvas.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package MCview;
20
21 import java.io.*;
22 import java.util.*;
23
24 // JBPNote TODO: This class is quite noisy - needs proper log.info/log.debug
25 import java.awt.*;
26 import java.awt.event.*;
27
28 import jalview.analysis.*;
29 import jalview.datamodel.*;
30
31 public class AppletPDBCanvas
32     extends Panel implements MouseListener, MouseMotionListener
33 {
34
35   MCMatrix idmat = new MCMatrix(3, 3);
36   MCMatrix objmat = new MCMatrix(3, 3);
37   boolean redrawneeded = true;
38   int omx = 0;
39   int mx = 0;
40   int omy = 0;
41   int my = 0;
42   public PDBfile pdb;
43   int bsize;
44   Image img;
45   Graphics ig;
46   Dimension prefsize;
47   float[] centre = new float[3];
48   float[] width = new float[3];
49   float maxwidth;
50   float scale;
51   String inStr;
52   String inType;
53   boolean bysequence = true;
54   boolean depthcue = true;
55   boolean wire = false;
56   boolean bymolecule = false;
57   boolean zbuffer = true;
58   boolean dragging;
59   int xstart;
60   int xend;
61   int ystart;
62   int yend;
63   int xmid;
64   int ymid;
65   Font font = new Font("Helvetica", Font.PLAIN, 10);
66   jalview.appletgui.SeqCanvas seqcanvas;
67   public Sequence sequence;
68   final StringBuffer mappingDetails = new StringBuffer();
69   String appletToolTip = null;
70   int toolx, tooly;
71   PDBChain mainchain;
72   Vector highlightRes;
73   boolean pdbAction = false;
74   Bond highlightBond1, highlightBond2;
75   boolean errorLoading = false;
76   boolean seqColoursReady = false;
77   jalview.appletgui.FeatureRenderer fr;
78
79   public AppletPDBCanvas(jalview.appletgui.SeqCanvas seqcanvas, Sequence seq)
80   {
81     this.seqcanvas = seqcanvas;
82     this.sequence = seq;
83
84     seqcanvas.setPDBCanvas(this);
85     addKeyListener(new KeyAdapter()
86     {
87
88       public void keyPressed(KeyEvent evt)
89       {
90         doKeyPressed(evt);
91       }
92     });
93   }
94
95   public void setPDBFile(PDBfile pdb)
96   {
97     int max = -10;
98     int maxchain = -1;
99     int pdbstart = 0;
100     int pdbend = 0;
101     int seqstart = 0;
102     int seqend = 0;
103     AlignSeq maxAlignseq = null; ;
104
105     for (int i = 0; i < pdb.chains.size(); i++)
106     {
107
108       mappingDetails.append("\n\nPDB Sequence is :\nSequence = " +
109                             ( (PDBChain) pdb.chains.elementAt(i)).sequence.
110                             getSequenceAsString());
111       mappingDetails.append("\nNo of residues = " +
112                             ( (PDBChain) pdb.chains.elementAt(i)).residues.size() +
113                             "\n\n");
114
115       // Now lets compare the sequences to get
116       // the start and end points.
117       // Align the sequence to the pdb
118       AlignSeq as = new AlignSeq(sequence,
119                                  ( (PDBChain) pdb.chains.elementAt(i)).sequence,
120                                  "pep");
121       as.calcScoreMatrix();
122       as.traceAlignment();
123       PrintStream ps = new PrintStream(System.out)
124       {
125         public void print(String x)
126         {
127           mappingDetails.append(x);
128         }
129
130         public void println()
131         {
132           mappingDetails.append("\n");
133         }
134       };
135
136       as.printAlignment(ps);
137
138       if (as.maxscore > max)
139       {
140         max = as.maxscore;
141         maxchain = i;
142
143         pdbstart = as.seq2start;
144         pdbend = as.seq2end;
145         seqstart = as.seq1start + sequence.getStart() - 1;
146         seqend = as.seq1end + sequence.getEnd() - 1;
147         maxAlignseq = as;
148       }
149
150       mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
151       mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
152     }
153
154     mainchain = (PDBChain) pdb.chains.elementAt(maxchain);
155
156     mainchain.pdbstart = pdbstart;
157     mainchain.pdbend = pdbend;
158     mainchain.seqstart = seqstart;
159     mainchain.seqend = seqend;
160     mainchain.isVisible = true;
161     mainchain.makeExactMapping(maxAlignseq, sequence);
162     mainchain.transferRESNUMFeatures(sequence, null);
163     this.pdb = pdb;
164     this.prefsize = new Dimension(getSize().width, getSize().height);
165
166     //Initialize the matrices to identity
167     for (int i = 0; i < 3; i++)
168     {
169       for (int j = 0; j < 3; j++)
170       {
171         if (i != j)
172         {
173           idmat.addElement(i, j, 0);
174           objmat.addElement(i, j, 0);
175         }
176         else
177         {
178           idmat.addElement(i, j, 1);
179           objmat.addElement(i, j, 1);
180         }
181       }
182     }
183
184     addMouseMotionListener(this);
185     addMouseListener(this);
186
187     findCentre();
188     findWidth();
189
190     setupBonds();
191
192     scale = findScale();
193   }
194
195   Vector visiblebonds;
196   void setupBonds()
197   {
198     seqColoursReady = false;
199     // Sort the bonds by z coord
200     visiblebonds = new Vector();
201
202     for (int ii = 0; ii < pdb.chains.size(); ii++)
203     {
204       if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
205       {
206         Vector tmp = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
207
208         for (int i = 0; i < tmp.size(); i++)
209         {
210           visiblebonds.addElement(tmp.elementAt(i));
211         }
212       }
213     }
214     updateSeqColours();
215     seqColoursReady = true;
216     redrawneeded = true;
217     repaint();
218   }
219
220   public void findWidth()
221   {
222     float[] max = new float[3];
223     float[] min = new float[3];
224
225     max[0] = (float) - 1e30;
226     max[1] = (float) - 1e30;
227     max[2] = (float) - 1e30;
228
229     min[0] = (float) 1e30;
230     min[1] = (float) 1e30;
231     min[2] = (float) 1e30;
232
233     for (int ii = 0; ii < pdb.chains.size(); ii++)
234     {
235       if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
236       {
237         Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
238
239         for (int i = 0; i < bonds.size(); i++)
240         {
241           Bond tmp = (Bond) bonds.elementAt(i);
242
243           if (tmp.start[0] >= max[0])
244           {
245             max[0] = tmp.start[0];
246           }
247
248           if (tmp.start[1] >= max[1])
249           {
250             max[1] = tmp.start[1];
251           }
252
253           if (tmp.start[2] >= max[2])
254           {
255             max[2] = tmp.start[2];
256           }
257
258           if (tmp.start[0] <= min[0])
259           {
260             min[0] = tmp.start[0];
261           }
262
263           if (tmp.start[1] <= min[1])
264           {
265             min[1] = tmp.start[1];
266           }
267
268           if (tmp.start[2] <= min[2])
269           {
270             min[2] = tmp.start[2];
271           }
272
273           if (tmp.end[0] >= max[0])
274           {
275             max[0] = tmp.end[0];
276           }
277
278           if (tmp.end[1] >= max[1])
279           {
280             max[1] = tmp.end[1];
281           }
282
283           if (tmp.end[2] >= max[2])
284           {
285             max[2] = tmp.end[2];
286           }
287
288           if (tmp.end[0] <= min[0])
289           {
290             min[0] = tmp.end[0];
291           }
292
293           if (tmp.end[1] <= min[1])
294           {
295             min[1] = tmp.end[1];
296           }
297
298           if (tmp.end[2] <= min[2])
299           {
300             min[2] = tmp.end[2];
301           }
302         }
303       }
304     }
305
306     width[0] = (float) Math.abs(max[0] - min[0]);
307     width[1] = (float) Math.abs(max[1] - min[1]);
308     width[2] = (float) Math.abs(max[2] - min[2]);
309
310     maxwidth = width[0];
311
312     if (width[1] > width[0])
313     {
314       maxwidth = width[1];
315     }
316
317     if (width[2] > width[1])
318     {
319       maxwidth = width[2];
320     }
321
322     // System.out.println("Maxwidth = " + maxwidth);
323   }
324
325   public float findScale()
326   {
327     int dim;
328     int width;
329     int height;
330
331     if (getSize().width != 0)
332     {
333       width = getSize().width;
334       height = getSize().height;
335     }
336     else
337     {
338       width = prefsize.width;
339       height = prefsize.height;
340     }
341
342     if (width < height)
343     {
344       dim = width;
345     }
346     else
347     {
348       dim = height;
349     }
350
351     return (float) (dim / (1.5d * maxwidth));
352   }
353
354   public void findCentre()
355   {
356     float xtot = 0;
357     float ytot = 0;
358     float ztot = 0;
359
360     int bsize = 0;
361
362     //Find centre coordinate
363     for (int ii = 0; ii < pdb.chains.size(); ii++)
364     {
365       if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
366       {
367         Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
368
369         bsize += bonds.size();
370
371         for (int i = 0; i < bonds.size(); i++)
372         {
373           xtot = xtot + ( (Bond) bonds.elementAt(i)).start[0] +
374               ( (Bond) bonds.elementAt(i)).end[0];
375
376           ytot = ytot + ( (Bond) bonds.elementAt(i)).start[1] +
377               ( (Bond) bonds.elementAt(i)).end[1];
378
379           ztot = ztot + ( (Bond) bonds.elementAt(i)).start[2] +
380               ( (Bond) bonds.elementAt(i)).end[2];
381         }
382       }
383     }
384
385     centre[0] = xtot / (2 * (float) bsize);
386     centre[1] = ytot / (2 * (float) bsize);
387     centre[2] = ztot / (2 * (float) bsize);
388   }
389
390   public void paint(Graphics g)
391   {
392
393     if (errorLoading)
394     {
395       g.setColor(Color.white);
396       g.fillRect(0, 0, getSize().width, getSize().height);
397       g.setColor(Color.black);
398       g.setFont(new Font("Verdana", Font.BOLD, 14));
399       g.drawString("Error loading PDB data!!", 50, getSize().height / 2);
400       return;
401     }
402
403     if (!seqColoursReady)
404     {
405       g.setColor(Color.black);
406       g.setFont(new Font("Verdana", Font.BOLD, 14));
407       g.drawString("Fetching PDB data...", 50, getSize().height / 2);
408       return;
409     }
410
411     //Only create the image at the beginning -
412     //this saves much memory usage
413     if ( (img == null) || (prefsize.width != getSize().width) ||
414         (prefsize.height != getSize().height))
415     {
416
417       try
418       {
419         prefsize.width = getSize().width;
420         prefsize.height = getSize().height;
421
422         scale = findScale();
423         img = createImage(prefsize.width, prefsize.height);
424         ig = img.getGraphics();
425
426         redrawneeded = true;
427       }
428       catch (Exception ex)
429       {
430         ex.printStackTrace();
431       }
432     }
433
434     if (redrawneeded)
435     {
436       drawAll(ig, prefsize.width, prefsize.height);
437       redrawneeded = false;
438     }
439     if (appletToolTip != null)
440     {
441       ig.setColor(Color.red);
442       ig.drawString(appletToolTip, toolx, tooly);
443     }
444
445     g.drawImage(img, 0, 0, this);
446
447     pdbAction = false;
448   }
449
450   public void drawAll(Graphics g, int width, int height)
451   {
452     ig.setColor(Color.black);
453     ig.fillRect(0, 0, width, height);
454     drawScene(ig);
455     drawLabels(ig);
456   }
457
458   void setColours(jalview.schemes.ColourSchemeI cs)
459   {
460     bysequence = false;
461     pdb.setColours(cs);
462     redrawneeded = true;
463     repaint();
464   }
465
466   public void updateSeqColours()
467   {
468     if (pdbAction)
469     {
470       return;
471     }
472
473     if (bysequence && pdb != null)
474     {
475       for (int ii = 0; ii < pdb.chains.size(); ii++)
476       {
477         colourBySequence( (PDBChain) pdb.chains.elementAt(ii));
478       }
479     }
480
481     redrawneeded = true;
482     repaint();
483   }
484
485   int findTrueIndex(int pos)
486   {
487     // returns the alignment position for a residue
488     int j = sequence.getStart();
489     int i = 0;
490
491     while ( (i < sequence.getLength()) && (j <= sequence.getEnd()) &&
492            (j <= pos + 1))
493     {
494       if (!jalview.util.Comparison.isGap(sequence.getCharAt(i)))
495       {
496         j++;
497       }
498
499       i++;
500     }
501
502     if (i > 1)
503     {
504       i--;
505     }
506
507     if ( (j == sequence.getEnd()) && (j < pos))
508     {
509       return sequence.getEnd() + 1;
510     }
511     else
512     {
513       return i;
514     }
515   }
516
517   // This method has been taken out of PDBChain to allow
518   // Applet and Application specific sequence renderers to be used
519   void colourBySequence(PDBChain chain)
520   {
521     boolean showFeatures = false;
522
523     if (seqcanvas.getViewport().getShowSequenceFeatures())
524     {
525       if (fr == null)
526       {
527         fr = new jalview.appletgui.FeatureRenderer(seqcanvas.getViewport());
528       }
529       fr.transferSettings(seqcanvas.getFeatureRenderer());
530       showFeatures = true;
531     }
532
533     for (int i = 0; i < chain.bonds.size(); i++)
534     {
535       Bond tmp = (Bond) chain.bonds.elementAt(i);
536       tmp.startCol = Color.lightGray;
537       tmp.endCol = Color.lightGray;
538       if (chain != mainchain)
539       {
540         continue;
541       }
542
543       if ( (tmp.at1.resNumber >= ( (chain.offset + chain.pdbstart) - 1)) &&
544           (tmp.at1.resNumber <= ( (chain.offset + chain.pdbend) - 1)))
545       {
546
547         int index = findTrueIndex(tmp.at1.alignmentMapping);
548         //sequence.findIndex(tmp.at1.alignmentMapping);
549         if (index != -1)
550         {
551           tmp.startCol = seqcanvas.getSequenceRenderer().
552               getResidueBoxColour(sequence, index);
553
554           if (showFeatures)
555           {
556             tmp.startCol = fr.findFeatureColour(tmp.startCol, sequence, index);
557           }
558         }
559       }
560
561       int index = findTrueIndex(tmp.at2.alignmentMapping);
562       //sequence.findIndex( tmp.at2.alignmentMapping );
563       if (index != -1)
564       {
565         tmp.endCol = seqcanvas.getSequenceRenderer().
566             getResidueBoxColour(sequence, index);
567
568         if (showFeatures)
569         {
570           tmp.endCol = fr.findFeatureColour(tmp.endCol, sequence, index);
571         }
572       }
573     }
574   }
575
576   Zsort zsort;
577   public void drawScene(Graphics g)
578   {
579     if (zbuffer)
580     {
581       if (zsort == null)
582       {
583         zsort = new Zsort();
584       }
585
586       zsort.Zsort(visiblebonds);
587     }
588
589     Bond tmpBond = null;
590     for (int i = 0; i < visiblebonds.size(); i++)
591     {
592       tmpBond = (Bond) visiblebonds.elementAt(i);
593
594       xstart = (int) ( ( (tmpBond.start[0] - centre[0]) * scale) +
595                       (getSize().width / 2));
596       ystart = (int) ( ( (tmpBond.start[1] - centre[1]) * scale) +
597                       (getSize().height / 2));
598
599       xend = (int) ( ( (tmpBond.end[0] - centre[0]) * scale) +
600                     (getSize().width / 2));
601       yend = (int) ( ( (tmpBond.end[1] - centre[1]) * scale) +
602                     (getSize().height / 2));
603
604       xmid = (xend + xstart) / 2;
605       ymid = (yend + ystart) / 2;
606
607       if (depthcue && !bymolecule)
608       {
609         if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
610         {
611           g.setColor(tmpBond.startCol.darker().darker());
612           drawLine(g, xstart, ystart, xmid, ymid);
613
614           g.setColor(tmpBond.endCol.darker().darker());
615           drawLine(g, xmid, ymid, xend, yend);
616         }
617         else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
618         {
619           g.setColor(tmpBond.startCol.darker());
620           drawLine(g, xstart, ystart, xmid, ymid);
621
622           g.setColor(tmpBond.endCol.darker());
623           drawLine(g, xmid, ymid, xend, yend);
624         }
625         else
626         {
627           g.setColor(tmpBond.startCol);
628           drawLine(g, xstart, ystart, xmid, ymid);
629
630           g.setColor(tmpBond.endCol);
631           drawLine(g, xmid, ymid, xend, yend);
632         }
633
634       }
635       else if (depthcue && bymolecule)
636       {
637         if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
638         {
639           g.setColor(Color.green.darker().darker());
640           drawLine(g, xstart, ystart, xend, yend);
641         }
642         else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
643         {
644           g.setColor(Color.green.darker());
645           drawLine(g, xstart, ystart, xend, yend);
646         }
647         else
648         {
649           g.setColor(Color.green);
650           drawLine(g, xstart, ystart, xend, yend);
651         }
652       }
653       else if (!depthcue && !bymolecule)
654       {
655         g.setColor(tmpBond.startCol);
656         drawLine(g, xstart, ystart, xmid, ymid);
657         g.setColor(tmpBond.endCol);
658         drawLine(g, xmid, ymid, xend, yend);
659       }
660       else
661       {
662         drawLine(g, xstart, ystart, xend, yend);
663       }
664
665       if (highlightBond1 != null && highlightBond1 == tmpBond)
666       {
667         g.setColor(Color.white);
668         drawLine(g, xmid, ymid, xend, yend);
669       }
670
671       if (highlightBond2 != null && highlightBond2 == tmpBond)
672       {
673         g.setColor(Color.white);
674         drawLine(g, xstart, ystart, xmid, ymid);
675       }
676
677     }
678   }
679
680   public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
681   {
682     if (!wire)
683     {
684       if ( ( (float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
685       {
686         g.drawLine(x1, y1, x2, y2);
687         g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1);
688         g.drawLine(x1, y1 - 1, x2, y2 - 1);
689       }
690       else
691       {
692         g.setColor(g.getColor().brighter());
693         g.drawLine(x1, y1, x2, y2);
694         g.drawLine(x1 + 1, y1, x2 + 1, y2);
695         g.drawLine(x1 - 1, y1, x2 - 1, y2);
696       }
697     }
698     else
699     {
700       g.drawLine(x1, y1, x2, y2);
701     }
702   }
703
704   public Dimension minimumsize()
705   {
706     return prefsize;
707   }
708
709   public Dimension preferredsize()
710   {
711     return prefsize;
712   }
713
714   public void doKeyPressed(KeyEvent evt)
715   {
716     if (evt.getKeyCode() == KeyEvent.VK_UP)
717     {
718       scale = (float) (scale * 1.1);
719       redrawneeded = true;
720       repaint();
721     }
722     else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
723     {
724       scale = (float) (scale * 0.9);
725       redrawneeded = true;
726       repaint();
727     }
728   }
729
730   public void mousePressed(MouseEvent e)
731   {
732     pdbAction = true;
733     Atom fatom = findAtom(e.getX(), e.getY());
734     if (fatom != null)
735     {
736       fatom.isSelected = !fatom.isSelected;
737
738       redrawneeded = true;
739       repaint();
740       if (foundchain != -1)
741       {
742         PDBChain chain = (PDBChain) pdb.chains.elementAt(foundchain);
743         if (chain == mainchain)
744         {
745           if (fatom.alignmentMapping != -1)
746           {
747             if (highlightRes == null)
748             {
749               highlightRes = new Vector();
750             }
751
752             if (highlightRes.contains(fatom.alignmentMapping + "" + ""))
753             {
754               highlightRes.removeElement(fatom.alignmentMapping + "");
755             }
756             else
757             {
758               highlightRes.addElement(fatom.alignmentMapping + "");
759             }
760           }
761         }
762       }
763
764     }
765     mx = e.getX();
766     my = e.getY();
767     omx = mx;
768     omy = my;
769     dragging = false;
770   }
771
772   public void mouseMoved(MouseEvent e)
773   {
774     pdbAction = true;
775     if (highlightBond1 != null)
776     {
777       highlightBond1.at2.isSelected = false;
778       highlightBond2.at1.isSelected = false;
779       highlightBond1 = null;
780       highlightBond2 = null;
781     }
782
783     Atom fatom = findAtom(e.getX(), e.getY());
784
785     PDBChain chain = null;
786     if (foundchain != -1)
787     {
788       chain = (PDBChain) pdb.chains.elementAt(foundchain);
789       if (chain == mainchain)
790       {
791         highlightSeqcanvas(fatom.alignmentMapping);
792       }
793     }
794
795     if (fatom != null)
796     {
797       toolx = e.getX();
798       tooly = e.getY();
799
800       appletToolTip = chain.id + ":" + fatom.resNumber + " " + fatom.resName;
801       redrawneeded = true;
802       repaint();
803     }
804     else
805     {
806       highlightSeqcanvas( -1);
807       appletToolTip = null;
808       redrawneeded = true;
809       repaint();
810     }
811   }
812
813   void highlightSeqcanvas(int pos)
814   {
815     SearchResults searchResults = new SearchResults();
816     if (highlightRes != null)
817     {
818       for (int i = 0; i < highlightRes.size(); i++)
819       {
820         int a = Integer.parseInt(highlightRes.elementAt(
821             i).toString()) + 1;
822
823         searchResults.addResult(sequence, a, a);
824       }
825     }
826
827     if (pos != -1)
828     {
829       searchResults.addResult(sequence, pos + 1, pos + 1);
830     }
831
832     seqcanvas.highlightSearchResults(searchResults);
833   }
834
835   public void mouseClicked(MouseEvent e)
836   {
837   }
838
839   public void mouseEntered(MouseEvent e)
840   {
841   }
842
843   public void mouseExited(MouseEvent e)
844   {
845   }
846
847   public void mouseDragged(MouseEvent evt)
848   {
849     int x = evt.getX();
850     int y = evt.getY();
851     mx = x;
852     my = y;
853
854     MCMatrix objmat = new MCMatrix(3, 3);
855     objmat.setIdentity();
856
857     if ( (evt.getModifiers() & Event.META_MASK) != 0)
858     {
859       objmat.rotatez( (float) ( (mx - omx)));
860     }
861     else
862     {
863       objmat.rotatex( (float) ( (my - omy)));
864       objmat.rotatey( (float) ( (omx - mx)));
865     }
866
867     //Alter the bonds
868     for (int ii = 0; ii < pdb.chains.size(); ii++)
869     {
870       Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
871
872       for (int i = 0; i < bonds.size(); i++)
873       {
874         Bond tmpBond = (Bond) bonds.elementAt(i);
875
876         //Translate the bond so the centre is 0,0,0
877         tmpBond.translate( -centre[0], -centre[1], -centre[2]);
878
879         //Now apply the rotation matrix
880         tmpBond.start = objmat.vectorMultiply(tmpBond.start);
881         tmpBond.end = objmat.vectorMultiply(tmpBond.end);
882
883         //Now translate back again
884         tmpBond.translate(centre[0], centre[1], centre[2]);
885       }
886     }
887
888     objmat = null;
889
890     omx = mx;
891     omy = my;
892
893     dragging = true;
894
895     redrawneeded = true;
896
897     repaint();
898   }
899
900   public void mouseReleased(MouseEvent evt)
901   {
902     dragging = false;
903     return;
904   }
905
906   void drawLabels(Graphics g)
907   {
908
909     for (int ii = 0; ii < pdb.chains.size(); ii++)
910     {
911       PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
912
913       if (chain.isVisible)
914       {
915         Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
916
917         for (int i = 0; i < bonds.size(); i++)
918         {
919           Bond tmpBond = (Bond) bonds.elementAt(i);
920
921           if (tmpBond.at1.isSelected)
922           {
923             labelAtom(g, tmpBond, 1);
924           }
925
926           if (tmpBond.at2.isSelected)
927           {
928
929             labelAtom(g, tmpBond, 2);
930           }
931         }
932       }
933     }
934   }
935
936   public void labelAtom(Graphics g, Bond b, int n)
937   {
938     g.setFont(font);
939
940     if (n == 1)
941     {
942       int xstart = (int) ( ( (b.start[0] - centre[0]) * scale) +
943                           (getSize().width / 2));
944       int ystart = (int) ( ( (b.start[1] - centre[1]) * scale) +
945                           (getSize().height / 2));
946
947       g.setColor(Color.red);
948       g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
949     }
950
951     if (n == 2)
952     {
953       int xstart = (int) ( ( (b.end[0] - centre[0]) * scale) +
954                           (getSize().width / 2));
955       int ystart = (int) ( ( (b.end[1] - centre[1]) * scale) +
956                           (getSize().height / 2));
957
958       g.setColor(Color.red);
959       g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
960     }
961   }
962
963   int foundchain = -1;
964   public Atom findAtom(int x, int y)
965   {
966     Atom fatom = null;
967
968     foundchain = -1;
969
970     for (int ii = 0; ii < pdb.chains.size(); ii++)
971     {
972       PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
973       int truex;
974       Bond tmpBond = null;
975
976       if (chain.isVisible)
977       {
978         Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
979
980         for (int i = 0; i < bonds.size(); i++)
981         {
982           tmpBond = (Bond) bonds.elementAt(i);
983
984           truex = (int) ( ( (tmpBond.start[0] - centre[0]) * scale) +
985                          (getSize().width / 2));
986
987           if (Math.abs(truex - x) <= 2)
988           {
989             int truey = (int) ( ( (tmpBond.start[1] - centre[1]) * scale) +
990                                (getSize().height / 2));
991
992             if (Math.abs(truey - y) <= 2)
993             {
994               fatom = tmpBond.at1;
995               foundchain = ii;
996               break;
997             }
998           }
999         }
1000
1001         // Still here? Maybe its the last bond
1002
1003         truex = (int) ( ( (tmpBond.end[0] - centre[0]) * scale) +
1004                        (getSize().width / 2));
1005
1006         if (Math.abs(truex - x) <= 2)
1007         {
1008           int truey = (int) ( ( (tmpBond.end[1] - centre[1]) * scale) +
1009                              (getSize().height / 2));
1010
1011           if (Math.abs(truey - y) <= 2)
1012           {
1013             fatom = tmpBond.at2;
1014             foundchain = ii;
1015             break;
1016           }
1017         }
1018
1019       }
1020
1021       if (fatom != null) //)&& chain.ds != null)
1022       {
1023         chain = (PDBChain) pdb.chains.elementAt(foundchain);
1024       }
1025     }
1026
1027     return fatom;
1028   }
1029
1030   public void update(Graphics g)
1031   {
1032     paint(g);
1033   }
1034
1035   public void highlightRes(int ii)
1036   {
1037     if (!seqColoursReady)
1038     {
1039       return;
1040     }
1041
1042     if (highlightRes != null
1043         && highlightRes.contains( (ii - 1) + ""))
1044     {
1045       return;
1046     }
1047
1048     int index = -1;
1049     Bond tmpBond;
1050     for (index = 0; index < mainchain.bonds.size(); index++)
1051     {
1052       tmpBond = (Bond) mainchain.bonds.elementAt(index);
1053       if (tmpBond.at1.alignmentMapping == ii - 1)
1054       {
1055         if (highlightBond1 != null)
1056         {
1057           highlightBond1.at2.isSelected = false;
1058         }
1059
1060         if (highlightBond2 != null)
1061         {
1062           highlightBond2.at1.isSelected = false;
1063         }
1064
1065         highlightBond1 = null;
1066         highlightBond2 = null;
1067
1068         if (index > 0)
1069         {
1070           highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
1071           highlightBond1.at2.isSelected = true;
1072         }
1073
1074         if (index != mainchain.bonds.size())
1075         {
1076           highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
1077           highlightBond2.at1.isSelected = true;
1078         }
1079
1080         break;
1081       }
1082     }
1083
1084     redrawneeded = true;
1085     repaint();
1086   }
1087
1088   public void setAllchainsVisible(boolean b)
1089   {
1090     for (int ii = 0; ii < pdb.chains.size(); ii++)
1091     {
1092       PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
1093       chain.isVisible = b;
1094     }
1095     mainchain.isVisible = true;
1096     findCentre();
1097     setupBonds();
1098   }
1099
1100 }