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 bbiwarg.Input.InputHandling;
using bbiwarg.Input.InputProviding;
using bbiwarg.Utility;
using bbiwarg.Recognition.FingerRecognition;
using bbiwarg.Recognition.PalmRecognition;
using Emgu.CV.UI;
namespace bbiwarg.Output.GlassesOutput
{
///
/// A Windows Form which displays a fullscreen window to be shown on augmented reality glasses.
///
public partial class GlassesWindow : Form
{
///
/// the input provider
///
private InputProvider inputProvider;
///
/// the input handler
///
private InputHandler inputHandler;
///
/// timer to periodically update the window
///
private System.Windows.Forms.Timer timer;
///
/// id of the current frame
///
private int currentFrameID;
///
/// true iff the window is showing the latest data
///
private bool guiUpToDate;
///
/// size of the input images
///
private ImageSize inputSize;
///
/// size of the image show on the glasses
///
private ImageSize outputSize;
///
/// the image shown on the glasses
///
private OutputImage image;
///
/// projection from the input image plane to a plane which lies in front of the wearer of the glasses (output plane)
///
private Projection2DTo2D projection;
///
/// position of the current calibration point in the output plane
///
private Vector2D currentCalibrationPoint;
///
/// true iff the calibration image has the latest data
///
private bool calibrationImageUpToDate;
///
/// random number generator
///
private Random rand;
///
/// Creates a GlassesWindow.
///
/// input provider
/// input handler
/// title of the window
/// the screen this window is shown on
/// the update interval for the window in ms
public GlassesWindow(InputProvider inputProvider, InputHandler inputHandler, String name, Screen screen, int updateInterval)
{
InitializeComponent();
this.inputProvider = inputProvider;
this.inputHandler = inputHandler;
this.inputSize = inputHandler.ImageSize;
this.outputSize = new ImageSize(screen.Bounds.Width, screen.Bounds.Height);
guiUpToDate = false;
calibrationImageUpToDate = false;
rand = new Random();
currentCalibrationPoint = getRandomOutputPoint();
projection = new Projection2DTo2D(inputSize, outputSize, Parameters.GlassesWindowNumCalibrationPoints);
Name = name;
Text = name;
timer = new System.Windows.Forms.Timer();
timer.Interval = updateInterval;
timer.Tick += update;
timer.Start();
KeyPreview = true;
//fullscreen
FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
Location = screen.Bounds.Location;
Size = screen.Bounds.Size;
}
///
/// Stops the input provider when closing the window.
///
/// event arguments
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
inputProvider.stop();
}
///
/// Updates the window.
///
/// the event sender
/// the event arguments
private void update(object sender, EventArgs e)
{
Utility.Timer.start("GlassesWindow.update");
if (!inputProvider.IsActive)
Close();
if (projection.IsCalibrated)
{
FrameData frameData = inputHandler.FrameData;
if (frameData != null)
{
lock (frameData)
{
if (currentFrameID != frameData.FrameID)
{
currentFrameID = frameData.FrameID;
Utility.Timer.start("GlassesWindow.update::updateImage");
updateImage(frameData);
Utility.Timer.stop("GlassesWindow.update::updateImage");
}
}
}
}
else
{
if (!calibrationImageUpToDate)
updateCalibrationImage();
}
if (!guiUpToDate)
{
Utility.Timer.start("GlassesWindow.update::updateGUI");
updateGUI();
Utility.Timer.stop("GlassesWindow.update::updateGUI");
}
Utility.Timer.stop("GlassesWindow.update");
}
///
/// Updates the glasses image.
///
/// data for the new frame
private void updateImage(FrameData frameData)
{
guiUpToDate = false;
if (image != null)
image.Dispose();
image = new OutputImage(outputSize);
foreach (Palm palm in frameData.TrackedPalms)
{
Quadrangle quadInput = palm.Quad;
Vector2D a = projection.projectPoint(quadInput.TopLeft);
Vector2D b = projection.projectPoint(quadInput.TopRight);
Vector2D c = projection.projectPoint(quadInput.BottomRight);
Vector2D d = projection.projectPoint(quadInput.BottomLeft);
Quadrangle quadOutput = new Quadrangle(a, b, c, d);
image.drawQuadrangleGrid(quadOutput, Color.Yellow, Color.Orange, 3, 4);
}
foreach (Finger finger in frameData.TrackedFingers)
{
Vector2D tipProjected = projection.projectPoint(finger.TipPoint);
image.fillCircle(tipProjected, 10, Color.Yellow);
}
}
///
/// Updates the calibration image.
///
private void updateCalibrationImage()
{
guiUpToDate = false;
if (image != null)
image.Dispose();
image = new OutputImage(outputSize);
image.fillCircle(currentCalibrationPoint, 25, Color.Orange);
}
///
/// Updates the gui elements.
///
private void updateGUI()
{
// update image boxes
imageBox.Image = image;
guiUpToDate = true;
}
///
/// Handle key down events by showing the next point or finishing or resetting the calibration.
///
/// event sender
/// event arguments
private void GlassesWindow_OnKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.K)
{
FrameData frameData = inputHandler.FrameData;
if (frameData != null)
{
lock (frameData)
{
if (frameData.TrackedFingers.Count == 1)
{
Vector2D pointOutput = currentCalibrationPoint;
Vector2D pointInput = frameData.TrackedFingers[0].TipPoint;
projection.addCalibrationPoints(pointInput, pointOutput);
currentCalibrationPoint = getRandomOutputPoint();
}
}
}
}
else if (e.KeyCode == Keys.R)
{
projection.reset();
currentCalibrationPoint = getRandomOutputPoint();
}
}
///
/// Returns a random point in the glasses image.
///
///
private Vector2D getRandomOutputPoint()
{
return outputSize.getAbsolutePoint(new Vector2D((float)rand.NextDouble(), (float)rand.NextDouble()));
}
}
}