// Copyright (C) 2015 Marek Kowalski (M.Kowalski@ire.pw.edu.pl), Jacek Naruniec (J.Naruniec@ire.pw.edu.pl)
// License: MIT Software License See LICENSE.txt for the full license.
// If you use this software in your research, then please use the following citation:
// Kowalski, M.; Naruniec, J.; Daniluk, M.: "LiveScan3D: A Fast and Inexpensive 3D Data
// Acquisition System for Multiple Kinect v2 Sensors". in 3D Vision (3DV), 2015 International Conference on, Lyon, France, 2015
// @INPROCEEDINGS{Kowalski15,
// author={Kowalski, M. and Naruniec, J. and Daniluk, M.},
// booktitle={3D Vision (3DV), 2015 International Conference on},
// title={LiveScan3D: A Fast and Inexpensive 3D Data Acquisition System for Multiple Kinect v2 Sensors},
// year={2015},
// }
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Globalization;
namespace KinectServer
{
public partial class SettingsForm : Form
{
public KinectSettings oSettings;
public KinectServer oServer;
private Timer scrollTimer = null;
bool bFormLoaded = false;
public SettingsForm()
{
InitializeComponent();
}
private void SettingsForm_Load(object sender, EventArgs e)
{
txtMinX.Text = oSettings.aMinBounds[0].ToString(CultureInfo.InvariantCulture);
txtMinY.Text = oSettings.aMinBounds[1].ToString(CultureInfo.InvariantCulture);
txtMinZ.Text = oSettings.aMinBounds[2].ToString(CultureInfo.InvariantCulture);
txtMaxX.Text = oSettings.aMaxBounds[0].ToString(CultureInfo.InvariantCulture);
txtMaxY.Text = oSettings.aMaxBounds[1].ToString(CultureInfo.InvariantCulture);
txtMaxZ.Text = oSettings.aMaxBounds[2].ToString(CultureInfo.InvariantCulture);
chFilter.Checked = oSettings.bFilter;
txtFilterNeighbors.Text = oSettings.nFilterNeighbors.ToString();
txtFilterDistance.Text = oSettings.fFilterThreshold.ToString(CultureInfo.InvariantCulture);
lisMarkers.DataSource = oSettings.lMarkerPoses;
chBodyData.Checked = oSettings.bStreamOnlyBodies;
chSkeletons.Checked = oSettings.bShowSkeletons;
cbCompressionLevel.SelectedText = oSettings.iCompressionLevel.ToString();
chMerge.Checked = oSettings.bMergeScansForSave;
txtICPIters.Text = oSettings.nNumICPIterations.ToString();
txtRefinIters.Text = oSettings.nNumRefineIters.ToString();
btSyncEnable.Enabled = true;
btSyncDisable.Enabled = false;
chAutoExposureEnabled.Checked = oSettings.bAutoExposureEnabled;
trManualExposure.Value = oSettings.nExposureStep;
if (oSettings.bSaveAsBinaryPLY)
{
rBinaryPly.Checked = true;
rAsciiPly.Checked = false;
}
else
{
rBinaryPly.Checked = false;
rAsciiPly.Checked = true;
}
bFormLoaded = true;
}
void UpdateClients()
{
if (bFormLoaded)
{
oServer.SendSettings();
}
}
void UpdateMarkerFields()
{
if (lisMarkers.SelectedIndex >= 0)
{
MarkerPose pose = oSettings.lMarkerPoses[lisMarkers.SelectedIndex];
float X, Y, Z;
pose.GetOrientation(out X, out Y, out Z);
txtOrientationX.Text = X.ToString(CultureInfo.InvariantCulture);
txtOrientationY.Text = Y.ToString(CultureInfo.InvariantCulture);
txtOrientationZ.Text = Z.ToString(CultureInfo.InvariantCulture);
txtTranslationX.Text = pose.pose.t[0].ToString(CultureInfo.InvariantCulture);
txtTranslationY.Text = pose.pose.t[1].ToString(CultureInfo.InvariantCulture);
txtTranslationZ.Text = pose.pose.t[2].ToString(CultureInfo.InvariantCulture);
txtId.Text = pose.id.ToString(CultureInfo.InvariantCulture);
}
else
{
txtOrientationX.Text = "";
txtOrientationY.Text = "";
txtOrientationZ.Text = "";
txtTranslationX.Text = "";
txtTranslationY.Text = "";
txtTranslationZ.Text = "";
txtId.Text = "";
}
}
private void txtMinX_TextChanged(object sender, EventArgs e)
{
Single.TryParse(txtMinX.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out oSettings.aMinBounds[0]);
UpdateClients();
}
private void txtMinY_TextChanged(object sender, EventArgs e)
{
Single.TryParse(txtMinY.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out oSettings.aMinBounds[1]);
UpdateClients();
}
private void txtMinZ_TextChanged(object sender, EventArgs e)
{
Single.TryParse(txtMinZ.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out oSettings.aMinBounds[2]);
UpdateClients();
}
private void txtMaxX_TextChanged(object sender, EventArgs e)
{
Single.TryParse(txtMaxX.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out oSettings.aMaxBounds[0]);
UpdateClients();
}
private void txtMaxY_TextChanged(object sender, EventArgs e)
{
Single.TryParse(txtMaxY.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out oSettings.aMaxBounds[1]);
UpdateClients();
}
private void txtMaxZ_TextChanged(object sender, EventArgs e)
{
Single.TryParse(txtMaxZ.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out oSettings.aMaxBounds[2]);
UpdateClients();
}
private void chFilter_CheckedChanged(object sender, EventArgs e)
{
oSettings.bFilter = chFilter.Checked;
UpdateClients();
}
private void txtFilterNeighbors_TextChanged(object sender, EventArgs e)
{
Int32.TryParse(txtFilterNeighbors.Text, out oSettings.nFilterNeighbors);
UpdateClients();
}
private void txtFilterDistance_TextChanged(object sender, EventArgs e)
{
Single.TryParse(txtFilterDistance.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out oSettings.fFilterThreshold);
UpdateClients();
}
private void txtICPIters_TextChanged(object sender, EventArgs e)
{
Int32.TryParse(txtICPIters.Text, out oSettings.nNumICPIterations);
}
private void txtRefinIters_TextChanged(object sender, EventArgs e)
{
Int32.TryParse(txtRefinIters.Text, out oSettings.nNumRefineIters);
}
private void chMerge_CheckedChanged(object sender, EventArgs e)
{
oSettings.bMergeScansForSave = chMerge.Checked;
}
private void btAdd_Click(object sender, EventArgs e)
{
lock (oSettings)
oSettings.lMarkerPoses.Add(new MarkerPose());
lisMarkers.SelectedIndex = oSettings.lMarkerPoses.Count - 1;
UpdateMarkerFields();
UpdateClients();
}
private void btRemove_Click(object sender, EventArgs e)
{
if (oSettings.lMarkerPoses.Count > 0)
{
oSettings.lMarkerPoses.RemoveAt(lisMarkers.SelectedIndex);
lisMarkers.SelectedIndex = oSettings.lMarkerPoses.Count - 1;
UpdateMarkerFields();
UpdateClients();
}
}
private void lisMarkers_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateMarkerFields();
}
private void txtOrientationX_TextChanged(object sender, EventArgs e)
{
if (lisMarkers.SelectedIndex >= 0)
{
MarkerPose pose = oSettings.lMarkerPoses[lisMarkers.SelectedIndex];
float X, Y, Z;
pose.GetOrientation(out X, out Y, out Z);
Single.TryParse(txtOrientationX.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out X);
pose.SetOrientation(X, Y, Z);
UpdateClients();
}
}
private void txtOrientationY_TextChanged(object sender, EventArgs e)
{
if (lisMarkers.SelectedIndex >= 0)
{
MarkerPose pose = oSettings.lMarkerPoses[lisMarkers.SelectedIndex];
float X, Y, Z;
pose.GetOrientation(out X, out Y, out Z);
Single.TryParse(txtOrientationY.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out Y);
pose.SetOrientation(X, Y, Z);
UpdateClients();
}
}
private void txtOrientationZ_TextChanged(object sender, EventArgs e)
{
if (lisMarkers.SelectedIndex >= 0)
{
MarkerPose pose = oSettings.lMarkerPoses[lisMarkers.SelectedIndex];
float X, Y, Z;
pose.GetOrientation(out X, out Y, out Z);
Single.TryParse(txtOrientationZ.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out Z);
pose.SetOrientation(X, Y, Z);
UpdateClients();
}
}
private void txtTranslationX_TextChanged(object sender, EventArgs e)
{
if (lisMarkers.SelectedIndex >= 0)
{
float X;
MarkerPose pose = oSettings.lMarkerPoses[lisMarkers.SelectedIndex];
Single.TryParse(txtTranslationX.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out X);
pose.pose.t[0] = X;
UpdateClients();
}
}
private void txtTranslationY_TextChanged(object sender, EventArgs e)
{
if (lisMarkers.SelectedIndex >= 0)
{
float Y;
MarkerPose pose = oSettings.lMarkerPoses[lisMarkers.SelectedIndex];
Single.TryParse(txtTranslationY.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out Y);
pose.pose.t[1] = Y;
UpdateClients();
}
}
private void txtTranslationZ_TextChanged(object sender, EventArgs e)
{
if (lisMarkers.SelectedIndex >= 0)
{
float Z;
MarkerPose pose = oSettings.lMarkerPoses[lisMarkers.SelectedIndex];
Single.TryParse(txtTranslationZ.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out Z);
pose.pose.t[2] = Z;
UpdateClients();
}
}
private void txtId_TextChanged(object sender, EventArgs e)
{
if (lisMarkers.SelectedIndex >= 0)
{
int id;
MarkerPose pose = oSettings.lMarkerPoses[lisMarkers.SelectedIndex];
Int32.TryParse(txtId.Text, out id);
pose.id = id;
UpdateClients();
}
}
private void chBodyData_CheckedChanged(object sender, EventArgs e)
{
oSettings.bStreamOnlyBodies = chBodyData.Checked;
UpdateClients();
}
private void PlyFormat_CheckedChanged(object sender, EventArgs e)
{
if (rAsciiPly.Checked)
{
oSettings.bSaveAsBinaryPLY = false;
}
else
{
oSettings.bSaveAsBinaryPLY = true;
}
}
private void chSkeletons_CheckedChanged(object sender, EventArgs e)
{
oSettings.bShowSkeletons = chSkeletons.Checked;
}
private void cbCompressionLevel_SelectedIndexChanged(object sender, EventArgs e)
{
int index = cbCompressionLevel.SelectedIndex;
if (index == 0)
oSettings.iCompressionLevel = 0;
else if (index == 2)
oSettings.iCompressionLevel = 2;
else
{
string value = cbCompressionLevel.SelectedItem.ToString();
bool tryParse = Int32.TryParse(value, out oSettings.iCompressionLevel);
if (!tryParse)
oSettings.iCompressionLevel = 0;
}
UpdateClients();
}
private void btSyncEnable_click(object sender, EventArgs e)
{
if (oServer.GetAllDevicesInitialized() && oServer.nClientCount > 1)
{
oServer.RequestDeviceSyncState();
btSyncEnable.Enabled = false;
btSyncDisable.Enabled = true;
//Disable the Auto Exposure, as this could interfere with the temporal sync
chAutoExposureEnabled.Enabled = false;
trManualExposure.Enabled = true;
chAutoExposureEnabled.CheckState = CheckState.Unchecked;
}
}
private void btSyncDisable_click(object sender, EventArgs e)
{
if (oServer.GetAllDevicesInitialized())
{
oServer.DisableTemporalSync();
btSyncEnable.Enabled = true;
btSyncDisable.Enabled = false;
chAutoExposureEnabled.Enabled = true;
}
}
public void ActivateTempSyncEnableButton()
{
//As a Form code is run on a single UI thread, we need to communicate with that thread via Invoke
this.BeginInvoke(new MethodInvoker(delegate
{
btSyncEnable.Enabled = true;
btSyncDisable.Enabled = false;
chAutoExposureEnabled.Enabled = true;
}));
}
private void chAutoExposureEnabled_CheckedChanged(object sender, EventArgs e)
{
oSettings.bAutoExposureEnabled = chAutoExposureEnabled.Checked;
UpdateClients();
trManualExposure.Enabled = !oSettings.bAutoExposureEnabled;
}
///
/// When the user scrolls on the trackbar, we wait a short amount of time to check if the user has scrolled again.
/// This prevents the Manual Exposure to be set too often, and only sets it when the user has stopped scrolling.
/// Code taken from: https://stackoverflow.com/a/15687418
///
///
///
private void trManualExposure_Scroll(object sender, EventArgs e)
{
if (scrollTimer == null)
{
// Will tick every 500ms
scrollTimer = new Timer()
{
Enabled = false,
Interval = 300,
Tag = (sender as TrackBar).Value
};
scrollTimer.Tick += (s, ea) =>
{
// check to see if the value has changed since we last ticked
if (trManualExposure.Value == (int)scrollTimer.Tag)
{
// scrolling has stopped so we are good to go ahead and do stuff
scrollTimer.Stop();
// Send the changed exposure to the devices
//Clamp Exposure Step between -11 and 1
int exposureStep = trManualExposure.Value;
int exposureStepClamped = exposureStep < -11 ? -11 : exposureStep > 1 ? 1 : exposureStep;
oSettings.nExposureStep = exposureStepClamped;
UpdateClients();
scrollTimer.Dispose();
scrollTimer = null;
}
else
{
// record the last value seen
scrollTimer.Tag = trManualExposure.Value;
}
};
scrollTimer.Start();
}
}
private void SettingsForm_FormClosed(object sender, FormClosedEventArgs e)
{
oServer.SetSettingsForm(null);
}
}
}