using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Anoto; using System.Threading; //using Ivy; using IvyBus; using System.Media; using AnotoData; //using Data; using Microsoft.Ink; namespace Anoto { public partial class FormAnotoSupervision : Form { Recognizer TheRecognizer; RecognizerContext TheRecognizerContext; // AppDatabase TheData; DateTime LastDataUpdate; private SoundPlayer SoundPenDown = new SoundPlayer(); private SoundPlayer SoundPenUp = new SoundPlayer(); private const int MAX_LOG_LENGTH = 100; Anoto.GenericStreamer.PenManagerClass PenManager; // AnotoStrip[] Strips; List HotAreas; AnotoRadarScreen TheAnotoRadarScreen; AnotoStripBoard TheAntotoStripBoard; Dictionary> PensPoints; Dictionary PensBrush; Dictionary Pens; List AnotoPens; Mutex mutex; Random Rnd; Bitmap DrawingArea; private SolidBrush TranparentBlack; XMLStateMachine StateMAchine; public FormAnotoSupervision() { InitializeComponent(); StateMAchine = new XMLStateMachine(); StateMAchine.StateTable = "XMLStates.xml"; StateMAchine.CurrentState = "Start"; // TheData = new AppDatabase(TheIvyBus); } void TheIvyDomain_DomainChanged(object sender, EventArgs e) { TheIvyBus.ivy.Stop(); TheIvyBus.ivy.Start(TheIvyDomain.Domain); } private void Form1_Load(object sender, EventArgs e) { // TheRecognizer.; //TheRecognizer.CreateRecognizerContext(); TranparentBlack = new SolidBrush(Color.FromArgb(100, 0, 0, 0)); TheIvyDomain.Location = new Point(0, 30); DrawingArea = new Bitmap(pictureBox1.Width, pictureBox1.Height); pictureBox1.Image = DrawingArea; //Start IVY TheIvyBus.ivy.Start(TheIvyDomain.Domain); TheIvyDomain.DomainChanged += new EventHandler(TheIvyDomain_DomainChanged); this.Controls.Add(TheIvyDomain); AnotoPens = new List(); PenManager = new Anoto.GenericStreamer.PenManagerClass(); PenManager.PenConnected += new Anoto.GenericStreamer._IPenManagerEvents_PenConnectedEventHandler(pm_PenConnected); PenManager.PenDisconnected += new GenericStreamer._IPenManagerEvents_PenDisconnectedEventHandler(PenManager_PenDisconnected); PenManager.NewCoordinate += new Anoto.GenericStreamer._IPenManagerEvents_NewCoordinateEventHandler(PenManager_NewCoordinate); PenManager.PenDown += new Anoto.GenericStreamer._IPenManagerEvents_PenDownEventHandler(PenManager_PenDown); PenManager.PenUp += new Anoto.GenericStreamer._IPenManagerEvents_PenUpEventHandler(PenManager_PenUp); PenManager.Start(); mutex = new Mutex(); InitDictionary(); Rnd = new Random(); AnotoStrip[] Strips = AnotoStrip.LoadFileStrip("Strips.csv"); HotAreas = new List(); foreach (var strip in Strips) { HotAreas.Add(strip); } TheAnotoRadarScreen = new AnotoRadarScreen(); HotAreas.Add(TheAnotoRadarScreen); TheAntotoStripBoard = new AnotoStripBoard(); HotAreas.Add(TheAntotoStripBoard); listBoxHotAreas.Items.Clear(); foreach (var ha in HotAreas) { listBoxHotAreas.Items.Add(ha); } //Load sounds LoadSounds(); } private void LoadSounds() { this.SoundPenDown.SoundLocation = "PenDown.wav"; this.SoundPenDown.LoadAsync(); this.SoundPenUp.SoundLocation = "PenUp.wav"; this.SoundPenUp.LoadAsync(); } private void InitDictionary() { PensPoints = new Dictionary>(); PensBrush = new Dictionary(); Pens = new Dictionary(); } #region Pen management/ events void pm_PenConnected(string penSerial, Anoto.GenericStreamer.PenType PenType, ulong time, string productName, ushort pid) { AnotoPen pen = new AnotoPen(penSerial, PenType, time, productName, pid); AnotoPens.Add(pen); this.Invoke(new MethodInvoker(delegate() { listBoxAnotoPens.Items.Add(pen); AddLog("Pen connected " + penSerial + " " + PenType.ToString() + " " + productName); })); // Console.WriteLine("Pen connected " + penSerial + " " + PenType.ToString() + " " + productName); if (!PensPoints.ContainsKey(penSerial)) PensPoints.Add(penSerial, new List()); else PensPoints[penSerial] = new List(); if (!PensBrush.ContainsKey(penSerial)) PensBrush.Add(penSerial, new SolidBrush(Color.FromArgb(255, Rnd.Next(255), Rnd.Next(255), Rnd.Next(255)))); else PensBrush[penSerial] = new SolidBrush(Color.FromArgb(255, Rnd.Next(255), Rnd.Next(255), Rnd.Next(255))); if (!Pens.ContainsKey(penSerial)) Pens.Add(penSerial, new Pen(Color.FromArgb(255, Rnd.Next(255), Rnd.Next(255), Rnd.Next(255)))); else Pens[penSerial] = new Pen(Color.FromArgb(255, Rnd.Next(255), Rnd.Next(255), Rnd.Next(255))); } void PenManager_PenDisconnected(string penSerial, GenericStreamer.PenType PenType, ulong time) { this.Invoke(new MethodInvoker(delegate() { mutex.WaitOne(); AnotoPen p = null; foreach (AnotoPen item in listBoxAnotoPens.Items) { if (item.PenSerial == penSerial) p = item; } if (p != null) { listBoxAnotoPens.Items.Remove(p); AddLog("Pen Disconnected " + penSerial + " " + PenType.ToString()); } mutex.ReleaseMutex(); })); } List> InkMarks = new List>(); DateTime LastDateTimePenUp = DateTime.Now; /// /// After one second, the trail is no more valid /// int MaxMillisecondForNewtrail = 1000; void PenManager_PenUp(string penSerial, Anoto.GenericStreamer.PenType PenType, ulong time, byte penDownSeqNbr, int isSpcdGenerated) { this.Invoke(new MethodInvoker(delegate() { AddLog("Pen Up " + penSerial + " "); if (checkBoxEnableSound.Checked) SoundPenUp.Play(); // Console.WriteLine("Pen Up " + penSerial + " time " + time); if ((DateTime.Now - LastDateTimePenUp).TotalMilliseconds > MaxMillisecondForNewtrail) { //MaxMillisecondForNewtrail second has past since the last trail //Erase previous Data InkMarks = new List>(); } //Copie the data the the current text recognizer List tmpLst = new List(); foreach (var pt in PensPoints[penSerial]) { tmpLst.Add(pt); } InkMarks.Add(tmpLst); //Try to recogize It TryRecognition(); LastDateTimePenUp = DateTime.Now; pictureBox1.Invalidate(); })); } private void TryRecognition() { // Declare a new TabletPropertyDescriptionCollection (this is new in 1.7) TabletPropertyDescriptionCollection tpdc = new TabletPropertyDescriptionCollection(); // Define the X and Y extents for this TabletPropertyDescriptionCollection TabletPropertyMetrics tpmX = new TabletPropertyMetrics(); tpmX.Maximum = AnotoData.AnotoHotArea.MaxX; TabletPropertyMetrics tpmY = new TabletPropertyMetrics(); tpmY.Maximum = tpmX.Maximum = AnotoData.AnotoHotArea.MaxY; // Define the NormalPressure for the Tablet PropertyDescriptionCollection TabletPropertyMetrics tpmNP = new TabletPropertyMetrics(); // This defines 1024 levels of pressure tpmNP.Maximum = 1024; TabletPropertyMetrics tpmSt = new TabletPropertyMetrics(); // Add each of the propertyMetrics to the TabletPropertyDescriptionCollection // This defines what the data stream will look like, in this case (X, Y, NP) tpdc.Add(new TabletPropertyDescription(PacketProperty.X, tpmX)); tpdc.Add(new TabletPropertyDescription(PacketProperty.Y, tpmY)); // tpdc.Add(new TabletPropertyDescription(PacketProperty.TimerTick, tpmSt)); // tpdc.Add(new TabletPropertyDescription(PacketProperty.NormalPressure, tpmNP)); InkCollector myInkCollector = new InkCollector(); bool hasValideStrokes = false; foreach (var stroke in InkMarks) { if (stroke.Count > 0) { Point point; Point[] pts = new Point[stroke.Count]; int[] data = new int[stroke.Count * tpdc.Count]; int index = 0; int data_index = 0; foreach (PointF pt in stroke) { int x = (int)(pt.X * AnotoData.AnotoHotArea.MaxX); data.SetValue(x, data_index++); int y = (int)(pt.Y * AnotoData.AnotoHotArea.MaxY); data.SetValue(y, data_index++); //????? // data.SetValue(1000 + 100 * data_index , data_index++); // data.SetValue(512, data_index++); point = new Point(x, y); pts.SetValue(point, index++); hasValideStrokes = true; } //Convert this array of ink space points to pixels. //myInkCollector.Renderer.PixelToInkSpace(inkArea.Handle, ref pts); //Stroke stroke = myInkCollector.Ink.CreateStroke(pts); Stroke inkStroke = myInkCollector.Ink.CreateStroke(data, tpdc); myInkCollector.Ink.Strokes.Add(inkStroke); } } if (hasValideStrokes) { TheRecognizerContext = new RecognizerContext(); RecognitionStatus recognitionStatus; //TheRecognizerContext.Factoid = Microsoft.Ink.Factoid.Number+"|" + Microsoft.Ink.Factoid.LowerChar // + "|" + Microsoft.Ink.Factoid.UpperChar;// ""; TheRecognizerContext.Factoid = "(0|1|2|3|4|5|6|7|8|9|)"; TheRecognizerContext.RecognitionFlags = RecognitionModes.Coerce; TheRecognizerContext.Strokes = myInkCollector.Ink.Strokes; RecognitionResult rr = TheRecognizerContext.Recognize(out recognitionStatus); if (rr != null) textBoxRecognition.Text = rr.ToString(); } /* //throw new NotImplementedException(); RecognitionStatus recognitionStatus; //Create the stroke collection Strokes strokes; Point[] pts = new Point[InkMarks.Count]; int index = 0; foreach (var p in InkMarks) { pts[index] = new Point((int)(p.X * AnotoData.AnotoHotArea.MaxX), (int)(p.X * AnotoData.AnotoHotArea.MaxY) ); index++; } Stroke stroke = null; stroke.SetPoints(pts); TheRecognizerContext.Strokes.Add(stroke); TheRecognizerContext.Recognize(out recognitionStatus);*/ } void PenManager_PenDown(string penSerial, Anoto.GenericStreamer.PenType PenType, ulong time, byte penDownSeqNbr, Anoto.GenericStreamer.PenTipType PenTipType, int isValidColor, byte r, byte g, byte b, int isSpcdGenerated) { // Console.WriteLine("Pen Down " + penSerial + " time " + time); this.Invoke(new MethodInvoker(delegate() { mutex.WaitOne(); PensPoints.Remove(penSerial); PensPoints.Add(penSerial, new List()); AddLog("Pen Down " + penSerial + " "); if (checkBoxEnableSound.Checked) SoundPenDown.Play(); mutex.ReleaseMutex(); })); } void PenManager_NewCoordinate(string penSerial, Anoto.GenericStreamer.PenType PenType, ulong time, string page, int x, int y, byte imgSeqNbr, byte force) { this.Invoke(new MethodInvoker(delegate() { mutex.WaitOne(); PensPoints[penSerial].Add(AnotoHotArea.GetHomogeneousCoordinate(x, y)); mutex.ReleaseMutex(); // Console.WriteLine("Pen NewCoordinate " + penSerial + " time " + time + " x " + x + " y " + y); if ((DateTime.Now - LastDataUpdate).TotalMilliseconds > 100) { PopulateGraphicalData(page, x, y, force); LastDataUpdate = DateTime.Now; } PopulateData(penSerial, page, x, y, force); })); } #endregion private void AddLog(string p) { listBoxEvents.Items.Insert(0, p + " " + DateTime.Now.ToString("HH:mm:ss")); if (listBoxEvents.Items.Count > MAX_LOG_LENGTH) listBoxEvents.Items.RemoveAt(listBoxEvents.Items.Count - 1); } private void PopulateGraphicalData(string page, int x, int y, byte force) { this.Invoke(new MethodInvoker(delegate() { SetProgressBarValue(progressBarX, x); SetProgressBarValue(progressBarY, y); SetProgressBarValue(progressBarForce, (int)force); labelX.Text = "X: " + x; labelY.Text = "Y: " + y; labelPage.Text = page; pictureBox1.Invalidate(); })); } public AnotoHotArea GetHotArea(int x, int y, string page) { AnotoHotArea result = null; foreach (var s in HotAreas) { if (s.IsInside(x, y, page))// AnotoHotArea.PagesIP[s.PageIndex] == page) { return s; } } return result; } private void PopulateData(string penSerial, string page, int x, int y, byte force) { this.Invoke(new MethodInvoker(delegate() { //Find the Strip name // AnotoHotArea hotArea = AnotoHotArea AnotoHotArea hotArea = GetHotArea(x, y, page); if (hotArea is AnotoStrip) { AnotoStrip strip = (AnotoStrip)hotArea; SubCategories cell = strip.GetStripArea(x, y); labelStripInfo.Text = cell.ToString() + " : " + strip.GetTextForCell(cell) + Environment.NewLine + " " + strip.ToString(); // TheIvyBus.SendMsg("SelectionEvent acc=bordeaux wp=WP1 role=TC Flight=" + strip.SSR); //Halo if (LastSSR != strip.SSR) { TheIvyBus.SendMsg("SelectionEvent Flight=" + LastSSR + " Perform=False"); string ivySMG = "SelectionEvent Flight=" + strip.SSR + " Perform=True"; LastSSR = strip.SSR; TheIvyBus.SendMsg(ivySMG); AddLog(ivySMG); } /* if ((cell != StateMachineCurrentCell) || (StateMachineCurrentStrip != strip)) { Console.WriteLine("New Action"); //Test if new message: StateMachineInput(cell, strip); }*/ } if (hotArea is AnotoRadarScreen) { AnotoRadarScreen screen = (AnotoRadarScreen)hotArea; labelStripInfo.Text = "Screen"; //send the pen down to the SimpleRadar Screen screen.SendIvyMsg(penSerial, x, y, page, TheIvyBus); }; if (hotArea is AnotoStripBoard) { AnotoStripBoard stripBoard = (AnotoStripBoard)hotArea; labelStripInfo.Text = "Strip Board"; } })); } private AnotoStrip StateMachineCurrentStrip; private SubCategories StateMachineCurrentCell; string LastAlidadeStart = ""; string LastAlidadeStop = ""; string LastSSR = ""; public void DisplayAlidade(string start, string stop) { if (!string.IsNullOrEmpty(LastAlidadeStart)) { //hide the previous alidate TheIvyBus.SendMsg("DistanceFeedbackOff acc=bordeaux wp=WP1 role=TC Start=" + LastAlidadeStart + " End=" + LastAlidadeStop); } //If the same previous start and stop do nothing -> remove the alidade if (!((start == LastAlidadeStart) && (stop == LastAlidadeStop))) { //Show the new alidade TheIvyBus.SendMsg("DistanceFeedbackOn acc=bordeaux wp=WP1 role=TC Start=" + start + " End=" + stop); LastAlidadeStop = stop; LastAlidadeStart = start; } else { LastAlidadeStop = ""; LastAlidadeStart = ""; } } public void StateMachineInput(SubCategories cell, AnotoStrip strip) { StateMachineCurrentStrip = strip; StateMachineCurrentCell = cell; string ivySMG = ""; if (StateMAchine.Next(cell.ToString()) != String.Empty) { Console.WriteLine(StateMAchine.Action); //New state switch (StateMAchine.Action) { case "Hilight": //Send IVY Selection event ivySMG = "SelectionEvent Flight=" + strip.SSR + " Perform=True"; TheIvyBus.SendMsg(ivySMG); AddLog(ivySMG); break; case "AlidadeInfoInfo": //Send IVY Selection event DisplayAlidade(StateMachineCurrentStrip.SSR, strip.SSR); // TheIvyBus.SendMsg("DistanceFeedbackOn acc=bordeaux wp=WP1 role=TC Start=" + StateMachineCurrentStrip.SSR + " End=" + strip.SSR); break; case "AlidadeInfoBeacon": //Send IVY Selection event DisplayAlidade(StateMachineCurrentStrip.SSR, strip.GetTextForCell(cell)); // TheIvyBus.SendMsg("DistanceFeedbackOn acc=bordeaux wp=WP1 role=TC Start=" + StateMachineCurrentStrip.SSR + " End=" + strip.GetTextForCell(cell)); break; case "AlidadeBeaconInfo": //Send IVY Selection event DisplayAlidade(StateMachineCurrentStrip.GetTextForCell(StateMachineCurrentCell), strip.SSR); // TheIvyBus.SendMsg("DistanceFeedbackOn acc=bordeaux wp=WP1 role=TC Start=" + StateMachineCurrentStrip.GetTextForCell(StateMachineCurrentCell) + " End=" + strip.SSR); break; default: break; } }; } void SetProgressBarValue(ProgressBar pb, int val) { if (val < pb.Minimum) pb.Minimum = val; if (val > pb.Maximum) pb.Maximum = val; pb.Value = val; } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { PenManager.Stop(); } private void pictureBox1_Paint(object sender, PaintEventArgs e) { //draw the dots Graphics g = e.Graphics; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.FillRectangle(Brushes.White, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height)); mutex.WaitOne(); float scale = 15; Pen penPreviousStrokes = new Pen(Brushes.Black); foreach (var pts in InkMarks) { Point[] p = new Point[pts.Count]; int index = 0; foreach (var l in pts) { p[index] = new Point((int)(l.X * pictureBox1.Width ) , (int)(l.Y * pictureBox1.Height)); index++; } if ( p.Length > 1) g.DrawLines(penPreviousStrokes, p); } foreach (var pen in PensPoints) { //if (pen.Value.Count > 1) // g.DrawLines(Pens[pen.Key], pen.Value.ToArray()); foreach (var point in pen.Value) { float x = pictureBox1.Width * point.X; float y = pictureBox1.Height * point.Y; g.FillEllipse(TranparentBlack, x, y, 4, 4); } if (pen.Value.Count != 0) PopulateData("", "", (int)pen.Value.Last().X, (int)pen.Value.Last().Y, 0); } mutex.ReleaseMutex(); } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { TheIvyBus.ivy.Stop(); } private void listBoxHotAreas_SelectedIndexChanged(object sender, EventArgs e) { if (listBoxHotAreas.SelectedItem != null) { PropertyAnotoHotArea.SelectedObject = (AnotoHotArea)listBoxHotAreas.SelectedItem; } } private void buttonPlay_Click(object sender, EventArgs e) { SoundPenDown.Play(); } private void button1_Click(object sender, EventArgs e) { SoundPenUp.Play(); } } }