2 * Jalview - A Sequence Alignment Editor and Viewer
3 * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
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.
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.
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
24 // JBPNote TODO: This class is quite noisy - needs proper log.info/log.debug
26 import java.awt.event.*;
29 import jalview.analysis.*;
30 import jalview.datamodel.*;
32 public class PDBCanvas
33 extends JPanel implements MouseListener, MouseMotionListener
35 MCMatrix idmat = new MCMatrix(3, 3);
36 MCMatrix objmat = new MCMatrix(3, 3);
37 boolean redrawneeded = true;
47 float[] centre = new float[3];
48 float[] width = new float[3];
53 boolean bysequence = true;
54 boolean depthcue = true;
56 boolean bymolecule = false;
57 boolean zbuffer = true;
65 Font font = new Font("Helvetica", Font.PLAIN, 10);
66 jalview.gui.SeqCanvas seqcanvas;
67 public Sequence sequence;
68 final StringBuffer mappingDetails = new StringBuffer();
71 boolean pdbAction = false;
72 boolean seqColoursReady = false;
73 jalview.gui.FeatureRenderer fr;
74 Color backgroundColour = Color.black;
76 public PDBCanvas(jalview.gui.SeqCanvas seqcanvas, Sequence seq)
78 this.seqcanvas = seqcanvas;
80 seqcanvas.setPDBCanvas(this);
83 public void setPDBFile(PDBfile pdb)
91 AlignSeq maxAlignseq = null;
93 for (int i = 0; i < pdb.chains.size(); i++)
96 mappingDetails.append("\n\nPDB Sequence is :\nSequence = " +
97 ( (PDBChain) pdb.chains.elementAt(i)).sequence.
98 getSequenceAsString());
99 mappingDetails.append("\nNo of residues = " +
100 ( (PDBChain) pdb.chains.elementAt(i)).residues.size() +
103 // Now lets compare the sequences to get
104 // the start and end points.
105 // Align the sequence to the pdb
106 AlignSeq as = new AlignSeq(sequence,
107 ( (PDBChain) pdb.chains.elementAt(i)).sequence,
109 as.calcScoreMatrix();
111 PrintStream ps = new PrintStream(System.out)
113 public void print(String x)
115 mappingDetails.append(x);
118 public void println()
120 mappingDetails.append("\n");
124 as.printAlignment(ps);
126 if (as.maxscore > max)
130 pdbstart = as.seq2start;
132 seqstart = as.seq1start + sequence.getStart() - 1;
133 seqend = as.seq1end + sequence.getEnd() - 1;
137 mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
138 mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
141 mainchain = (PDBChain) pdb.chains.elementAt(maxchain);
143 mainchain.pdbstart = pdbstart;
144 mainchain.pdbend = pdbend;
145 mainchain.seqstart = seqstart;
146 mainchain.seqend = seqend;
147 mainchain.isVisible = true;
148 mainchain.makeExactMapping(maxAlignseq, sequence);
149 mainchain.transferRESNUMFeatures(sequence.getDatasetSequence(), null);
150 seqcanvas.getFeatureRenderer().featuresAdded();
152 this.prefsize = new Dimension(getWidth(), getHeight());
154 //Initialize the matrices to identity
155 for (int i = 0; i < 3; i++)
157 for (int j = 0; j < 3; j++)
161 idmat.addElement(i, j, 0);
162 objmat.addElement(i, j, 0);
166 idmat.addElement(i, j, 1);
167 objmat.addElement(i, j, 1);
172 addMouseMotionListener(this);
173 addMouseListener(this);
175 addMouseWheelListener(new MouseWheelListener()
177 public void mouseWheelMoved(MouseWheelEvent e)
179 if (e.getWheelRotation() > 0)
181 scale = (float) (scale * 1.1);
188 scale = (float) (scale * 0.9);
202 ToolTipManager.sharedInstance().registerComponent(this);
203 ToolTipManager.sharedInstance().setInitialDelay(0);
204 ToolTipManager.sharedInstance().setDismissDelay(10000);
210 seqColoursReady = false;
211 // Sort the bonds by z coord
212 visiblebonds = new Vector();
214 for (int ii = 0; ii < pdb.chains.size(); ii++)
216 if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
218 Vector tmp = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
220 for (int i = 0; i < tmp.size(); i++)
222 visiblebonds.addElement(tmp.elementAt(i));
228 seqColoursReady = true;
233 public void findWidth()
235 float[] max = new float[3];
236 float[] min = new float[3];
238 max[0] = (float) - 1e30;
239 max[1] = (float) - 1e30;
240 max[2] = (float) - 1e30;
242 min[0] = (float) 1e30;
243 min[1] = (float) 1e30;
244 min[2] = (float) 1e30;
246 for (int ii = 0; ii < pdb.chains.size(); ii++)
248 if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
250 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
252 for (int i = 0; i < bonds.size(); i++)
254 Bond tmp = (Bond) bonds.elementAt(i);
256 if (tmp.start[0] >= max[0])
258 max[0] = tmp.start[0];
261 if (tmp.start[1] >= max[1])
263 max[1] = tmp.start[1];
266 if (tmp.start[2] >= max[2])
268 max[2] = tmp.start[2];
271 if (tmp.start[0] <= min[0])
273 min[0] = tmp.start[0];
276 if (tmp.start[1] <= min[1])
278 min[1] = tmp.start[1];
281 if (tmp.start[2] <= min[2])
283 min[2] = tmp.start[2];
286 if (tmp.end[0] >= max[0])
291 if (tmp.end[1] >= max[1])
296 if (tmp.end[2] >= max[2])
301 if (tmp.end[0] <= min[0])
306 if (tmp.end[1] <= min[1])
311 if (tmp.end[2] <= min[2])
319 System.out.println("xmax " + max[0] + " min " + min[0]);
320 System.out.println("ymax " + max[1] + " min " + min[1]);
321 System.out.println("zmax " + max[2] + " min " + min[2]);*/
323 width[0] = (float) Math.abs(max[0] - min[0]);
324 width[1] = (float) Math.abs(max[1] - min[1]);
325 width[2] = (float) Math.abs(max[2] - min[2]);
329 if (width[1] > width[0])
334 if (width[2] > width[1])
339 // System.out.println("Maxwidth = " + maxwidth);
342 public float findScale()
351 height = getHeight();
355 width = prefsize.width;
356 height = prefsize.height;
368 return (float) (dim / (1.5d * maxwidth));
371 public void findCentre()
379 //Find centre coordinate
380 for (int ii = 0; ii < pdb.chains.size(); ii++)
382 if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
384 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
386 bsize += bonds.size();
388 for (int i = 0; i < bonds.size(); i++)
390 xtot = xtot + ( (Bond) bonds.elementAt(i)).start[0] +
391 ( (Bond) bonds.elementAt(i)).end[0];
393 ytot = ytot + ( (Bond) bonds.elementAt(i)).start[1] +
394 ( (Bond) bonds.elementAt(i)).end[1];
396 ztot = ztot + ( (Bond) bonds.elementAt(i)).start[2] +
397 ( (Bond) bonds.elementAt(i)).end[2];
402 centre[0] = xtot / (2 * (float) bsize);
403 centre[1] = ytot / (2 * (float) bsize);
404 centre[2] = ztot / (2 * (float) bsize);
407 public void paintComponent(Graphics g)
409 super.paintComponent(g);
411 if (!seqColoursReady)
413 g.setColor(Color.black);
414 g.setFont(new Font("Verdana", Font.BOLD, 14));
415 g.drawString("Retrieving PDB data....", 20, getHeight() / 2);
419 //Only create the image at the beginning -
420 //this saves much memory usage
422 || (prefsize.width != getWidth())
423 || (prefsize.height != getHeight()))
426 prefsize.width = getWidth();
427 prefsize.height = getHeight();
430 img = createImage(prefsize.width, prefsize.height);
431 ig = img.getGraphics();
432 Graphics2D ig2 = (Graphics2D) ig;
434 ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
435 RenderingHints.VALUE_ANTIALIAS_ON);
442 drawAll(ig, prefsize.width, prefsize.height);
443 redrawneeded = false;
446 g.drawImage(img, 0, 0, this);
451 public void drawAll(Graphics g, int width, int height)
453 g.setColor(backgroundColour);
454 g.fillRect(0, 0, width, height);
459 public void updateSeqColours()
466 // System.out.println("update seq colours");
467 if (bysequence && pdb != null)
469 for (int ii = 0; ii < pdb.chains.size(); ii++)
471 colourBySequence( (PDBChain) pdb.chains.elementAt(ii));
479 int findTrueIndex(int pos)
481 // returns the alignment position for a residue
482 int j = sequence.getStart(); // first position in PDB atom coordinate sequence
485 while ( (i < sequence.getLength()) && (j <= pos + 1))
487 if (!jalview.util.Comparison.isGap(sequence.getCharAt(i)))
502 return sequence.getEnd() + 1;
510 // This method has been taken out of PDBChain to allow
511 // Applet and Application specific sequence renderers to be used
512 void colourBySequence(PDBChain chain)
514 // System.out.println("colour by seq");
515 boolean showFeatures = false;
516 if (seqcanvas.getViewport().getShowSequenceFeatures())
521 fr = new jalview.gui.FeatureRenderer(seqcanvas.getViewport());
524 fr.transferSettings(seqcanvas.getFeatureRenderer());
528 for (int i = 0; i < chain.bonds.size(); i++)
530 tmp = (Bond) chain.bonds.elementAt(i);
532 if (chain != mainchain)
537 //if ( (tmp.at1.resNumber >= ( (chain.offset + chain.pdbstart) - 1)) &&
538 // (tmp.at1.resNumber <= ( (chain.offset + chain.pdbend) - 1)))
540 int index = findTrueIndex(tmp.at1.alignmentMapping);
541 //sequence.findIndex(tmp.at1.alignmentMapping);
544 tmp.startCol = seqcanvas.getSequenceRenderer().
545 getResidueBoxColour(sequence, index);
549 tmp.startCol = fr.findFeatureColour(tmp.startCol, sequence, index);
552 if (tmp.startCol == null)
554 tmp.startCol = Color.white;
559 //if ( (tmp.at2.resNumber >= ( (chain.offset + chain.pdbstart) - 1)) &&
560 // (tmp.at2.resNumber <= ( (chain.pdbend + chain.offset) - 1)))
563 int index = findTrueIndex(tmp.at2.alignmentMapping);
564 //sequence.findIndex( tmp.at2.alignmentMapping );
567 tmp.endCol = seqcanvas.getSequenceRenderer().
568 getResidueBoxColour(sequence, index);
572 tmp.endCol = fr.findFeatureColour(tmp.endCol, sequence, index);
575 if (tmp.endCol == null)
577 tmp.endCol = Color.white;
585 public void drawScene(Graphics g)
594 zsort.Zsort(visiblebonds);
598 for (int i = 0; i < visiblebonds.size(); i++)
600 tmpBond = (Bond) visiblebonds.elementAt(i);
602 xstart = (int) ( ( (tmpBond.start[0] - centre[0]) * scale) +
604 ystart = (int) ( ( (tmpBond.start[1] - centre[1]) * scale) +
607 xend = (int) ( ( (tmpBond.end[0] - centre[0]) * scale) +
609 yend = (int) ( ( (tmpBond.end[1] - centre[1]) * scale) +
612 xmid = (xend + xstart) / 2;
613 ymid = (yend + ystart) / 2;
614 if (depthcue && !bymolecule)
616 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
619 g.setColor(tmpBond.startCol.darker().darker());
620 drawLine(g, xstart, ystart, xmid, ymid);
621 g.setColor(tmpBond.endCol.darker().darker());
622 drawLine(g, xmid, ymid, xend, yend);
625 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
627 g.setColor(tmpBond.startCol.darker());
628 drawLine(g, xstart, ystart, xmid, ymid);
630 g.setColor(tmpBond.endCol.darker());
631 drawLine(g, xmid, ymid, xend, yend);
635 g.setColor(tmpBond.startCol);
636 drawLine(g, xstart, ystart, xmid, ymid);
638 g.setColor(tmpBond.endCol);
639 drawLine(g, xmid, ymid, xend, yend);
642 else if (depthcue && bymolecule)
644 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
646 g.setColor(Color.green.darker().darker());
647 drawLine(g, xstart, ystart, xend, yend);
649 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
651 g.setColor(Color.green.darker());
652 drawLine(g, xstart, ystart, xend, yend);
656 g.setColor(Color.green);
657 drawLine(g, xstart, ystart, xend, yend);
660 else if (!depthcue && !bymolecule)
662 g.setColor(tmpBond.startCol);
663 drawLine(g, xstart, ystart, xmid, ymid);
664 g.setColor(tmpBond.endCol);
665 drawLine(g, xmid, ymid, xend, yend);
669 drawLine(g, xstart, ystart, xend, yend);
672 if (highlightBond1 != null && highlightBond1 == tmpBond)
674 g.setColor(tmpBond.endCol.brighter().brighter().brighter().brighter());
675 drawLine(g, xmid, ymid, xend, yend);
678 if (highlightBond2 != null && highlightBond2 == tmpBond)
680 g.setColor(tmpBond.startCol.brighter().brighter().brighter().brighter());
681 drawLine(g, xstart, ystart, xmid, ymid);
688 public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
692 if ( ( (float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
694 g.drawLine(x1, y1, x2, y2);
695 g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1);
696 g.drawLine(x1, y1 - 1, x2, y2 - 1);
700 g.setColor(g.getColor().brighter());
701 g.drawLine(x1, y1, x2, y2);
702 g.drawLine(x1 + 1, y1, x2 + 1, y2);
703 g.drawLine(x1 - 1, y1, x2 - 1, y2);
708 g.drawLine(x1, y1, x2, y2);
712 public Dimension minimumsize()
717 public Dimension preferredsize()
722 public void keyPressed(KeyEvent evt)
724 if (evt.getKeyCode() == KeyEvent.VK_UP)
726 scale = (float) (scale * 1.1);
730 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
732 scale = (float) (scale * 0.9);
738 public void mousePressed(MouseEvent e)
741 Atom fatom = findAtom(e.getX(), e.getY());
744 fatom.isSelected = !fatom.isSelected;
748 if (foundchain != -1)
750 PDBChain chain = (PDBChain) pdb.chains.elementAt(foundchain);
751 if (chain == mainchain)
753 if (fatom.alignmentMapping != -1)
755 if (highlightRes == null)
757 highlightRes = new Vector();
760 if (highlightRes.contains(fatom.alignmentMapping + ""))
762 highlightRes.remove(fatom.alignmentMapping + "");
766 highlightRes.add(fatom.alignmentMapping + "");
780 public void mouseMoved(MouseEvent e)
783 if (highlightBond1 != null)
785 highlightBond1.at2.isSelected = false;
786 highlightBond2.at1.isSelected = false;
787 highlightBond1 = null;
788 highlightBond2 = null;
791 Atom fatom = findAtom(e.getX(), e.getY());
793 PDBChain chain = null;
794 if (foundchain != -1)
796 chain = (PDBChain) pdb.chains.elementAt(foundchain);
797 if (chain == mainchain)
799 highlightSeqcanvas(fatom.alignmentMapping);
805 this.setToolTipText(chain.id + ":" + fatom.resNumber + " " +
810 highlightSeqcanvas( -1);
811 this.setToolTipText(null);
815 void highlightSeqcanvas(int pos)
817 SearchResults searchResults = new SearchResults();
818 if (highlightRes != null)
820 for (int i = 0; i < highlightRes.size(); i++)
822 int a = Integer.parseInt(highlightRes.elementAt(
825 searchResults.addResult(sequence, a, a);
831 searchResults.addResult(sequence, pos + 1, pos + 1);
834 seqcanvas.highlightSearchResults(searchResults);
837 public void mouseClicked(MouseEvent e)
840 public void mouseEntered(MouseEvent e)
843 public void mouseExited(MouseEvent e)
846 public void mouseDragged(MouseEvent evt)
853 MCMatrix objmat = new MCMatrix(3, 3);
854 objmat.setIdentity();
856 if ( (evt.getModifiers() & Event.META_MASK) != 0)
858 objmat.rotatez( (float) ( (mx - omx)));
862 objmat.rotatex( (float) ( (my - omy)));
863 objmat.rotatey( (float) ( (omx - mx)));
867 for (int ii = 0; ii < pdb.chains.size(); ii++)
869 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
871 for (int i = 0; i < bonds.size(); i++)
873 Bond tmpBond = (Bond) bonds.elementAt(i);
875 //Translate the bond so the centre is 0,0,0
876 tmpBond.translate( -centre[0], -centre[1], -centre[2]);
878 //Now apply the rotation matrix
879 tmpBond.start = objmat.vectorMultiply(tmpBond.start);
880 tmpBond.end = objmat.vectorMultiply(tmpBond.end);
882 //Now translate back again
883 tmpBond.translate(centre[0], centre[1], centre[2]);
899 public void mouseReleased(MouseEvent evt)
905 void drawLabels(Graphics g)
908 for (int ii = 0; ii < pdb.chains.size(); ii++)
910 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
914 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
916 for (int i = 0; i < bonds.size(); i++)
918 Bond tmpBond = (Bond) bonds.elementAt(i);
920 if (tmpBond.at1.isSelected)
922 labelAtom(g, tmpBond, 1);
925 if (tmpBond.at2.isSelected)
928 labelAtom(g, tmpBond, 2);
935 public void labelAtom(Graphics g, Bond b, int n)
938 g.setColor(Color.red);
941 int xstart = (int) ( ( (b.start[0] - centre[0]) * scale) +
943 int ystart = (int) ( ( (b.start[1] - centre[1]) * scale) +
946 g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
951 int xstart = (int) ( ( (b.end[0] - centre[0]) * scale) +
953 int ystart = (int) ( ( (b.end[1] - centre[1]) * scale) +
956 g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
961 public Atom findAtom(int x, int y)
967 for (int ii = 0; ii < pdb.chains.size(); ii++)
969 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
975 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
977 for (int i = 0; i < bonds.size(); i++)
979 tmpBond = (Bond) bonds.elementAt(i);
981 truex = (int) ( ( (tmpBond.start[0] - centre[0]) * scale) +
984 if (Math.abs(truex - x) <= 2)
986 int truey = (int) ( ( (tmpBond.start[1] - centre[1]) * scale) +
989 if (Math.abs(truey - y) <= 2)
998 // Still here? Maybe its the last bond
1000 truex = (int) ( ( (tmpBond.end[0] - centre[0]) * scale) +
1003 if (Math.abs(truex - x) <= 2)
1005 int truey = (int) ( ( (tmpBond.end[1] - centre[1]) * scale) +
1008 if (Math.abs(truey - y) <= 2)
1010 fatom = tmpBond.at2;
1018 if (fatom != null) //)&& chain.ds != null)
1020 chain = (PDBChain) pdb.chains.elementAt(foundchain);
1027 Bond highlightBond1, highlightBond2;
1028 public void highlightRes(int ii)
1030 if (!seqColoursReady)
1035 if (highlightRes != null
1036 && highlightRes.contains( (ii - 1) + ""))
1043 for (index = 0; index < mainchain.bonds.size(); index++)
1045 tmpBond = (Bond) mainchain.bonds.elementAt(index);
1046 if (tmpBond.at1.alignmentMapping == ii - 1)
1048 if (highlightBond1 != null)
1050 highlightBond1.at2.isSelected = false;
1053 if (highlightBond2 != null)
1055 highlightBond2.at1.isSelected = false;
1058 highlightBond1 = null;
1059 highlightBond2 = null;
1063 highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
1064 highlightBond1.at2.isSelected = true;
1067 if (index != mainchain.bonds.size())
1069 highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
1070 highlightBond2.at1.isSelected = true;
1077 redrawneeded = true;
1081 public void setAllchainsVisible(boolean b)
1083 for (int ii = 0; ii < pdb.chains.size(); ii++)
1085 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
1086 chain.isVisible = b;
1088 mainchain.isVisible = true;