2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
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
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.analysis.AlignSeq;
24 import jalview.appletgui.AlignmentPanel;
25 import jalview.appletgui.FeatureRenderer;
26 import jalview.appletgui.SequenceRenderer;
27 import jalview.datamodel.PDBEntry;
28 import jalview.datamodel.SequenceI;
29 import jalview.structure.AtomSpec;
30 import jalview.structure.StructureListener;
31 import jalview.structure.StructureMapping;
32 import jalview.structure.StructureSelectionManager;
33 import jalview.util.MessageManager;
35 import java.awt.Color;
36 import java.awt.Dimension;
37 import java.awt.Event;
39 import java.awt.Graphics;
40 import java.awt.Image;
41 // JBPNote TODO: This class is quite noisy - needs proper log.info/log.debug
42 import java.awt.Panel;
43 import java.awt.event.KeyAdapter;
44 import java.awt.event.KeyEvent;
45 import java.awt.event.MouseEvent;
46 import java.awt.event.MouseListener;
47 import java.awt.event.MouseMotionListener;
48 import java.io.PrintStream;
49 import java.util.List;
50 import java.util.Vector;
52 public class AppletPDBCanvas extends Panel implements MouseListener,
53 MouseMotionListener, StructureListener
56 MCMatrix idmat = new MCMatrix(3, 3);
58 MCMatrix objmat = new MCMatrix(3, 3);
60 boolean redrawneeded = true;
82 float[] centre = new float[3];
84 float[] width = new float[3];
94 boolean bysequence = true;
96 boolean depthcue = true;
100 boolean bymolecule = false;
102 boolean zbuffer = true;
118 Font font = new Font("Helvetica", Font.PLAIN, 10);
120 public SequenceI[] sequence;
122 final StringBuffer mappingDetails = new StringBuffer();
124 String appletToolTip = null;
130 Vector<String> highlightRes;
132 boolean pdbAction = false;
134 Bond highlightBond1, highlightBond2;
136 boolean errorLoading = false;
138 boolean seqColoursReady = false;
144 StructureSelectionManager ssm;
146 public AppletPDBCanvas(PDBEntry pdbentry, SequenceI[] seq,
147 String[] chains, AlignmentPanel ap, String protocol)
151 this.pdbentry = pdbentry;
154 ssm = StructureSelectionManager
155 .getStructureSelectionManager(ap.av.applet);
159 pdb = ssm.setMapping(seq, chains, pdbentry.getFile(), protocol);
161 if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE))
163 pdbentry.setFile("INLINE" + pdb.id);
166 } catch (Exception ex)
168 ex.printStackTrace();
172 pdbentry.setId(pdb.id);
174 ssm.addStructureViewerListener(this);
185 // JUST DEAL WITH ONE SEQUENCE FOR NOW
186 SequenceI sequence = seq[0];
188 for (int i = 0; i < pdb.chains.size(); i++)
191 mappingDetails.append("\n\nPDB Sequence is :\nSequence = "
192 + pdb.chains.elementAt(i).sequence.getSequenceAsString());
193 mappingDetails.append("\nNo of residues = "
194 + pdb.chains.elementAt(i).residues.size() + "\n\n");
196 // Now lets compare the sequences to get
197 // the start and end points.
198 // Align the sequence to the pdb
199 // TODO: DNa/Pep switch
200 AlignSeq as = new AlignSeq(sequence,
201 pdb.chains.elementAt(i).sequence,
202 pdb.chains.elementAt(i).isNa ? AlignSeq.DNA : AlignSeq.PEP);
203 as.calcScoreMatrix();
205 PrintStream ps = new PrintStream(System.out)
207 public void print(String x)
209 mappingDetails.append(x);
212 public void println()
214 mappingDetails.append("\n");
218 as.printAlignment(ps);
220 if (as.maxscore > max)
225 pdbstart = as.seq2start;
227 seqstart = as.seq1start + sequence.getStart() - 1;
228 seqend = as.seq1end + sequence.getEnd() - 1;
231 mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
232 mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
235 mainchain = pdb.chains.elementAt(maxchain);
237 mainchain.pdbstart = pdbstart;
238 mainchain.pdbend = pdbend;
239 mainchain.seqstart = seqstart;
240 mainchain.seqend = seqend;
241 mainchain.isVisible = true;
242 // mainchain.makeExactMapping(maxAlignseq, sequence);
243 // mainchain.transferRESNUMFeatures(sequence, null);
245 this.prefsize = new Dimension(getSize().width, getSize().height);
247 // Initialize the matrices to identity
248 for (int i = 0; i < 3; i++)
250 for (int j = 0; j < 3; j++)
254 idmat.addElement(i, j, 0);
255 objmat.addElement(i, j, 0);
259 idmat.addElement(i, j, 1);
260 objmat.addElement(i, j, 1);
265 addMouseMotionListener(this);
266 addMouseListener(this);
268 addKeyListener(new KeyAdapter()
270 public void keyPressed(KeyEvent evt)
284 Vector<Bond> visiblebonds;
288 seqColoursReady = false;
289 // Sort the bonds by z coord
290 visiblebonds = new Vector<Bond>();
292 for (int ii = 0; ii < pdb.chains.size(); ii++)
294 if (pdb.chains.elementAt(ii).isVisible)
296 Vector<Bond> tmp = pdb.chains.elementAt(ii).bonds;
298 for (int i = 0; i < tmp.size(); i++)
300 visiblebonds.addElement(tmp.elementAt(i));
304 seqColoursReady = true;
310 public void findWidth()
312 float[] max = new float[3];
313 float[] min = new float[3];
315 max[0] = (float) -1e30;
316 max[1] = (float) -1e30;
317 max[2] = (float) -1e30;
319 min[0] = (float) 1e30;
320 min[1] = (float) 1e30;
321 min[2] = (float) 1e30;
323 for (int ii = 0; ii < pdb.chains.size(); ii++)
325 if (pdb.chains.elementAt(ii).isVisible)
327 Vector<Bond> bonds = pdb.chains.elementAt(ii).bonds;
329 for (Bond tmp : bonds)
331 if (tmp.start[0] >= max[0])
333 max[0] = tmp.start[0];
336 if (tmp.start[1] >= max[1])
338 max[1] = tmp.start[1];
341 if (tmp.start[2] >= max[2])
343 max[2] = tmp.start[2];
346 if (tmp.start[0] <= min[0])
348 min[0] = tmp.start[0];
351 if (tmp.start[1] <= min[1])
353 min[1] = tmp.start[1];
356 if (tmp.start[2] <= min[2])
358 min[2] = tmp.start[2];
361 if (tmp.end[0] >= max[0])
366 if (tmp.end[1] >= max[1])
371 if (tmp.end[2] >= max[2])
376 if (tmp.end[0] <= min[0])
381 if (tmp.end[1] <= min[1])
386 if (tmp.end[2] <= min[2])
394 width[0] = Math.abs(max[0] - min[0]);
395 width[1] = Math.abs(max[1] - min[1]);
396 width[2] = Math.abs(max[2] - min[2]);
400 if (width[1] > width[0])
405 if (width[2] > width[1])
410 // System.out.println("Maxwidth = " + maxwidth);
413 public float findScale()
419 if (getSize().width != 0)
421 width = getSize().width;
422 height = getSize().height;
426 width = prefsize.width;
427 height = prefsize.height;
439 return (float) (dim / (1.5d * maxwidth));
442 public void findCentre()
450 // Find centre coordinate
451 for (int ii = 0; ii < pdb.chains.size(); ii++)
453 if (pdb.chains.elementAt(ii).isVisible)
455 Vector<Bond> bonds = pdb.chains.elementAt(ii).bonds;
457 bsize += bonds.size();
461 xtot = xtot + b.start[0] + b.end[0];
462 ytot = ytot + b.start[1] + b.end[1];
463 ztot = ztot + b.start[2] + b.end[2];
468 centre[0] = xtot / (2 * (float) bsize);
469 centre[1] = ytot / (2 * (float) bsize);
470 centre[2] = ztot / (2 * (float) bsize);
473 public void paint(Graphics g)
478 g.setColor(Color.white);
479 g.fillRect(0, 0, getSize().width, getSize().height);
480 g.setColor(Color.black);
481 g.setFont(new Font("Verdana", Font.BOLD, 14));
483 MessageManager.getString("label.error_loading_pdb_data"), 50,
484 getSize().height / 2);
488 if (!seqColoursReady)
490 g.setColor(Color.black);
491 g.setFont(new Font("Verdana", Font.BOLD, 14));
492 g.drawString(MessageManager.getString("label.fetching_pdb_data"), 50,
493 getSize().height / 2);
497 // Only create the image at the beginning -
498 // this saves much memory usage
499 if ((img == null) || (prefsize.width != getSize().width)
500 || (prefsize.height != getSize().height))
505 prefsize.width = getSize().width;
506 prefsize.height = getSize().height;
509 img = createImage(prefsize.width, prefsize.height);
510 ig = img.getGraphics();
513 } catch (Exception ex)
515 ex.printStackTrace();
521 drawAll(ig, prefsize.width, prefsize.height);
522 redrawneeded = false;
524 if (appletToolTip != null)
526 ig.setColor(Color.red);
527 ig.drawString(appletToolTip, toolx, tooly);
530 g.drawImage(img, 0, 0, this);
535 public void drawAll(Graphics g, int width, int height)
537 ig.setColor(Color.black);
538 ig.fillRect(0, 0, width, height);
543 public void setColours(jalview.schemes.ColourSchemeI cs)
551 // This method has been taken out of PDBChain to allow
552 // Applet and Application specific sequence renderers to be used
553 void colourBySequence()
555 SequenceRenderer sr = new SequenceRenderer(ap.av);
557 StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
559 boolean showFeatures = false;
560 if (ap.av.isShowSequenceFeatures())
564 fr = new jalview.appletgui.FeatureRenderer(ap.av);
567 fr.transferSettings(ap.getFeatureRenderer());
573 if (bysequence && pdb != null)
575 for (int ii = 0; ii < pdb.chains.size(); ii++)
577 chain = pdb.chains.elementAt(ii);
579 for (int i = 0; i < chain.bonds.size(); i++)
581 Bond tmp = chain.bonds.elementAt(i);
582 tmp.startCol = Color.lightGray;
583 tmp.endCol = Color.lightGray;
584 if (chain != mainchain)
589 for (int s = 0; s < sequence.length; s++)
591 for (int m = 0; m < mapping.length; m++)
593 if (mapping[m].getSequence() == sequence[s])
595 int pos = mapping[m].getSeqPos(tmp.at1.resNumber) - 1;
598 pos = sequence[s].findIndex(pos);
599 tmp.startCol = sr.getResidueBoxColour(sequence[s], pos);
602 tmp.startCol = fr.findFeatureColour(tmp.startCol,
606 pos = mapping[m].getSeqPos(tmp.at2.resNumber) - 1;
609 pos = sequence[s].findIndex(pos);
610 tmp.endCol = sr.getResidueBoxColour(sequence[s], pos);
613 tmp.endCol = fr.findFeatureColour(tmp.endCol,
628 public void drawScene(Graphics g)
637 zsort.sort(visiblebonds);
641 for (int i = 0; i < visiblebonds.size(); i++)
643 tmpBond = visiblebonds.elementAt(i);
645 xstart = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2));
646 ystart = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getSize().height / 2));
648 xend = (int) (((tmpBond.end[0] - centre[0]) * scale) + (getSize().width / 2));
649 yend = (int) (((centre[1] - tmpBond.end[1]) * scale) + (getSize().height / 2));
651 xmid = (xend + xstart) / 2;
652 ymid = (yend + ystart) / 2;
654 if (depthcue && !bymolecule)
656 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
658 g.setColor(tmpBond.startCol.darker().darker());
659 drawLine(g, xstart, ystart, xmid, ymid);
661 g.setColor(tmpBond.endCol.darker().darker());
662 drawLine(g, xmid, ymid, xend, yend);
664 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
666 g.setColor(tmpBond.startCol.darker());
667 drawLine(g, xstart, ystart, xmid, ymid);
669 g.setColor(tmpBond.endCol.darker());
670 drawLine(g, xmid, ymid, xend, yend);
674 g.setColor(tmpBond.startCol);
675 drawLine(g, xstart, ystart, xmid, ymid);
677 g.setColor(tmpBond.endCol);
678 drawLine(g, xmid, ymid, xend, yend);
682 else if (depthcue && bymolecule)
684 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
686 g.setColor(Color.green.darker().darker());
687 drawLine(g, xstart, ystart, xend, yend);
689 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
691 g.setColor(Color.green.darker());
692 drawLine(g, xstart, ystart, xend, yend);
696 g.setColor(Color.green);
697 drawLine(g, xstart, ystart, xend, yend);
700 else if (!depthcue && !bymolecule)
702 g.setColor(tmpBond.startCol);
703 drawLine(g, xstart, ystart, xmid, ymid);
704 g.setColor(tmpBond.endCol);
705 drawLine(g, xmid, ymid, xend, yend);
709 drawLine(g, xstart, ystart, xend, yend);
712 if (highlightBond1 != null && highlightBond1 == tmpBond)
714 g.setColor(Color.white);
715 drawLine(g, xmid, ymid, xend, yend);
718 if (highlightBond2 != null && highlightBond2 == tmpBond)
720 g.setColor(Color.white);
721 drawLine(g, xstart, ystart, xmid, ymid);
727 public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
731 if (((float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
733 g.drawLine(x1, y1, x2, y2);
734 g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1);
735 g.drawLine(x1, y1 - 1, x2, y2 - 1);
739 g.setColor(g.getColor().brighter());
740 g.drawLine(x1, y1, x2, y2);
741 g.drawLine(x1 + 1, y1, x2 + 1, y2);
742 g.drawLine(x1 - 1, y1, x2 - 1, y2);
747 g.drawLine(x1, y1, x2, y2);
751 public Dimension minimumsize()
756 public Dimension preferredsize()
761 public void doKeyPressed(KeyEvent evt)
763 if (evt.getKeyCode() == KeyEvent.VK_UP)
765 scale = (float) (scale * 1.1);
769 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
771 scale = (float) (scale * 0.9);
777 public void mousePressed(MouseEvent e)
780 Atom fatom = findAtom(e.getX(), e.getY());
783 fatom.isSelected = !fatom.isSelected;
787 if (foundchain != -1)
789 PDBChain chain = pdb.chains.elementAt(foundchain);
790 if (chain == mainchain)
792 if (fatom.alignmentMapping != -1)
794 if (highlightRes == null)
796 highlightRes = new Vector<String>();
799 final String atomString = Integer
800 .toString(fatom.alignmentMapping);
801 if (highlightRes.contains(atomString))
803 highlightRes.removeElement(atomString);
807 highlightRes.addElement(atomString);
821 public void mouseMoved(MouseEvent e)
824 if (highlightBond1 != null)
826 highlightBond1.at2.isSelected = false;
827 highlightBond2.at1.isSelected = false;
828 highlightBond1 = null;
829 highlightBond2 = null;
832 Atom fatom = findAtom(e.getX(), e.getY());
834 PDBChain chain = null;
835 if (foundchain != -1)
837 chain = pdb.chains.elementAt(foundchain);
838 if (chain == mainchain)
840 mouseOverStructure(fatom.resNumber, chain.id);
849 appletToolTip = chain.id + ":" + fatom.resNumber + " "
856 mouseOverStructure(-1, chain != null ? chain.id : null);
857 appletToolTip = null;
863 public void mouseClicked(MouseEvent e)
867 public void mouseEntered(MouseEvent e)
871 public void mouseExited(MouseEvent e)
875 public void mouseDragged(MouseEvent evt)
882 MCMatrix objmat = new MCMatrix(3, 3);
883 objmat.setIdentity();
885 if ((evt.getModifiers() & Event.META_MASK) != 0)
887 objmat.rotatez(((mx - omx)));
891 objmat.rotatex(((omy - my)));
892 objmat.rotatey(((omx - mx)));
896 for (PDBChain chain : pdb.chains)
898 for (Bond tmpBond : chain.bonds)
900 // Translate the bond so the centre is 0,0,0
901 tmpBond.translate(-centre[0], -centre[1], -centre[2]);
903 // Now apply the rotation matrix
904 tmpBond.start = objmat.vectorMultiply(tmpBond.start);
905 tmpBond.end = objmat.vectorMultiply(tmpBond.end);
907 // Now translate back again
908 tmpBond.translate(centre[0], centre[1], centre[2]);
924 public void mouseReleased(MouseEvent evt)
930 void drawLabels(Graphics g)
933 for (PDBChain chain : pdb.chains)
937 for (Bond tmpBond : chain.bonds)
939 if (tmpBond.at1.isSelected)
941 labelAtom(g, tmpBond, 1);
944 if (tmpBond.at2.isSelected)
946 labelAtom(g, tmpBond, 2);
953 public void labelAtom(Graphics g, Bond b, int n)
959 int xstart = (int) (((b.start[0] - centre[0]) * scale) + (getSize().width / 2));
960 int ystart = (int) (((centre[1] - b.start[1]) * scale) + (getSize().height / 2));
962 g.setColor(Color.red);
963 g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
968 int xstart = (int) (((b.end[0] - centre[0]) * scale) + (getSize().width / 2));
969 int ystart = (int) (((centre[1] - b.end[1]) * scale) + (getSize().height / 2));
971 g.setColor(Color.red);
972 g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
978 public Atom findAtom(int x, int y)
984 for (int ii = 0; ii < pdb.chains.size(); ii++)
986 PDBChain chain = pdb.chains.elementAt(ii);
992 Vector<Bond> bonds = pdb.chains.elementAt(ii).bonds;
994 for (int i = 0; i < bonds.size(); i++)
996 tmpBond = bonds.elementAt(i);
998 truex = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2));
1000 if (Math.abs(truex - x) <= 2)
1002 int truey = (int) (((centre[1] - tmpBond.start[1]) * scale) + (getSize().height / 2));
1004 if (Math.abs(truey - y) <= 2)
1006 fatom = tmpBond.at1;
1013 // Still here? Maybe its the last bond
1015 truex = (int) (((tmpBond.end[0] - centre[0]) * scale) + (getSize().width / 2));
1017 if (Math.abs(truex - x) <= 2)
1019 int truey = (int) (((tmpBond.end[1] - centre[1]) * scale) + (getSize().height / 2));
1021 if (Math.abs(truey - y) <= 2)
1023 fatom = tmpBond.at2;
1031 if (fatom != null) // )&& chain.ds != null)
1033 chain = pdb.chains.elementAt(foundchain);
1040 public void update(Graphics g)
1045 public void highlightRes(int ii)
1047 if (!seqColoursReady)
1052 if (highlightRes != null && highlightRes.contains((ii - 1) + ""))
1059 for (index = 0; index < mainchain.bonds.size(); index++)
1061 tmpBond = mainchain.bonds.elementAt(index);
1062 if (tmpBond.at1.alignmentMapping == ii - 1)
1064 if (highlightBond1 != null)
1066 highlightBond1.at2.isSelected = false;
1069 if (highlightBond2 != null)
1071 highlightBond2.at1.isSelected = false;
1074 highlightBond1 = null;
1075 highlightBond2 = null;
1079 highlightBond1 = mainchain.bonds.elementAt(index - 1);
1080 highlightBond1.at2.isSelected = true;
1083 if (index != mainchain.bonds.size())
1085 highlightBond2 = mainchain.bonds.elementAt(index);
1086 highlightBond2.at1.isSelected = true;
1093 redrawneeded = true;
1097 public void setAllchainsVisible(boolean b)
1099 for (int ii = 0; ii < pdb.chains.size(); ii++)
1101 PDBChain chain = pdb.chains.elementAt(ii);
1102 chain.isVisible = b;
1104 mainchain.isVisible = true;
1109 // ////////////////////////////////
1110 // /StructureListener
1111 public String[] getPdbFile()
1113 return new String[] { pdbentry.getFile() };
1118 public void mouseOverStructure(int pdbResNum, String chain)
1120 if (lastMessage == null || !lastMessage.equals(pdbResNum + chain))
1122 ssm.mouseOverStructure(pdbResNum, chain, pdbentry.getFile());
1125 lastMessage = pdbResNum + chain;
1128 StringBuffer resetLastRes = new StringBuffer();
1130 StringBuffer eval = new StringBuffer();
1133 * Highlight the specified atoms in the structure.
1138 public void highlightAtoms(List<AtomSpec> atoms)
1140 if (!seqColoursReady)
1144 for (AtomSpec atom : atoms)
1146 int atomIndex = atom.getAtomIndex();
1148 if (highlightRes != null
1149 && highlightRes.contains((atomIndex - 1) + ""))
1154 highlightAtom(atomIndex);
1157 redrawneeded = true;
1164 protected void highlightAtom(int atomIndex)
1168 for (index = 0; index < mainchain.bonds.size(); index++)
1170 tmpBond = mainchain.bonds.elementAt(index);
1171 if (tmpBond.at1.atomIndex == atomIndex)
1173 if (highlightBond1 != null)
1175 highlightBond1.at2.isSelected = false;
1178 if (highlightBond2 != null)
1180 highlightBond2.at1.isSelected = false;
1183 highlightBond1 = null;
1184 highlightBond2 = null;
1188 highlightBond1 = mainchain.bonds.elementAt(index - 1);
1189 highlightBond1.at2.isSelected = true;
1192 if (index != mainchain.bonds.size())
1194 highlightBond2 = mainchain.bonds.elementAt(index);
1195 highlightBond2.at1.isSelected = true;
1203 public Color getColour(int atomIndex, int pdbResNum, String chain,
1207 // if (!pdbfile.equals(pdbentry.getFile()))
1210 // return new Color(viewer.getAtomArgb(atomIndex));
1213 public void updateColours(Object source)
1216 redrawneeded = true;
1221 public void releaseReferences(Object svl)
1223 // TODO Auto-generated method stub
1228 public boolean isListeningFor(SequenceI seq)
1230 if (sequence != null)
1232 for (SequenceI s : sequence)