/* * MultiTracing, a demo testing the thread- safetiness of the Chart2D. * Copyright (c) 2007 - 2011 Achim Westermann, Achim.Westermann@gmx.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * If you modify or optimize the code in a useful way please let me know. * Achim.Westermann@gmx.de */ package info.monitorenter.gui.chart.demos; import info.monitorenter.gui.chart.Chart2D; import info.monitorenter.gui.chart.ITrace2D; import info.monitorenter.gui.chart.rangepolicies.RangePolicyMinimumViewport; import info.monitorenter.gui.chart.traces.Trace2DSimple; import info.monitorenter.gui.chart.views.ChartPanel; import info.monitorenter.util.Range; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; /** * <p> * An example that tests the ability of multithreaded use of a single * <code>Chart2D</code>. Six different Threads are painting subsequently a * single point to the chart and go to a sleep. After having painted the whole * trace, each Thread sleeps for a random time, removes it's trace, sleeps for * another random time and starts again. <br> * To be true: the data for the <code>TracePoint</code> instances is computed a * single time at startup. * </p> * <p> * This test may blow your CPU. I am currently working on an AMD Athlon 1200, * 512 MB RAM so I did not get these problems. * </p> * * @version $Revision: 1.13 $ * * @author <a href='mailto:Achim.Westermann@gmx.de'>Achim Westermann </a> */ public final class MultiTracing extends JFrame { /** * Thread that adds a trace to a chart, paints the points with configurable * sleep breaks and then removes it. It then goes to sleep and starts this * cycle anew. * <p> * * @author <a href="mailto:Achim.Westermann@gmx.de">Achim Westermann </a> * * * @version $Revision: 1.13 $ */ static final class AddPaintRemoveThread extends Thread { /** The y values to paint. */ private double[] m_data; /** the chart to use. */ private Chart2D m_innnerChart; /** The break the Thread takes between painting two points. */ private long m_sleep; /** The trace to paint to. */ private ITrace2D m_trace; /** * Creates an instance that paints data to the trace that is added to the * chart. * <p> * * @param chart * the chart to use. * * @param trace * the trace to add points to. * * @param data * the y values of the points to add. * * @param sleep * the length of the sleep break between painting points in ms. */ public AddPaintRemoveThread(final Chart2D chart, final ITrace2D trace, final double[] data, final long sleep) { this.m_innnerChart = chart; this.m_trace = trace; this.m_trace.setName(this.getName()); this.m_data = data; this.m_sleep = sleep; } /** * @see java.lang.Runnable#run() */ @Override public void run() { try { while (true) { if (Chart2D.DEBUG_THREADING) { System.out.println(this.getName() + "(" + Thread.currentThread().getName() + ") adding trace."); } this.m_innnerChart.addTrace(this.m_trace); for (int i = 0; i < this.m_data.length; i++) { if (Chart2D.DEBUG_THREADING) { System.out.println("Thread "+ this.getName() + " adding point to " + this.m_trace.getName()); } this.m_trace.addPoint(i, this.m_data[i]); try { Thread.sleep(this.m_sleep); } catch (InterruptedException e) { e.printStackTrace(System.err); } } try { Thread.sleep((long) (Math.random() * this.m_sleep)); } catch (InterruptedException e) { e.printStackTrace(System.err); } if (Chart2D.DEBUG_THREADING) { System.out.println(this.getName() + "(" + Thread.currentThread().getName() + ") removing trace."); } this.m_innnerChart.removeTrace(this.m_trace); this.m_trace.removeAllPoints(); try { Thread.sleep((long) (Math.random() * this.m_sleep)); } catch (InterruptedException e) { e.printStackTrace(System.err); } } } catch (Throwable f) { f.printStackTrace(System.err); } } } /** * Generated <code>serialVersionUID</code>. */ private static final long serialVersionUID = 3256722879394820657L; /** Sleep break time between adding two points. */ private static final int SLEEP = 100; /** * Main entry. * <p> * * @param args * ignored. */ public static void main(final String[] args) { /* * [[xa 1,..,xa n],..,[xf 1,...,xf n]] */ final double[][] data = new double[6][200]; final java.util.Random rand = new java.util.Random(); // first traces data // recursive entry: data[0][0] = rand.nextDouble() * 5; for (int i = 1; i < data[0].length; i++) { data[0][i] = (rand.nextDouble() < 0.5) ? data[0][i - 1] + rand.nextDouble() * 5 : data[0][i - 1] - rand.nextDouble() * 5; } // second trace double tmp; for (int i = 0; i < data[0].length; i++) { tmp = Math.pow(Math.E, ((double) i) / 40) + (Math.random() < 0.5 ? data[0][i] : -data[0][i]); data[1][i] = tmp; } // third trace for (int i = 0; i < data[0].length; i++) { data[2][i] = Math.pow(Math.cos(((double) i) / 10) * 5, 2); } // fourth trace: numerical integration of fist trace's previous entries. // recursive entry: data[3][0] = data[0][0]; tmp = 0; for (int i = 1; i < data[0].length; i++) { for (int j = Math.max(0, i - 10); j <= i; j++) { tmp += data[0][j]; } data[3][i] = tmp / (((double) i) + 1); tmp = 0; } // fifth trace addition of second trace and third trace for (int i = 0; i < data[0].length; i++) { data[4][i] = data[1][i] + data[2][i] * (0.1 * -data[0][i]); } // sixth trace: addition of first and second trace for (int i = 0; i < data[0].length; i++) { data[5][i] = data[0][i] + data[2][i]; } final MultiTracing wnd = new MultiTracing(); // wnd.setForceXRange(new Range(0, data[0].length + 10)); // wnd.setForceYRange(MultiTracing.getRange(data)); wnd.setLocation(100, 300); wnd.setSize(800, 300); wnd.setResizable(true); wnd.setVisible(true); ITrace2D trace; // first Thread: trace = new Trace2DSimple(); trace.setColor(Color.red); new AddPaintRemoveThread(wnd.m_chart, trace, data[0], MultiTracing.SLEEP).start(); // second Thread: trace = new Trace2DSimple(); trace.setColor(Color.green); new AddPaintRemoveThread(wnd.m_chart, trace, data[1], (long) (MultiTracing.SLEEP * 1.5)) .start(); // third Thread: trace = new Trace2DSimple(); trace.setColor(Color.blue); new AddPaintRemoveThread(wnd.m_chart, trace, data[2], (MultiTracing.SLEEP * 2)).start(); // fourth Thread: trace = new Trace2DSimple(); trace.setColor(Color.cyan); new AddPaintRemoveThread(wnd.m_chart, trace, data[3], (long) (MultiTracing.SLEEP * 2.5)) .start(); // fifth Thread: trace = new Trace2DSimple(); trace.setColor(Color.black); new AddPaintRemoveThread(wnd.m_chart, trace, data[4], (MultiTracing.SLEEP * 3)).start(); // sixth Thread: trace = new Trace2DSimple(); trace.setColor(Color.white); new AddPaintRemoveThread(wnd.m_chart, trace, data[5], (long) (MultiTracing.SLEEP * 3.5)) .start(); } /** The chart to fill. */ protected Chart2D m_chart = null; /** Defcon. */ public MultiTracing() { super("MultiTracing"); this.m_chart = new Chart2D(); this.m_chart.getAxisX().setPaintGrid(true); this.m_chart.getAxisY().setPaintGrid(true); this.m_chart.setBackground(Color.lightGray); this.m_chart.setGridColor(new Color(0xDD, 0xDD, 0xDD)); // add WindowListener this.addWindowListener(new WindowAdapter() { /** * @see java.awt.event.WindowAdapter#windowClosing(java.awt.event.WindowEvent) */ @Override public void windowClosing(final WindowEvent e) { System.exit(0); } }); Container contentPane = this.getContentPane(); contentPane.setLayout(new BorderLayout()); contentPane.add(new ChartPanel(this.m_chart), BorderLayout.CENTER); } /** * Enforces to display a certain visible x range that will be expanded if * traces in the chart have higher or lower values. * <p> * * @param forceXRange * the range that at least has to be kept visible. */ public void setForceXRange(final Range forceXRange) { this.m_chart.getAxisX().setRangePolicy(new RangePolicyMinimumViewport(forceXRange)); } /** * Enforces to display a certain visible x range that will be expanded if * traces in the chart have higher or lower values. * <p> * * @param forceYRange * the range that at least has to be kept visible. */ public void setForceYRange(final Range forceYRange) { this.m_chart.getAxisY().setRangePolicy(new RangePolicyMinimumViewport(forceYRange)); } }