123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- using System;
- using System.Collections.Generic;
- using System.Drawing;
- using System.Diagnostics;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using bbiwarg.Recognition.TouchRecognition;
- using bbiwarg.Utility;
- using bbiwarg.Input.InputHandling;
- namespace bbiwarg.Output.DebugOutput
- {
- /// <summary>
- /// Provides an image showing touch events.
- /// </summary>
- class TouchEventVisualizer
- {
- /// <summary>
- /// used to prevent running <see cref="handleNewFrameData"/> and <see cref="getOutputImage"/> simultaneously from different threads
- /// </summary>
- private Object sync;
- /// <summary>
- /// used to store the relative time at which the touch events occured
- /// </summary>
- private Stopwatch timer;
- /// <summary>
- /// all touch events starting at the last TouchDown, indexed by a unique id
- /// </summary>
- private Dictionary<int, List<Vector2D>> activeTouches;
- /// <summary>
- /// old touch events which are stored for a limited time, indexed by a unique id
- /// </summary>
- private Dictionary<int, List<Vector2D>> oldTouches;
- /// <summary>
- /// relative times of last frame updates which are stored for a limited time, indexed by a unique id
- /// </summary>
- private Dictionary<int, long> lastUpdates;
- /// <summary>
- /// the next free id, used as a unique id for the dictionaries
- /// </summary>
- private int nextFreeID;
- /// <summary>
- /// Creates a TouchEventVisualizer.
- /// </summary>
- public TouchEventVisualizer()
- {
- sync = new object();
- reset();
- }
- /// <summary>
- /// Resets the touch events and the timer.
- /// </summary>
- public void reset()
- {
- timer = new Stopwatch();
- timer.Start();
- nextFreeID = 1;
- activeTouches = new Dictionary<int, List<Vector2D>>();
- oldTouches = new Dictionary<int, List<Vector2D>>();
- lastUpdates = new Dictionary<int, long>();
- }
- /// <summary>
- /// Handles the event that a new frame is finished processing by updating the touch events.
- /// </summary>
- /// <param name="sender">event sender</param>
- /// <param name="e">event arguments</param>
- public void handleNewFrameData(object sender, NewProcessedFrameEventArgs e)
- {
- FrameData frameData = e.FrameData;
- lock (frameData) lock (sync)
- {
- if (frameData.ResetFlag)
- reset();
- foreach (TouchEvent te in frameData.TouchEvents)
- {
- switch (te.Type)
- {
- case TouchEventType.Down:
- activeTouches.Add(te.Touch.TrackID, new List<Vector2D>());
- activeTouches[te.Touch.TrackID].Add(te.Touch.RelativePosition);
- break;
- case TouchEventType.Move:
- activeTouches[te.Touch.TrackID].Add(te.Touch.RelativePosition);
- break;
- case TouchEventType.Up:
- activeTouches[te.Touch.TrackID].Add(te.Touch.RelativePosition);
- oldTouches.Add(nextFreeID, activeTouches[te.Touch.TrackID]);
- lastUpdates.Add(nextFreeID, timer.ElapsedMilliseconds);
- activeTouches.Remove(te.Touch.TrackID);
- nextFreeID++;
- break;
- }
- }
- }
- }
- /// <summary>
- /// Returns an output image showing the touch events.
- /// </summary>
- /// <param name="imageSize">output image size</param>
- /// <param name="numRows">number of rows in the palm grid</param>
- /// <param name="numColumns">number columns in the palm grid</param>
- /// <returns>image showing touch events</returns>
- public OutputImage getOutputImage(ImageSize imageSize, int numRows, int numColumns)
- {
- lock (sync)
- {
- long currentTime = timer.ElapsedMilliseconds;
- removeOldPositions(currentTime - Parameters.TouchEventVisualizerFadeOutTime);
- OutputImage outputImage = new OutputImage(imageSize);
- int imageWidth = imageSize.Width;
- int imageHeight = imageSize.Height;
- // border
- outputImage.drawBorder(Parameters.TouchEventVisualizerGridColor);
- // draw grid
- int widthPerColumn = imageWidth / numColumns;
- int heightPerRow = imageHeight / numRows;
- // find active blocks
- bool[,] activeBlocks = new bool[numRows, numColumns];
- if (numRows * numColumns > 1)
- {
- foreach (List<Vector2D> positions in activeTouches.Values)
- {
- Vector2D lastPosition = positions.Last();
- int activeRow = (int)Math.Min(lastPosition.Y * numRows, numRows - 1);
- int activeCol = (int)Math.Min(lastPosition.X * numColumns, numColumns - 1);
- activeBlocks[activeRow, activeCol] = true;
- }
- }
- // draw blocks
- int index = 1;
- for (int row = 0; row < numRows; row++)
- {
- for (int col = 0; col < numColumns; col++)
- {
- if (activeBlocks[row, col])
- outputImage.fillRectangle(new Rectangle(col * widthPerColumn, row * heightPerRow, widthPerColumn, heightPerRow), Parameters.TouchEventVisualizerActiveBlockColor);
- int x = (int)((col + 0.5f) * widthPerColumn) - 5;
- int y = (int)((row + 0.5f) * heightPerRow) + 5;
- outputImage.drawText(new Point(x,y), index.ToString(), Parameters.TouchEventVisualizerTextColor);
- index++;
- }
- }
- // draw grid
- for (int i = 0; i <= numColumns; i++)
- outputImage.drawLineSegment(new LineSegment2D(new Vector2D(i * widthPerColumn, 0), new Vector2D(i * widthPerColumn, imageHeight - 1)), Parameters.TouchEventVisualizerGridColor);
- for (int i = 0; i <= numRows; i++)
- outputImage.drawLineSegment(new LineSegment2D(new Vector2D(0, i * heightPerRow), new Vector2D(imageWidth - 1, i * heightPerRow)), Parameters.TouchEventVisualizerGridColor);
- // draw active touches
- foreach (List<Vector2D> positions in activeTouches.Values)
- outputImage.drawTouchGesture(positions, imageSize.MaxPixel);
- // draw old touches (fade out)
- foreach (int id in oldTouches.Keys)
- {
- List<Vector2D> positions = oldTouches[id];
- long lastUpdate = lastUpdates[id];
- float opacity = 1 - ((currentTime - lastUpdate) / (float)Parameters.TouchEventVisualizerFadeOutTime);
- outputImage.drawTouchGesture(positions, imageSize.MaxPixel, opacity);
- }
- return outputImage;
- }
- }
- /// <summary>
- /// Removes old touch events and update times.
- /// </summary>
- /// <param name="breakTime">every touch event which occured before breakTime is removed</param>
- private void removeOldPositions(long breakTime)
- {
- List<int> ids = new List<int>(lastUpdates.Keys);
- for (int i = ids.Count - 1; i >= 0; i--)
- {
- int id = ids[i];
- if (breakTime > lastUpdates[id])
- {
- oldTouches.Remove(id);
- lastUpdates.Remove(id);
- }
- }
- }
- }
- }
|