/* * Jalview - A Sequence Alignment Editor and Viewer * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package MCview; import jalview.analysis.AlignSeq; import jalview.datamodel.*; // JBPNote TODO: This class is quite noisy - needs proper log.info/log.debug import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; public class AppletPDBCanvas extends Panel implements MouseListener, MouseMotionListener { MCMatrix idmat = new MCMatrix(3, 3); MCMatrix objmat = new MCMatrix(3, 3); boolean redrawneeded = true; int omx = 0; int mx = 0; int omy = 0; int my = 0; public PDBfile pdb; int bsize; Image img; Graphics ig; Dimension prefsize; float[] centre = new float[3]; float[] width = new float[3]; float maxwidth; float scale; String inStr; String inType; boolean bysequence = true; boolean depthcue = true; boolean wire = false; boolean bymolecule = false; boolean zbuffer = true; boolean dragging; int xstart; int xend; int ystart; int yend; int xmid; int ymid; Font font = new Font("Helvetica", Font.PLAIN, 10); jalview.appletgui.SeqCanvas seqcanvas; public Sequence sequence; final StringBuffer mappingDetails = new StringBuffer(); String appletToolTip = null; int toolx, tooly; PDBChain mainchain; Vector highlightRes; boolean pdbAction = false; Bond highlightBond1, highlightBond2; boolean errorLoading = false; public AppletPDBCanvas(jalview.appletgui.SeqCanvas seqcanvas, Sequence seq) { this.seqcanvas = seqcanvas; this.sequence = seq; seqcanvas.setPDBCanvas(this); addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent evt) { doKeyPressed(evt); } }); } public void setPDBFile(PDBfile pdb) { int max = -10; int maxchain = -1; int pdbstart = 0; int pdbend = 0; int seqstart = 0; int seqend = 0; AlignSeq maxAlignseq = null;; for (int i = 0; i < pdb.chains.size(); i++) { mappingDetails.append("\n\nPDB Sequence is :\nSequence = " + ((PDBChain) pdb.chains.elementAt(i)).sequence.getSequence()); mappingDetails.append("\nNo of residues = " + ((PDBChain) pdb.chains.elementAt(i)).residues.size()+"\n\n"); // Now lets compare the sequences to get // the start and end points. // Align the sequence to the pdb AlignSeq as = new AlignSeq(sequence, ((PDBChain) pdb.chains.elementAt(i)).sequence, "pep"); as.calcScoreMatrix(); as.traceAlignment(); PrintStream ps = new PrintStream(System.out) { public void print(String x) { mappingDetails.append(x); } public void println() { mappingDetails.append("\n"); } }; as.printAlignment(ps); if (as.maxscore > max) { max = as.maxscore; maxchain = i; pdbstart = as.seq2start; pdbend = as.seq2end; seqstart = as.seq1start + sequence.getStart()-1; seqend = as.seq1end + sequence.getEnd()-1; maxAlignseq = as; } mappingDetails.append("\nPDB start/end " + pdbstart + " " + pdbend); mappingDetails.append("\nSEQ start/end "+ seqstart + " " + seqend); } mainchain = (PDBChain) pdb.chains.elementAt(maxchain); mainchain.pdbstart = pdbstart; mainchain.pdbend = pdbend; mainchain.seqstart = seqstart; mainchain.seqend = seqend; mainchain.isVisible = true; mainchain.makeExactMapping(maxAlignseq, sequence); this.pdb = pdb; this.prefsize = new Dimension(getSize().width, getSize().height); //Initialize the matrices to identity for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (i != j) { idmat.addElement(i, j, 0); objmat.addElement(i, j, 0); } else { idmat.addElement(i, j, 1); objmat.addElement(i, j, 1); } } } addMouseMotionListener(this); addMouseListener(this); findCentre(); findWidth(); setupBonds(); scale = findScale(); } Vector visiblebonds; void setupBonds() { // Sort the bonds by z coord visiblebonds = new Vector(); for (int ii = 0; ii < pdb.chains.size(); ii++) { if ( ( (PDBChain) pdb.chains.elementAt(ii)).isVisible) { Vector tmp = ( (PDBChain) pdb.chains.elementAt(ii)).bonds; for (int i = 0; i < tmp.size(); i++) { visiblebonds.addElement(tmp.elementAt(i)); } } } updateSeqColours(); redrawneeded = true; repaint(); } public void findWidth() { float[] max = new float[3]; float[] min = new float[3]; max[0] = (float) -1e30; max[1] = (float) -1e30; max[2] = (float) -1e30; min[0] = (float) 1e30; min[1] = (float) 1e30; min[2] = (float) 1e30; for (int ii = 0; ii < pdb.chains.size(); ii++) { if (((PDBChain) pdb.chains.elementAt(ii)).isVisible) { Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds; for (int i = 0; i < bonds.size(); i++) { Bond tmp = (Bond) bonds.elementAt(i); if (tmp.start[0] >= max[0]) { max[0] = tmp.start[0]; } if (tmp.start[1] >= max[1]) { max[1] = tmp.start[1]; } if (tmp.start[2] >= max[2]) { max[2] = tmp.start[2]; } if (tmp.start[0] <= min[0]) { min[0] = tmp.start[0]; } if (tmp.start[1] <= min[1]) { min[1] = tmp.start[1]; } if (tmp.start[2] <= min[2]) { min[2] = tmp.start[2]; } if (tmp.end[0] >= max[0]) { max[0] = tmp.end[0]; } if (tmp.end[1] >= max[1]) { max[1] = tmp.end[1]; } if (tmp.end[2] >= max[2]) { max[2] = tmp.end[2]; } if (tmp.end[0] <= min[0]) { min[0] = tmp.end[0]; } if (tmp.end[1] <= min[1]) { min[1] = tmp.end[1]; } if (tmp.end[2] <= min[2]) { min[2] = tmp.end[2]; } } } } width[0] = (float) Math.abs(max[0] - min[0]); width[1] = (float) Math.abs(max[1] - min[1]); width[2] = (float) Math.abs(max[2] - min[2]); maxwidth = width[0]; if (width[1] > width[0]) { maxwidth = width[1]; } if (width[2] > width[1]) { maxwidth = width[2]; } // System.out.println("Maxwidth = " + maxwidth); } public float findScale() { int dim; int width; int height; if (getSize().width != 0) { width = getSize().width; height = getSize().height; } else { width = prefsize.width; height = prefsize.height; } if (width < height) { dim = width; } else { dim = height; } return (float) (dim / (1.5d * maxwidth)); } public void findCentre() { float xtot = 0; float ytot = 0; float ztot = 0; int bsize = 0; //Find centre coordinate for (int ii = 0; ii < pdb.chains.size(); ii++) { if (((PDBChain) pdb.chains.elementAt(ii)).isVisible) { Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds; bsize += bonds.size(); for (int i = 0; i < bonds.size(); i++) { xtot = xtot + ((Bond) bonds.elementAt(i)).start[0] + ((Bond) bonds.elementAt(i)).end[0]; ytot = ytot + ((Bond) bonds.elementAt(i)).start[1] + ((Bond) bonds.elementAt(i)).end[1]; ztot = ztot + ((Bond) bonds.elementAt(i)).start[2] + ((Bond) bonds.elementAt(i)).end[2]; } } } centre[0] = xtot / (2 * (float) bsize); centre[1] = ytot / (2 * (float) bsize); centre[2] = ztot / (2 * (float) bsize); } public void paint(Graphics g) { if(errorLoading) { g.setColor(Color.white); g.fillRect(0,0,getSize().width, getSize().height); g.setColor(Color.black); g.setFont(new Font("Verdana", Font.BOLD, 14)); g.drawString("Error loading PDB data!!", 50, getSize().height/2); return; } else if(visiblebonds==null) { g.setColor(Color.black); g.setFont(new Font("Verdana", Font.BOLD, 14)); g.drawString("Fetching PDB data...", 50, getSize().height/2); return; } //Only create the image at the beginning - //this saves much memory usage if ((img == null) || (prefsize.width != getSize().width) || (prefsize.height != getSize().height)) { try{ prefsize.width = getSize().width; prefsize.height = getSize().height; scale = findScale(); img = createImage(prefsize.width, prefsize.height); ig = img.getGraphics(); redrawneeded = true; }catch(Exception ex) { ex.printStackTrace(); } } if (redrawneeded) { drawAll(ig, prefsize.width, prefsize.height); redrawneeded = false; } if(appletToolTip!=null) { ig.setColor(Color.red); ig.drawString(appletToolTip, toolx, tooly); } g.drawImage(img, 0, 0, this); pdbAction = false; } public void drawAll(Graphics g, int width, int height) { ig.setColor(Color.black); ig.fillRect(0, 0, width, height); drawScene(ig); drawLabels(ig); } public void updateSeqColours() { if (pdbAction) { return; } if(bysequence && pdb!=null) { for (int ii = 0; ii < pdb.chains.size(); ii++) { colourBySequence((PDBChain) pdb.chains.elementAt(ii)); } } redrawneeded=true; repaint(); } int findTrueIndex(int pos) { // returns the alignment position for a residue int j = sequence.getStart(); int i = 0; while ( (i < sequence.getLength()) && (j <= sequence.getEnd()) && (j <= pos+1)) { if (!jalview.util.Comparison.isGap(sequence.getCharAt(i))) { j++; } i++; } if(i>1) i--; if ( (j == sequence.getEnd()) && (j < pos)) { return sequence.getEnd() + 1; } else { return i; } } // This method has been taken out of PDBChain to allow // Applet and Application specific sequence renderers to be used void colourBySequence(PDBChain chain) { for (int i = 0; i < chain.bonds.size(); i++) { Bond tmp = (Bond) chain.bonds.elementAt(i); tmp.startCol = Color.lightGray; tmp.endCol = Color.lightGray; if(chain!=mainchain) continue; if ( (tmp.at1.resNumber >= ( (chain.offset + chain.pdbstart) - 1)) && (tmp.at1.resNumber <= ( (chain.offset + chain.pdbend) - 1))) { int index = findTrueIndex(tmp.at1.alignmentMapping); //sequence.findIndex(tmp.at1.alignmentMapping); if (index != -1) { tmp.startCol = seqcanvas.getSequenceRenderer(). getResidueBoxColour( sequence, index); // tmp.startCol = seqcanvas.getFeatureRenderer(). // findFeatureColour(tmp.startCol, sequence, index); } } int index = findTrueIndex(tmp.at2.alignmentMapping); //sequence.findIndex( tmp.at2.alignmentMapping ); if (index != -1) { tmp.endCol = seqcanvas.getSequenceRenderer(). getResidueBoxColour( sequence, index); // tmp.endCol = seqcanvas.getFeatureRenderer(). // findFeatureColour(tmp.endCol, sequence, index); } } } public void drawScene(Graphics g) { if (zbuffer) { Zsort.Zsort(visiblebonds); } Bond tmpBond=null; for (int i = 0; i < visiblebonds.size(); i++) { tmpBond = (Bond) visiblebonds.elementAt(i); xstart = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2)); ystart = (int) (((tmpBond.start[1] - centre[1]) * scale) + (getSize().height / 2)); xend = (int) (((tmpBond.end[0] - centre[0]) * scale) + (getSize().width / 2)); yend = (int) (((tmpBond.end[1] - centre[1]) * scale) + (getSize().height / 2)); xmid = (xend + xstart) / 2; ymid = (yend + ystart) / 2; if (depthcue && !bymolecule) { if (tmpBond.start[2] < (centre[2] - (maxwidth / 6))) { g.setColor(tmpBond.startCol.darker().darker()); drawLine(g, xstart, ystart, xmid, ymid); g.setColor(tmpBond.endCol.darker().darker()); drawLine(g, xmid, ymid, xend, yend); } else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6))) { g.setColor(tmpBond.startCol.darker()); drawLine(g, xstart, ystart, xmid, ymid); g.setColor(tmpBond.endCol.darker()); drawLine(g, xmid, ymid, xend, yend); } else { g.setColor(tmpBond.startCol); drawLine(g, xstart, ystart, xmid, ymid); g.setColor(tmpBond.endCol); drawLine(g, xmid, ymid, xend, yend); } } else if (depthcue && bymolecule) { if (tmpBond.start[2] < (centre[2] - (maxwidth / 6))) { g.setColor(Color.green.darker().darker()); drawLine(g, xstart, ystart, xend, yend); } else if (tmpBond.start[2] < (centre[2] + (maxwidth / 6))) { g.setColor(Color.green.darker()); drawLine(g, xstart, ystart, xend, yend); } else { g.setColor(Color.green); drawLine(g, xstart, ystart, xend, yend); } } else if (!depthcue && !bymolecule) { g.setColor(tmpBond.startCol); drawLine(g, xstart, ystart, xmid, ymid); g.setColor(tmpBond.endCol); drawLine(g, xmid, ymid, xend, yend); } else { drawLine(g, xstart, ystart, xend, yend); } if(highlightBond1!=null && highlightBond1==tmpBond) { g.setColor(Color.white); drawLine(g, xmid, ymid, xend, yend); } if(highlightBond2!=null && highlightBond2==tmpBond) { g.setColor(Color.white); drawLine(g, xstart, ystart, xmid, ymid); } } } public void drawLine(Graphics g, int x1, int y1, int x2, int y2) { if (!wire) { if (((float) Math.abs(y2 - y1) / (float) Math.abs(x2 - x1)) < 0.5) { g.drawLine(x1, y1, x2, y2); g.drawLine(x1 + 1, y1 + 1, x2 + 1, y2 + 1); g.drawLine(x1, y1 - 1, x2, y2 - 1); } else { g.setColor(g.getColor().brighter()); g.drawLine(x1, y1, x2, y2); g.drawLine(x1 + 1, y1, x2 + 1, y2); g.drawLine(x1 - 1, y1, x2 - 1, y2); } } else { g.drawLine(x1, y1, x2, y2); } } public Dimension minimumsize() { return prefsize; } public Dimension preferredsize() { return prefsize; } public void doKeyPressed(KeyEvent evt) { if (evt.getKeyCode() == KeyEvent.VK_UP) { scale = (float) (scale * 1.1); redrawneeded = true; repaint(); } else if (evt.getKeyCode() == KeyEvent.VK_DOWN) { scale = (float) (scale * 0.9); redrawneeded = true; repaint(); } } public void mousePressed(MouseEvent e) { pdbAction = true; Atom fatom = findAtom(e.getX(), e.getY()); if(fatom!=null) { fatom.isSelected = !fatom.isSelected; redrawneeded = true; repaint(); if (foundchain != -1) { PDBChain chain = (PDBChain) pdb.chains.elementAt(foundchain); if (chain == mainchain) { if (fatom.alignmentMapping != -1) { if (highlightRes == null) highlightRes = new Vector(); if (highlightRes.contains(fatom.alignmentMapping+"" + "")) highlightRes.removeElement(fatom.alignmentMapping + ""); else highlightRes.addElement(fatom.alignmentMapping + ""); } } } } mx = e.getX(); my = e.getY(); omx = mx; omy = my; dragging = false; } public void mouseMoved(MouseEvent e) { pdbAction = true; if(highlightBond1!=null) { highlightBond1.at2.isSelected = false; highlightBond2.at1.isSelected = false; highlightBond1 = null; highlightBond2 = null; } Atom fatom = findAtom(e.getX(), e.getY()); PDBChain chain = null; if(foundchain!=-1) { chain = (PDBChain) pdb.chains.elementAt(foundchain); if(chain == mainchain) { highlightSeqcanvas( fatom.alignmentMapping ); } } if (fatom != null) { toolx = e.getX(); tooly = e.getY(); appletToolTip = chain.id+":"+ fatom.resNumber+" "+ fatom.resName; redrawneeded = true; repaint(); } else { highlightSeqcanvas( -1); appletToolTip = null; redrawneeded = true; repaint(); } } void highlightSeqcanvas(int pos) { int index = seqcanvas.getViewport().getAlignment().findIndex(sequence); int size = pos==-1?0:3; if(highlightRes!=null) size += highlightRes.size()*3; int [] array = new int[size]; int i=0; if(highlightRes!=null) { for (i = 0; i < highlightRes.size(); i++) { int a = Integer.parseInt(highlightRes.elementAt( i).toString())+1; array[i * 3] = index; array[ (i * 3) + 1] = a; array[ (i * 3) + 2] = a; } } if(pos!=-1) { array[i * 3] = index; array[i * 3 + 1] = pos+1; array[i * 3 + 2] = pos+1; } seqcanvas.highlightSearchResults(array); } public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mouseDragged(MouseEvent evt) { int x = evt.getX(); int y = evt.getY(); mx = x; my = y; MCMatrix objmat = new MCMatrix(3, 3); objmat.setIdentity(); if ((evt.getModifiers() & Event.META_MASK) != 0) { objmat.rotatez((float) ((mx - omx))); } else { objmat.rotatex((float) ((my - omy))); objmat.rotatey((float) ((omx - mx))); } //Alter the bonds for (int ii = 0; ii < pdb.chains.size(); ii++) { Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds; for (int i = 0; i < bonds.size(); i++) { Bond tmpBond = (Bond) bonds.elementAt(i); //Translate the bond so the centre is 0,0,0 tmpBond.translate(-centre[0], -centre[1], -centre[2]); //Now apply the rotation matrix tmpBond.start = objmat.vectorMultiply(tmpBond.start); tmpBond.end = objmat.vectorMultiply(tmpBond.end); //Now translate back again tmpBond.translate(centre[0], centre[1], centre[2]); } } objmat = null; omx = mx; omy = my; dragging = true; redrawneeded = true; repaint(); } public void mouseReleased(MouseEvent evt) { dragging = false; return; } void drawLabels(Graphics g) { for (int ii = 0; ii < pdb.chains.size(); ii++) { PDBChain chain = (PDBChain) pdb.chains.elementAt(ii); if (chain.isVisible) { Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds; for (int i = 0; i < bonds.size(); i++) { Bond tmpBond = (Bond) bonds.elementAt(i); if (tmpBond.at1.isSelected) { labelAtom(g, tmpBond, 1); } if (tmpBond.at2.isSelected) { labelAtom(g, tmpBond, 2); } } } } } public void labelAtom(Graphics g, Bond b, int n) { g.setFont(font); if (n == 1) { int xstart = (int) (((b.start[0] - centre[0]) * scale) + (getSize().width / 2)); int ystart = (int) (((b.start[1] - centre[1]) * scale) + (getSize().height / 2)); g.setColor(Color.red); g.drawString(b.at1.resName + "-" + b.at1.resNumber, xstart, ystart); } if (n == 2) { int xstart = (int) (((b.end[0] - centre[0]) * scale) + (getSize().width / 2)); int ystart = (int) (((b.end[1] - centre[1]) * scale) + (getSize().height / 2)); g.setColor(Color.red); g.drawString(b.at2.resName + "-" + b.at2.resNumber, xstart, ystart); } } int foundchain = -1; public Atom findAtom(int x, int y) { Atom fatom = null; foundchain = -1; for (int ii = 0; ii < pdb.chains.size(); ii++) { PDBChain chain = (PDBChain) pdb.chains.elementAt(ii); int truex; Bond tmpBond=null; if (chain.isVisible) { Vector bonds = ((PDBChain) pdb.chains.elementAt(ii)).bonds; for (int i = 0; i < bonds.size(); i++) { tmpBond = (Bond) bonds.elementAt(i); truex = (int) (((tmpBond.start[0] - centre[0]) * scale) + (getSize().width / 2)); if (Math.abs(truex - x) <= 2) { int truey = (int) (((tmpBond.start[1] - centre[1]) * scale) + (getSize().height / 2)); if (Math.abs(truey - y) <= 2) { fatom = tmpBond.at1; foundchain = ii; break; } } } // Still here? Maybe its the last bond truex = (int) ( ( (tmpBond.end[0] - centre[0]) * scale) + (getSize().width / 2)); if (Math.abs(truex - x) <= 2) { int truey = (int) ( ( (tmpBond.end[1] - centre[1]) * scale) + (getSize().height / 2)); if (Math.abs(truey - y) <= 2) { fatom = tmpBond.at2; foundchain = ii; break; } } } if (fatom != null) //)&& chain.ds != null) { chain = (PDBChain) pdb.chains.elementAt(foundchain); } } return fatom; } public void update(Graphics g) { paint(g); } public void highlightRes(int ii) { if (highlightRes != null && highlightRes.contains((ii-1) + "")) { return; } int index = -1; Bond tmpBond; for(index=0; index 0) { highlightBond1 = (Bond) mainchain.bonds.elementAt(index - 1); highlightBond1.at2.isSelected = true; } if (index != mainchain.bonds.size()) { highlightBond2 = (Bond) mainchain.bonds.elementAt(index); highlightBond2.at1.isSelected = true; } break; } } redrawneeded = true; repaint(); } public void setAllchainsVisible(boolean b) { for (int ii = 0; ii < pdb.chains.size(); ii++) { PDBChain chain = (PDBChain) pdb.chains.elementAt(ii); chain.isVisible = b; } mainchain.isVisible = true; findCentre(); setupBonds(); } }