package madsdf.shimmer.gui;
import static com.google.common.base.Preconditions.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Queues;
import com.google.common.eventbus.Subscribe;
import info.monitorenter.gui.chart.Chart2D;
import info.monitorenter.gui.chart.IAxis;
import info.monitorenter.gui.chart.IAxis.AxisTitle;
import info.monitorenter.gui.chart.ITrace2D;
import info.monitorenter.gui.chart.rangepolicies.ARangePolicy;
import info.monitorenter.gui.chart.traces.Trace2DLtd;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Paint;
import java.awt.Stroke;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.CopyOnWriteArrayList;
import org.jfree.chart.ChartColor;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
/**
* Draw the chart on the main frame and save the data received from the
* Bluetooth device.
*
* Java version : JDK 1.6.0_21 IDE : Netbeans 7.1.1
*
* @author Gregoire Aubert
* @version 1.0
*/
public class ChartsDrawer {
// Range policy that returns the all-time max/min
public static class RangePolicyMaxSeen extends ARangePolicy {
private double min;
private double max;
public RangePolicyMaxSeen() {
this(Double.MAX_VALUE, Double.MIN_VALUE);
}
public RangePolicyMaxSeen(double min, double max) {
super();
this.min = min;
this.max = max;
}
@Override
public double getMax(double chartMin, double chartMax) {
max = Math.max(max, chartMax);
return max;
}
@Override
public double getMin(double chartMin, double chartMax) {
min = Math.min(min, chartMin);
return min;
}
}
private final ConcurrentLinkedDeque<AccelGyro.Sample> receivedValues =
new ConcurrentLinkedDeque();
final int N_KEPT = 400;
// Pairs of (color, stroke) to use to get consistent drawing based on serie
// id across application
public final static Color[] colors = new Color[]{
Color.RED, Color.GREEN, Color.BLUE, Color.BLACK,
Color.CYAN, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.YELLOW,
ChartColor.VERY_DARK_RED, ChartColor.VERY_DARK_GREEN,
ChartColor.VERY_DARK_BLUE, ChartColor.GRAY,
ChartColor.VERY_DARK_CYAN
};
private final static Stroke contStroke = new BasicStroke(1.0f);
private final static Stroke dashStroke = new BasicStroke(1.0f,
BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f,
new float[]{10.0f}, 0.0f);
public final static Stroke[] strokes = new Stroke[]{
contStroke, contStroke, contStroke, contStroke,
contStroke, contStroke, contStroke,
contStroke, contStroke,
dashStroke, dashStroke,
dashStroke, dashStroke,
dashStroke
};
private ITrace2D[] accelTraces = new ITrace2D[]{
new Trace2DLtd(100),
new Trace2DLtd(100),
new Trace2DLtd(100),};
private ITrace2D[] gyroTraces = new ITrace2D[]{
new Trace2DLtd(100),
new Trace2DLtd(100),
new Trace2DLtd(100),};
/**
* Constructor
*
* @param panAccel will contain the acceleration chart
* @param panGyro will contain the gyroscope chart
*/
public ChartsDrawer(Chart2D chartAccel, Chart2D chartGyro) {
createChart(chartAccel, accelTraces, "accel", "Acc m/s^2");
createChart(chartGyro, gyroTraces, "gyro", "Angular speed rad/s");
}
private static void createChart(Chart2D chart, ITrace2D[] traces,
String name, String yAxisLabel) {
// Cleanup - necessary when we switch between calibrated and uncalibrated
chart.removeAllTraces();
final String[] axesNames = new String[]{"x", "y", "z"};
for (int i = 0; i < 3; ++i) {
chart.addTrace(traces[i]);
traces[i].setName(name + "_" + axesNames[i]);
traces[i].setColor(colors[i]);
traces[i].setStroke(strokes[i]);
}
IAxis yAxis = chart.getAxisY();
//yAxis.setAxisTitle(new AxisTitle(yAxisLabel));
yAxis.setPaintScale(true);
yAxis.getAxisTitle().setTitle(null);
yAxis.setRangePolicy(new RangePolicyMaxSeen());
IAxis xAxis = chart.getAxisX();
xAxis.setPaintScale(false);
xAxis.getAxisTitle().setTitle(null);
}
public void addSample(AccelGyro.Sample sample) {
// Add the sample in the complete list
receivedValues.addLast(sample);
while (receivedValues.size() > N_KEPT) {
receivedValues.removeFirst();
}
final long now = System.currentTimeMillis();
accelTraces[0].addPoint(now, sample.accel[0]);
accelTraces[1].addPoint(now, sample.accel[1]);
accelTraces[2].addPoint(now, sample.accel[2]);
gyroTraces[0].addPoint(now, sample.gyro[0]);
gyroTraces[1].addPoint(now, sample.gyro[1]);
gyroTraces[2].addPoint(now, sample.gyro[2]);
}
static class Data {
public float[][] accel;
public float[][] gyro;
public Data(float[][] accel, float[][] gyro) {
this.accel = accel;
this.gyro = gyro;
}
}
public Data getRecentData() {
float[][] accelData = new float[3][];
float[][] gyroData = new float[3][];
for (int i = 0; i < 3; ++i) {
accelData[i] = new float[N_KEPT];
gyroData[i] = new float[N_KEPT];
}
ArrayList<AccelGyro.Sample> allSamples = Lists.newArrayList(receivedValues);
int start = Math.max(0, allSamples.size() - N_KEPT);
int datai = 0;
for (int i = start; i < allSamples.size(); ++i) {
for (int j = 0; j < 3; ++j) {
accelData[j][datai] = allSamples.get(i).accel[j];
gyroData[j][datai] = allSamples.get(i).gyro[j];
}
++datai;
}
return new Data(accelData, gyroData);
}
}