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