com.vectionvr.jort.gui.MainFrame.java Source code

Java tutorial

Introduction

Here is the source code for com.vectionvr.jort.gui.MainFrame.java

Source

/**
 * Copyright (C) 2014 Bnome SPRL (info@bnome.be)
 *
 * This file is part of VectionVR Stabilizer.
 *
 * VectionVR Stabilizer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * VectionVR Stabilizer 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with VectionVR Stabilizer.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.vectionvr.jort.gui;

import static com.vectionvr.jort.gui.SettingsManager.getSettingsManager;
import static com.vectionvr.jort.jogl.CameraViews.FirstPerson;
import static java.awt.BorderLayout.CENTER;
import static java.awt.Desktop.getDesktop;
import static java.awt.Desktop.isDesktopSupported;
import static java.lang.Integer.parseInt;
import static java.lang.Math.abs;
import static java.lang.Math.toDegrees;
import static java.lang.System.nanoTime;
import static javax.swing.SwingUtilities.invokeLater;
import static jssc.SerialPortList.getPortNames;
import static org.apache.commons.lang3.ArrayUtils.isEmpty;

import java.awt.Color;
import java.awt.Component;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.text.DecimalFormat;
import java.text.NumberFormat;

import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLJPanel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import com.jogamp.opengl.util.FPSAnimator;
import com.vectionvr.jort.data.SensorData;
import com.vectionvr.jort.jogl.WorldScene;
import com.vectionvr.jort.net.UDPSender;
import com.vectionvr.jort.serial.ImuOrientationDataStreamer;
import com.vectionvr.jort.serial.SensorException;
import com.vectionvr.jort.serial.StreamingSensorEventListener;

/**
 * @author (Nicolas Chalon) n.chalon@bnome.be
 */
public class MainFrame extends javax.swing.JFrame implements Runnable, StreamingSensorEventListener {

    private FPSAnimator animator;
    final WorldScene scene = new WorldScene();
    private static final NumberFormat DECIMAL_FORMAT = new DecimalFormat("0.00");
    private static final NumberFormat SHORT_DECIMAL_FORMAT = new DecimalFormat("##0.0 ");
    private static final NumberFormat INT_FORMAT = new DecimalFormat("###0");
    private final SettingsManager settingsManager;
    private boolean running;
    private final UDPSender udpSender = new UDPSender();
    private ImuOrientationDataStreamer streamer;
    private long counterStartTime;
    private SensorData lastSensorData;
    private int counter;
    private SettingsDialog settingsDialog = new SettingsDialog(this, true);
    private float absMaxX = 0f;
    private float absMaxY = 0f;
    private float absMaxZ = 0f;

    public MainFrame() {
        initComponents();
        setPortItems();
        init3DView();
        settingsManager = getSettingsManager(this);
    }

    private void init3DView() {
        final GLProfile glp = GLProfile.getDefault();
        final GLCapabilities caps = new GLCapabilities(glp);
        caps.setDoubleBuffered(true);
        caps.setHardwareAccelerated(true);
        caps.setSampleBuffers(true);
        final GLJPanel canvas = new GLJPanel(caps);
        animator = new FPSAnimator(canvas, 100);
        animator.setIgnoreExceptions(true);
        animator.setPrintExceptions(false);
        orientationPanel.add(canvas, CENTER);
        canvas.addGLEventListener(scene);
        scene.setBackgroundColor(new float[] { 0f, 0f, 0f, .3f });
        scene.setCamera(FirstPerson);
        scene.setLineWidth(2f);
        scene.setCubeEnabled(true);
        scene.setGridEnabled(false);
        scene.setCubeSize(10f);
    }

    /**
     * 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() {

        jButton1 = new javax.swing.JButton();
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        hostName = new javax.swing.JFormattedTextField();
        port = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        jPanel3 = new javax.swing.JPanel();
        jLabel7 = new javax.swing.JLabel();
        rate = new javax.swing.JLabel();
        jLabel9 = new javax.swing.JLabel();
        jLabel11 = new javax.swing.JLabel();
        delay = new javax.swing.JLabel();
        temperature = new javax.swing.JLabel();
        jLabel8 = new javax.swing.JLabel();
        jLabel10 = new javax.swing.JLabel();
        jLabel12 = new javax.swing.JLabel();
        orientationPanel = new javax.swing.JPanel();
        tareButton = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        jLabel3 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        direction = new javax.swing.JComboBox();
        jLabel5 = new javax.swing.JLabel();
        reverseX = new javax.swing.JCheckBox();
        reverseY = new javax.swing.JCheckBox();
        reverseZ = new javax.swing.JCheckBox();
        refreshPortsButton = new javax.swing.JButton();
        jLabel22 = new javax.swing.JLabel();
        lockX1 = new javax.swing.JCheckBox();
        lockY1 = new javax.swing.JCheckBox();
        lockZ1 = new javax.swing.JCheckBox();
        deviceChooser = new javax.swing.JComboBox();
        settingsButton = new javax.swing.JButton();
        jPanel5 = new javax.swing.JPanel();
        jLabel14 = new javax.swing.JLabel();
        zAxisAngle = new javax.swing.JLabel();
        jLabel13 = new javax.swing.JLabel();
        xAxisAngle = new javax.swing.JLabel();
        yAxisAngle = new javax.swing.JLabel();
        jLabel15 = new javax.swing.JLabel();
        jPanel6 = new javax.swing.JPanel();
        jLabel16 = new javax.swing.JLabel();
        maxZAxisAngle = new javax.swing.JLabel();
        jLabel17 = new javax.swing.JLabel();
        maxXAxisAngle = new javax.swing.JLabel();
        maxYAxisAngle = new javax.swing.JLabel();
        jLabel18 = new javax.swing.JLabel();
        jLabelLink = new javax.swing.JLabel();
        jLabel6 = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Vection-VR Stabilizer");
        setIconImage(new ImageIcon(getClass().getClassLoader().getResource("imgs/logo.png")).getImage());
        setMinimumSize(new java.awt.Dimension(478, 340));
        setResizable(false);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowOpened(java.awt.event.WindowEvent evt) {
                formWindowOpened(evt);
            }

            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });

        jButton1.setBackground(new java.awt.Color(51, 204, 0));
        jButton1.setFont(jButton1.getFont().deriveFont(jButton1.getFont().getSize() + 2f));
        jButton1.setText("Start");
        jButton1.setEnabled(false);
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Destination"));

        jLabel1.setText("Host");

        hostName.setText("::1");

        port.setText("27015");

        jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        jLabel2.setText("Port");

        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()
                        .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 36,
                                javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(hostName)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 28,
                                javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(port,
                                javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap()));
        jPanel1Layout.setVerticalGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(jPanel1Layout.createSequentialGroup().addGroup(jPanel1Layout
                        .createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(hostName, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(port, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(jLabel1).addComponent(jLabel2))
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)));

        jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Status"));

        jLabel7.setText("Rate");

        rate.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        rate.setText("N/A");

        jLabel9.setText("Delay");

        jLabel11.setText("Temp");

        delay.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        delay.setText("N/A");

        temperature.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        temperature.setText("N/A");

        jLabel8.setText("p/s");

        jLabel10.setText("ms");

        jLabel12.setText("C");

        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(jPanel3Layout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(jPanel3Layout.createSequentialGroup().addContainerGap().addGroup(jPanel3Layout
                        .createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                        .addComponent(jLabel9, javax.swing.GroupLayout.Alignment.LEADING,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE,
                                Short.MAX_VALUE)
                        .addComponent(jLabel11, javax.swing.GroupLayout.Alignment.LEADING,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE,
                                Short.MAX_VALUE)
                        .addComponent(jLabel7, javax.swing.GroupLayout.Alignment.LEADING,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE,
                                Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel3Layout
                                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addComponent(delay, javax.swing.GroupLayout.DEFAULT_SIZE, 50, Short.MAX_VALUE)
                                .addComponent(rate, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(temperature, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(
                                jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                        .addComponent(jLabel12, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(jLabel10, javax.swing.GroupLayout.Alignment.TRAILING,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(jLabel8, javax.swing.GroupLayout.Alignment.TRAILING))
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)));
        jPanel3Layout.setVerticalGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup()
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(jLabel7)
                                .addComponent(rate, javax.swing.GroupLayout.PREFERRED_SIZE, 16,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(jLabel8))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(jLabel9).addComponent(delay).addComponent(jLabel10))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(jLabel11).addComponent(temperature).addComponent(jLabel12))
                        .addContainerGap()));

        orientationPanel.setIgnoreRepaint(true);
        orientationPanel.setMinimumSize(new java.awt.Dimension(100, 83));
        orientationPanel.setPreferredSize(new java.awt.Dimension(100, 83));
        orientationPanel.setLayout(new java.awt.BorderLayout());

        tareButton.setText("Tare");
        tareButton.setEnabled(false);
        tareButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                tareButtonActionPerformed(evt);
            }
        });

        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Device"));

        jLabel3.setText("USB port");

        jLabel4.setText("Direction");

        direction.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "X: Right, Y: Up, Z: Forward",
                "X: Right, Y: Forward, Z: Up", "X: Up, Y: Right, Z: Forward", "X: Forward, Y: Right, Z: Up",
                "X: Up, Y: Forward, Z: Right", "X: Forward, Y: Up, Z: Right" }));
        direction.setSelectedIndex(1);

        jLabel5.setText("Reverse axis");

        reverseX.setText("X");

        reverseY.setSelected(true);
        reverseY.setText("Y");

        reverseZ.setText("Z");

        refreshPortsButton.setText("Refresh");
        refreshPortsButton.setToolTipText("Refresh list");
        refreshPortsButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                refreshPortsButtonActionPerformed(evt);
            }
        });

        jLabel22.setText("Lock axis");

        lockX1.setText("X");

        lockY1.setText("Y");

        lockZ1.setText("Z");

        deviceChooser.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "    -- No device --" }));

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
                jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(jPanel2Layout
                        .createSequentialGroup().addContainerGap().addGroup(jPanel2Layout
                                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel5, javax.swing.GroupLayout.DEFAULT_SIZE, 90, Short.MAX_VALUE)
                                .addComponent(jLabel22, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addComponent(direction, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addGroup(jPanel2Layout.createSequentialGroup().addGroup(jPanel2Layout
                                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addGroup(jPanel2Layout
                                                .createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                                                .addGroup(jPanel2Layout.createSequentialGroup().addComponent(lockX1)
                                                        .addPreferredGap(
                                                                javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                        .addComponent(lockY1)
                                                        .addPreferredGap(
                                                                javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                        .addComponent(lockZ1))
                                                .addGroup(jPanel2Layout.createSequentialGroup()
                                                        .addComponent(reverseX)
                                                        .addPreferredGap(
                                                                javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                        .addComponent(reverseY)
                                                        .addPreferredGap(
                                                                javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                        .addComponent(reverseZ)))
                                        .addGroup(jPanel2Layout.createSequentialGroup()
                                                .addComponent(deviceChooser, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                        178, javax.swing.GroupLayout.PREFERRED_SIZE)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                .addComponent(refreshPortsButton,
                                                        javax.swing.GroupLayout.PREFERRED_SIZE, 75,
                                                        javax.swing.GroupLayout.PREFERRED_SIZE)))
                                        .addGap(0, 0, Short.MAX_VALUE)))
                        .addContainerGap()));
        jPanel2Layout.setVerticalGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(jPanel2Layout.createSequentialGroup()
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(refreshPortsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 29,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(jLabel3).addComponent(deviceChooser,
                                        javax.swing.GroupLayout.PREFERRED_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(jLabel4).addComponent(direction,
                                        javax.swing.GroupLayout.PREFERRED_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addComponent(jLabel5)
                                .addGroup(jPanel2Layout
                                        .createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                        .addComponent(reverseX).addComponent(reverseY).addComponent(reverseZ)))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED,
                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addGroup(jPanel2Layout
                                        .createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                        .addComponent(lockX1).addComponent(lockY1).addComponent(lockZ1))
                                .addComponent(jLabel22))
                        .addContainerGap()));

        settingsButton.setText("Settings");
        settingsButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                settingsButtonActionPerformed(evt);
            }
        });

        jPanel5.setBorder(javax.swing.BorderFactory.createTitledBorder("Angles"));

        jLabel14.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        jLabel14.setText("Y");

        zAxisAngle.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        zAxisAngle.setText("N/A");

        jLabel13.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        jLabel13.setText("X");

        xAxisAngle.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        xAxisAngle.setText("N/A");

        yAxisAngle.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        yAxisAngle.setText("N/A");

        jLabel15.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        jLabel15.setText("Z");

        javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5);
        jPanel5.setLayout(jPanel5Layout);
        jPanel5Layout.setHorizontalGroup(jPanel5Layout
                .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(jPanel5Layout.createSequentialGroup().addContainerGap()
                        .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addComponent(jLabel14, javax.swing.GroupLayout.DEFAULT_SIZE, 28, Short.MAX_VALUE)
                                .addComponent(jLabel15, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel13, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addComponent(xAxisAngle, javax.swing.GroupLayout.Alignment.TRAILING,
                                        javax.swing.GroupLayout.PREFERRED_SIZE, 55,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(yAxisAngle, javax.swing.GroupLayout.Alignment.TRAILING,
                                        javax.swing.GroupLayout.PREFERRED_SIZE, 55,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(zAxisAngle, javax.swing.GroupLayout.Alignment.TRAILING,
                                        javax.swing.GroupLayout.PREFERRED_SIZE, 55,
                                        javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addContainerGap()));
        jPanel5Layout.setVerticalGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel5Layout.createSequentialGroup()
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(xAxisAngle).addComponent(jLabel13))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(jLabel14, javax.swing.GroupLayout.PREFERRED_SIZE, 16,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(yAxisAngle))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(zAxisAngle).addComponent(jLabel15))
                        .addContainerGap()));

        jPanel6.setBorder(javax.swing.BorderFactory.createTitledBorder("Max"));

        jLabel16.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        jLabel16.setText("Y");

        maxZAxisAngle.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        maxZAxisAngle.setText("N/A");

        jLabel17.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        jLabel17.setText("X");

        maxXAxisAngle.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        maxXAxisAngle.setText("N/A");

        maxYAxisAngle.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        maxYAxisAngle.setText("N/A");

        jLabel18.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
        jLabel18.setText("Z");

        javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6);
        jPanel6.setLayout(jPanel6Layout);
        jPanel6Layout
                .setHorizontalGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(jPanel6Layout.createSequentialGroup().addContainerGap()
                                .addGroup(jPanel6Layout
                                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                        .addComponent(jLabel16, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(jLabel17, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(jLabel18, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(
                                        jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                .addComponent(maxXAxisAngle, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                        73, Short.MAX_VALUE)
                                                .addComponent(maxYAxisAngle, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                                .addComponent(maxZAxisAngle, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                .addContainerGap()));
        jPanel6Layout.setVerticalGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel6Layout.createSequentialGroup()
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(maxXAxisAngle).addComponent(jLabel17))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(jLabel16, javax.swing.GroupLayout.PREFERRED_SIZE, 16,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addComponent(maxYAxisAngle))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(maxZAxisAngle).addComponent(jLabel18))
                        .addContainerGap()));

        jLabelLink.setForeground(new java.awt.Color(51, 51, 255));
        jLabelLink.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabelLink.setText("www.vectionvr.com");
        jLabelLink.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jLabelLinkMouseClicked(evt);
            }
        });

        jLabel6.setFont(new java.awt.Font("Lucida Grande", 0, 12)); // NOI18N
        jLabel6.setText("Provided by Bnome under GPLv3 license");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup().addContainerGap().addGroup(layout
                        .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addGroup(layout.createSequentialGroup()
                                                .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                .addComponent(jPanel5, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE,
                                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                                        javax.swing.GroupLayout.PREFERRED_SIZE)))
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addComponent(tareButton, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(settingsButton, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(orientationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 117,
                                                Short.MAX_VALUE)
                                        .addComponent(jButton1, javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                        .addGroup(layout.createSequentialGroup()
                                .addComponent(jLabel6, javax.swing.GroupLayout.PREFERRED_SIZE, 262,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabelLink, javax.swing.GroupLayout.PREFERRED_SIZE, 137,
                                        javax.swing.GroupLayout.PREFERRED_SIZE)))
                        .addContainerGap()));
        layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
                javax.swing.GroupLayout.Alignment.TRAILING,
                layout.createSequentialGroup().addContainerGap()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jButton1, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                .addGroup(layout.createSequentialGroup().addComponent(tareButton)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(settingsButton))
                                .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addComponent(orientationPanel, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jPanel3, javax.swing.GroupLayout.Alignment.TRAILING,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        Short.MAX_VALUE)
                                .addComponent(jPanel5, javax.swing.GroupLayout.Alignment.TRAILING,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        Short.MAX_VALUE)
                                .addComponent(jPanel6, javax.swing.GroupLayout.DEFAULT_SIZE,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 8, Short.MAX_VALUE)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                .addComponent(jLabelLink).addComponent(jLabel6))
                        .addContainerGap()));

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void refreshPortsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshPortsButtonActionPerformed
        setPortItems();
    }//GEN-LAST:event_refreshPortsButtonActionPerformed

    private void settingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_settingsButtonActionPerformed
        settingsDialog.setLocationRelativeTo(null);
        settingsDialog.setVisible(true);
    }//GEN-LAST:event_settingsButtonActionPerformed

    private void jLabelLinkMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jLabelLinkMouseClicked
        if (evt.getClickCount() > 0) {
            if (isDesktopSupported()) {
                try {
                    URI uri = new URI("http://www.vectionvr.com");
                    getDesktop().browse(uri);
                } catch (IOException ex) {
                } catch (URISyntaxException ex) {
                }
            } else {
            }
        }
    }//GEN-LAST:event_jLabelLinkMouseClicked

    private void formWindowOpened(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowOpened
    }//GEN-LAST:event_formWindowOpened

    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
        stopSending();
    }//GEN-LAST:event_formWindowClosing

    private void jButton1ActionPerformed(final java.awt.event.ActionEvent evt) {// GEN-FIRST:event_jButton1ActionPerformed
        if (running) {
            stopSending();
            jButton1.setText("Start");
            jButton1.setBackground(Color.GREEN);
            temperature.setText("N/A");
            delay.setText("N/A");
            rate.setText("N/A");
            xAxisAngle.setText("N/A");
            yAxisAngle.setText("N/A");
            zAxisAngle.setText("N/A");
            running = false;
        } else {
            temperature.setText(" - ");
            delay.setText(" - ");
            rate.setText(" - ");
            xAxisAngle.setText(" - ");
            yAxisAngle.setText(" - ");
            zAxisAngle.setText(" - ");
            jButton1.setText("Stop");
            jButton1.setBackground(Color.RED);
            startSending();
            running = true;
        }
        tareButton.setEnabled(running);
        refreshPortsButton.setEnabled(!running);
        settingsButton.setEnabled(!running);
        setComponentsEnabled(!running);
    }// GEN-LAST:event_jButton1ActionPerformed

    private void tareButtonActionPerformed(final java.awt.event.ActionEvent evt) {// GEN-FIRST:event_tareButtonActionPerformed
        streamer.tare();
        absMaxX = 0;
        absMaxY = 0;
        absMaxZ = 0;
    }// GEN-LAST:event_tareButtonActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel delay;
    private javax.swing.JComboBox deviceChooser;
    private javax.swing.JComboBox direction;
    private javax.swing.JFormattedTextField hostName;
    private javax.swing.JButton jButton1;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel10;
    private javax.swing.JLabel jLabel11;
    private javax.swing.JLabel jLabel12;
    private javax.swing.JLabel jLabel13;
    private javax.swing.JLabel jLabel14;
    private javax.swing.JLabel jLabel15;
    private javax.swing.JLabel jLabel16;
    private javax.swing.JLabel jLabel17;
    private javax.swing.JLabel jLabel18;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel22;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JLabel jLabel9;
    private javax.swing.JLabel jLabelLink;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel5;
    private javax.swing.JPanel jPanel6;
    private javax.swing.JCheckBox lockX1;
    private javax.swing.JCheckBox lockY1;
    private javax.swing.JCheckBox lockZ1;
    private javax.swing.JLabel maxXAxisAngle;
    private javax.swing.JLabel maxYAxisAngle;
    private javax.swing.JLabel maxZAxisAngle;
    private javax.swing.JPanel orientationPanel;
    private javax.swing.JTextField port;
    private javax.swing.JLabel rate;
    private javax.swing.JButton refreshPortsButton;
    private javax.swing.JCheckBox reverseX;
    private javax.swing.JCheckBox reverseY;
    private javax.swing.JCheckBox reverseZ;
    private javax.swing.JButton settingsButton;
    private javax.swing.JButton tareButton;
    private javax.swing.JLabel temperature;
    private javax.swing.JLabel xAxisAngle;
    private javax.swing.JLabel yAxisAngle;
    private javax.swing.JLabel zAxisAngle;
    // End of variables declaration//GEN-END:variables

    private void setPortItems() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                refreshPortsButton.setEnabled(false);
                deviceChooser.removeAllItems();
                deviceChooser.setEnabled(false);
                boolean validPorts = false;
                final String[] portList = getPortNames();
                if (isEmpty(portList)) {
                    deviceChooser.addItem("    -- No device --");
                    jButton1.setBackground(null);
                } else {
                    validPorts = true;
                    for (String portName : portList) {
                        deviceChooser.addItem(portName);
                    }
                    jButton1.setBackground(Color.GREEN);
                    deviceChooser.setEnabled(true);
                }
                jButton1.setEnabled(validPorts);
                refreshPortsButton.setEnabled(true);
            }
        }).start();
    }

    private void setComponentsEnabled(final boolean enabled) {
        for (final Component component : getContentPane().getComponents()) {
            setChildsEnabled(component, enabled);
        }
    }

    private void setChildsEnabled(final Component component, final boolean enabled) {
        if (component instanceof JPanel) {
            for (final Component subComponent : ((JPanel) component).getComponents()) {
                setChildsEnabled(subComponent, enabled);
            }
        } else if (!(component instanceof JLabel) && !(component instanceof JButton)) {
            component.setEnabled(enabled);
        }
    }

    private void startSending() {
        absMaxX = 0;
        absMaxY = 0;
        absMaxZ = 0;
        new Thread(this).start();
    }

    private void stopSending() {
        running = false;
        if (streamer != null) {
            streamer.stop();
        }
        if (udpSender != null) {
            udpSender.stop();
        }
    }

    @Override
    public void run() {
        try {
            startUdpSender();
            setupStreamer();
            while (running) {
                updateMax();
                outputStatistics();
                suspend(1f);
            }
        } catch (final UnknownHostException ex) {
            showError("The provided destination address is not valid.");
            jButton1ActionPerformed(null);
        } catch (final NumberFormatException ex) {
            showError("The provided destination port is not valid.");
            jButton1ActionPerformed(null);
        }
    }

    private void showError(final String message) {
        invokeLater(new Runnable() {
            @Override
            public void run() {
                JOptionPane.showMessageDialog(MainFrame.this, message, "Error", JOptionPane.ERROR_MESSAGE);
            }
        });
    }

    private void startUdpSender() throws UnknownHostException, NumberFormatException {
        udpSender.setDestinationAddress(hostName.getText());
        udpSender.setDestinationPort(parseInt(port.getText()));
        new Thread(udpSender).start();
    }

    private void setupStreamer() throws NumberFormatException {
        streamer = new ImuOrientationDataStreamer((String) deviceChooser.getSelectedItem());
        streamer.setDirectionAxis(direction.getSelectedIndex());
        streamer.setReverseAxis(reverseX.isSelected(), reverseY.isSelected(), reverseZ.isSelected());
        streamer.setAccelerometerRange((byte) settingsDialog.getAccelerometerRange().getSelectedIndex());
        streamer.setCompassRange((byte) settingsDialog.getCompassRange().getSelectedIndex());
        streamer.setGyroscopeRange((byte) settingsDialog.getGyroscopeRange().getSelectedIndex());
        streamer.setInterval(getInterval());
        streamer.setLockX(lockX1.isSelected());
        streamer.setLockY(lockY1.isSelected());
        streamer.setLockZ(lockZ1.isSelected());

        streamer.registerListener(this);
        new Thread(streamer).start();
    }

    @Override
    public void sensorStarted(final ImuOrientationDataStreamer sensor) {
        counterStartTime = nanoTime();
        tareButton.setEnabled(true);
        animator.start();
    }

    @Override
    public void onSensorData(final SensorData data) {
        udpSender.onSensorData(data);
        scene.update(data);
        lastSensorData = data;
        ++counter;
    }

    @Override
    public void sensorStopped() {
        scene.reset();
        try {
            animator.stop();
        } catch (final Exception e) {
        }
    }

    private void outputStatistics() {
        if (streamer.getStatistics() != null && streamer.getStatistics().get() > 0) {
            final double timeDiff = nanoTime() - counterStartTime;
            rate.setText((short) (counter / (timeDiff / 1e9)) + "");
            delay.setText(DECIMAL_FORMAT.format(udpSender.getRunningAverage()));
            temperature.setText(INT_FORMAT.format(lastSensorData.getTemperature()));
            xAxisAngle.setText(SHORT_DECIMAL_FORMAT.format(toDegrees(lastSensorData.getEulerAngle().getxAxis())));
            yAxisAngle.setText(SHORT_DECIMAL_FORMAT.format(toDegrees(lastSensorData.getEulerAngle().getyAxis())));
            zAxisAngle.setText(SHORT_DECIMAL_FORMAT.format(toDegrees(lastSensorData.getEulerAngle().getzAxis())));
            maxXAxisAngle.setText(SHORT_DECIMAL_FORMAT.format(toDegrees(absMaxX)));
            maxYAxisAngle.setText(SHORT_DECIMAL_FORMAT.format(toDegrees(absMaxY)));
            maxZAxisAngle.setText(SHORT_DECIMAL_FORMAT.format(toDegrees(absMaxZ)));
        }
        counter = 0;
        counterStartTime = nanoTime();
    }

    private static void suspend(final float durationInSeconds) {
        try {
            Thread.sleep((long) (durationInSeconds * 1000f));
        } catch (final Exception e) {
        }
    }

    @Override
    public void handleException(final SensorException e) {
        showError("There was an error using the sensor. Please check your cable.");
        jButton1ActionPerformed(null);
    }

    private int getInterval() {
        return parseInt(settingsDialog.getIntervalInput().getText());
    }

    private void updateMax() {
        if (lastSensorData != null) {
            if (abs(lastSensorData.getEulerAngle().getxAxis()) > absMaxX) {
                absMaxX = abs(lastSensorData.getEulerAngle().getxAxis());
            }
            if (abs(lastSensorData.getEulerAngle().getyAxis()) > absMaxY) {
                absMaxY = abs(lastSensorData.getEulerAngle().getyAxis());
            }
            if (abs(lastSensorData.getEulerAngle().getzAxis()) > absMaxZ) {
                absMaxZ = abs(lastSensorData.getEulerAngle().getzAxis());
            }
        }
    }
}