/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package madsdf.shimmer.gui; import static com.google.common.base.Preconditions.*; import java.awt.Color; import java.awt.Paint; import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.io.OutputStream; import java.io.Writer; import java.util.Arrays; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JComponent; import javax.swing.JFormattedTextField; import javax.swing.JSpinner; import javax.swing.SpinnerNumberModel; import javax.swing.text.DefaultFormatter; 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.PlotOrientation; import org.jfree.chart.plot.ValueMarker; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.time.FixedMillisecond; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; /** * * @author julien */ public class CaptureEditFrame extends javax.swing.JFrame { private XYSeries[] accelSeries = new XYSeries[3]; private JFreeChart accelChart; private XYSeries[] gyroSeries = new XYSeries[3]; private JFreeChart gyroChart; private SpinnerNumberModel startSpinnerModel; private SpinnerNumberModel endSpinnerModel; private ValueMarker startMarker; private ValueMarker endMarker; private File saveFolder; private final String namePrefix; private float[][] accelData; private float[][] gyroData; private final int length; private static float[][] arrCopy(float[][] arr) { float[][] out = new float[arr.length][]; for (int i = 0; i < arr.length; ++i) { out[i] = new float[arr[i].length]; for (int j = 0; j < arr[i].length; ++j) { out[i][j] = arr[i][j]; } } return out; } /** * Creates new form CaptureEditFrame * - accel, gyro : 3xn arrays of values */ public CaptureEditFrame(String saveDir, String namePrefix, float[][] accel, float[][] gyro, int length) { checkState(accel.length == 3); checkState(accel[0].length == gyro[0].length); initComponents(); this.length = length; this.namePrefix = namePrefix; this.saveFolder = new File(saveDir); this.accelData = arrCopy(accel); this.gyroData = arrCopy(gyro); saveFolder.mkdirs(); startMarker = new ValueMarker(0); startMarker.setPaint(Color.BLUE); endMarker = new ValueMarker(accel[0].length - 1); endMarker.setPaint(Color.BLUE); { accelChart = createChartForTimeSeries("Acceleration", "accel", accelSeries, accel, startMarker, endMarker); ChartPanel cPanel = (ChartPanel)panAccel; cPanel.setChart(accelChart); } { gyroChart = createChartForTimeSeries("Gyroscope", "gyro", gyroSeries, gyro, startMarker, endMarker); ChartPanel cPanel = (ChartPanel)panGyro; cPanel.setChart(gyroChart); } startSpinnerModel = (SpinnerNumberModel) startSpinner.getModel(); endSpinnerModel = (SpinnerNumberModel) endSpinner.getModel(); startSpinnerModel.setMinimum(0); startSpinnerModel.setMaximum(accel[0].length - 1); endSpinnerModel.setMinimum(0); endSpinnerModel.setMaximum(accel[0].length - 1); endSpinnerModel.setValue(Math.max(length, accel[0].length - 1)); spinnerSetCommitOnEdit(startSpinner); spinnerSetCommitOnEdit(endSpinner); } // Create plot for a 3 axis time series (accel or gyro) private static JFreeChart createChartForTimeSeries( String title, String name, XYSeries[] series, float[][] data, ValueMarker startMarker, ValueMarker endMarker) { XYSeriesCollection col = new XYSeriesCollection(); series[0] = new XYSeries("X", true, false); col.addSeries(series[0]); series[1] = new XYSeries("Y", true, false); col.addSeries(series[1]); series[2] = new XYSeries("Z", true, false); col.addSeries(series[2]); for (int i = 0; i < data.length; ++i) { for (int j = 0; j < data[i].length; ++j) { series[i].add(j, data[i][j]); } } JFreeChart chart = ChartFactory.createXYLineChart( title, "Samples", name, col, PlotOrientation.VERTICAL, true, false, false); XYPlot plot = chart.getXYPlot(); plot.addDomainMarker(startMarker); plot.addDomainMarker(endMarker); plot.setRangeGridlinesVisible(false); // Hide the grid in the graph plot.setDomainGridlinesVisible(false); plot.setBackgroundPaint(Color.WHITE); ValueAxis axisAcc = plot.getDomainAxis(); axisAcc.setTickMarksVisible(true); // Define the tick count axisAcc.setMinorTickCount(10); axisAcc.setAutoRange(true); //axisAcc.setFixedAutoRange(NUM_VISIBLE); // Define the number of visible value axisAcc.setTickLabelsVisible(true); // Hide the axis labels plot.setRenderer(new XYLineAndShapeRenderer(true, false) { @Override public Paint lookupSeriesPaint(int series) { checkState(series >= 0 && series < 3); switch (series) { case 0: return Color.RED; case 1: return Color.GREEN; case 2: return Color.BLUE; default: return Color.BLACK; } } }); return chart; } private static void spinnerSetCommitOnEdit(JSpinner spinner) { JComponent comp = spinner.getEditor(); JFormattedTextField field = (JFormattedTextField) comp.getComponent(0); DefaultFormatter formatter = (DefaultFormatter) field.getFormatter(); formatter.setCommitsOnValidEdit(true); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { panAccel = new ChartPanel(null); panGyro = new ChartPanel(null); jPanel1 = new javax.swing.JPanel(); jLabel1 = new javax.swing.JLabel(); startSpinner = new javax.swing.JSpinner(); jLabel2 = new javax.swing.JLabel(); endSpinner = new javax.swing.JSpinner(); jLabel3 = new javax.swing.JLabel(); commandSpinner = new javax.swing.JSpinner(); saveButton = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.Y_AXIS)); javax.swing.GroupLayout panAccelLayout = new javax.swing.GroupLayout(panAccel); panAccel.setLayout(panAccelLayout); panAccelLayout.setHorizontalGroup( panAccelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 453, Short.MAX_VALUE) ); panAccelLayout.setVerticalGroup( panAccelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 124, Short.MAX_VALUE) ); getContentPane().add(panAccel); javax.swing.GroupLayout panGyroLayout = new javax.swing.GroupLayout(panGyro); panGyro.setLayout(panGyroLayout); panGyroLayout.setHorizontalGroup( panGyroLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 453, Short.MAX_VALUE) ); panGyroLayout.setVerticalGroup( panGyroLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 124, Short.MAX_VALUE) ); getContentPane().add(panGyro); jLabel1.setText("Start"); startSpinner.setModel(new javax.swing.SpinnerNumberModel()); startSpinner.addChangeListener(new javax.swing.event.ChangeListener() { public void stateChanged(javax.swing.event.ChangeEvent evt) { startSpinnerStateChanged(evt); } }); jLabel2.setText("End"); endSpinner.setModel(new javax.swing.SpinnerNumberModel()); endSpinner.setEnabled(false); endSpinner.addChangeListener(new javax.swing.event.ChangeListener() { public void stateChanged(javax.swing.event.ChangeEvent evt) { endSpinnerStateChanged(evt); } }); jLabel3.setText("Command"); commandSpinner.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(0), Integer.valueOf(0), null, Integer.valueOf(1))); saveButton.setText("Save"); saveButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { saveButtonActionPerformed(evt); } }); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(saveButton) .addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(startSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jLabel2)) .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(jLabel3) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(commandSpinner))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(endSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE))) .addContainerGap(193, Short.MAX_VALUE)) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel1) .addComponent(startSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel2) .addComponent(endSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(18, 18, 18) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel3) .addComponent(commandSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(18, 18, 18) .addComponent(saveButton) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); getContentPane().add(jPanel1); pack(); }// </editor-fold>//GEN-END:initComponents private void startSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_startSpinnerStateChanged final int start = (Integer)startSpinnerModel.getValue(); startMarker.setValue(start); endSpinnerModel.setValue(start + length); }//GEN-LAST:event_startSpinnerStateChanged private void endSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_endSpinnerStateChanged endMarker.setValue((Integer)endSpinnerModel.getValue()); }//GEN-LAST:event_endSpinnerStateChanged private static void writeAxis(BufferedWriter w, String name, float[] vals) throws IOException { w.write(name + " : "); for (int i = 0; i < vals.length; ++i) { w.write(String.format("%.15g", vals[i])); if (i < vals.length - 1) { w.write(";"); } } w.write("\n"); } private BufferedWriter createFile(int command) throws IOException { final String prefix = namePrefix + "_movement_" + command; File[] existing = saveFolder.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.startsWith(prefix); } }); // Find the maximum sample number in existing files Pattern fpat = Pattern.compile(prefix + "_(\\d+).txt"); int maxSample = 0; for (File f: existing) { final Matcher m = fpat.matcher(f.getName()); if (m.matches()) { final int num = Integer.parseInt(m.group(1)); maxSample = Math.max(maxSample, num); } } final String fname = prefix + "_" + (maxSample + 1) + ".txt"; return new BufferedWriter( new FileWriter(saveFolder.getAbsolutePath() + "/" + fname)); } private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed try { int command = (Integer)((SpinnerNumberModel)commandSpinner.getModel()).getValue(); int start = (Integer)startSpinnerModel.getValue(); int end = (Integer)endSpinnerModel.getValue(); System.out.println("Saving from " + start + " to " + end + "( => " + (end - start) + " samples"); if (end - start != length) { System.out.println("Too short movement !"); } BufferedWriter saveWriter = createFile(command); // TODO: Should increment sample number ? saveWriter.write("COMMAND " + command + " SAMPLE 1\n"); writeAxis(saveWriter, "Accel X", Arrays.copyOfRange(accelData[0], start, end)); writeAxis(saveWriter, "Accel Y", Arrays.copyOfRange(accelData[1], start, end)); writeAxis(saveWriter, "Accel Z", Arrays.copyOfRange(accelData[2], start, end)); writeAxis(saveWriter, "Gyro X", Arrays.copyOfRange(gyroData[0], start, end)); writeAxis(saveWriter, "Gyro Y", Arrays.copyOfRange(gyroData[1], start, end)); writeAxis(saveWriter, "Gyro Z", Arrays.copyOfRange(gyroData[2], start, end)); saveWriter.close(); } catch (IOException ex) { Logger.getLogger(CaptureEditFrame.class.getName()).log(Level.SEVERE, null, ex); } }//GEN-LAST:event_saveButtonActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) throws FileNotFoundException, IOException { /* Set the Nimbus look and feel */ //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html */ try { for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { javax.swing.UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException ex) { java.util.logging.Logger.getLogger(CaptureEditFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (InstantiationException ex) { java.util.logging.Logger.getLogger(CaptureEditFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { java.util.logging.Logger.getLogger(CaptureEditFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(CaptureEditFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } //</editor-fold> final float[][] accel1 = { {3497, 3523, 3655, 3665, 3652, 3565, 3449, 3319, 3271, 3175, 3105, 2996, 2956, 2911, 2785, 2717, 2574, 2426, 2374, 2264, 2177, 2040, 1930, 1797, 1567, 1309, 1068, 876, 776, 692, 676, 640, 473, 315, 149, 46, 22, 22, 22, 26, 95, 161, 273, 342, 456, 599, 808, 986, 1129, 1288, 1400, 1519, 1724, 1822, 1922, 2008, 2066, 2125, 2144, 2172, 2322, 2906, 3722, 4074, 3872, 3743, 3773, 3943, 4077, 4076, 4071, 3812, 3641, 3668, 3587, 3477, 3406, 3344, 3258, 3175, 3108, 3004, 2970, 2924, 2867, 2852, 2838, 2779, 2817, 2832, 2833, 2852, 2881, 2879, 2851, 2877, 2857, 2847, 2794, 2758}, {2353, 2399, 2427, 2454, 2462, 2466, 2402, 2392, 2372, 2276, 2191, 2153, 2094, 2139, 2147, 2102, 2119, 2090, 2079, 2113, 2136, 2249, 2270, 2273, 2278, 2255, 2226, 2165, 2134, 2074, 2013, 1974, 1913, 1879, 1853, 1841, 1813, 1775, 1752, 1731, 1730, 1758, 1754, 1786, 1784, 1806, 1793, 1792, 1807, 1800, 1831, 1857, 1869, 1942, 2009, 2054, 2179, 2333, 2469, 2712, 2907, 3086, 3269, 3192, 3124, 3258, 3354, 3279, 3143, 2869, 2595, 2457, 2352, 2266, 2207, 2168, 2139, 2120, 2132, 2142, 2138, 2183, 2176, 2160, 2150, 2140, 2107, 2037, 2057, 2082, 2081, 2087, 2083, 2108, 2082, 2052, 2070, 2062, 2076, 2050}, {1681, 1665, 1674, 1656, 1693, 1666, 1643, 1621, 1614, 1639, 1652, 1738, 1759, 1778, 1793, 1804, 1850, 1882, 1890, 1917, 1967, 1945, 1934, 1916, 1898, 1894, 1791, 1727, 1694, 1780, 1806, 1773, 1814, 1828, 1856, 1852, 1837, 1826, 1780, 1750, 1729, 1729, 1658, 1684, 1691, 1745, 1788, 1800, 1852, 1816, 1807, 1748, 1787, 1777, 1776, 1851, 1846, 1807, 1681, 1578, 1496, 1508, 1692, 1867, 1700, 1446, 1501, 1808, 2107, 2151, 2026, 1949, 1835, 1856, 1957, 1955, 1975, 1990, 1971, 1987, 1968, 1945, 1923, 1900, 1888, 1899, 1947, 1954, 1950, 1955, 1939, 1919, 1930, 1932, 1922, 1931, 1963, 1964, 1949, 1948} }; final float[][] gyro1 = { {200, 200, 200, 3665, 3652, 3565, 3449, 3319, 3271, 3175, 3105, 2996, 2956, 2911, 2785, 2717, 2574, 2426, 2374, 2264, 2177, 2040, 1930, 1797, 1567, 1309, 1068, 876, 776, 692, 676, 640, 473, 315, 149, 46, 22, 22, 22, 26, 95, 161, 273, 342, 456, 599, 808, 986, 1129, 1288, 1400, 1519, 1724, 1822, 1922, 2008, 2066, 2125, 2144, 2172, 2322, 2906, 3722, 4074, 3872, 3743, 3773, 3943, 4077, 4076, 4071, 3812, 3641, 3668, 3587, 3477, 3406, 3344, 3258, 3175, 3108, 3004, 2970, 2924, 2867, 2852, 2838, 2779, 2817, 2832, 2833, 2852, 2881, 2879, 2851, 2877, 2857, 2847, 2794, 2758}, {1681, 1665, 1674, 1656, 1693, 1666, 1643, 1621, 1614, 1639, 1652, 1738, 1759, 1778, 1793, 1804, 1850, 1882, 1890, 1917, 1967, 1945, 1934, 1916, 1898, 1894, 1791, 1727, 1694, 1780, 1806, 1773, 1814, 1828, 1856, 1852, 1837, 1826, 1780, 1750, 1729, 1729, 1658, 1684, 1691, 1745, 1788, 1800, 1852, 1816, 1807, 1748, 1787, 1777, 1776, 1851, 1846, 1807, 1681, 1578, 1496, 1508, 1692, 1867, 1700, 1446, 1501, 1808, 2107, 2151, 2026, 1949, 1835, 1856, 1957, 1955, 1975, 1990, 1971, 1987, 1968, 1945, 1923, 1900, 1888, 1899, 1947, 1954, 1950, 1955, 1939, 1919, 1930, 1932, 1922, 1931, 1963, 1964, 1949, 1948}, {1681, 1665, 1674, 1656, 1693, 1666, 1643, 1621, 1614, 1639, 1652, 1738, 1759, 1778, 1793, 1804, 1850, 1882, 1890, 1917, 1967, 1945, 1934, 1916, 1898, 1894, 1791, 1727, 1694, 1780, 1806, 1773, 1814, 1828, 1856, 1852, 1837, 1826, 1780, 1750, 1729, 1729, 1658, 1684, 1691, 1745, 1788, 1800, 1852, 1816, 1807, 1748, 1787, 1777, 1776, 1851, 1846, 1807, 1681, 1578, 1496, 1508, 1692, 1867, 1700, 1446, 1501, 1808, 2107, 2151, 2026, 1949, 1835, 1856, 1957, 1955, 1975, 1990, 1971, 1987, 1968, 1945, 1923, 1900, 1888, 1899, 1947, 1954, 1950, 1955, 1939, 1919, 1930, 1932, 1922, 1931, 1963, 1964, 1949, 1948} }; /* Create and display the form */ java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new CaptureEditFrame("movements", "", accel1, gyro1, 75).setVisible(true); } }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JSpinner commandSpinner; private javax.swing.JSpinner endSpinner; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JPanel jPanel1; private javax.swing.JPanel panAccel; private javax.swing.JPanel panGyro; private javax.swing.JButton saveButton; private javax.swing.JSpinner startSpinner; // End of variables declaration//GEN-END:variables }