using bbiwarg.Input.InputHandling; using bbiwarg.Input.InputProviding; using bbiwarg.Recognition.FingerRecognition; using bbiwarg.Recognition.PalmRecognition; using bbiwarg.Utility; using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace bbiwarg.Output.GlassesOutput { /// /// A Windows Form which displays a fullscreen window to be shown on augmented reality glasses. /// public partial class GlassesWindow : Form { /// /// true iff the calibration image has the latest data /// private bool calibrationImageUpToDate; /// /// position of the current calibration point in the output plane /// private Vector2D currentCalibrationPoint; /// /// id of the current frame /// private int currentFrameID; /// /// true iff the window is showing the latest data /// private bool guiUpToDate; /// /// the image shown on the glasses /// private OutputImage image; /// /// the input handler /// private InputHandler inputHandler; /// /// the input provider /// private InputProvider inputProvider; /// /// size of the input images /// private ImageSize inputSize; /// /// size of the image show on the glasses /// private ImageSize outputSize; /// /// projection from the input image plane to a plane which lies in front of the wearer of the glasses (output plane) /// private Projection2DTo2D projection; /// /// random number generator /// private Random rand; /// /// timer to periodically update the window /// private System.Windows.Forms.Timer timer; /// /// 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(); } /// /// Returns a random point in the glasses image. /// /// private Vector2D getRandomOutputPoint() { return outputSize.getAbsolutePoint(new Vector2D((float)rand.NextDouble(), (float)rand.NextDouble())); } /// /// 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(); } } /// /// 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 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; } /// /// 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); } } } }