import java.awt.*; import java.awt.event.*; import java.util.*; public class XYCanvas extends Canvas implements MouseListener, MouseMotionListener{ XYApplet app; int oldWidth = -1; int oldHeight = -1; int imageOffset = 15; int startX, startY, endX, endY; // mouse positions int boxXStartIndex, boxYStartIndex, boxXEndIndex, boxYEndIndex; // box position in spin indices int boxX, boxY, boxWidth, boxHeight; // box position in pixels int centerX, centerY; // center of the box in pixels double initialAngle, finalAngle; // angles with respect to x axis, the difference determines angle of rotation boolean spinsSet=false; // set to true if a spin or a bloc of spins have been selected Image image = null; public XYCanvas(XYApplet app) { super(); this.app = app; addMouseListener(this); addMouseMotionListener(this); } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { Dimension size = getSize(); g.draw3DRect(imageOffset-5, imageOffset-5, size.width - 2*imageOffset+10, size.height - 2*imageOffset+10, true); if(app.experiment != null) { int width = size.width - 2*imageOffset; int height = size.height - 2*imageOffset; // if the window has been resized if(oldWidth != width || oldHeight != height || image == null) { image = createImage(width, height); oldWidth = width; oldHeight = height; } Graphics buff = image.getGraphics(); buff.clearRect(0, 0, width, height); app.experiment.drawSpins(buff, 0, 0, width, height); g.drawImage(image, imageOffset, imageOffset, this); app.displayVariables(); } } // when a mouse is pressed, either a bloc of spins have been selected, waiting to be rotated, // in which case, we assume a gray rectangle is drawn indicating the bloc of selected spins; // or no spins have been selected, in which case we assume no box is shown, then we start to // draw the box of selected spins. public void mousePressed(MouseEvent e) { if(app.status != 's' || app.experiment == null || image == null) return; if(spinsSet) // if spins have been selected, calculate angle of rotation initialAngle = finalAngle = computeAngle(e.getX() - imageOffset - centerX, centerY - e.getY() + imageOffset); // convert display y-axis to convention y-axis; buffer coordinates and canvas coordinates differ by 15 else { startX = e.getX() - imageOffset; // buffer coordinates and canvas coordinates differ by 15 startY = e.getY() - imageOffset; boxXStartIndex = boxXEndIndex = boxYStartIndex = boxYEndIndex = 0; boxX = boxY = boxWidth = boxHeight = 0; } } // when the mouse is dragged inside the canvas, if spins are being selected, erase the previously // drawn gray box, and draw a new box according to the current mouse position; or if spins have // been selected, calculate the angle of rotation and draw the roated spins with the box outside. public void mouseDragged(MouseEvent e) { if(app.status != 's' || app.experiment == null || image == null) return; Graphics buff = image.getGraphics(); Graphics g = this.getGraphics(); if(!spinsSet) { buff.setXORMode(Color.white); buff.setColor(Color.gray); buff.drawRect(boxX, boxY, boxWidth, boxHeight); // clear the previously drawn rectangle endX = e.getX() - imageOffset; endY = e.getY() - imageOffset; int minX = startX, maxX = endX; if(maxX < minX) { maxX = minX; minX = endX; } int minY = startY, maxY = endY; if(maxY < minY) { maxY = minY; minY = endY; } double dx = (double)(oldWidth) / app.L; double dy = (double)(oldHeight) / app.L; boxXStartIndex = (int)(minX/dx); boxYStartIndex = (int)(minY/dy); boxXEndIndex = (int)(maxX/dx); boxYEndIndex = (int)(maxY/dy); boxX = (int)(boxXStartIndex * dx) + 1; // +1 so the box boundary will be clearly shown boxY = (int)(boxYStartIndex * dy) + 1; boxWidth = (int)((boxXEndIndex - boxXStartIndex + 1) * dx) - 2; boxHeight = (int)((boxYEndIndex - boxYStartIndex + 1) * dy) - 2; centerX = boxX + boxWidth/2; centerY = boxY + boxHeight/2; buff.drawRect(boxX, boxY, boxWidth, boxHeight); g.drawImage(image, imageOffset, imageOffset, this); } else { double tempAngle = finalAngle; finalAngle = computeAngle(e.getX() - imageOffset - centerX, centerY - e.getY() + imageOffset); app.experiment.rotateSpinBloc(boxXStartIndex, boxYStartIndex, boxXEndIndex, boxYEndIndex, finalAngle - tempAngle); repaint(boxX, boxY, boxWidth, boxHeight); buff.setPaintMode(); buff.setColor(Color.gray); buff.drawRect(boxX, boxY, boxWidth, boxHeight); buff.setColor(Color.red); buff.drawOval(centerX - 3, centerY - 3, 6, 6); g.drawImage(image, imageOffset, imageOffset, this); } } // when a mouse is released, either the selection of spins is done, or the rotation of spins is done public void mouseReleased(MouseEvent e) { if(app.status != 's' || app.experiment == null || image == null) return; mouseDragged(e); // performs the drawing of rectangle and spins, etc. spinsSet = !spinsSet; if(!spinsSet) // repaint if the spins have finished the rotation repaint(); else { Graphics buff = image.getGraphics(); buff.setPaintMode(); } } public void mouseMoved(MouseEvent e) { if(app.status != 's' || app.experiment == null || image == null) return; if(spinsSet == false) app.showStatus("Mouse press, drag, and release on the canvas selects a bloc of spins."); else app.showStatus("Mouse press, drag, and release changes the orientation of the selected spins."); } public void mouseExited(MouseEvent e) { app.showStatus(""); if(app.status != 's' || app.experiment == null || image == null) return; spinsSet = false; Graphics buff = image.getGraphics(); buff.setPaintMode(); repaint(); } private double computeAngle(double x, double y) { if(x == 0) { if(y >0) return Math.PI/2; else if(y<0) return (-Math.PI/2); else return 0; // if the point is at origin, return 0 } double angle = Math.atan(y/x); if(x<0) angle += Math.PI; return angle; } public void mouseEntered(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } }