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.*;
28 import jalview.analysis.*;
29 import jalview.datamodel.*;
31 public class AppletPDBCanvas
32 extends Panel 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.appletgui.SeqCanvas seqcanvas;
67 public Sequence sequence;
68 final StringBuffer mappingDetails = new StringBuffer();
69 String appletToolTip = null;
73 boolean pdbAction = false;
74 Bond highlightBond1, highlightBond2;
75 boolean errorLoading = false;
76 boolean seqColoursReady = false;
77 jalview.appletgui.FeatureRenderer fr;
79 public AppletPDBCanvas(jalview.appletgui.SeqCanvas seqcanvas, Sequence seq)
81 this.seqcanvas = seqcanvas;
84 seqcanvas.setPDBCanvas(this);
85 addKeyListener(new KeyAdapter()
88 public void keyPressed(KeyEvent evt)
95 public void setPDBFile(PDBfile pdb)
103 AlignSeq maxAlignseq = null; ;
105 for (int i = 0; i < pdb.chains.size(); i++)
108 mappingDetails.append("\n\nPDB Sequence is :\nSequence = " +
109 ( (PDBChain) pdb.chains.elementAt(i)).sequence.
110 getSequenceAsString());
111 mappingDetails.append("\nNo of residues = " +
112 ( (PDBChain) pdb.chains.elementAt(i)).residues.size() +
115 // Now lets compare the sequences to get
116 // the start and end points.
117 // Align the sequence to the pdb
118 AlignSeq as = new AlignSeq(sequence,
119 ( (PDBChain) pdb.chains.elementAt(i)).sequence,
121 as.calcScoreMatrix();
123 PrintStream ps = new PrintStream(System.out)
125 public void print(String x)
127 mappingDetails.append(x);
130 public void println()
132 mappingDetails.append("\n");
136 as.printAlignment(ps);
138 if (as.maxscore > max)
143 pdbstart = as.seq2start;
145 seqstart = as.seq1start + sequence.getStart() - 1;
146 seqend = as.seq1end + sequence.getEnd() - 1;
150 mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend);
151 mappingDetails.append("\nSEQ start/end " + seqstart + " " + seqend);
154 mainchain = (PDBChain) pdb.chains.elementAt(maxchain);
156 mainchain.pdbstart = pdbstart;
157 mainchain.pdbend = pdbend;
158 mainchain.seqstart = seqstart;
159 mainchain.seqend = seqend;
160 mainchain.isVisible = true;
161 mainchain.makeExactMapping(maxAlignseq, sequence);
162 mainchain.transferRESNUMFeatures(sequence, null);
164 this.prefsize = new Dimension(getSize().width, getSize().height);
166 //Initialize the matrices to identity
167 for (int i = 0; i < 3; i++)
169 for (int j = 0; j < 3; j++)
173 idmat.addElement(i, j, 0);
174 objmat.addElement(i, j, 0);
178 idmat.addElement(i, j, 1);
179 objmat.addElement(i, j, 1);
184 addMouseMotionListener(this);
185 addMouseListener(this);
198 seqColoursReady = false;
199 // Sort the bonds by z coord
200 visiblebonds = new Vector();
202 for (int ii = 0; ii < pdb.chains.size(); ii++)
204 if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
206 Vector tmp = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
208 for (int i = 0; i < tmp.size(); i++)
210 visiblebonds.addElement(tmp.elementAt(i));
215 seqColoursReady = true;
220 public void findWidth()
222 float[] max = new float[3];
223 float[] min = new float[3];
225 max[0] = (float) - 1e30;
226 max[1] = (float) - 1e30;
227 max[2] = (float) - 1e30;
229 min[0] = (float) 1e30;
230 min[1] = (float) 1e30;
231 min[2] = (float) 1e30;
233 for (int ii = 0; ii < pdb.chains.size(); ii++)
235 if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
237 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
239 for (int i = 0; i < bonds.size(); i++)
241 Bond tmp = (Bond) bonds.elementAt(i);
243 if (tmp.start[0] >= max[0])
245 max[0] = tmp.start[0];
248 if (tmp.start[1] >= max[1])
250 max[1] = tmp.start[1];
253 if (tmp.start[2] >= max[2])
255 max[2] = tmp.start[2];
258 if (tmp.start[0] <= min[0])
260 min[0] = tmp.start[0];
263 if (tmp.start[1] <= min[1])
265 min[1] = tmp.start[1];
268 if (tmp.start[2] <= min[2])
270 min[2] = tmp.start[2];
273 if (tmp.end[0] >= max[0])
278 if (tmp.end[1] >= max[1])
283 if (tmp.end[2] >= max[2])
288 if (tmp.end[0] <= min[0])
293 if (tmp.end[1] <= min[1])
298 if (tmp.end[2] <= min[2])
306 width[0] = (float) Math.abs(max[0] - min[0]);
307 width[1] = (float) Math.abs(max[1] - min[1]);
308 width[2] = (float) Math.abs(max[2] - min[2]);
312 if (width[1] > width[0])
317 if (width[2] > width[1])
322 // System.out.println("Maxwidth = " + maxwidth);
325 public float findScale()
331 if (getSize().width != 0)
333 width = getSize().width;
334 height = getSize().height;
338 width = prefsize.width;
339 height = prefsize.height;
351 return (float) (dim / (1.5d * maxwidth));
354 public void findCentre()
362 //Find centre coordinate
363 for (int ii = 0; ii < pdb.chains.size(); ii++)
365 if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible)
367 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
369 bsize += bonds.size();
371 for (int i = 0; i < bonds.size(); i++)
373 xtot = xtot + ( (Bond) bonds.elementAt(i)).start[0] +
374 ( (Bond) bonds.elementAt(i)).end[0];
376 ytot = ytot + ( (Bond) bonds.elementAt(i)).start[1] +
377 ( (Bond) bonds.elementAt(i)).end[1];
379 ztot = ztot + ( (Bond) bonds.elementAt(i)).start[2] +
380 ( (Bond) bonds.elementAt(i)).end[2];
385 centre[0] = xtot / (2 * (float) bsize);
386 centre[1] = ytot / (2 * (float) bsize);
387 centre[2] = ztot / (2 * (float) bsize);
390 public void paint(Graphics g)
395 g.setColor(Color.white);
396 g.fillRect(0, 0, getSize().width, getSize().height);
397 g.setColor(Color.black);
398 g.setFont(new Font("Verdana", Font.BOLD, 14));
399 g.drawString("Error loading PDB data!!", 50, getSize().height / 2);
403 if (!seqColoursReady)
405 g.setColor(Color.black);
406 g.setFont(new Font("Verdana", Font.BOLD, 14));
407 g.drawString("Fetching PDB data...", 50, getSize().height / 2);
411 //Only create the image at the beginning -
412 //this saves much memory usage
413 if ( (img == null) || (prefsize.width != getSize().width) ||
414 (prefsize.height != getSize().height))
419 prefsize.width = getSize().width;
420 prefsize.height = getSize().height;
423 img = createImage(prefsize.width, prefsize.height);
424 ig = img.getGraphics();
430 ex.printStackTrace();
436 drawAll(ig, prefsize.width, prefsize.height);
437 redrawneeded = false;
439 if (appletToolTip != null)
441 ig.setColor(Color.red);
442 ig.drawString(appletToolTip, toolx, tooly);
445 g.drawImage(img, 0, 0, this);
450 public void drawAll(Graphics g, int width, int height)
452 ig.setColor(Color.black);
453 ig.fillRect(0, 0, width, height);
458 void setColours(jalview.schemes.ColourSchemeI cs)
466 public void updateSeqColours()
473 if (bysequence && pdb != null)
475 for (int ii = 0; ii < pdb.chains.size(); ii++)
477 colourBySequence( (PDBChain) pdb.chains.elementAt(ii));
485 int findTrueIndex(int pos)
487 // returns the alignment position for a residue
488 int j = sequence.getStart();
491 while ( (i < sequence.getLength()) && (j <= sequence.getEnd()) &&
494 if (!jalview.util.Comparison.isGap(sequence.getCharAt(i)))
507 if ( (j == sequence.getEnd()) && (j < pos))
509 return sequence.getEnd() + 1;
517 // This method has been taken out of PDBChain to allow
518 // Applet and Application specific sequence renderers to be used
519 void colourBySequence(PDBChain chain)
521 boolean showFeatures = false;
523 if (seqcanvas.getViewport().getShowSequenceFeatures())
527 fr = new jalview.appletgui.FeatureRenderer(seqcanvas.getViewport());
529 fr.transferSettings(seqcanvas.getFeatureRenderer());
533 for (int i = 0; i < chain.bonds.size(); i++)
535 Bond tmp = (Bond) chain.bonds.elementAt(i);
536 tmp.startCol = Color.lightGray;
537 tmp.endCol = Color.lightGray;
538 if (chain != mainchain)
543 if ( (tmp.at1.resNumber >= ( (chain.offset + chain.pdbstart) - 1)) &&
544 (tmp.at1.resNumber <= ( (chain.offset + chain.pdbend) - 1)))
547 int index = findTrueIndex(tmp.at1.alignmentMapping);
548 //sequence.findIndex(tmp.at1.alignmentMapping);
551 tmp.startCol = seqcanvas.getSequenceRenderer().
552 getResidueBoxColour(sequence, index);
556 tmp.startCol = fr.findFeatureColour(tmp.startCol, sequence, index);
561 int index = findTrueIndex(tmp.at2.alignmentMapping);
562 //sequence.findIndex( tmp.at2.alignmentMapping );
565 tmp.endCol = seqcanvas.getSequenceRenderer().
566 getResidueBoxColour(sequence, index);
570 tmp.endCol = fr.findFeatureColour(tmp.endCol, sequence, index);
577 public void drawScene(Graphics g)
586 zsort.Zsort(visiblebonds);
590 for (int i = 0; i < visiblebonds.size(); i++)
592 tmpBond = (Bond) visiblebonds.elementAt(i);
594 xstart = (int) ( ( (tmpBond.start[0] - centre[0]) * scale) +
595 (getSize().width / 2));
596 ystart = (int) ( ( (tmpBond.start[1] - centre[1]) * scale) +
597 (getSize().height / 2));
599 xend = (int) ( ( (tmpBond.end[0] - centre[0]) * scale) +
600 (getSize().width / 2));
601 yend = (int) ( ( (tmpBond.end[1] - centre[1]) * scale) +
602 (getSize().height / 2));
604 xmid = (xend + xstart) / 2;
605 ymid = (yend + ystart) / 2;
607 if (depthcue && !bymolecule)
609 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
611 g.setColor(tmpBond.startCol.darker().darker());
612 drawLine(g, xstart, ystart, xmid, ymid);
614 g.setColor(tmpBond.endCol.darker().darker());
615 drawLine(g, xmid, ymid, xend, yend);
617 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
619 g.setColor(tmpBond.startCol.darker());
620 drawLine(g, xstart, ystart, xmid, ymid);
622 g.setColor(tmpBond.endCol.darker());
623 drawLine(g, xmid, ymid, xend, yend);
627 g.setColor(tmpBond.startCol);
628 drawLine(g, xstart, ystart, xmid, ymid);
630 g.setColor(tmpBond.endCol);
631 drawLine(g, xmid, ymid, xend, yend);
635 else if (depthcue && bymolecule)
637 if (tmpBond.start[2] < (centre[2] - (maxwidth / 6)))
639 g.setColor(Color.green.darker().darker());
640 drawLine(g, xstart, ystart, xend, yend);
642 else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6)))
644 g.setColor(Color.green.darker());
645 drawLine(g, xstart, ystart, xend, yend);
649 g.setColor(Color.green);
650 drawLine(g, xstart, ystart, xend, yend);
653 else if (!depthcue && !bymolecule)
655 g.setColor(tmpBond.startCol);
656 drawLine(g, xstart, ystart, xmid, ymid);
657 g.setColor(tmpBond.endCol);
658 drawLine(g, xmid, ymid, xend, yend);
662 drawLine(g, xstart, ystart, xend, yend);
665 if (highlightBond1 != null && highlightBond1 == tmpBond)
667 g.setColor(Color.white);
668 drawLine(g, xmid, ymid, xend, yend);
671 if (highlightBond2 != null && highlightBond2 == tmpBond)
673 g.setColor(Color.white);
674 drawLine(g, xstart, ystart, xmid, ymid);
680 public void drawLine(Graphics g, int x1, int y1, int x2, int y2)
684 if ( ( (float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5)
686 g.drawLine(x1, y1, x2, y2);
687 g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1);
688 g.drawLine(x1, y1 - 1, x2, y2 - 1);
692 g.setColor(g.getColor().brighter());
693 g.drawLine(x1, y1, x2, y2);
694 g.drawLine(x1 + 1, y1, x2 + 1, y2);
695 g.drawLine(x1 - 1, y1, x2 - 1, y2);
700 g.drawLine(x1, y1, x2, y2);
704 public Dimension minimumsize()
709 public Dimension preferredsize()
714 public void doKeyPressed(KeyEvent evt)
716 if (evt.getKeyCode() == KeyEvent.VK_UP)
718 scale = (float) (scale * 1.1);
722 else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
724 scale = (float) (scale * 0.9);
730 public void mousePressed(MouseEvent e)
733 Atom fatom = findAtom(e.getX(), e.getY());
736 fatom.isSelected = !fatom.isSelected;
740 if (foundchain != -1)
742 PDBChain chain = (PDBChain) pdb.chains.elementAt(foundchain);
743 if (chain == mainchain)
745 if (fatom.alignmentMapping != -1)
747 if (highlightRes == null)
749 highlightRes = new Vector();
752 if (highlightRes.contains(fatom.alignmentMapping + "" + ""))
754 highlightRes.removeElement(fatom.alignmentMapping + "");
758 highlightRes.addElement(fatom.alignmentMapping + "");
772 public void mouseMoved(MouseEvent e)
775 if (highlightBond1 != null)
777 highlightBond1.at2.isSelected = false;
778 highlightBond2.at1.isSelected = false;
779 highlightBond1 = null;
780 highlightBond2 = null;
783 Atom fatom = findAtom(e.getX(), e.getY());
785 PDBChain chain = null;
786 if (foundchain != -1)
788 chain = (PDBChain) pdb.chains.elementAt(foundchain);
789 if (chain == mainchain)
791 highlightSeqcanvas(fatom.alignmentMapping);
800 appletToolTip = chain.id + ":" + fatom.resNumber + " " + fatom.resName;
806 highlightSeqcanvas( -1);
807 appletToolTip = null;
813 void highlightSeqcanvas(int pos)
815 SearchResults searchResults = new SearchResults();
816 if (highlightRes != null)
818 for (int i = 0; i < highlightRes.size(); i++)
820 int a = Integer.parseInt(highlightRes.elementAt(
823 searchResults.addResult(sequence, a, a);
829 searchResults.addResult(sequence, pos + 1, pos + 1);
832 seqcanvas.highlightSearchResults(searchResults);
835 public void mouseClicked(MouseEvent e)
839 public void mouseEntered(MouseEvent e)
843 public void mouseExited(MouseEvent e)
847 public void mouseDragged(MouseEvent evt)
854 MCMatrix objmat = new MCMatrix(3, 3);
855 objmat.setIdentity();
857 if ( (evt.getModifiers() & Event.META_MASK) != 0)
859 objmat.rotatez( (float) ( (mx - omx)));
863 objmat.rotatex( (float) ( (my - omy)));
864 objmat.rotatey( (float) ( (omx - mx)));
868 for (int ii = 0; ii < pdb.chains.size(); ii++)
870 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
872 for (int i = 0; i < bonds.size(); i++)
874 Bond tmpBond = (Bond) bonds.elementAt(i);
876 //Translate the bond so the centre is 0,0,0
877 tmpBond.translate( -centre[0], -centre[1], -centre[2]);
879 //Now apply the rotation matrix
880 tmpBond.start = objmat.vectorMultiply(tmpBond.start);
881 tmpBond.end = objmat.vectorMultiply(tmpBond.end);
883 //Now translate back again
884 tmpBond.translate(centre[0], centre[1], centre[2]);
900 public void mouseReleased(MouseEvent evt)
906 void drawLabels(Graphics g)
909 for (int ii = 0; ii < pdb.chains.size(); ii++)
911 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
915 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
917 for (int i = 0; i < bonds.size(); i++)
919 Bond tmpBond = (Bond) bonds.elementAt(i);
921 if (tmpBond.at1.isSelected)
923 labelAtom(g, tmpBond, 1);
926 if (tmpBond.at2.isSelected)
929 labelAtom(g, tmpBond, 2);
936 public void labelAtom(Graphics g, Bond b, int n)
942 int xstart = (int) ( ( (b.start[0] - centre[0]) * scale) +
943 (getSize().width / 2));
944 int ystart = (int) ( ( (b.start[1] - centre[1]) * scale) +
945 (getSize().height / 2));
947 g.setColor(Color.red);
948 g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart);
953 int xstart = (int) ( ( (b.end[0] - centre[0]) * scale) +
954 (getSize().width / 2));
955 int ystart = (int) ( ( (b.end[1] - centre[1]) * scale) +
956 (getSize().height / 2));
958 g.setColor(Color.red);
959 g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart);
964 public Atom findAtom(int x, int y)
970 for (int ii = 0; ii < pdb.chains.size(); ii++)
972 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
978 Vector bonds = ( (PDBChain) pdb.chains.elementAt(ii)).bonds;
980 for (int i = 0; i < bonds.size(); i++)
982 tmpBond = (Bond) bonds.elementAt(i);
984 truex = (int) ( ( (tmpBond.start[0] - centre[0]) * scale) +
985 (getSize().width / 2));
987 if (Math.abs(truex - x) <= 2)
989 int truey = (int) ( ( (tmpBond.start[1] - centre[1]) * scale) +
990 (getSize().height / 2));
992 if (Math.abs(truey - y) <= 2)
1001 // Still here? Maybe its the last bond
1003 truex = (int) ( ( (tmpBond.end[0] - centre[0]) * scale) +
1004 (getSize().width / 2));
1006 if (Math.abs(truex - x) <= 2)
1008 int truey = (int) ( ( (tmpBond.end[1] - centre[1]) * scale) +
1009 (getSize().height / 2));
1011 if (Math.abs(truey - y) <= 2)
1013 fatom = tmpBond.at2;
1021 if (fatom != null) //)&& chain.ds != null)
1023 chain = (PDBChain) pdb.chains.elementAt(foundchain);
1030 public void update(Graphics g)
1035 public void highlightRes(int ii)
1037 if (!seqColoursReady)
1042 if (highlightRes != null
1043 && highlightRes.contains( (ii - 1) + ""))
1050 for (index = 0; index < mainchain.bonds.size(); index++)
1052 tmpBond = (Bond) mainchain.bonds.elementAt(index);
1053 if (tmpBond.at1.alignmentMapping == ii - 1)
1055 if (highlightBond1 != null)
1057 highlightBond1.at2.isSelected = false;
1060 if (highlightBond2 != null)
1062 highlightBond2.at1.isSelected = false;
1065 highlightBond1 = null;
1066 highlightBond2 = null;
1070 highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1);
1071 highlightBond1.at2.isSelected = true;
1074 if (index != mainchain.bonds.size())
1076 highlightBond2 = (Bond) mainchain.bonds.elementAt(index);
1077 highlightBond2.at1.isSelected = true;
1084 redrawneeded = true;
1088 public void setAllchainsVisible(boolean b)
1090 for (int ii = 0; ii < pdb.chains.size(); ii++)
1092 PDBChain chain = (PDBChain) pdb.chains.elementAt(ii);
1093 chain.isVisible = b;
1095 mainchain.isVisible = true;