2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3 * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
23 // JBPNote TODO: This class is quite noisy - needs proper log.info/log.debug
25 import java.awt.event.*;
28 import jalview.analysis.*;
29 import jalview.datamodel.*;
31 import jalview.structure.*;
33 public class PDBCanvas extends JPanel implements MouseListener,
34 MouseMotionListener, StructureListener
36 boolean redrawneeded = true;
58 float[] centre = new float[3];
60 float[] width = new float[3];
70 boolean bysequence = true;
72 boolean depthcue = true;
76 boolean bymolecule = false;
78 boolean zbuffer = true;
94 Font font = new Font("Helvetica", Font.PLAIN, 10);
96 jalview.gui.SeqCanvas seqcanvas;
98 public SequenceI[] sequence;
100 final StringBuffer mappingDetails = new StringBuffer();
106 boolean pdbAction = false;
108 boolean seqColoursReady = false;
110 jalview.gui.FeatureRenderer fr;
112 Color backgroundColour = Color.black;
116 StructureSelectionManager ssm;
120 void init(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
121 AlignmentPanel ap, String protocol)
124 this.pdbentry = pdbentry;
127 ssm = ap.av.getStructureSelectionManager();
131 pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol);
133 if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
134 pdbentry.setFile("INLINE" + pdb.id);
136 } catch (Exception ex)
138 ex.printStackTrace();
144 errorMessage = "Error loading file: " + pdbentry.getId();
147 pdbentry.setId(pdb.id);
149 ssm.addStructureViewerListener(this);
160 // JUST DEAL WITH ONE SEQUENCE FOR NOW
161 SequenceI sequence = seq[0];
163 for (int i = 0; i < pdb.chains.size(); i++)
166 mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
167 + ((PDBChain) pdb.chains.elementAt(i)).sequence
168 .getSequenceAsString());
169 mappingDetails.append("\nNo of residues = "
170 + ((PDBChain) pdb.chains.elementAt(i)).residues.size()
173 // Now lets compare the sequences to get
174 // the start and end points.
175 // Align the sequence to the pdb
176 AlignSeq as = new AlignSeq(sequence,
177 ((PDBChain) pdb.chains.elementAt(i)).sequence, "pep");
178 as.calcScoreMatrix();
180 PrintStream ps = new PrintStream(System.out)
182 public void print(String x)
184 mappingDetails.append(x);
187 public void println()
189 mappingDetails.append("\n");
193 as.printAlignment(ps);
195 if (as.maxscore > max)
200 pdbstart = as.seq2start;
202 seqstart = as.seq1start + sequence.getStart() - 1;
203 seqend = as.seq1end + sequence.getEnd() - 1;
206 mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
207 mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
210 mainchain = (PDBChain) pdb.chains.elementAt(maxchain);
212 mainchain.pdbstart = pdbstart;
213 mainchain.pdbend = pdbend;
214 mainchain.seqstart = seqstart;
215 mainchain.seqend = seqend;
216 mainchain.isVisible = true;
219 this.prefsize = new Dimension(getSize().width, getSize().height);
221 addMouseMotionListener(this);
222 addMouseListener(this);
224 addKeyListener(new KeyAdapter()
226 public void keyPressed(KeyEvent evt)
239 ToolTipManager.sharedInstance().registerComponent(this);
240 ToolTipManager.sharedInstance().setInitialDelay(0);
241 ToolTipManager.sharedInstance().setDismissDelay(10000);
248 seqColoursReady = false;
249 // Sort the bonds by z coord
250 visiblebonds = new Vector();
252 for (int ii = 0; ii < pdb.chains.size(); ii++)
254 if (((PDBChain) pdb.chains.elementAt(ii)).isVisible)
256 Vector tmp = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
258 for (int i = 0; i < tmp.size(); i++)
260 visiblebonds.addElement(tmp.elementAt(i));
266 seqColoursReady = true;
271 public void findWidth()
273 float[] max = new float[3];
274 float[] min = new float[3];
276 max[0] = (float) -1e30;
277 max[1] = (float) -1e30;
278 max[2] = (float) -1e30;
280 min[0] = (float) 1e30;
281 min[1] = (float) 1e30;
282 min[2] = (float) 1e30;
284 for (int ii = 0; ii < pdb.chains.size(); ii++)
286 if (((PDBChain) pdb.chains.elementAt(ii)).isVisible)
288 Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
290 for (int i = 0; i < bonds.size(); i++)
292 Bond tmp = (Bond) bonds.elementAt(i);
294 if (tmp.start[0] >= max[0])
296 max[0] = tmp.start[0];
299 if (tmp.start[1] >= max[1])
301 max[1] = tmp.start[1];
304 if (tmp.start[2] >= max[2])
306 max[2] = tmp.start[2];
309 if (tmp.start[0] <= min[0])
311 min[0] = tmp.start[0];
314 if (tmp.start[1] <= min[1])
316 min[1] = tmp.start[1];
319 if (tmp.start[2] <= min[2])
321 min[2] = tmp.start[2];
324 if (tmp.end[0] >= max[0])
329 if (tmp.end[1] >= max[1])
334 if (tmp.end[2] >= max[2])
339 if (tmp.end[0] <= min[0])
344 if (tmp.end[1] <= min[1])
349 if (tmp.end[2] <= min[2])
357 * System.out.println("xmax " + max[0] + " min " + min[0]);
358 * System.out.println("ymax " + max[1] + " min " + min[1]);
359 * System.out.println("zmax " + max[2] + " min " + min[2]);
362 width[0] = (float) Math.abs(max[0] - min[0]);
363 width[1] = (float) Math.abs(max[1] - min[1]);
364 width[2] = (float) Math.abs(max[2] - min[2]);
368 if (width[1] > width[0])
373 if (width[2] > width[1])
378 // System.out.println("Maxwidth = " + maxwidth);
381 public float findScale()
390 height = getHeight();
394 width = prefsize.width;
395 height = prefsize.height;
407 return (float) (dim / (1.5d * maxwidth));
410 public void findCentre()
418 // Find centre coordinate
419 for (int ii = 0; ii < pdb.chains.size(); ii++)
421 if (((PDBChain) pdb.chains.elementAt(ii)).isVisible)
423 Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
425 bsize += bonds.size();
427 for (int i = 0; i < bonds.size(); i++)
429 xtot = xtot + ((Bond) bonds.elementAt(i)).start[0]
430 + ((Bond) bonds.elementAt(i)).end[0];
432 ytot = ytot + ((Bond) bonds.elementAt(i)).start[1]
433 + ((Bond) bonds.elementAt(i)).end[1];
435 ztot = ztot + ((Bond) bonds.elementAt(i)).start[2]
436 + ((Bond) bonds.elementAt(i)).end[2];
441 centre[0] = xtot / (2 * (float) bsize);
442 centre[1] = ytot / (2 * (float) bsize);
443 centre[2] = ztot / (2 * (float) bsize);
446 public void paintComponent(Graphics g)
448 super.paintComponent(g);
450 if (!seqColoursReady || errorMessage != null)
452 g.setColor(Color.black);
453 g.setFont(new Font("Verdana", Font.BOLD, 14));
454 g.drawString(errorMessage == null ? "Retrieving PDB data...."
455 : errorMessage, 20, getHeight() / 2);
459 // Only create the image at the beginning -
460 // this saves much memory usage
461 if ((img == null) || (prefsize.width != getWidth())
462 || (prefsize.height != getHeight()))
465 prefsize.width = getWidth();
466 prefsize.height = getHeight();
469 img = createImage(prefsize.width, prefsize.height);
470 ig = img.getGraphics();
471 Graphics2D ig2 = (Graphics2D) ig;
473 ig2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
474 RenderingHints.VALUE_ANTIALIAS_ON);
481 drawAll(ig, prefsize.width, prefsize.height);
482 redrawneeded = false;
485 g.drawImage(img, 0, 0, this);
490 public void drawAll(Graphics g, int width, int height)
492 g.setColor(backgroundColour);
493 g.fillRect(0, 0, width, height);
498 public void updateSeqColours()
511 // This method has been taken out of PDBChain to allow
512 // Applet and Application specific sequence renderers to be used
513 void colourBySequence()
515 SequenceRenderer sr = new SequenceRenderer(ap.av);
517 StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
519 boolean showFeatures = false;
520 if (ap.av.getShowSequenceFeatures())
524 fr = new FeatureRenderer(ap);
527 fr.transferSettings(ap.alignFrame.getFeatureRenderer());
533 if (bysequence && pdb != null)
535 for (int ii = 0; ii < pdb.chains.size(); ii++)
537 chain = (PDBChain) pdb.chains.elementAt(ii);
539 for (int i = 0; i < chain.bonds.size(); i++)
541 Bond tmp = (Bond) chain.bonds.elementAt(i);
542 tmp.startCol = Color.lightGray;
543 tmp.endCol = Color.lightGray;
544 if (chain != mainchain)
549 for (int s = 0; s < sequence.length; s++)
551 for (int m = 0; m < mapping.length; m++)
553 if (mapping[m].getSequence() == sequence[s])
555 int pos = mapping[m].getSeqPos(tmp.at1.resNumber) - 1;
558 pos = sequence[s].findIndex(pos);
559 tmp.startCol = sr.getResidueBoxColour(sequence[s], pos);
562 tmp.startCol = fr.findFeatureColour(tmp.startCol,
566 pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
569 pos = sequence[s].findIndex(pos);
570 tmp.endCol = sr.getResidueBoxColour(sequence[s], pos);
573 tmp.endCol = fr.findFeatureColour(tmp.endCol,
588 public void drawScene(Graphics g)
597 zsort.Zsort(visiblebonds);
601 for (int i = 0; i < visiblebonds.size(); i++)
603 tmpBond = (Bond) visiblebonds.elementAt(i);
605 xstart = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getWidth() / 2));
606 ystart = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getHeight() / 2));
608 xend = (int) (((tmpBond.end[0] - centre[0]) * scale) + (getWidth() / 2));
609 yend = (int) (((centre[1] - tmpBond.end[1]) * scale) + (getHeight() / 2));
611 xmid = (xend + xstart) / 2;
612 ymid = (yend + ystart) / 2;
613 if (depthcue && !bymolecule)
615 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
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);
624 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
626 g.setColor(tmpBond.startCol.darker());
627 drawLine(g, xstart, ystart, xmid, ymid);
629 g.setColor(tmpBond.endCol.darker());
630 drawLine(g, xmid, ymid, xend, yend);
634 g.setColor(tmpBond.startCol);
635 drawLine(g, xstart, ystart, xmid, ymid);
637 g.setColor(tmpBond.endCol);
638 drawLine(g, xmid, ymid, xend, yend);
641 else if (depthcue && bymolecule)
643 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
645 g.setColor(Color.green.darker().darker());
646 drawLine(g, xstart, ystart, xend, yend);
648 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
650 g.setColor(Color.green.darker());
651 drawLine(g, xstart, ystart, xend, yend);
655 g.setColor(Color.green);
656 drawLine(g, xstart, ystart, xend, yend);
659 else if (!depthcue && !bymolecule)
661 g.setColor(tmpBond.startCol);
662 drawLine(g, xstart, ystart, xmid, ymid);
663 g.setColor(tmpBond.endCol);
664 drawLine(g, xmid, ymid, xend, yend);
668 drawLine(g, xstart, ystart, xend, yend);
671 if (highlightBond1 != null && highlightBond1 == tmpBond)
673 g.setColor(tmpBond.endCol.brighter().brighter().brighter()
675 drawLine(g, xmid, ymid, xend, yend);
678 if (highlightBond2 != null && highlightBond2 == tmpBond)
680 g.setColor(tmpBond.startCol.brighter().brighter().brighter()
682 drawLine(g, xstart, ystart, xmid, ymid);
689 public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
693 if (((float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
695 g.drawLine(x1, y1, x2, y2);
696 g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1);
697 g.drawLine(x1, y1 - 1, x2, y2 - 1);
701 g.setColor(g.getColor().brighter());
702 g.drawLine(x1, y1, x2, y2);
703 g.drawLine(x1 + 1, y1, x2 + 1, y2);
704 g.drawLine(x1 - 1, y1, x2 - 1, y2);
709 g.drawLine(x1, y1, x2, y2);
713 public Dimension minimumsize()
718 public Dimension preferredsize()
723 public void keyPressed(KeyEvent evt)
725 if (evt.getKeyCode() == KeyEvent.VK_UP)
727 scale = (float) (scale * 1.1);
731 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
733 scale = (float) (scale * 0.9);
739 public void mousePressed(MouseEvent e)
742 Atom fatom = findAtom(e.getX(), e.getY());
745 fatom.isSelected = !fatom.isSelected;
749 if (foundchain != -1)
751 PDBChain chain = (PDBChain) pdb.chains.elementAt(foundchain);
752 if (chain == mainchain)
754 if (fatom.alignmentMapping != -1)
756 if (highlightRes == null)
758 highlightRes = new Vector();
761 if (highlightRes.contains(fatom.alignmentMapping + ""))
763 highlightRes.remove(fatom.alignmentMapping + "");
767 highlightRes.add(fatom.alignmentMapping + "");
781 public void mouseMoved(MouseEvent e)
784 if (highlightBond1 != null)
786 highlightBond1.at2.isSelected = false;
787 highlightBond2.at1.isSelected = false;
788 highlightBond1 = null;
789 highlightBond2 = null;
792 Atom fatom = findAtom(e.getX(), e.getY());
794 PDBChain chain = null;
795 if (foundchain != -1)
797 chain = (PDBChain) pdb.chains.elementAt(foundchain);
798 if (chain == mainchain)
800 mouseOverStructure(fatom.resNumber, chain.id);
806 this.setToolTipText(chain.id + ":" + fatom.resNumber + " "
811 mouseOverStructure(-1, chain != null ? chain.id : null);
812 this.setToolTipText(null);
816 public void mouseClicked(MouseEvent e)
820 public void mouseEntered(MouseEvent e)
824 public void mouseExited(MouseEvent e)
828 public void mouseDragged(MouseEvent evt)
835 MCMatrix objmat = new MCMatrix(3, 3);
836 objmat.setIdentity();
838 if ((evt.getModifiers() & Event.META_MASK) != 0)
840 objmat.rotatez((float) ((mx - omx)));
844 objmat.rotatex((float) ((my - omy)));
845 objmat.rotatey((float) ((omx - mx)));
849 for (int ii = 0; ii < pdb.chains.size(); ii++)
851 Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
853 for (int i = 0; i < bonds.size(); i++)
855 Bond tmpBond = (Bond) bonds.elementAt(i);
857 // Translate the bond so the centre is 0,0,0
858 tmpBond.translate(-centre[0], -centre[1], -centre[2]);
860 // Now apply the rotation matrix
861 tmpBond.start = objmat.vectorMultiply(tmpBond.start);
862 tmpBond.end = objmat.vectorMultiply(tmpBond.end);
864 // Now translate back again
865 tmpBond.translate(centre[0], centre[1], centre[2]);
881 public void mouseReleased(MouseEvent evt)
887 void drawLabels(Graphics g)
890 for (int ii = 0; ii < pdb.chains.size(); ii++)
892 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
896 Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
898 for (int i = 0; i < bonds.size(); i++)
900 Bond tmpBond = (Bond) bonds.elementAt(i);
902 if (tmpBond.at1.isSelected)
904 labelAtom(g, tmpBond, 1);
907 if (tmpBond.at2.isSelected)
910 labelAtom(g, tmpBond, 2);
917 public void labelAtom(Graphics g, Bond b, int n)
920 g.setColor(Color.red);
923 int xstart = (int) (((b.start[0] - centre[0]) * scale) + (getWidth() / 2));
924 int ystart = (int) (((centre[1] - b.start[1]) * scale) + (getHeight() / 2));
926 g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
931 int xstart = (int) (((b.end[0] - centre[0]) * scale) + (getWidth() / 2));
932 int ystart = (int) (((centre[1] - b.end[1]) * scale) + (getHeight() / 2));
934 g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
940 public Atom findAtom(int x, int y)
946 for (int ii = 0; ii < pdb.chains.size(); ii++)
948 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
954 Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
956 for (int i = 0; i < bonds.size(); i++)
958 tmpBond = (Bond) bonds.elementAt(i);
960 truex = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getWidth() / 2));
962 if (Math.abs(truex - x) <= 2)
964 int truey = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getHeight() / 2));
966 if (Math.abs(truey - y) <= 2)
975 // Still here? Maybe its the last bond
977 truex = (int) (((tmpBond.end[0] - centre[0]) * scale) + (getWidth() / 2));
979 if (Math.abs(truex - x) <= 2)
981 int truey = (int) (((tmpBond.end[1] - centre[1]) * scale) + (getHeight() / 2));
983 if (Math.abs(truey - y) <= 2)
993 if (fatom != null) // )&& chain.ds != null)
995 chain = (PDBChain) pdb.chains.elementAt(foundchain);
1002 Bond highlightBond1, highlightBond2;
1004 public void highlightRes(int ii)
1006 if (!seqColoursReady)
1011 if (highlightRes != null && highlightRes.contains((ii - 1) + ""))
1018 for (index = 0; index < mainchain.bonds.size(); index++)
1020 tmpBond = (Bond) mainchain.bonds.elementAt(index);
1021 if (tmpBond.at1.alignmentMapping == ii - 1)
1023 if (highlightBond1 != null)
1025 highlightBond1.at2.isSelected = false;
1028 if (highlightBond2 != null)
1030 highlightBond2.at1.isSelected = false;
1033 highlightBond1 = null;
1034 highlightBond2 = null;
1038 highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
1039 highlightBond1.at2.isSelected = true;
1042 if (index != mainchain.bonds.size())
1044 highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
1045 highlightBond2.at1.isSelected = true;
1052 redrawneeded = true;
1056 public void setAllchainsVisible(boolean b)
1058 for (int ii = 0; ii < pdb.chains.size(); ii++)
1060 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
1061 chain.isVisible = b;
1063 mainchain.isVisible = true;
1068 // ////////////////////////////////
1069 // /StructureListener
1070 public String[] getPdbFile()
1073 { pdbentry.getFile() };
1078 public void mouseOverStructure(int pdbResNum, String chain)
1080 if (lastMessage == null || !lastMessage.equals(pdbResNum + chain))
1081 ssm.mouseOverStructure(pdbResNum, chain, pdbentry.getFile());
1083 lastMessage = pdbResNum + chain;
1086 StringBuffer resetLastRes = new StringBuffer();
1088 StringBuffer eval = new StringBuffer();
1090 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
1093 if (!seqColoursReady)
1098 if (highlightRes != null && highlightRes.contains((atomIndex - 1) + ""))
1105 for (index = 0; index < mainchain.bonds.size(); index++)
1107 tmpBond = (Bond) mainchain.bonds.elementAt(index);
1108 if (tmpBond.at1.atomIndex == atomIndex)
1110 if (highlightBond1 != null)
1112 highlightBond1.at2.isSelected = false;
1115 if (highlightBond2 != null)
1117 highlightBond2.at1.isSelected = false;
1120 highlightBond1 = null;
1121 highlightBond2 = null;
1125 highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
1126 highlightBond1.at2.isSelected = true;
1129 if (index != mainchain.bonds.size())
1131 highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
1132 highlightBond2.at1.isSelected = true;
1139 redrawneeded = true;
1143 public Color getColour(int atomIndex, int pdbResNum, String chain,
1147 // if (!pdbfile.equals(pdbentry.getFile()))
1150 // return new Color(viewer.getAtomArgb(atomIndex));
1153 public void updateColours(Object source)
1156 redrawneeded = true;
1161 public void releaseReferences(Object svl)
1163 // TODO Auto-generated method stub