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 import jalview.structure.*;
34 public class PDBCanvas
35 extends JPanel implements MouseListener, MouseMotionListener, StructureListener
37 boolean redrawneeded = true;
48 float[] centre = new float[3];
49 float[] width = new float[3];
54 boolean bysequence = true;
55 boolean depthcue = true;
57 boolean bymolecule = false;
58 boolean zbuffer = true;
66 Font font = new Font("Helvetica", Font.PLAIN, 10);
67 jalview.gui.SeqCanvas seqcanvas;
68 public SequenceI [] sequence;
69 final StringBuffer mappingDetails = new StringBuffer();
72 boolean pdbAction = false;
73 boolean seqColoursReady = false;
74 jalview.gui.FeatureRenderer fr;
75 Color backgroundColour = Color.black;
77 StructureSelectionManager ssm;
81 void init(PDBEntry pdbentry,
88 this.pdbentry = pdbentry;
91 ssm = StructureSelectionManager.getStructureSelectionManager();
94 pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol);
96 if(protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
97 pdbentry.setFile("INLINE"+pdb.id);
101 ex.printStackTrace();
107 errorMessage = "Error loading file: "+pdbentry.getId();
110 pdbentry.setId(pdb.id);
112 ssm.addStructureViewerListener(this);
123 //JUST DEAL WITH ONE SEQUENCE FOR NOW
124 SequenceI sequence = seq[0];
126 for (int i = 0; i < pdb.chains.size(); i++)
129 mappingDetails.append("\n\nPDB Sequence is :\nSequence = " +
130 ( (PDBChain) pdb.chains.elementAt(i)).sequence.
131 getSequenceAsString());
132 mappingDetails.append("\nNo of residues = " +
133 ( (PDBChain) pdb.chains.elementAt(i)).residues.size() +
136 // Now lets compare the sequences to get
137 // the start and end points.
138 // Align the sequence to the pdb
139 AlignSeq as = new AlignSeq(sequence,
140 ( (PDBChain) pdb.chains.elementAt(i)).sequence,
142 as.calcScoreMatrix();
144 PrintStream ps = new PrintStream(System.out)
146 public void print(String x)
148 mappingDetails.append(x);
151 public void println()
153 mappingDetails.append("\n");
157 as.printAlignment(ps);
159 if (as.maxscore > max)
164 pdbstart = as.seq2start;
166 seqstart = as.seq1start + sequence.getStart() - 1;
167 seqend = as.seq1end + sequence.getEnd() - 1;
170 mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
171 mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
174 mainchain = (PDBChain) pdb.chains.elementAt(maxchain);
176 mainchain.pdbstart = pdbstart;
177 mainchain.pdbend = pdbend;
178 mainchain.seqstart = seqstart;
179 mainchain.seqend = seqend;
180 mainchain.isVisible = true;
183 this.prefsize = new Dimension(getSize().width, getSize().height);
186 addMouseMotionListener(this);
187 addMouseListener(this);
189 addKeyListener(new KeyAdapter()
191 public void keyPressed(KeyEvent evt)
204 ToolTipManager.sharedInstance().registerComponent(this);
205 ToolTipManager.sharedInstance().setInitialDelay(0);
206 ToolTipManager.sharedInstance().setDismissDelay(10000);
212 seqColoursReady = false;
213 // Sort the bonds by z coord
214 visiblebonds = new Vector();
216 for (int ii = 0; ii < pdb.chains.size(); ii++)
218 if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
220 Vector tmp = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
222 for (int i = 0; i < tmp.size(); i++)
224 visiblebonds.addElement(tmp.elementAt(i));
230 seqColoursReady = true;
235 public void findWidth()
237 float[] max = new float[3];
238 float[] min = new float[3];
240 max[0] = (float) - 1e30;
241 max[1] = (float) - 1e30;
242 max[2] = (float) - 1e30;
244 min[0] = (float) 1e30;
245 min[1] = (float) 1e30;
246 min[2] = (float) 1e30;
248 for (int ii = 0; ii < pdb.chains.size(); ii++)
250 if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
252 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
254 for (int i = 0; i < bonds.size(); i++)
256 Bond tmp = (Bond) bonds.elementAt(i);
258 if (tmp.start[0] >= max[0])
260 max[0] = tmp.start[0];
263 if (tmp.start[1] >= max[1])
265 max[1] = tmp.start[1];
268 if (tmp.start[2] >= max[2])
270 max[2] = tmp.start[2];
273 if (tmp.start[0] <= min[0])
275 min[0] = tmp.start[0];
278 if (tmp.start[1] <= min[1])
280 min[1] = tmp.start[1];
283 if (tmp.start[2] <= min[2])
285 min[2] = tmp.start[2];
288 if (tmp.end[0] >= max[0])
293 if (tmp.end[1] >= max[1])
298 if (tmp.end[2] >= max[2])
303 if (tmp.end[0] <= min[0])
308 if (tmp.end[1] <= min[1])
313 if (tmp.end[2] <= min[2])
321 System.out.println("xmax " + max[0] + " min " + min[0]);
322 System.out.println("ymax " + max[1] + " min " + min[1]);
323 System.out.println("zmax " + max[2] + " min " + min[2]);*/
325 width[0] = (float) Math.abs(max[0] - min[0]);
326 width[1] = (float) Math.abs(max[1] - min[1]);
327 width[2] = (float) Math.abs(max[2] - min[2]);
331 if (width[1] > width[0])
336 if (width[2] > width[1])
341 // System.out.println("Maxwidth = " + maxwidth);
344 public float findScale()
353 height = getHeight();
357 width = prefsize.width;
358 height = prefsize.height;
370 return (float) (dim / (1.5d * maxwidth));
373 public void findCentre()
381 //Find centre coordinate
382 for (int ii = 0; ii < pdb.chains.size(); ii++)
384 if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
386 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
388 bsize += bonds.size();
390 for (int i = 0; i < bonds.size(); i++)
392 xtot = xtot + ( (Bond) bonds.elementAt(i)).start[0] +
393 ( (Bond) bonds.elementAt(i)).end[0];
395 ytot = ytot + ( (Bond) bonds.elementAt(i)).start[1] +
396 ( (Bond) bonds.elementAt(i)).end[1];
398 ztot = ztot + ( (Bond) bonds.elementAt(i)).start[2] +
399 ( (Bond) bonds.elementAt(i)).end[2];
404 centre[0] = xtot / (2 * (float) bsize);
405 centre[1] = ytot / (2 * (float) bsize);
406 centre[2] = ztot / (2 * (float) bsize);
409 public void paintComponent(Graphics g)
411 super.paintComponent(g);
413 if (!seqColoursReady || errorMessage!=null)
415 g.setColor(Color.black);
416 g.setFont(new Font("Verdana", Font.BOLD, 14));
417 g.drawString(errorMessage==null?
418 "Retrieving PDB data....":errorMessage,
419 20, getHeight() / 2);
423 //Only create the image at the beginning -
424 //this saves much memory usage
426 || (prefsize.width != getWidth())
427 || (prefsize.height != getHeight()))
430 prefsize.width = getWidth();
431 prefsize.height = getHeight();
434 img = createImage(prefsize.width, prefsize.height);
435 ig = img.getGraphics();
436 Graphics2D ig2 = (Graphics2D) ig;
438 ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
439 RenderingHints.VALUE_ANTIALIAS_ON);
446 drawAll(ig, prefsize.width, prefsize.height);
447 redrawneeded = false;
450 g.drawImage(img, 0, 0, this);
455 public void drawAll(Graphics g, int width, int height)
457 g.setColor(backgroundColour);
458 g.fillRect(0, 0, width, height);
463 public void updateSeqColours()
477 // This method has been taken out of PDBChain to allow
478 // Applet and Application specific sequence renderers to be used
479 void colourBySequence()
481 SequenceRenderer sr = new SequenceRenderer(ap.av);
483 StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
485 boolean showFeatures = false;
486 if (ap.av.getShowSequenceFeatures())
490 fr = new FeatureRenderer(ap);
493 fr.transferSettings(ap.alignFrame.getFeatureRenderer());
499 if (bysequence && pdb != null)
501 for (int ii = 0; ii < pdb.chains.size(); ii++)
503 chain = (PDBChain) pdb.chains.elementAt(ii);
505 for (int i = 0; i < chain.bonds.size(); i++)
507 Bond tmp = (Bond) chain.bonds.elementAt(i);
508 tmp.startCol = Color.lightGray;
509 tmp.endCol = Color.lightGray;
510 if (chain != mainchain)
515 for (int s = 0; s < sequence.length; s++)
517 for (int m = 0; m < mapping.length; m++)
519 if (mapping[m].getSequence() == sequence[s])
521 int pos = mapping[m].getSeqPos(tmp.at1.resNumber)-1;
524 pos = sequence[s].findIndex(pos);
525 tmp.startCol = sr.getResidueBoxColour(sequence[s], pos);
528 tmp.startCol = fr.findFeatureColour(tmp.startCol,
533 pos = mapping[m].getSeqPos(tmp.at2.resNumber)-1;
536 pos = sequence[s].findIndex(pos);
537 tmp.endCol = sr.getResidueBoxColour(sequence[s], pos);
540 tmp.endCol = fr.findFeatureColour(tmp.endCol,
555 public void drawScene(Graphics g)
564 zsort.Zsort(visiblebonds);
568 for (int i = 0; i < visiblebonds.size(); i++)
570 tmpBond = (Bond) visiblebonds.elementAt(i);
572 xstart = (int) ( ( (tmpBond.start[0] - centre[0]) * scale) +
574 ystart = (int) ( ( (centre[1] - tmpBond.start[1] ) * scale) +
577 xend = (int) ( ( (tmpBond.end[0] - centre[0]) * scale) +
579 yend = (int) ( ( (centre[1] - tmpBond.end[1] ) * scale) +
582 xmid = (xend + xstart) / 2;
583 ymid = (yend + ystart) / 2;
584 if (depthcue && !bymolecule)
586 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
589 g.setColor(tmpBond.startCol.darker().darker());
590 drawLine(g, xstart, ystart, xmid, ymid);
591 g.setColor(tmpBond.endCol.darker().darker());
592 drawLine(g, xmid, ymid, xend, yend);
595 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
597 g.setColor(tmpBond.startCol.darker());
598 drawLine(g, xstart, ystart, xmid, ymid);
600 g.setColor(tmpBond.endCol.darker());
601 drawLine(g, xmid, ymid, xend, yend);
605 g.setColor(tmpBond.startCol);
606 drawLine(g, xstart, ystart, xmid, ymid);
608 g.setColor(tmpBond.endCol);
609 drawLine(g, xmid, ymid, xend, yend);
612 else if (depthcue && bymolecule)
614 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
616 g.setColor(Color.green.darker().darker());
617 drawLine(g, xstart, ystart, xend, yend);
619 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
621 g.setColor(Color.green.darker());
622 drawLine(g, xstart, ystart, xend, yend);
626 g.setColor(Color.green);
627 drawLine(g, xstart, ystart, xend, yend);
630 else if (!depthcue && !bymolecule)
632 g.setColor(tmpBond.startCol);
633 drawLine(g, xstart, ystart, xmid, ymid);
634 g.setColor(tmpBond.endCol);
635 drawLine(g, xmid, ymid, xend, yend);
639 drawLine(g, xstart, ystart, xend, yend);
642 if (highlightBond1 != null && highlightBond1 == tmpBond)
644 g.setColor(tmpBond.endCol.brighter().brighter().brighter().brighter());
645 drawLine(g, xmid, ymid, xend, yend);
648 if (highlightBond2 != null && highlightBond2 == tmpBond)
650 g.setColor(tmpBond.startCol.brighter().brighter().brighter().brighter());
651 drawLine(g, xstart, ystart, xmid, ymid);
658 public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
662 if ( ( (float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
664 g.drawLine(x1, y1, x2, y2);
665 g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1);
666 g.drawLine(x1, y1 - 1, x2, y2 - 1);
670 g.setColor(g.getColor().brighter());
671 g.drawLine(x1, y1, x2, y2);
672 g.drawLine(x1 + 1, y1, x2 + 1, y2);
673 g.drawLine(x1 - 1, y1, x2 - 1, y2);
678 g.drawLine(x1, y1, x2, y2);
682 public Dimension minimumsize()
687 public Dimension preferredsize()
692 public void keyPressed(KeyEvent evt)
694 if (evt.getKeyCode() == KeyEvent.VK_UP)
696 scale = (float) (scale * 1.1);
700 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
702 scale = (float) (scale * 0.9);
708 public void mousePressed(MouseEvent e)
711 Atom fatom = findAtom(e.getX(), e.getY());
714 fatom.isSelected = !fatom.isSelected;
718 if (foundchain != -1)
720 PDBChain chain = (PDBChain) pdb.chains.elementAt(foundchain);
721 if (chain == mainchain)
723 if (fatom.alignmentMapping != -1)
725 if (highlightRes == null)
727 highlightRes = new Vector();
730 if (highlightRes.contains(fatom.alignmentMapping + ""))
732 highlightRes.remove(fatom.alignmentMapping + "");
736 highlightRes.add(fatom.alignmentMapping + "");
750 public void mouseMoved(MouseEvent e)
753 if (highlightBond1 != null)
755 highlightBond1.at2.isSelected = false;
756 highlightBond2.at1.isSelected = false;
757 highlightBond1 = null;
758 highlightBond2 = null;
761 Atom fatom = findAtom(e.getX(), e.getY());
763 PDBChain chain = null;
764 if (foundchain != -1)
766 chain = (PDBChain) pdb.chains.elementAt(foundchain);
767 if (chain == mainchain)
769 mouseOverStructure(fatom.resNumber, chain.id);
775 this.setToolTipText(chain.id + ":" + fatom.resNumber + " " +
780 mouseOverStructure(-1, chain!=null?chain.id:null);
781 this.setToolTipText(null);
785 public void mouseClicked(MouseEvent e)
788 public void mouseEntered(MouseEvent e)
791 public void mouseExited(MouseEvent e)
794 public void mouseDragged(MouseEvent evt)
801 MCMatrix objmat = new MCMatrix(3, 3);
802 objmat.setIdentity();
804 if ( (evt.getModifiers() & Event.META_MASK) != 0)
806 objmat.rotatez( (float) ( (mx - omx)));
810 objmat.rotatex( (float) ( (my - omy)));
811 objmat.rotatey( (float) ( (omx - mx)));
815 for (int ii = 0; ii < pdb.chains.size(); ii++)
817 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
819 for (int i = 0; i < bonds.size(); i++)
821 Bond tmpBond = (Bond) bonds.elementAt(i);
823 //Translate the bond so the centre is 0,0,0
824 tmpBond.translate( -centre[0], -centre[1], -centre[2]);
826 //Now apply the rotation matrix
827 tmpBond.start = objmat.vectorMultiply(tmpBond.start);
828 tmpBond.end = objmat.vectorMultiply(tmpBond.end);
830 //Now translate back again
831 tmpBond.translate(centre[0], centre[1], centre[2]);
847 public void mouseReleased(MouseEvent evt)
853 void drawLabels(Graphics g)
856 for (int ii = 0; ii < pdb.chains.size(); ii++)
858 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
862 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
864 for (int i = 0; i < bonds.size(); i++)
866 Bond tmpBond = (Bond) bonds.elementAt(i);
868 if (tmpBond.at1.isSelected)
870 labelAtom(g, tmpBond, 1);
873 if (tmpBond.at2.isSelected)
876 labelAtom(g, tmpBond, 2);
883 public void labelAtom(Graphics g, Bond b, int n)
886 g.setColor(Color.red);
889 int xstart = (int) ( ( (b.start[0] - centre[0]) * scale) +
891 int ystart = (int) ( ( (centre[1] - b.start[1] ) * scale) +
894 g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
899 int xstart = (int) ( ( (b.end[0] - centre[0]) * scale) +
901 int ystart = (int) ( ( (centre[1] - b.end[1] ) * scale) +
904 g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
909 public Atom findAtom(int x, int y)
915 for (int ii = 0; ii < pdb.chains.size(); ii++)
917 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
923 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
925 for (int i = 0; i < bonds.size(); i++)
927 tmpBond = (Bond) bonds.elementAt(i);
929 truex = (int) ( ( (tmpBond.start[0] - centre[0]) * scale) +
932 if (Math.abs(truex - x) <= 2)
934 int truey = (int) ( ( (centre[1] - tmpBond.start[1] ) * scale) +
937 if (Math.abs(truey - y) <= 2)
946 // Still here? Maybe its the last bond
948 truex = (int) ( ( (tmpBond.end[0] - centre[0]) * scale) +
951 if (Math.abs(truex - x) <= 2)
953 int truey = (int) ( ( (tmpBond.end[1] - centre[1]) * scale) +
956 if (Math.abs(truey - y) <= 2)
966 if (fatom != null) //)&& chain.ds != null)
968 chain = (PDBChain) pdb.chains.elementAt(foundchain);
975 Bond highlightBond1, highlightBond2;
976 public void highlightRes(int ii)
978 if (!seqColoursReady)
983 if (highlightRes != null
984 && highlightRes.contains( (ii - 1) + ""))
991 for (index = 0; index < mainchain.bonds.size(); index++)
993 tmpBond = (Bond) mainchain.bonds.elementAt(index);
994 if (tmpBond.at1.alignmentMapping == ii - 1)
996 if (highlightBond1 != null)
998 highlightBond1.at2.isSelected = false;
1001 if (highlightBond2 != null)
1003 highlightBond2.at1.isSelected = false;
1006 highlightBond1 = null;
1007 highlightBond2 = null;
1011 highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
1012 highlightBond1.at2.isSelected = true;
1015 if (index != mainchain.bonds.size())
1017 highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
1018 highlightBond2.at1.isSelected = true;
1025 redrawneeded = true;
1029 public void setAllchainsVisible(boolean b)
1031 for (int ii = 0; ii < pdb.chains.size(); ii++)
1033 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
1034 chain.isVisible = b;
1036 mainchain.isVisible = true;
1041 //////////////////////////////////
1042 ///StructureListener
1043 public String getPdbFile()
1045 return pdbentry.getFile();
1050 public void mouseOverStructure(int pdbResNum, String chain)
1052 if (lastMessage == null || !lastMessage.equals(pdbResNum+chain))
1053 ssm.mouseOverStructure(pdbResNum, chain, pdbentry.getFile());
1055 lastMessage = pdbResNum+chain;
1058 StringBuffer resetLastRes = new StringBuffer();
1059 StringBuffer eval = new StringBuffer();
1061 public void highlightAtom(int atomIndex, int pdbResNum, String chain, String pdbfile)
1063 if (!seqColoursReady)
1068 if (highlightRes != null
1069 && highlightRes.contains( (atomIndex - 1) + ""))
1076 for (index = 0; index < mainchain.bonds.size(); index++)
1078 tmpBond = (Bond) mainchain.bonds.elementAt(index);
1079 if (tmpBond.at1.atomIndex == atomIndex)
1081 if (highlightBond1 != null)
1083 highlightBond1.at2.isSelected = false;
1086 if (highlightBond2 != null)
1088 highlightBond2.at1.isSelected = false;
1091 highlightBond1 = null;
1092 highlightBond2 = null;
1096 highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
1097 highlightBond1.at2.isSelected = true;
1100 if (index != mainchain.bonds.size())
1102 highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
1103 highlightBond2.at1.isSelected = true;
1110 redrawneeded = true;
1115 public Color getColour(int atomIndex, int pdbResNum, String chain, String pdbfile)
1118 // if (!pdbfile.equals(pdbentry.getFile()))
1121 //return new Color(viewer.getAtomArgb(atomIndex));
1124 public void updateColours(Object source)
1127 redrawneeded = true;