2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3 * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, 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.*;
27 import jalview.analysis.*;
28 import jalview.datamodel.*;
30 import jalview.appletgui.*;
31 import jalview.structure.*;
33 public class AppletPDBCanvas extends Panel implements MouseListener,
34 MouseMotionListener, StructureListener
37 MCMatrix idmat = new MCMatrix(3, 3);
39 MCMatrix objmat = new MCMatrix(3, 3);
41 boolean redrawneeded = true;
63 float[] centre = new float[3];
65 float[] width = new float[3];
75 boolean bysequence = true;
77 boolean depthcue = true;
81 boolean bymolecule = false;
83 boolean zbuffer = true;
99 Font font = new Font("Helvetica", Font.PLAIN, 10);
101 public SequenceI[] sequence;
103 final StringBuffer mappingDetails = new StringBuffer();
105 String appletToolTip = null;
113 boolean pdbAction = false;
115 Bond highlightBond1, highlightBond2;
117 boolean errorLoading = false;
119 boolean seqColoursReady = false;
125 StructureSelectionManager ssm;
127 public AppletPDBCanvas(PDBEntry pdbentry, SequenceI[] seq,
128 String[] chains, AlignmentPanel ap, String protocol)
132 this.pdbentry = pdbentry;
135 ssm = StructureSelectionManager
136 .getStructureSelectionManager(ap.av.applet);
140 pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol);
142 if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
143 pdbentry.setFile("INLINE" + pdb.id);
145 } catch (Exception ex)
147 ex.printStackTrace();
151 pdbentry.setId(pdb.id);
153 ssm.addStructureViewerListener(this);
164 // JUST DEAL WITH ONE SEQUENCE FOR NOW
165 SequenceI sequence = seq[0];
167 for (int i = 0; i < pdb.chains.size(); i++)
170 mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
171 + ((PDBChain) pdb.chains.elementAt(i)).sequence
172 .getSequenceAsString());
173 mappingDetails.append("\nNo of residues = "
174 + ((PDBChain) pdb.chains.elementAt(i)).residues.size()
177 // Now lets compare the sequences to get
178 // the start and end points.
179 // Align the sequence to the pdb
180 // TODO: DNa/Pep switch
181 AlignSeq as = new AlignSeq(sequence,
182 ((PDBChain) pdb.chains.elementAt(i)).sequence,
183 ((PDBChain) pdb.chains.elementAt(i)).isNa ? AlignSeq.DNA
185 as.calcScoreMatrix();
187 PrintStream ps = new PrintStream(System.out)
189 public void print(String x)
191 mappingDetails.append(x);
194 public void println()
196 mappingDetails.append("\n");
200 as.printAlignment(ps);
202 if (as.maxscore > max)
207 pdbstart = as.seq2start;
209 seqstart = as.seq1start + sequence.getStart() - 1;
210 seqend = as.seq1end + sequence.getEnd() - 1;
213 mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
214 mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
217 mainchain = (PDBChain) pdb.chains.elementAt(maxchain);
219 mainchain.pdbstart = pdbstart;
220 mainchain.pdbend = pdbend;
221 mainchain.seqstart = seqstart;
222 mainchain.seqend = seqend;
223 mainchain.isVisible = true;
224 // mainchain.makeExactMapping(maxAlignseq, sequence);
225 // mainchain.transferRESNUMFeatures(sequence, null);
227 this.prefsize = new Dimension(getSize().width, getSize().height);
229 // Initialize the matrices to identity
230 for (int i = 0; i < 3; i++)
232 for (int j = 0; j < 3; j++)
236 idmat.addElement(i, j, 0);
237 objmat.addElement(i, j, 0);
241 idmat.addElement(i, j, 1);
242 objmat.addElement(i, j, 1);
247 addMouseMotionListener(this);
248 addMouseListener(this);
250 addKeyListener(new KeyAdapter()
252 public void keyPressed(KeyEvent evt)
270 seqColoursReady = false;
271 // Sort the bonds by z coord
272 visiblebonds = new Vector();
274 for (int ii = 0; ii < pdb.chains.size(); ii++)
276 if (((PDBChain) pdb.chains.elementAt(ii)).isVisible)
278 Vector tmp = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
280 for (int i = 0; i < tmp.size(); i++)
282 visiblebonds.addElement(tmp.elementAt(i));
286 seqColoursReady = true;
292 public void findWidth()
294 float[] max = new float[3];
295 float[] min = new float[3];
297 max[0] = (float) -1e30;
298 max[1] = (float) -1e30;
299 max[2] = (float) -1e30;
301 min[0] = (float) 1e30;
302 min[1] = (float) 1e30;
303 min[2] = (float) 1e30;
305 for (int ii = 0; ii < pdb.chains.size(); ii++)
307 if (((PDBChain) pdb.chains.elementAt(ii)).isVisible)
309 Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
311 for (int i = 0; i < bonds.size(); i++)
313 Bond tmp = (Bond) bonds.elementAt(i);
315 if (tmp.start[0] >= max[0])
317 max[0] = tmp.start[0];
320 if (tmp.start[1] >= max[1])
322 max[1] = tmp.start[1];
325 if (tmp.start[2] >= max[2])
327 max[2] = tmp.start[2];
330 if (tmp.start[0] <= min[0])
332 min[0] = tmp.start[0];
335 if (tmp.start[1] <= min[1])
337 min[1] = tmp.start[1];
340 if (tmp.start[2] <= min[2])
342 min[2] = tmp.start[2];
345 if (tmp.end[0] >= max[0])
350 if (tmp.end[1] >= max[1])
355 if (tmp.end[2] >= max[2])
360 if (tmp.end[0] <= min[0])
365 if (tmp.end[1] <= min[1])
370 if (tmp.end[2] <= min[2])
378 width[0] = (float) Math.abs(max[0] - min[0]);
379 width[1] = (float) Math.abs(max[1] - min[1]);
380 width[2] = (float) Math.abs(max[2] - min[2]);
384 if (width[1] > width[0])
389 if (width[2] > width[1])
394 // System.out.println("Maxwidth = " + maxwidth);
397 public float findScale()
403 if (getSize().width != 0)
405 width = getSize().width;
406 height = getSize().height;
410 width = prefsize.width;
411 height = prefsize.height;
423 return (float) (dim / (1.5d * maxwidth));
426 public void findCentre()
434 // Find centre coordinate
435 for (int ii = 0; ii < pdb.chains.size(); ii++)
437 if (((PDBChain) pdb.chains.elementAt(ii)).isVisible)
439 Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
441 bsize += bonds.size();
443 for (int i = 0; i < bonds.size(); i++)
445 xtot = xtot + ((Bond) bonds.elementAt(i)).start[0]
446 + ((Bond) bonds.elementAt(i)).end[0];
448 ytot = ytot + ((Bond) bonds.elementAt(i)).start[1]
449 + ((Bond) bonds.elementAt(i)).end[1];
451 ztot = ztot + ((Bond) bonds.elementAt(i)).start[2]
452 + ((Bond) bonds.elementAt(i)).end[2];
457 centre[0] = xtot / (2 * (float) bsize);
458 centre[1] = ytot / (2 * (float) bsize);
459 centre[2] = ztot / (2 * (float) bsize);
462 public void paint(Graphics g)
467 g.setColor(Color.white);
468 g.fillRect(0, 0, getSize().width, getSize().height);
469 g.setColor(Color.black);
470 g.setFont(new Font("Verdana", Font.BOLD, 14));
471 g.drawString("Error loading PDB data!!", 50, getSize().height / 2);
475 if (!seqColoursReady)
477 g.setColor(Color.black);
478 g.setFont(new Font("Verdana", Font.BOLD, 14));
479 g.drawString("Fetching PDB data...", 50, getSize().height / 2);
483 // Only create the image at the beginning -
484 // this saves much memory usage
485 if ((img == null) || (prefsize.width != getSize().width)
486 || (prefsize.height != getSize().height))
491 prefsize.width = getSize().width;
492 prefsize.height = getSize().height;
495 img = createImage(prefsize.width, prefsize.height);
496 ig = img.getGraphics();
499 } catch (Exception ex)
501 ex.printStackTrace();
507 drawAll(ig, prefsize.width, prefsize.height);
508 redrawneeded = false;
510 if (appletToolTip != null)
512 ig.setColor(Color.red);
513 ig.drawString(appletToolTip, toolx, tooly);
516 g.drawImage(img, 0, 0, this);
521 public void drawAll(Graphics g, int width, int height)
523 ig.setColor(Color.black);
524 ig.fillRect(0, 0, width, height);
529 public void setColours(jalview.schemes.ColourSchemeI cs)
537 // This method has been taken out of PDBChain to allow
538 // Applet and Application specific sequence renderers to be used
539 void colourBySequence()
541 SequenceRenderer sr = new SequenceRenderer(ap.av);
543 StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
545 boolean showFeatures = false;
546 if (ap.av.getShowSequenceFeatures())
550 fr = new jalview.appletgui.FeatureRenderer(ap.av);
553 fr.transferSettings(ap.getFeatureRenderer());
559 if (bysequence && pdb != null)
561 for (int ii = 0; ii < pdb.chains.size(); ii++)
563 chain = (PDBChain) pdb.chains.elementAt(ii);
565 for (int i = 0; i < chain.bonds.size(); i++)
567 Bond tmp = (Bond) chain.bonds.elementAt(i);
568 tmp.startCol = Color.lightGray;
569 tmp.endCol = Color.lightGray;
570 if (chain != mainchain)
575 for (int s = 0; s < sequence.length; s++)
577 for (int m = 0; m < mapping.length; m++)
579 if (mapping[m].getSequence() == sequence[s])
581 int pos = mapping[m].getSeqPos(tmp.at1.resNumber) - 1;
584 pos = sequence[s].findIndex(pos);
585 tmp.startCol = sr.getResidueBoxColour(sequence[s], pos);
588 tmp.startCol = fr.findFeatureColour(tmp.startCol,
592 pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
595 pos = sequence[s].findIndex(pos);
596 tmp.endCol = sr.getResidueBoxColour(sequence[s], pos);
599 tmp.endCol = fr.findFeatureColour(tmp.endCol,
614 public void drawScene(Graphics g)
623 zsort.Zsort(visiblebonds);
627 for (int i = 0; i < visiblebonds.size(); i++)
629 tmpBond = (Bond) visiblebonds.elementAt(i);
631 xstart = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2));
632 ystart = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getSize().height / 2));
634 xend = (int) (((tmpBond.end[0] - centre[0]) * scale) + (getSize().width / 2));
635 yend = (int) (((centre[1] - tmpBond.end[1]) * scale) + (getSize().height / 2));
637 xmid = (xend + xstart) / 2;
638 ymid = (yend + ystart) / 2;
640 if (depthcue && !bymolecule)
642 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
644 g.setColor(tmpBond.startCol.darker().darker());
645 drawLine(g, xstart, ystart, xmid, ymid);
647 g.setColor(tmpBond.endCol.darker().darker());
648 drawLine(g, xmid, ymid, xend, yend);
650 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
652 g.setColor(tmpBond.startCol.darker());
653 drawLine(g, xstart, ystart, xmid, ymid);
655 g.setColor(tmpBond.endCol.darker());
656 drawLine(g, xmid, ymid, xend, yend);
660 g.setColor(tmpBond.startCol);
661 drawLine(g, xstart, ystart, xmid, ymid);
663 g.setColor(tmpBond.endCol);
664 drawLine(g, xmid, ymid, xend, yend);
668 else if (depthcue && bymolecule)
670 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
672 g.setColor(Color.green.darker().darker());
673 drawLine(g, xstart, ystart, xend, yend);
675 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
677 g.setColor(Color.green.darker());
678 drawLine(g, xstart, ystart, xend, yend);
682 g.setColor(Color.green);
683 drawLine(g, xstart, ystart, xend, yend);
686 else if (!depthcue && !bymolecule)
688 g.setColor(tmpBond.startCol);
689 drawLine(g, xstart, ystart, xmid, ymid);
690 g.setColor(tmpBond.endCol);
691 drawLine(g, xmid, ymid, xend, yend);
695 drawLine(g, xstart, ystart, xend, yend);
698 if (highlightBond1 != null && highlightBond1 == tmpBond)
700 g.setColor(Color.white);
701 drawLine(g, xmid, ymid, xend, yend);
704 if (highlightBond2 != null && highlightBond2 == tmpBond)
706 g.setColor(Color.white);
707 drawLine(g, xstart, ystart, xmid, ymid);
713 public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
717 if (((float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
719 g.drawLine(x1, y1, x2, y2);
720 g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1);
721 g.drawLine(x1, y1 - 1, x2, y2 - 1);
725 g.setColor(g.getColor().brighter());
726 g.drawLine(x1, y1, x2, y2);
727 g.drawLine(x1 + 1, y1, x2 + 1, y2);
728 g.drawLine(x1 - 1, y1, x2 - 1, y2);
733 g.drawLine(x1, y1, x2, y2);
737 public Dimension minimumsize()
742 public Dimension preferredsize()
747 public void doKeyPressed(KeyEvent evt)
749 if (evt.getKeyCode() == KeyEvent.VK_UP)
751 scale = (float) (scale * 1.1);
755 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
757 scale = (float) (scale * 0.9);
763 public void mousePressed(MouseEvent e)
766 Atom fatom = findAtom(e.getX(), e.getY());
769 fatom.isSelected = !fatom.isSelected;
773 if (foundchain != -1)
775 PDBChain chain = (PDBChain) pdb.chains.elementAt(foundchain);
776 if (chain == mainchain)
778 if (fatom.alignmentMapping != -1)
780 if (highlightRes == null)
782 highlightRes = new Vector();
785 if (highlightRes.contains(fatom.alignmentMapping + "" + ""))
787 highlightRes.removeElement(fatom.alignmentMapping + "");
791 highlightRes.addElement(fatom.alignmentMapping + "");
805 public void mouseMoved(MouseEvent e)
808 if (highlightBond1 != null)
810 highlightBond1.at2.isSelected = false;
811 highlightBond2.at1.isSelected = false;
812 highlightBond1 = null;
813 highlightBond2 = null;
816 Atom fatom = findAtom(e.getX(), e.getY());
818 PDBChain chain = null;
819 if (foundchain != -1)
821 chain = (PDBChain) pdb.chains.elementAt(foundchain);
822 if (chain == mainchain)
824 mouseOverStructure(fatom.resNumber, chain.id);
833 appletToolTip = chain.id + ":" + fatom.resNumber + " "
840 mouseOverStructure(-1, chain != null ? chain.id : null);
841 appletToolTip = null;
847 public void mouseClicked(MouseEvent e)
851 public void mouseEntered(MouseEvent e)
855 public void mouseExited(MouseEvent e)
859 public void mouseDragged(MouseEvent evt)
866 MCMatrix objmat = new MCMatrix(3, 3);
867 objmat.setIdentity();
869 if ((evt.getModifiers() & Event.META_MASK) != 0)
871 objmat.rotatez((float) ((mx - omx)));
875 objmat.rotatex((float) ((omy - my)));
876 objmat.rotatey((float) ((omx - mx)));
880 for (int ii = 0; ii < pdb.chains.size(); ii++)
882 Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
884 for (int i = 0; i < bonds.size(); i++)
886 Bond tmpBond = (Bond) bonds.elementAt(i);
888 // Translate the bond so the centre is 0,0,0
889 tmpBond.translate(-centre[0], -centre[1], -centre[2]);
891 // Now apply the rotation matrix
892 tmpBond.start = objmat.vectorMultiply(tmpBond.start);
893 tmpBond.end = objmat.vectorMultiply(tmpBond.end);
895 // Now translate back again
896 tmpBond.translate(centre[0], centre[1], centre[2]);
912 public void mouseReleased(MouseEvent evt)
918 void drawLabels(Graphics g)
921 for (int ii = 0; ii < pdb.chains.size(); ii++)
923 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
927 Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
929 for (int i = 0; i < bonds.size(); i++)
931 Bond tmpBond = (Bond) bonds.elementAt(i);
933 if (tmpBond.at1.isSelected)
935 labelAtom(g, tmpBond, 1);
938 if (tmpBond.at2.isSelected)
941 labelAtom(g, tmpBond, 2);
948 public void labelAtom(Graphics g, Bond b, int n)
954 int xstart = (int) (((b.start[0] - centre[0]) * scale) + (getSize().width / 2));
955 int ystart = (int) (((centre[1] - b.start[1]) * scale) + (getSize().height / 2));
957 g.setColor(Color.red);
958 g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
963 int xstart = (int) (((b.end[0] - centre[0]) * scale) + (getSize().width / 2));
964 int ystart = (int) (((centre[1] - b.end[1]) * scale) + (getSize().height / 2));
966 g.setColor(Color.red);
967 g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
973 public Atom findAtom(int x, int y)
979 for (int ii = 0; ii < pdb.chains.size(); ii++)
981 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
987 Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds;
989 for (int i = 0; i < bonds.size(); i++)
991 tmpBond = (Bond) bonds.elementAt(i);
993 truex = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2));
995 if (Math.abs(truex - x) <= 2)
997 int truey = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getSize().height / 2));
999 if (Math.abs(truey - y) <= 2)
1001 fatom = tmpBond.at1;
1008 // Still here? Maybe its the last bond
1010 truex = (int) (((tmpBond.end[0] - centre[0]) * scale) + (getSize().width / 2));
1012 if (Math.abs(truex - x) <= 2)
1014 int truey = (int) (((tmpBond.end[1] - centre[1]) * scale) + (getSize().height / 2));
1016 if (Math.abs(truey - y) <= 2)
1018 fatom = tmpBond.at2;
1026 if (fatom != null) // )&& chain.ds != null)
1028 chain = (PDBChain) pdb.chains.elementAt(foundchain);
1035 public void update(Graphics g)
1040 public void highlightRes(int ii)
1042 if (!seqColoursReady)
1047 if (highlightRes != null && highlightRes.contains((ii - 1) + ""))
1054 for (index = 0; index < mainchain.bonds.size(); index++)
1056 tmpBond = (Bond) mainchain.bonds.elementAt(index);
1057 if (tmpBond.at1.alignmentMapping == ii - 1)
1059 if (highlightBond1 != null)
1061 highlightBond1.at2.isSelected = false;
1064 if (highlightBond2 != null)
1066 highlightBond2.at1.isSelected = false;
1069 highlightBond1 = null;
1070 highlightBond2 = null;
1074 highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
1075 highlightBond1.at2.isSelected = true;
1078 if (index != mainchain.bonds.size())
1080 highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
1081 highlightBond2.at1.isSelected = true;
1088 redrawneeded = true;
1092 public void setAllchainsVisible(boolean b)
1094 for (int ii = 0; ii < pdb.chains.size(); ii++)
1096 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
1097 chain.isVisible = b;
1099 mainchain.isVisible = true;
1104 // ////////////////////////////////
1105 // /StructureListener
1106 public String[] getPdbFile()
1109 { pdbentry.getFile() };
1114 public void mouseOverStructure(int pdbResNum, String chain)
1116 if (lastMessage == null || !lastMessage.equals(pdbResNum + chain))
1117 ssm.mouseOverStructure(pdbResNum, chain, pdbentry.getFile());
1119 lastMessage = pdbResNum + chain;
1122 StringBuffer resetLastRes = new StringBuffer();
1124 StringBuffer eval = new StringBuffer();
1126 public void highlightAtom(int atomIndex, int pdbResNum, String chain,
1129 if (!seqColoursReady)
1134 if (highlightRes != null && highlightRes.contains((atomIndex - 1) + ""))
1141 for (index = 0; index < mainchain.bonds.size(); index++)
1143 tmpBond = (Bond) mainchain.bonds.elementAt(index);
1144 if (tmpBond.at1.atomIndex == atomIndex)
1146 if (highlightBond1 != null)
1148 highlightBond1.at2.isSelected = false;
1151 if (highlightBond2 != null)
1153 highlightBond2.at1.isSelected = false;
1156 highlightBond1 = null;
1157 highlightBond2 = null;
1161 highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
1162 highlightBond1.at2.isSelected = true;
1165 if (index != mainchain.bonds.size())
1167 highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
1168 highlightBond2.at1.isSelected = true;
1175 redrawneeded = true;
1179 public Color getColour(int atomIndex, int pdbResNum, String chain,
1183 // if (!pdbfile.equals(pdbentry.getFile()))
1186 // return new Color(viewer.getAtomArgb(atomIndex));
1189 public void updateColours(Object source)
1192 redrawneeded = true;
1197 public void releaseReferences(Object svl)
1199 // TODO Auto-generated method stub