You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
869 lines
33 KiB
869 lines
33 KiB
|
6 years ago
|
/*
|
||
|
|
TUIO C# Library - part of the reacTIVision project
|
||
|
|
Copyright (c) 2005-2014 Martin Kaltenbrunner <martin@tuio.org>
|
||
|
|
|
||
|
|
This library is free software; you can redistribute it and/or
|
||
|
|
modify it under the terms of the GNU Lesser General Public
|
||
|
|
License as published by the Free Software Foundation; either
|
||
|
|
version 3.0 of the License, or (at your option) any later version.
|
||
|
|
|
||
|
|
This library is distributed in the hope that it will be useful,
|
||
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
|
Lesser General Public License for more details.
|
||
|
|
|
||
|
|
You should have received a copy of the GNU Lesser General Public
|
||
|
|
License along with this library.
|
||
|
|
*/
|
||
|
|
|
||
|
|
using System;
|
||
|
|
using System.Threading;
|
||
|
|
using System.Collections;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
|
||
|
|
using OSC.NET;
|
||
|
|
|
||
|
|
namespace TUIO
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* <remarks>
|
||
|
|
* The TuioClient class is the central TUIO protocol decoder component. It provides a simple callback infrastructure using the {@link TuioListener} interface.
|
||
|
|
* In order to receive and decode TUIO messages an instance of TuioClient needs to be created. The TuioClient instance then generates TUIO events
|
||
|
|
* which are broadcasted to all registered classes that implement the {@link TuioListener} interface.
|
||
|
|
* </remarks>
|
||
|
|
* <example>
|
||
|
|
* <code>
|
||
|
|
* TuioClient client = new TuioClient();
|
||
|
|
* client.addTuioListener(myTuioListener);
|
||
|
|
* client.start();
|
||
|
|
* </code>
|
||
|
|
* </example>
|
||
|
|
*
|
||
|
|
* @author Martin Kaltenbrunner
|
||
|
|
* @version 1.1,5
|
||
|
|
*/
|
||
|
|
public class TuioClient
|
||
|
|
{
|
||
|
|
private bool connected = false;
|
||
|
|
private int port = 3333;
|
||
|
|
private OSCReceiver receiver;
|
||
|
|
private Thread thread;
|
||
|
|
|
||
|
|
private object cursorSync = new object();
|
||
|
|
private object objectSync = new object();
|
||
|
|
private object blobSync = new object();
|
||
|
|
|
||
|
|
private Dictionary<long, TuioObject> objectList = new Dictionary<long, TuioObject>(32);
|
||
|
|
private List<long> aliveObjectList = new List<long>(32);
|
||
|
|
private List<long> newObjectList = new List<long>(32);
|
||
|
|
private Dictionary<long, TuioCursor> cursorList = new Dictionary<long, TuioCursor>(32);
|
||
|
|
private List<long> aliveCursorList = new List<long>(32);
|
||
|
|
private List<long> newCursorList = new List<long>(32);
|
||
|
|
private Dictionary<long, TuioBlob> blobList = new Dictionary<long, TuioBlob>(32);
|
||
|
|
private List<long> aliveBlobList = new List<long>(32);
|
||
|
|
private List<long> newBlobList = new List<long>(32);
|
||
|
|
private List<TuioObject> frameObjects = new List<TuioObject>(32);
|
||
|
|
private List<TuioCursor> frameCursors = new List<TuioCursor>(32);
|
||
|
|
private List<TuioBlob> frameBlobs = new List<TuioBlob>(32);
|
||
|
|
|
||
|
|
private List<TuioCursor> freeCursorList = new List<TuioCursor>();
|
||
|
|
private int maxCursorID = -1;
|
||
|
|
private List<TuioBlob> freeBlobList = new List<TuioBlob>();
|
||
|
|
private int maxBlobID = -1;
|
||
|
|
|
||
|
|
private int currentFrame = 0;
|
||
|
|
private TuioTime currentTime;
|
||
|
|
|
||
|
|
private List<TuioListener> listenerList = new List<TuioListener>();
|
||
|
|
|
||
|
|
#region Constructors
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* The default constructor creates a client that listens to the default TUIO port 3333</summary>
|
||
|
|
*/
|
||
|
|
public TuioClient() { }
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* This constructor creates a client that listens to the provided port</summary>
|
||
|
|
* <param name="port">the listening port number</param>
|
||
|
|
*/
|
||
|
|
public TuioClient(int port)
|
||
|
|
{
|
||
|
|
this.port = port;
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region Connection Methods
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* Returns the port number listening to.</summary>
|
||
|
|
* <returns>the listening port number</returns>
|
||
|
|
*/
|
||
|
|
public int getPort()
|
||
|
|
{
|
||
|
|
return port;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* The TuioClient starts listening to TUIO messages on the configured UDP port
|
||
|
|
* All reveived TUIO messages are decoded and the resulting TUIO events are broadcasted to all registered TuioListeners</summary>
|
||
|
|
*/
|
||
|
|
public void connect()
|
||
|
|
{
|
||
|
|
|
||
|
|
TuioTime.initSession();
|
||
|
|
currentTime = new TuioTime();
|
||
|
|
currentTime.reset();
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
receiver = new OSCReceiver(port);
|
||
|
|
connected = true;
|
||
|
|
thread = new Thread(new ThreadStart(listen));
|
||
|
|
thread.Start();
|
||
|
|
}
|
||
|
|
catch (Exception e)
|
||
|
|
{
|
||
|
|
Console.WriteLine("failed to connect to port " + port);
|
||
|
|
Console.WriteLine(e.Message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* The TuioClient stops listening to TUIO messages on the configured UDP port</summary>
|
||
|
|
*/
|
||
|
|
public void disconnect()
|
||
|
|
{
|
||
|
|
connected = false;
|
||
|
|
if (receiver != null) receiver.Close();
|
||
|
|
receiver = null;
|
||
|
|
|
||
|
|
aliveObjectList.Clear();
|
||
|
|
aliveCursorList.Clear();
|
||
|
|
aliveBlobList.Clear();
|
||
|
|
objectList.Clear();
|
||
|
|
cursorList.Clear();
|
||
|
|
blobList.Clear();
|
||
|
|
frameObjects.Clear();
|
||
|
|
frameCursors.Clear();
|
||
|
|
frameBlobs.Clear();
|
||
|
|
freeCursorList.Clear();
|
||
|
|
freeBlobList.Clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* Returns true if this TuioClient is currently connected.</summary>
|
||
|
|
* <returns>true if this TuioClient is currently connected</returns>
|
||
|
|
*/
|
||
|
|
public bool isConnected() { return connected; }
|
||
|
|
|
||
|
|
private void listen()
|
||
|
|
{
|
||
|
|
while (connected)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
OSCPacket packet = receiver.Receive();
|
||
|
|
if (packet != null)
|
||
|
|
{
|
||
|
|
if (packet.IsBundle())
|
||
|
|
{
|
||
|
|
ArrayList messages = packet.Values;
|
||
|
|
for (int i = 0; i < messages.Count; i++)
|
||
|
|
{
|
||
|
|
processMessage((OSCMessage)messages[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else processMessage((OSCMessage)packet);
|
||
|
|
}
|
||
|
|
else Console.WriteLine("null packet");
|
||
|
|
}
|
||
|
|
catch (Exception e) { Console.WriteLine(e.Message); }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* The OSC callback method where all TUIO messages are received and decoded
|
||
|
|
* and where the TUIO event callbacks are dispatched</summary>
|
||
|
|
* <param name="message">the received OSC message</param>
|
||
|
|
*/
|
||
|
|
private void processMessage(OSCMessage message)
|
||
|
|
{
|
||
|
|
string address = message.Address;
|
||
|
|
ArrayList args = message.Values;
|
||
|
|
string command = (string)args[0];
|
||
|
|
|
||
|
|
if (address == "/tuio/2Dobj")
|
||
|
|
{
|
||
|
|
if (command == "set")
|
||
|
|
{
|
||
|
|
|
||
|
|
long s_id = (int)args[1];
|
||
|
|
int f_id = (int)args[2];
|
||
|
|
float xpos = (float)args[3];
|
||
|
|
float ypos = (float)args[4];
|
||
|
|
float angle = (float)args[5];
|
||
|
|
float xspeed = (float)args[6];
|
||
|
|
float yspeed = (float)args[7];
|
||
|
|
float rspeed = (float)args[8];
|
||
|
|
float maccel = (float)args[9];
|
||
|
|
float raccel = (float)args[10];
|
||
|
|
|
||
|
|
lock (objectSync)
|
||
|
|
{
|
||
|
|
if (!objectList.ContainsKey(s_id))
|
||
|
|
{
|
||
|
|
TuioObject addObject = new TuioObject(s_id, f_id, xpos, ypos, angle);
|
||
|
|
frameObjects.Add(addObject);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
TuioObject tobj = objectList[s_id];
|
||
|
|
if (tobj == null) return;
|
||
|
|
if ((tobj.X != xpos) || (tobj.Y != ypos) || (tobj.Angle != angle) || (tobj.XSpeed != xspeed) || (tobj.YSpeed != yspeed) || (tobj.RotationSpeed != rspeed) || (tobj.MotionAccel != maccel) || (tobj.RotationAccel != raccel))
|
||
|
|
{
|
||
|
|
|
||
|
|
TuioObject updateObject = new TuioObject(s_id, f_id, xpos, ypos, angle);
|
||
|
|
updateObject.update(xpos, ypos, angle, xspeed, yspeed, rspeed, maccel, raccel);
|
||
|
|
frameObjects.Add(updateObject);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (command == "alive")
|
||
|
|
{
|
||
|
|
|
||
|
|
newObjectList.Clear();
|
||
|
|
for (int i = 1; i < args.Count; i++)
|
||
|
|
{
|
||
|
|
// get the message content
|
||
|
|
long s_id = (int)args[i];
|
||
|
|
newObjectList.Add(s_id);
|
||
|
|
// reduce the object list to the lost objects
|
||
|
|
if (aliveObjectList.Contains(s_id))
|
||
|
|
aliveObjectList.Remove(s_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
// remove the remaining objects
|
||
|
|
lock (objectSync)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < aliveObjectList.Count; i++)
|
||
|
|
{
|
||
|
|
long s_id = aliveObjectList[i];
|
||
|
|
TuioObject removeObject = objectList[s_id];
|
||
|
|
removeObject.remove(currentTime);
|
||
|
|
frameObjects.Add(removeObject);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (command == "fseq")
|
||
|
|
{
|
||
|
|
int fseq = (int)args[1];
|
||
|
|
bool lateFrame = false;
|
||
|
|
|
||
|
|
if (fseq > 0)
|
||
|
|
{
|
||
|
|
if (fseq > currentFrame) currentTime = TuioTime.SessionTime;
|
||
|
|
if ((fseq >= currentFrame) || ((currentFrame - fseq) > 100)) currentFrame = fseq;
|
||
|
|
else lateFrame = true;
|
||
|
|
}
|
||
|
|
else if ((TuioTime.SessionTime.TotalMilliseconds - currentTime.TotalMilliseconds) > 100)
|
||
|
|
{
|
||
|
|
currentTime = TuioTime.SessionTime;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!lateFrame)
|
||
|
|
{
|
||
|
|
|
||
|
|
IEnumerator<TuioObject> frameEnum = frameObjects.GetEnumerator();
|
||
|
|
while (frameEnum.MoveNext())
|
||
|
|
{
|
||
|
|
TuioObject tobj = frameEnum.Current;
|
||
|
|
|
||
|
|
switch (tobj.TuioState)
|
||
|
|
{
|
||
|
|
case TuioObject.TUIO_REMOVED:
|
||
|
|
TuioObject removeObject = tobj;
|
||
|
|
removeObject.remove(currentTime);
|
||
|
|
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.removeTuioObject(removeObject);
|
||
|
|
}
|
||
|
|
lock (objectSync)
|
||
|
|
{
|
||
|
|
objectList.Remove(removeObject.SessionID);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case TuioObject.TUIO_ADDED:
|
||
|
|
TuioObject addObject = new TuioObject(currentTime, tobj.SessionID, tobj.SymbolID, tobj.X, tobj.Y, tobj.Angle);
|
||
|
|
lock (objectSync)
|
||
|
|
{
|
||
|
|
objectList.Add(addObject.SessionID, addObject);
|
||
|
|
}
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.addTuioObject(addObject);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
TuioObject updateObject = getTuioObject(tobj.SessionID);
|
||
|
|
if ((tobj.X != updateObject.X && tobj.XSpeed == 0) || (tobj.Y != updateObject.Y && tobj.YSpeed == 0))
|
||
|
|
updateObject.update(currentTime, tobj.X, tobj.Y, tobj.Angle);
|
||
|
|
else
|
||
|
|
updateObject.update(currentTime, tobj.X, tobj.Y, tobj.Angle, tobj.XSpeed, tobj.YSpeed, tobj.RotationSpeed, tobj.MotionAccel, tobj.RotationAccel);
|
||
|
|
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.updateTuioObject(updateObject);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.refresh(new TuioTime(currentTime));
|
||
|
|
}
|
||
|
|
|
||
|
|
List<long> buffer = aliveObjectList;
|
||
|
|
aliveObjectList = newObjectList;
|
||
|
|
// recycling the List
|
||
|
|
newObjectList = buffer;
|
||
|
|
}
|
||
|
|
frameObjects.Clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (address == "/tuio/2Dcur")
|
||
|
|
{
|
||
|
|
|
||
|
|
if (command == "set")
|
||
|
|
{
|
||
|
|
|
||
|
|
long s_id = (int)args[1];
|
||
|
|
float xpos = (float)args[2];
|
||
|
|
float ypos = (float)args[3];
|
||
|
|
float xspeed = (float)args[4];
|
||
|
|
float yspeed = (float)args[5];
|
||
|
|
float maccel = (float)args[6];
|
||
|
|
|
||
|
|
lock (cursorList)
|
||
|
|
{
|
||
|
|
if (!cursorList.ContainsKey(s_id))
|
||
|
|
{
|
||
|
|
|
||
|
|
TuioCursor addCursor = new TuioCursor(s_id, -1, xpos, ypos);
|
||
|
|
frameCursors.Add(addCursor);
|
||
|
|
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
TuioCursor tcur = (TuioCursor)cursorList[s_id];
|
||
|
|
if (tcur == null) return;
|
||
|
|
if ((tcur.X != xpos) || (tcur.Y != ypos) || (tcur.XSpeed != xspeed) || (tcur.YSpeed != yspeed) || (tcur.MotionAccel != maccel))
|
||
|
|
{
|
||
|
|
TuioCursor updateCursor = new TuioCursor(s_id, tcur.CursorID, xpos, ypos);
|
||
|
|
updateCursor.update(xpos, ypos, xspeed, yspeed, maccel);
|
||
|
|
frameCursors.Add(updateCursor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (command == "alive")
|
||
|
|
{
|
||
|
|
|
||
|
|
newCursorList.Clear();
|
||
|
|
for (int i = 1; i < args.Count; i++)
|
||
|
|
{
|
||
|
|
// get the message content
|
||
|
|
long s_id = (int)args[i];
|
||
|
|
newCursorList.Add(s_id);
|
||
|
|
// reduce the cursor list to the lost cursors
|
||
|
|
if (aliveCursorList.Contains(s_id))
|
||
|
|
aliveCursorList.Remove(s_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
// remove the remaining cursors
|
||
|
|
lock (cursorSync)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < aliveCursorList.Count; i++)
|
||
|
|
{
|
||
|
|
long s_id = aliveCursorList[i];
|
||
|
|
if (!cursorList.ContainsKey(s_id)) continue;
|
||
|
|
TuioCursor removeCursor = cursorList[s_id];
|
||
|
|
removeCursor.remove(currentTime);
|
||
|
|
frameCursors.Add(removeCursor);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (command == "fseq")
|
||
|
|
{
|
||
|
|
int fseq = (int)args[1];
|
||
|
|
bool lateFrame = false;
|
||
|
|
|
||
|
|
if (fseq > 0)
|
||
|
|
{
|
||
|
|
if (fseq > currentFrame) currentTime = TuioTime.SessionTime;
|
||
|
|
if ((fseq >= currentFrame) || ((currentFrame - fseq) > 100)) currentFrame = fseq;
|
||
|
|
else lateFrame = true;
|
||
|
|
}
|
||
|
|
else if ((TuioTime.SessionTime.TotalMilliseconds - currentTime.TotalMilliseconds) > 100)
|
||
|
|
{
|
||
|
|
currentTime = TuioTime.SessionTime;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!lateFrame)
|
||
|
|
{
|
||
|
|
|
||
|
|
IEnumerator<TuioCursor> frameEnum = frameCursors.GetEnumerator();
|
||
|
|
while (frameEnum.MoveNext())
|
||
|
|
{
|
||
|
|
TuioCursor tcur = frameEnum.Current;
|
||
|
|
switch (tcur.TuioState)
|
||
|
|
{
|
||
|
|
case TuioCursor.TUIO_REMOVED:
|
||
|
|
TuioCursor removeCursor = tcur;
|
||
|
|
removeCursor.remove(currentTime);
|
||
|
|
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.removeTuioCursor(removeCursor);
|
||
|
|
}
|
||
|
|
lock (cursorSync)
|
||
|
|
{
|
||
|
|
cursorList.Remove(removeCursor.SessionID);
|
||
|
|
|
||
|
|
if (removeCursor.CursorID == maxCursorID)
|
||
|
|
{
|
||
|
|
maxCursorID = -1;
|
||
|
|
|
||
|
|
if (cursorList.Count > 0)
|
||
|
|
{
|
||
|
|
|
||
|
|
IEnumerator<KeyValuePair<long, TuioCursor>> clist = cursorList.GetEnumerator();
|
||
|
|
while (clist.MoveNext())
|
||
|
|
{
|
||
|
|
int f_id = clist.Current.Value.CursorID;
|
||
|
|
if (f_id > maxCursorID) maxCursorID = f_id;
|
||
|
|
}
|
||
|
|
|
||
|
|
List<TuioCursor> freeCursorBuffer = new List<TuioCursor>();
|
||
|
|
IEnumerator<TuioCursor> flist = freeCursorList.GetEnumerator();
|
||
|
|
while (flist.MoveNext())
|
||
|
|
{
|
||
|
|
TuioCursor testCursor = flist.Current;
|
||
|
|
if (testCursor.CursorID < maxCursorID) freeCursorBuffer.Add(testCursor);
|
||
|
|
}
|
||
|
|
freeCursorList = freeCursorBuffer;
|
||
|
|
}
|
||
|
|
else freeCursorList.Clear();
|
||
|
|
}
|
||
|
|
else if (removeCursor.CursorID < maxCursorID) freeCursorList.Add(removeCursor);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case TuioCursor.TUIO_ADDED:
|
||
|
|
TuioCursor addCursor;
|
||
|
|
lock (cursorSync)
|
||
|
|
{
|
||
|
|
int c_id = cursorList.Count;
|
||
|
|
if ((cursorList.Count <= maxCursorID) && (freeCursorList.Count > 0))
|
||
|
|
{
|
||
|
|
TuioCursor closestCursor = freeCursorList[0];
|
||
|
|
IEnumerator<TuioCursor> testList = freeCursorList.GetEnumerator();
|
||
|
|
while (testList.MoveNext())
|
||
|
|
{
|
||
|
|
TuioCursor testCursor = testList.Current;
|
||
|
|
if (testCursor.getDistance(tcur) < closestCursor.getDistance(tcur)) closestCursor = testCursor;
|
||
|
|
}
|
||
|
|
c_id = closestCursor.CursorID;
|
||
|
|
freeCursorList.Remove(closestCursor);
|
||
|
|
}
|
||
|
|
else maxCursorID = c_id;
|
||
|
|
|
||
|
|
addCursor = new TuioCursor(currentTime, tcur.SessionID, c_id, tcur.X, tcur.Y);
|
||
|
|
cursorList.Add(addCursor.SessionID, addCursor);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.addTuioCursor(addCursor);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
TuioCursor updateCursor = getTuioCursor(tcur.SessionID);
|
||
|
|
if ((tcur.X != updateCursor.X && tcur.XSpeed == 0) || (tcur.Y != updateCursor.Y && tcur.YSpeed == 0))
|
||
|
|
updateCursor.update(currentTime, tcur.X, tcur.Y);
|
||
|
|
else
|
||
|
|
updateCursor.update(currentTime, tcur.X, tcur.Y, tcur.XSpeed, tcur.YSpeed, tcur.MotionAccel);
|
||
|
|
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.updateTuioCursor(updateCursor);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.refresh(new TuioTime(currentTime));
|
||
|
|
}
|
||
|
|
|
||
|
|
List<long> buffer = aliveCursorList;
|
||
|
|
aliveCursorList = newCursorList;
|
||
|
|
// recycling the List
|
||
|
|
newCursorList = buffer;
|
||
|
|
}
|
||
|
|
frameCursors.Clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (address == "/tuio/2Dblb")
|
||
|
|
{
|
||
|
|
|
||
|
|
if (command == "set")
|
||
|
|
{
|
||
|
|
|
||
|
|
long s_id = (int)args[1];
|
||
|
|
float xpos = (float)args[2];
|
||
|
|
float ypos = (float)args[3];
|
||
|
|
float angle = (float)args[4];
|
||
|
|
float width = (float)args[5];
|
||
|
|
float height = (float)args[6];
|
||
|
|
float area = (float)args[7];
|
||
|
|
float xspeed = (float)args[8];
|
||
|
|
float yspeed = (float)args[9];
|
||
|
|
float rspeed = (float)args[10];
|
||
|
|
float maccel = (float)args[11];
|
||
|
|
float raccel = (float)args[12];
|
||
|
|
|
||
|
|
lock (blobList)
|
||
|
|
{
|
||
|
|
if (!blobList.ContainsKey(s_id))
|
||
|
|
{
|
||
|
|
TuioBlob addBlob = new TuioBlob(s_id, -1, xpos, ypos, angle, width, height, area);
|
||
|
|
frameBlobs.Add(addBlob);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
TuioBlob tblb = (TuioBlob)blobList[s_id];
|
||
|
|
if (tblb == null) return;
|
||
|
|
if ((tblb.X != xpos) || (tblb.Y != ypos) || (tblb.Angle != angle) || (tblb.Width != width) || (tblb.Height != height) || (tblb.Area != area) || (tblb.XSpeed != xspeed) || (tblb.YSpeed != yspeed) || (tblb.RotationSpeed != rspeed) || (tblb.MotionAccel != maccel) || (tblb.RotationAccel != raccel))
|
||
|
|
{
|
||
|
|
TuioBlob updateBlob = new TuioBlob(s_id, tblb.BlobID, xpos, ypos, angle, width, height, area);
|
||
|
|
updateBlob.update(xpos, ypos, angle, width, height, area, xspeed, yspeed, rspeed, maccel, raccel);
|
||
|
|
frameBlobs.Add(updateBlob);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (command == "alive")
|
||
|
|
{
|
||
|
|
|
||
|
|
newBlobList.Clear();
|
||
|
|
for (int i = 1; i < args.Count; i++)
|
||
|
|
{
|
||
|
|
// get the message content
|
||
|
|
long s_id = (int)args[i];
|
||
|
|
newBlobList.Add(s_id);
|
||
|
|
// reduce the blob list to the lost blobs
|
||
|
|
if (aliveBlobList.Contains(s_id))
|
||
|
|
aliveBlobList.Remove(s_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
// remove the remaining blobs
|
||
|
|
lock (blobSync)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < aliveBlobList.Count; i++)
|
||
|
|
{
|
||
|
|
long s_id = aliveBlobList[i];
|
||
|
|
if (!blobList.ContainsKey(s_id)) continue;
|
||
|
|
TuioBlob removeBlob = blobList[s_id];
|
||
|
|
removeBlob.remove(currentTime);
|
||
|
|
frameBlobs.Add(removeBlob);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
else if (command == "fseq")
|
||
|
|
{
|
||
|
|
int fseq = (int)args[1];
|
||
|
|
bool lateFrame = false;
|
||
|
|
|
||
|
|
if (fseq > 0)
|
||
|
|
{
|
||
|
|
if (fseq > currentFrame) currentTime = TuioTime.SessionTime;
|
||
|
|
if ((fseq >= currentFrame) || ((currentFrame - fseq) > 100)) currentFrame = fseq;
|
||
|
|
else lateFrame = true;
|
||
|
|
}
|
||
|
|
else if ((TuioTime.SessionTime.TotalMilliseconds - currentTime.TotalMilliseconds) > 100)
|
||
|
|
{
|
||
|
|
currentTime = TuioTime.SessionTime;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!lateFrame)
|
||
|
|
{
|
||
|
|
|
||
|
|
IEnumerator<TuioBlob> frameEnum = frameBlobs.GetEnumerator();
|
||
|
|
while (frameEnum.MoveNext())
|
||
|
|
{
|
||
|
|
TuioBlob tblb = frameEnum.Current;
|
||
|
|
switch (tblb.TuioState)
|
||
|
|
{
|
||
|
|
case TuioBlob.TUIO_REMOVED:
|
||
|
|
TuioBlob removeBlob = tblb;
|
||
|
|
removeBlob.remove(currentTime);
|
||
|
|
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.removeTuioBlob(removeBlob);
|
||
|
|
}
|
||
|
|
lock (blobSync)
|
||
|
|
{
|
||
|
|
blobList.Remove(removeBlob.SessionID);
|
||
|
|
|
||
|
|
if (removeBlob.BlobID == maxBlobID)
|
||
|
|
{
|
||
|
|
maxBlobID = -1;
|
||
|
|
|
||
|
|
if (blobList.Count > 0)
|
||
|
|
{
|
||
|
|
|
||
|
|
IEnumerator<KeyValuePair<long, TuioBlob>> blist = blobList.GetEnumerator();
|
||
|
|
while (blist.MoveNext())
|
||
|
|
{
|
||
|
|
int b_id = blist.Current.Value.BlobID;
|
||
|
|
if (b_id > maxBlobID) maxBlobID = b_id;
|
||
|
|
}
|
||
|
|
|
||
|
|
List<TuioBlob> freeBlobBuffer = new List<TuioBlob>();
|
||
|
|
IEnumerator<TuioBlob> flist = freeBlobList.GetEnumerator();
|
||
|
|
while (flist.MoveNext())
|
||
|
|
{
|
||
|
|
TuioBlob testBlob = flist.Current;
|
||
|
|
if (testBlob.BlobID < maxBlobID) freeBlobBuffer.Add(testBlob);
|
||
|
|
}
|
||
|
|
freeBlobList = freeBlobBuffer;
|
||
|
|
}
|
||
|
|
else freeBlobList.Clear();
|
||
|
|
}
|
||
|
|
else if (removeBlob.BlobID < maxBlobID) freeBlobList.Add(removeBlob);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case TuioBlob.TUIO_ADDED:
|
||
|
|
TuioBlob addBlob;
|
||
|
|
lock (blobSync)
|
||
|
|
{
|
||
|
|
int b_id = blobList.Count;
|
||
|
|
if ((blobList.Count <= maxBlobID) && (freeBlobList.Count > 0))
|
||
|
|
{
|
||
|
|
TuioBlob closestBlob = freeBlobList[0];
|
||
|
|
IEnumerator<TuioBlob> testList = freeBlobList.GetEnumerator();
|
||
|
|
while (testList.MoveNext())
|
||
|
|
{
|
||
|
|
TuioBlob testBlob = testList.Current;
|
||
|
|
if (testBlob.getDistance(tblb) < closestBlob.getDistance(tblb)) closestBlob = testBlob;
|
||
|
|
}
|
||
|
|
b_id = closestBlob.BlobID;
|
||
|
|
freeBlobList.Remove(closestBlob);
|
||
|
|
}
|
||
|
|
else maxBlobID = b_id;
|
||
|
|
|
||
|
|
addBlob = new TuioBlob(currentTime, tblb.SessionID, b_id, tblb.X, tblb.Y, tblb.Angle, tblb.Width, tblb.Height, tblb.Area);
|
||
|
|
blobList.Add(addBlob.SessionID, addBlob);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.addTuioBlob(addBlob);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
TuioBlob updateBlob = getTuioBlob(tblb.SessionID);
|
||
|
|
if ((tblb.X != updateBlob.X && tblb.XSpeed == 0) || (tblb.Y != updateBlob.Y && tblb.YSpeed == 0) || (tblb.Angle != updateBlob.Angle && tblb.RotationSpeed == 0))
|
||
|
|
updateBlob.update(currentTime, tblb.X, tblb.Y, tblb.Angle, tblb.Width, tblb.Height, tblb.Area);
|
||
|
|
else
|
||
|
|
updateBlob.update(currentTime, tblb.X, tblb.Y, tblb.Angle, tblb.Width, tblb.Height, tblb.Area, tblb.XSpeed, tblb.YSpeed, tblb.RotationSpeed, tblb.MotionAccel, tblb.RotationAccel);
|
||
|
|
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.updateTuioBlob(updateBlob);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i = 0; i < listenerList.Count; i++)
|
||
|
|
{
|
||
|
|
TuioListener listener = (TuioListener)listenerList[i];
|
||
|
|
if (listener != null) listener.refresh(new TuioTime(currentTime));
|
||
|
|
}
|
||
|
|
|
||
|
|
List<long> buffer = aliveBlobList;
|
||
|
|
aliveBlobList = newBlobList;
|
||
|
|
// recycling the List
|
||
|
|
newBlobList = buffer;
|
||
|
|
}
|
||
|
|
frameBlobs.Clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#region Listener Management
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* Adds the provided TuioListener to the list of registered TUIO event listeners</summary>
|
||
|
|
* <param name="listener">the TuioListener to add</param>
|
||
|
|
*/
|
||
|
|
public void addTuioListener(TuioListener listener)
|
||
|
|
{
|
||
|
|
listenerList.Add(listener);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* Removes the provided TuioListener from the list of registered TUIO event listeners</summary>
|
||
|
|
* <param name="listener">the TuioListener to remove</param>
|
||
|
|
*/
|
||
|
|
public void removeTuioListener(TuioListener listener)
|
||
|
|
{
|
||
|
|
listenerList.Remove(listener);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* Removes all TuioListener from the list of registered TUIO event listeners</summary>
|
||
|
|
*/
|
||
|
|
public void removeAllTuioListeners()
|
||
|
|
{
|
||
|
|
listenerList.Clear();
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region Object Management
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* Returns a List of all currently active TuioObjects</summary>
|
||
|
|
* <returns>a List of all currently active TuioObjects</returns>
|
||
|
|
*/
|
||
|
|
public List<TuioObject> getTuioObjects()
|
||
|
|
{
|
||
|
|
List<TuioObject> listBuffer;
|
||
|
|
lock (objectSync)
|
||
|
|
{
|
||
|
|
listBuffer = new List<TuioObject>(objectList.Values);
|
||
|
|
}
|
||
|
|
return listBuffer;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* Returns a List of all currently active TuioCursors</summary>
|
||
|
|
* <returns>a List of all currently active TuioCursors</returns>
|
||
|
|
*/
|
||
|
|
public List<TuioCursor> getTuioCursors()
|
||
|
|
{
|
||
|
|
List<TuioCursor> listBuffer;
|
||
|
|
lock (cursorSync)
|
||
|
|
{
|
||
|
|
listBuffer = new List<TuioCursor>(cursorList.Values);
|
||
|
|
}
|
||
|
|
return listBuffer;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* Returns a List of all currently active TuioBlobs</summary>
|
||
|
|
* <returns>a List of all currently active TuioBlobs</returns>
|
||
|
|
*/
|
||
|
|
public List<TuioBlob> getTuioBlobs()
|
||
|
|
{
|
||
|
|
List<TuioBlob> listBuffer;
|
||
|
|
lock (blobSync)
|
||
|
|
{
|
||
|
|
listBuffer = new List<TuioBlob>(blobList.Values);
|
||
|
|
}
|
||
|
|
return listBuffer;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* Returns the TuioObject corresponding to the provided Session ID
|
||
|
|
* or NULL if the Session ID does not refer to an active TuioObject</summary>
|
||
|
|
* <returns>an active TuioObject corresponding to the provided Session ID or NULL</returns>
|
||
|
|
*/
|
||
|
|
public TuioObject getTuioObject(long s_id)
|
||
|
|
{
|
||
|
|
TuioObject tobject = null;
|
||
|
|
lock (objectSync)
|
||
|
|
{
|
||
|
|
objectList.TryGetValue(s_id, out tobject);
|
||
|
|
}
|
||
|
|
return tobject;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* Returns the TuioCursor corresponding to the provided Session ID
|
||
|
|
* or NULL if the Session ID does not refer to an active TuioCursor</summary>
|
||
|
|
* <returns>an active TuioCursor corresponding to the provided Session ID or NULL</returns>
|
||
|
|
*/
|
||
|
|
public TuioCursor getTuioCursor(long s_id)
|
||
|
|
{
|
||
|
|
TuioCursor tcursor = null;
|
||
|
|
lock (cursorSync)
|
||
|
|
{
|
||
|
|
cursorList.TryGetValue(s_id, out tcursor);
|
||
|
|
}
|
||
|
|
return tcursor;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* <summary>
|
||
|
|
* Returns the TuioBlob corresponding to the provided Session ID
|
||
|
|
* or NULL if the Session ID does not refer to an active TuioBlob</summary>
|
||
|
|
* <returns>an active TuioBlob corresponding to the provided Session ID or NULL</returns>
|
||
|
|
*/
|
||
|
|
public TuioBlob getTuioBlob(long s_id)
|
||
|
|
{
|
||
|
|
TuioBlob tblob = null;
|
||
|
|
lock (blobSync)
|
||
|
|
{
|
||
|
|
blobList.TryGetValue(s_id, out tblob);
|
||
|
|
}
|
||
|
|
return tblob;
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|