/*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\////////////////////////////*\ This class is an extention of Canvas. Runs its own thread. paint methods cannot be called directly by browser (good) \*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\////////////////////////////*/ import java.awt.*; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.text.DecimalFormat; import java.io.*; //! @brief The map. Stroboscopic map or Poincare' section. /// Data here can be stored on disk with the "Record" tool. class Map extends Canvas implements Runnable { private Thread myThread; private AFMSimulator afmSim; private boolean poincare; private BufferedImage image; private int ind; // always counts up after full reset. Indexes data array private int p_ind; // index for individual probe. resets each time a new probe starts private double zoom; private final int W = 500, H = 300; private final double INTERVAL = (double) W / AFMConstants.SAMPLES; private int delay = 100; private double A, B; // scaling factors private double x_center = 0, y_center = 0; private boolean yVsPY = false; private Graphics back; private Color backgroundColor; private Color textColor; private Color pointsColor; private double[][] data; private double[][] probePoints; private double x_i, y_i, px_i, py_i; // precise initial parameters private double xCoord_i, yCoord_i; // precise initial parameters of plot being viewed private double x_p, y_p, px_p, py_p; // initial params for a single probe private final double N_p = 100; // number of search iterations private int index_p; // keeps track of probe # private String lastInfo; private boolean probing; private boolean recording; private Color thisColor; // current probe AFM color // for data output to file: File I/O private FileWriter fw; private BufferedWriter out; private PrintWriter outFile; private DecimalFormat dataFormat; public Map() { setSize(W, H); afmSim = new AFMSimulator(); afmSim.setParams(AFMApplet.params[0], AFMApplet.params[1], AFMApplet.params[2], AFMApplet.params[3], AFMApplet.params[4], AFMApplet.params[5], AFMApplet.params[6], AFMApplet.params[7], AFMApplet.params[8]); afmSim.resetSim(); x_center = afmSim.getAFM().getX(0); y_center = afmSim.getAFM().getPX(0); image = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); backgroundColor = AFMConstants.BG_color; textColor = AFMConstants.text_color; pointsColor = AFMConstants.mapPoints_color; back = image.getGraphics(); back.setColor(backgroundColor); //background color back.fillRect(0,0,W,H); back.setColor(textColor); if (!yVsPY) back.drawString("( x, px )", 450, 20); else back.drawString("( y, py )", 450, 20); data = new double[1000000][4]; probePoints = new double[100][4]; ind = 0; p_ind = 0; index_p = 0; zoom = 100; A = 50 * zoom; B = 50 * zoom; x_i = 0; y_i = 0; px_i = 0; py_i = 0; x_p = 0; y_p = 0; px_p = 0; py_p = 0; xCoord_i = 0; yCoord_i = 0; lastInfo = ""; probing = false; recording = false; thisColor = new Color(0xFF); dataFormat = new DecimalFormat("0.0"); dataFormat.setMinimumFractionDigits(14); dataFormat.setMaximumFractionDigits(14); dataFormat.setMinimumIntegerDigits(4); addMouseListener(new ZoomListener()); addMouseMotionListener(new ZoomListener()); start_recording(); } public double[] getLastDataPoint(){ return data[ind - 1]; } public void start() { if (myThread != null) stop(); myThread = new Thread(this); myThread.start(); }//end start public Map(int _delay) { this(); delay = _delay; } public void poincare(boolean poincare) { this.poincare = poincare; } /* Will be called when "STOP PROBE" button is pushed */ public void toggleProbing() { probing = !probing; if (probing) probe(); if (!probing) { back.setColor(backgroundColor); back.drawString("Probing...", 440, 40); } } /* Will be called when the RECORD button is pressed/unpressed*/ public void toggleRecord() { recording = !recording; if(!recording) { back.setColor(backgroundColor); back.drawString("Recording...", 430, 60); } try { if(recording) outFile.println(); // add a blank line between two distinct sets of data } catch (Exception e) // do nothing if output file cannot be found/accessed (if running through browser) { } } public void toggleMap() { poincare = !poincare; back.setColor(backgroundColor); if(!poincare) back.drawString("Poincare'", 440, 290); else back.drawString("Stroboscopic", 410, 290); } /* Will be called when "PROBE" button is pushed */ public void probe() { probing = true; double x_m = ProbeData.x_m; double y_m = ProbeData.y_m; double px_m = ProbeData.px_m; double py_m = ProbeData.py_m; double x_dif = Math.abs(ProbeData.x_spanV / 2); double y_dif = Math.abs(ProbeData.y_spanV / 2); //System.out.println(x_dif + " " + y_dif); int i = 0; if (!yVsPY) { for (double iX = x_m - x_dif; iX <= x_m + x_dif + 1.e-13; iX += x_dif / 4) { for (double iPX = px_m - y_dif; iPX <= px_m + y_dif + 1.e-13; iPX += y_dif / 4) { probePoints[i][0] = iX; probePoints[i][1] = y_i; probePoints[i][2] = iPX; probePoints[i][3] = py_i; i++; } } } else { for (double iY = y_m - x_dif; iY <= y_m + x_dif + 1.e-13; iY += x_dif / 4) { for (double iPY = py_m - y_dif; iPY <= py_m + y_dif + 1.e-13; iPY += y_dif / 4) { probePoints[i][0] = x_i; probePoints[i][1] = iY; probePoints[i][2] = px_i; probePoints[i][3] = iPY; i++; } } } image = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); back = image.getGraphics(); back.setColor(backgroundColor); //background color back.fillRect(0,0,W,H); back.setColor(textColor); if (!yVsPY) back.drawString("( x, px )", 450, 20); else back.drawString("( y, py )", 450, 20); ind = 0; p_ind = 0; index_p = 0; afmSim.setParams(AFMApplet.params[0], AFMApplet.params[1], probePoints[0][0], probePoints[0][1], probePoints[0][2], probePoints[0][3], AFMApplet.params[6], AFMApplet.params[7], AFMApplet.params[8]); afmSim.resetSim(); //x_center=afmSim.getAFM().getX(0); y_center=afmSim.getAFM().getPX(0); }// end probe() public void start_recording() { String path = AFMConstants.path; // move to AFMConstants String fileName = AFMConstants.fileName; try { fw = new FileWriter(path + fileName); // open file for writing out = new BufferedWriter(fw); //bitstream outFile = new PrintWriter(out); //actual output channel } catch (Exception e) { System.out.println(e.getMessage()); } writeParameters(); }// end start_recording //! Rytis edits: output parameters, so that my afm_stdin(..) can understand. // /// Note, that surface phase is "reflected", to coincide with /// Rytis' definition of coordinate system. private void writeParameters() { try { outFile.println("# Surface function = " + afmSim.getSurface().getType() + "\n" + "# epsilon = " + AFMApplet.params[8] + "\n" + "# V = " + AFMApplet.params[7] + "\n" + "# PotLen = 1.0\n" + "# YCenter = " + AFMApplet.params[6] + "\n" + "# alpha (restit) = " + AFMApplet.params[1] + "\n" + "# phase = " + (0.5 - afmSim.getSurface().getP()) + "\n" + "# points = \n" + "# Frequency = \n" ); } catch (Exception e) { } }// end writeParameters public void record(double time) { back.setColor(AFMConstants.probeText_color); back.drawString("Recording...", 430, 60); // Output file data string (currently ( -x, -px, y, py ) ) ! note negatives of x, px! String outData = dataFormat.format(-data[ind][0]) + " " + dataFormat.format(-data[ind][1]) + " " + dataFormat.format(data[ind][2]) + " " + dataFormat.format(data[ind][3]); try { outFile.println(outData); } catch (Exception e) { } } public void reset() // should not repaint { image = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); back = image.getGraphics(); back.setColor(backgroundColor); //background color back.fillRect(0,0,W,H); back.setColor(textColor); if (!yVsPY) back.drawString("( x, px )", 450, 20); else back.drawString("( y, py )", 450, 20); ind = 0; setZoom(100); afmSim.setParams(AFMApplet.params[0], AFMApplet.params[1], AFMApplet.params[2], AFMApplet.params[3], AFMApplet.params[4], AFMApplet.params[5], AFMApplet.params[6], AFMApplet.params[7], AFMApplet.params[8]); afmSim.resetSim(); x_center = afmSim.getAFM().getX(0); y_center = afmSim.getAFM().getPX(0); probing = false; recording = false; writeParameters(); } public void reset(double newZoom) { image = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); //ind=0; setZoom(newZoom); back = image.getGraphics(); back.setColor(backgroundColor); back.fillRect(0,0,W,H); back.setColor(AFMConstants.mapMarker_color); int xDisp_i = (int) (W / 2 + A * (xCoord_i - x_center)); int yDisp_i = (int) (H / 2 + B * (yCoord_i - y_center)); back.drawOval(xDisp_i - 5, yDisp_i - 5, 10, 10); back.setColor(pointsColor); back.drawOval(xDisp_i, yDisp_i, 0, 0); back.setColor(textColor); int xDisp, yDisp; int select; if (!yVsPY) { select = 0; back.drawString("( x, px )", 450, 20); } else { select = 2; back.drawString("( y, py )", 450, 20); } if (probing) { back.setColor(AFMConstants.probeText_color); back.drawString("Probing...", 440, 40); } if (recording) { back.setColor(AFMConstants.probeText_color); back.drawString("Recording...", 430, 60); } back.setColor(pointsColor); for (int i = 0; i < ind; i++) { xDisp = (int) (W / 2 + A * (data[i][select] - x_center)); yDisp = (int) (H / 2 + B * (data[i][select + 1] - y_center)); back.drawOval(xDisp, yDisp, 0, 0); } }// end reset(newZoom) public void setZoom(double newZoom) { zoom = newZoom; A = 50 * zoom; B = 50 * zoom; } public void changePanel() { if (yVsPY == true) yVsPY = false; else yVsPY = true; if (!yVsPY) { xCoord_i = x_i; yCoord_i = px_i; x_center = x_i; y_center = px_i; } else { xCoord_i = y_i; yCoord_i = py_i; x_center = y_i; y_center = py_i; } reset(zoom); repaint(); } public void clear() { back.setColor(backgroundColor); back.fillRect(0, 0, W, H); back.setColor(textColor); if (!yVsPY) { back.drawString("( x, px )", 450, 20); } else { back.drawString("( y, py )", 450, 20); } if (probing) { back.setColor(AFMConstants.probeText_color); back.drawString("Probing...", 440, 40); } if (recording) { back.setColor(AFMConstants.probeText_color); back.drawString("Recording...", 430, 60); } } public void resume() { start(); } public void run() { while (myThread != null) { repaint(); try { Thread.sleep(delay); } catch (InterruptedException e) { this.stop(); } } }//end run public void stop() { myThread = null; //data = null; } public void cleanup() { try { outFile.close(); } catch (Exception e) { } data = null; myThread = null; afmSim = null; image = null; back = null; backgroundColor = null; textColor = null; pointsColor = null; data = null; probePoints = null; lastInfo = null; thisColor = null; // current probe AFM color } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { if(!poincare) { back = image.getGraphics(); back.setColor(AFMConstants.mapType_color); back.drawString("Stroboscopic", 410, 290); if (probing) { back.setColor(AFMConstants.probeText_color); back.drawString("Probing...", 440, 40); } if(afmSim.isDragging()) { back.setColor(AFMConstants.poincare_color); back.drawString("DRAGON!", 230, 290); } back.setColor(AFMConstants.info_color); back.drawString("Time = " + (ind+1), 20, 290); //afmSim.getAFM().getTime(AFMConstants.SAMPLES - 1) if(probing) back.setColor(thisColor); else back.setColor(pointsColor); /* Plots x Vs Px, with xCoord as x and yCoord as Px. Plotted as difference from L */ double xCoord, yCoord; int xDisp, yDisp; //(ind+1) here because this is always sampled at the end of the traversal // now changed to -Surface.L only. time is reset double time = afmSim.getAFM().getTime(AFMConstants.SAMPLES - 1); data[ind][0] = afmSim.getAFM().getX(AFMConstants.SAMPLES - 1) - Surface.L; // xCoord = x - L (difference from L) data[ind][1] = afmSim.getAFM().getPX(AFMConstants.SAMPLES - 1); // yCoord = px data[ind][2] = afmSim.getAFM().getY(AFMConstants.SAMPLES - 1); // xCoord = y data[ind][3] = afmSim.getAFM().getPY(AFMConstants.SAMPLES - 1); // yCoord = px //// Write data to file here if recording data //// // add functionality to maintain multiple data files later // if(recording) record(time); if (!yVsPY) { xCoord = data[ind][0] - x_center; yCoord = data[ind][1] - y_center; } else { xCoord = data[ind][2] - x_center; yCoord = data[ind][3] - y_center; } xDisp = (int) (W / 2 + A * xCoord); yDisp = (int) (H / 2 + B * yCoord);//-0.1*zoom); if (probing && p_ind == 0 || !probing && ind == 0) { back.setColor(AFMConstants.mapMarker_color); x_i = afmSim.getAFM().getX(0); y_i = afmSim.getAFM().getY(0); px_i = afmSim.getAFM().getPX(0); py_i = afmSim.getAFM().getPY(0); if (!yVsPY) { xCoord_i = afmSim.getAFM().getX(0); yCoord_i = afmSim.getAFM().getPX(0); } else { xCoord_i = afmSim.getAFM().getY(0); yCoord_i = afmSim.getAFM().getPY(0); } int xDisp_i = (int) (W / 2 + A * (xCoord_i - x_center)); int yDisp_i = (int) (H / 2 + B * (yCoord_i - y_center));//-0.1*zoom); back.drawOval(xDisp_i - 5, yDisp_i - 5, 10, 10); back.setColor(pointsColor); back.drawOval(xDisp_i, yDisp_i, 0, 0); } back.drawOval(xDisp, yDisp, 0, 0); findFocus(true, xDisp, yDisp); g.drawImage(image, 0, 0, this); back.setColor(backgroundColor); back.drawString("Time = " + (ind+1), 20, 290); findFocus(false, 0, 0); afmSim.getMore(); if(probing) { p_ind++; if (p_ind > 500) { p_ind = 0; probeNext(); // gets next point afmSim.setParams(AFMApplet.params[0], AFMApplet.params[1], x_p, y_p, px_p, py_p, AFMApplet.params[6], AFMApplet.params[7], AFMApplet.params[8]); afmSim.resetSim(); index_p++; thisColor = new Color(thisColor.getRGB() + 0x6FF0); } }// end if probing ind++; }// end if not poincare (is stroboscopic) else { int startInd = ind+1; back = image.getGraphics(); back.setColor(AFMConstants.mapType_color); back.drawString("Poincare'", 440, 290); if (probing) { back.setColor(AFMConstants.probeText_color); back.drawString("Probing...", 440, 40); } if(afmSim.isDragging()) { back.setColor(AFMConstants.poincare_color); back.drawString("DRAGON!", 230, 290); } back.setColor(AFMConstants.info_color); back.drawString("Time = " + (ind+1), 20, 290); //afmSim.getAFM().getTime(AFMConstants.SAMPLES - 1) if(probing) back.setColor(thisColor); else back.setColor(AFMConstants.mapPoints_color); /* Plots x Vs Px, with xCoord as x and yCoord as Px. Plotted as difference from L */ double xCoord[] = new double[1000], yCoord[] = new double[1000]; int xDisp[] = new int[1000], yDisp[] = new int[1000]; //(ind+1) here because this is always sampled at the end of the traversal // now changed to -Surface.L only. time is reset double[] time = new double[1000]; double[][] roots = afmSim.getRoots(); for(int i=0; i W || !show) back.drawString(">", W-10, H/2); if(yDisp < 0 || !show) back.drawString("^", W/2, 10); if(yDisp > H || !show) back.drawString("v", W/2, H-10); } /** * ActionListener for mouse clicks */ private class ZoomListener implements MouseListener, MouseMotionListener { /**This method does nothing*/ public void mousePressed(MouseEvent event) { ProbeData.x_init = (int) event.getPoint().getX(); ProbeData.y_init = (int) event.getPoint().getY(); } public void mouseReleased(MouseEvent event) { reset(zoom); int x_final = (int) event.getPoint().getX(); int y_final = (int) event.getPoint().getY(); back.setColor(AFMConstants.probeText_color); back.drawOval(ProbeData.x_pivot, ProbeData.y_pivot, ProbeData.x_span, ProbeData.y_span); // pivot is either initial or final point double x_mid = (double) (ProbeData.x_pivot*2 + ProbeData.x_span) / 2; double y_mid = (double) (ProbeData.y_pivot*2 + ProbeData.y_span) / 2; ProbeData.x_spanV = (double) (ProbeData.x_span - W / 2) / A + y_center; ProbeData.y_spanV = (double) (ProbeData.y_span - W / 2) / A + y_center; if (!yVsPY) { ProbeData.x_m = (double) (x_mid - W / 2) / A + x_center; ProbeData.px_m = (double) (y_mid - W / 2) / A + y_center; } else { ProbeData.y_m = (double) (x_mid - W / 2) / A + x_center; ProbeData.py_m = (double) (y_mid - W / 2) / A + y_center; } }// end mouseReleased /** * If a click is detected, this method will center the display on the click * and zoom in by a factor of 2 * * @param event the MouseEvent (click, pressed, released, etc.) */ public void mouseClicked(MouseEvent event) { double x = event.getPoint().getX(); double y = event.getPoint().getY(); if (AFMApplet.zoomTool.isSelected()) { x_center = (double) (x - W / 2) / A + x_center; // x_center holds *actual* x center value (in the system, not on the display) y_center = (double) (y - H / 2) / B + y_center; if (event.getButton() == MouseEvent.BUTTON1) reset(zoom * 2); else reset(zoom / 2); repaint(); //translate pixels to values } if (AFMApplet.centerTool.isSelected()) { x_center = (double) (x - W / 2) / A + x_center; y_center = (double) (y - H / 2) / B + y_center; reset(zoom); /***ADD CODE HERE***/ } if (AFMApplet.selectTool.isSelected()) { x_center = (double) (x - W / 2) / A + x_center; y_center = (double) (y - H / 2) / B + y_center; System.out.println("x = " + x_center + " y = " + y_center); if (!yVsPY) { AFMApplet.setControlText(Double.toString(afmSim.getAFM().getRestit()), Double.toString(x_center), Double.toString(y_i), Double.toString(y_center), Double.toString(py_i), Double.toString(afmSim.getAFM().getEquiPos()), Double.toString(afmSim.getAFM().getV()), Double.toString(afmSim.getAFM().getE())); afmSim.setParams(0, afmSim.getAFM().getRestit(), x_center, y_i, y_center, py_i, afmSim.getAFM().getEquiPos(), afmSim.getAFM().getV(), afmSim.getAFM().getE())/********************/; } else { AFMApplet.setControlText(Double.toString(afmSim.getAFM().getRestit()), Double.toString(x_i), Double.toString(x_center), Double.toString(px_i), Double.toString(y_center), Double.toString(afmSim.getAFM().getEquiPos()), Double.toString(afmSim.getAFM().getV()), Double.toString(afmSim.getAFM().getE())); afmSim.setParams(0, afmSim.getAFM().getRestit(), x_i, x_center, px_i, y_center, afmSim.getAFM().getEquiPos(), afmSim.getAFM().getV(), afmSim.getAFM().getE())/********************/; } afmSim.resetSim(); //AFMApplet.set_Clicked(); ind = 0; reset(zoom); /***ADD CODE HERE***/ } } /** * This method does nothing */ public void mouseEntered(MouseEvent event) { } /** * This method does nothing */ public void mouseExited(MouseEvent event) { } public void mouseMoved(MouseEvent event) { back = image.getGraphics(); double x = event.getPoint().getX(); double y = event.getPoint().getY(); double x_point = (double) (x - W / 2) / A + x_center; double y_point = (double) (y - H / 2) / B + y_center; back.setColor(backgroundColor); back.drawString(lastInfo, 20, 270); DecimalFormat dec = new DecimalFormat("0.###"); dec.setMaximumFractionDigits((int)Math.round(AFMMath.log2(zoom/100)) + 4); back.setColor(AFMConstants.info_color); lastInfo = "(" + dec.format(x_point) + ", " + dec.format(y_point) + ")"; back.drawString(lastInfo, 20, 270); /***ADD CODE HERE***/ } public void mouseDragged(MouseEvent event) { back = image.getGraphics(); back.setColor(backgroundColor); back.drawOval(ProbeData.x_pivot, ProbeData.y_pivot, ProbeData.x_span, ProbeData.y_span); ProbeData.x_current = (int) event.getPoint().getX(); ProbeData.y_current = (int) event.getPoint().getY(); ProbeData.x_span = Math.abs(ProbeData.x_current - ProbeData.x_init); ProbeData.y_span = Math.abs(ProbeData.y_current - ProbeData.y_init); if (ProbeData.x_current >= ProbeData.x_init) ProbeData.x_pivot = ProbeData.x_init; else ProbeData.x_pivot = ProbeData.x_current; if (ProbeData.y_current >= ProbeData.y_init) ProbeData.y_pivot = ProbeData.y_init; else ProbeData.y_pivot = ProbeData.y_current; back.setColor(pointsColor); back.drawOval(ProbeData.x_pivot, ProbeData.y_pivot, ProbeData.x_span, ProbeData.y_span); }//end mouseDragged }//end ZoomListener }//end Map class ProbeData { static int x_init, y_init; static int x_pivot, y_pivot; static int x_current, y_current; static int x_span, y_span; static double x_spanV, y_spanV; static double x_m, px_m, y_m, py_m; // precise mean value of flow region static double[] params_p; static double x_p, y_p, px_p, py_p; static double[] getNext() { return params_p; } }// end ProbeData