- 浏览: 49450 次
- 性别:
- 来自: 上海
文章分类
Touchlib源码注释-----TUIO.as
Touchlib源码注释-----TUIO.as 收藏
声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息
TUIO.as文件详细注释
TUIOObject.as TUIOEvent.as TUIOCursor.as文件详细注释
研究了一段时间的multiTouch,根据自己的理解也对代码做了很多注释,今天整理了一下Touchlib这个库的Actionscript 3版本的源码注释,现在发布出来,希望和大家一起讨论修正。也欢迎大家指出其中的错误或者发表自己的意见。后续的as文件,会在我整理完成后慢慢发布出来。好了直接贴代码(本人很想办一个openframeworks的中文论坛,然后会发布一些ccv和openframeworks的个人心得,希望有这个兴趣的朋友一起来研究研究)
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/li_007/archive/2010/01/01/5118098.aspx
package com.touchlib {
import flash.events.DataEvent;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.geom.Point;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.XMLSocket;
//import flash.system.System;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
//import flash.events.MouseEvent;
import flash.display.*;
import app.core.element.Wrapper;
import flash.events.MouseEvent;
public class TUIO
{
static var FLOSCSocket:XMLSocket;
static var FLOSCSocketHost:String;
static var FLOSCSocketPort:Number;
static var thestage:Stage;
// 存储了所有可用TUIOObject实例
static var objectArray:Array;
// 存储了所有可用TUIOOject对象的ID号,但是在本源文件中并没有用到这个变量
static var idArray:Array;
public static var debugMode:Boolean;
static var debugText:TextField;
static var debugToggle:TextField;
static var recordedXML:XML;
static var bRecording:Boolean = false;
//static var xmlPlaybackURL:String = "www/xml/test.xml";
static var xmlPlaybackURL:String = "";
static var xmlPlaybackLoader:URLLoader;
static var playbackXML:XML;
static var bInitialized = false;
// s : 当然舞台,传递文档类的this即可
// host : 服务器IP地址
// port : 端口,CCV默认为3000
// debugXMLFile : 调试用xml文件路径
// debug : 一个Boolen值,表示当前是否为调试状态(不一定需要调试xml)
//
// 这个是TUIO AS 3 Library的初始化函数,在flash工程的文档类开始调用就可以。
//
public static function init (s:DisplayObjectContainer, host:String, port:Number, debugXMLFile:String, dbug:Boolean = true):void
{
if(bInitialized)
return;
debugMode = dbug;
FLOSCSocketHost=host;
FLOSCSocketPort=port;
bInitialized = true;
thestage = s.stage; // 获取当然文档类的舞台
thestage.align = StageAlign.TOP_LEFT;
thestage.displayState = StageDisplayState.FULL_SCREEN;
objectArray = new Array();
idArray = new Array();
try
{
// 与服务端建立xml socket连接,比如CCV。
// 关于flash的xmlsocket编程大家可以自己去查阅Actionscript 3的文档
FLOSCSocket = new XMLSocket();
FLOSCSocket.addEventListener(Event.CLOSE, closeHandler);
FLOSCSocket.addEventListener(Event.CONNECT, connectHandler);
FLOSCSocket.addEventListener(DataEvent.DATA, dataHandler);
FLOSCSocket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
FLOSCSocket.addEventListener(ProgressEvent.PROGRESS, progressHandler);
FLOSCSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
FLOSCSocket.connect(host, port);
} catch (e)
{
}
// 如果当前是调试状态,设置一些调试所需元件
if(debugMode)
{
var format:TextFormat = new TextFormat();
debugText = new TextField();
format.font = "Verdana";
format.color = 0xFFFFFF;
format.size = 10;
debugText.defaultTextFormat = format;
debugText.autoSize = TextFieldAutoSize.LEFT;
debugText.background = true;
debugText.backgroundColor = 0x000000;
debugText.border = true;
debugText.borderColor = 0x333333;
// 将一个动态文本对象加到显示列表,并且将它放在显示列表的最上层。
// 其实这个debugText对象是实时显示调试状态下,触摸点的ID号,x和y坐标
thestage.addChild( debugText );
thestage.setChildIndex(debugText, thestage.numChildren-1);
recordedXML = <OSCPackets></OSCPackets>;
// 创建一个Sprite对象,调试作用,稍后介绍
var buttonSprite = new Sprite();
buttonSprite.graphics.beginFill(0xFFFFFF,1.0);
buttonSprite.graphics.drawRoundRect(0, -10, 50, 60,10);
buttonSprite.addEventListener(MouseEvent.CLICK, toggleDebug);
// 创建一个Wrapper对象,Wrapper对象类在app.core.element包中
var WrapperObject:Wrapper = new Wrapper(buttonSprite);
thestage.addChild(WrapperObject);
thestage.setChildIndex(WrapperObject, thestage.numChildren-1);
//trace(thestage.numChildren);
// 调试xml文件处理
if(xmlPlaybackURL != "")
{
xmlPlaybackLoader = new URLLoader();
xmlPlaybackLoader.addEventListener("complete", xmlPlaybackLoaded);
xmlPlaybackLoader.load(new URLRequest(xmlPlaybackURL));
thestage.addEventListener(Event.ENTER_FRAME, frameUpdate);
}
} else {
recordedXML = <OSCPackets></OSCPackets>;
bRecording = false;
}
}
// 调试xml文件加载完成事件处理函数
private static function xmlPlaybackLoaded(evt:Event) {
trace("Loaded xml debug data");
playbackXML = new XML(xmlPlaybackLoader.data);
}
//
private static function frameUpdate(evt:Event)
{
if(playbackXML && playbackXML.OSCPACKET && playbackXML.OSCPACKET[0])
{
processMessage(playbackXML.OSCPACKET[0]);
delete playbackXML.OSCPACKET[0];
}
}
// 从名字就可以看出来函数功能。根据id来查找所有存储在objectArray数组中的TUIOObject实例
public static function getObjectById(id:Number): TUIOObject
{
for(var i=0; i<objectArray.length; i++)
{
if(objectArray[i].ID == id)
{
//trace("found " + id);
return objectArray[i];
}
}
//trace("Notfound");
return null;
}
// 这个函数要结合TUIOObject类来理解。
public static function listenForObject(id:Number, reciever:Object)
{
var tmpObj:TUIOObject = getObjectById(id);
if(tmpObj)
{
tmpObj.addListener(reciever);
}
}
// 这个是最重要的数据处理函数
public static function processMessage(msg:XML)
{
var fseq:String;
var node:XML;
// 处理fseq消息,格式如下:
//
// /tuio/[profileName] fseq int32
// profileName 代表定义好的常用可感知用户界面配置
// fseq 消息标示
// int32 一个类型为int32的fseq值
for each(node in msg.MESSAGE)
{
if(node.ARGUMENT[0] && node.ARGUMENT[0].@VALUE == "fseq")
fseq = node.ARGUMENT[1].@VALUE;
}
/// trace("fseq = " + fseq);
// 处理alive消息,格式如下:
//
// uio/[profileName] alive [list of active sessionIDs]
// profileName 代表定义好的常用可感知用户界面配置
// alive 消息标示
// [list of active sessionIDs] 一系列当前有用的目标对象的id号
for each(node in msg.MESSAGE)
{
if(node.ARGUMENT[0] && node.ARGUMENT[0].@VALUE == "alive")
{
// 重置objectArray数组中存储的所有TUIOOject实例的isAlive属性
for each (var obj1:TUIOObject in objectArray)
{
obj1.isAlive = false;
}
// 在这个地方重新定义了一个array,但是是无用的变量。
var newIdArray:Array = new Array();
// 循环获得alive消息所有id
//
// alive消息是配合set消息来确定哪些blobs点是有用,也就是哪些set消息中包含的数据是有效的
// 可以结合CCV中的源码来理解
for each(var aliveItem:XML in node.ARGUMENT.(@VALUE != "alive"))
{
// 根据alive消息中的id,相应的TUIOObject实例的isAlive属性设置为true,也即是当前点可用
if(getObjectById(aliveItem.@VALUE))
getObjectById(aliveItem.@VALUE).isAlive = true;
}
//trace(idArray);
idArray = newIdArray;
}
}
// 处理set消息
for each(node in msg.MESSAGE)
{
if(node.ARGUMENT[0])
{
var type:String;
// 在这里要注意区别2Dobj和2Dcur这两种profile的区别,结构如下,具体请阅读TUIO Protocol Specification
//
// /tuio/2Dobj set s i x y a X Y A m r
// /tuio/2Dcur set s x y X Y m
//
// 由于本人结合研究的CCV发送的是/tuio/2Dcur消息结构,所以我先注释/tuio/2Dcur结构消息处理
// 对于/tuio/2Dobj消息处理的注释在以后补上。
if(node.@NAME == "/tuio/2Dobj")
{
type = node.ARGUMENT[0].@VALUE;
if(type == "set")
{
var sID = node.ARGUMENT[1].@VALUE;
var id = node.ARGUMENT[2].@VALUE;
var x = Number(node.ARGUMENT[3].@VALUE) * thestage.stageWidth;
var y = Number(node.ARGUMENT[4].@VALUE) * thestage.stageHeight;
var a = Number(node.ARGUMENT[5].@VALUE);
var X = Number(node.ARGUMENT[6].@VALUE);
var Y = Number(node.ARGUMENT[7].@VALUE);
var A = Number(node.ARGUMENT[8].@VALUE);
var m = node.ARGUMENT[9].@VALUE;
var r = node.ARGUMENT[10].@VALUE;
// send object update event..
var objArray:Array = thestage.getObjectsUnderPoint(new Point(x, y));
var stagePoint:Point = new Point(x,y);
var displayObjArray:Array = thestage.getObjectsUnderPoint(stagePoint);
var dobj = null;
// if(displayObjArray.length > 0)
// dobj = displayObjArray[displayObjArray.length-1];
var tuioobj = getObjectById(id);
if(tuioobj == null)
{
tuioobj = new TUIOObject("2Dobj", id, x, y, X, Y, sID, a, dobj);
thestage.addChild(tuioobj.spr);
objectArray.push(tuioobj);
tuioobj.notifyCreated();
} else {
tuioobj.spr.x = x;
tuioobj.spr.y = y;
tuioobj.x = x;
tuioobj.y = y;
tuioobj.dX = X;
tuioobj.dY = Y;
tuioobj.setObjOver(dobj);
tuioobj.notifyMoved();
}
try
{
if(tuioobj.obj && tuioobj.obj.parent)
{
var localPoint:Point = tuioobj.obj.parent.globalToLocal(stagePoint);
tuioobj.obj.dispatchEvent(new TUIOEvent(TUIOEvent.TUIO_MOVE, true, false, x, y, localPoint.x, localPoint.y, tuioobj.oldX, tuioobj.oldY, tuioobj.obj, false,false,false, true, m, "2Dobj", id, sID, a));
}
} catch (e)
{
}
}
}
//
// /tuio/2Dcur set s x y X Y m
//
else if(node.@NAME == "/tuio/2Dcur")
{
// trace("2dcur");
type = node.ARGUMENT[0].@VALUE;
// 判断消息类型是否为set
if(type == "set")
{
// 当前点的id
var id = node.ARGUMENT[1].@VALUE;
// 将x,y分别乘以舞台宽度和高度转化为当前点全局舞台坐标中的水平和垂直坐标
// 注意在这里为什么是分别对应乘以舞台宽度和高度,需要认真理解
var x = Number(node.ARGUMENT[2].@VALUE) * thestage.stageWidth;
var y = Number(node.ARGUMENT[3].@VALUE) * thestage.stageHeight;
// 分别是当前点的位移量
var X = Number(node.ARGUMENT[4].@VALUE);
var Y = Number(node.ARGUMENT[5].@VALUE);
// 这个值根据TUIO Protocol Specification的解释和CCV中源码实现,我的理解产生了矛盾。
// 需要我后续的实验验证。故再次不做注释说明,也希望那位与我共同讨论(leezhm@126.com)
var m = node.ARGUMENT[6].@VALUE;
//var area = node.ARGUMENT[7].@VALUE;
var stagePoint:Point = new Point(x, y);
// 下面代码段是一个理解重点
// 根据当前点坐标得到舞台上该点下面所有显示对象。关于getObjectsUnderPoint函数
// 可以查阅Actionscript 3的Docs,它返回的包含所有对象的一个数组
var displayObjArray:Array = thestage.getObjectsUnderPoint(stagePoint);
var dobj = null;
// 根据返回的数组,得到最上层的显示对象
//
// 为什么要得到这个最上层的显示对象呢?怎么实现触摸响应的呢?
// 比如:舞台上有一个MovieClip,在这个MC上有一个Button。
// 当你的手触摸到这个button的时候,我们得到了当前点坐标(肯定是stageX和stageY),这样我们
// 用上面的方法获得这个点下面所有的显示对象,包括button,MovieClip等。这个时候我们就要获取
// 最上层这个button,然后让这个button发送一个TUIOEvent.TUIO_DOWN等这样的事件。然后我们只需
// 要在我们的flash中的button上监听这个TUIO_DOWN事件就可以了。
//
// 理解了么?这就是由屏幕上一个点,到flash舞台上元素响应事件的原理。好好学习下Actionscript 3
// 的事件机制后理解这些吧。因为这个让我也想起了Box2D这个库中实现鼠标事件的原理。
if(displayObjArray.length > 0)
dobj = displayObjArray[displayObjArray.length-1];
var sztmp:String="";
// for(var i=0; i<displayObjArray.length; i++)
// sztmp += (displayObjArray[i] is InteractiveObject) + ",";
// trace(sztmp);
// 根据当前id号在objectArray数组中查找是否存在对于的TUIOOjbect实例
var tuioobj = getObjectById(id);
if(tuioobj == null)
{
// 不存在,则创建响应TUIOObject对象,并加入到舞台和数组中(个人觉得没必要加载到舞台,
// 况且为了加载还重新定义了一个Sprite,真是有点多此一举)
//
// 注意这里创建TUIOObject实例所传递的参数中最后一个参数。当然这也要结合TUIOObject类
// 来理解。具体的将会在TUIOObject类中注释。
tuioobj = new TUIOObject("2Dcur", id, x, y, X, Y, -1, 0, dobj);
//tuioobj.area = area;
thestage.addChild(tuioobj.spr);
objectArray.push(tuioobj);
// 发送TUIO_OVER和TUIO_DOWN消息(请结合TUIOObject代码来理解)
tuioobj.notifyCreated();
}
else
{
// 存在,则更新当前点的信息
tuioobj.spr.x = x;
tuioobj.spr.y = y;
tuioobj.x = x;
tuioobj.y = y;
//tuioobj.area = area;
tuioobj.dX = X;
tuioobj.dY = Y;
tuioobj.setObjOver(dobj);
tuioobj.notifyMoved();
}
try
{
// 发送TUIO_MOVE消息
if(tuioobj.obj && tuioobj.obj.parent)
{
var localPoint:Point = tuioobj.obj.parent.globalToLocal(stagePoint);
tuioobj.obj.dispatchEvent(new TUIOEvent(TUIOEvent.TUIO_MOVE, true, false, x, y, localPoint.x, localPoint.y, tuioobj.oldX, tuioobj.oldY, tuioobj.obj, false,false,false, true, m, "2Dobj", id, sID, a));
}
} catch (e)
{
trace("Dispatch event failed " + tuioobj.name);
}
}
}
}
}
// 设置调试显示文本
if(debugMode)
{
debugText.text = "";
debugText.y = -2000;
debugText.x = -2000;
}
for (var i=0; i<objectArray.length; i++ )
{
// 如果当前点非alive,则总objectArray数组中去掉,并且清楚当前点。
if(objectArray[i].isAlive == false)
{
objectArray[i].kill();
thestage.removeChild(objectArray[i].spr);
objectArray.splice(i, 1);
i--;
}
else
{
// 调试状态下显示当前点的坐标(stageX和stageY)
if(debugMode)
{
debugText.appendText(" " + (i + 1) +" - " +objectArray[i].ID + " X:" + int(objectArray[i].x) + " Y:" + int(objectArray[i].y) + " \n");
debugText.x = thestage.stageWidth-160;
debugText.y = 40;
}
}
}
}
private static function toggleDebug(e:Event)
{
if(!debugMode){
debugMode=true;
FLOSCSocket.connect(FLOSCSocketHost, FLOSCSocketPort);
e.target.x=20;
}
else{
debugMode=false;
FLOSCSocket.connect(FLOSCSocketHost, FLOSCSocketPort);
e.target.x=0;
}
// show XML
//bRecording = false;
//debugMode = false;
//debugText.text = recordedXML.toString();
//debugText.x = 0;
//debugText.y = 0;
}
private static function closeHandler(event:Event):void {
//trace("closeHandler: " + event);
}
private static function connectHandler(event:Event):void {
// trace("connectHandler: " + event);
}
private static function dataHandler(event:DataEvent):void {
//trace("dataHandler: " + event);
if(bRecording)
recordedXML.appendChild( XML(event.data) );
processMessage(XML(event.data));
}
private static function ioErrorHandler(event:IOErrorEvent):void {
// thestage.tfDebug.appendText("ioError: " + event + "\n");
trace("ioErrorHandler: " + event);
}
private static function progressHandler(event:ProgressEvent):void {
//trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal);
}
private static function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
// thestage.tfDebug.appendText("securityError: " + event + "\n");
}
}
}
Touchlib源码注释-----TUIO.as 收藏
声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息
TUIO.as文件详细注释
TUIOObject.as TUIOEvent.as TUIOCursor.as文件详细注释
研究了一段时间的multiTouch,根据自己的理解也对代码做了很多注释,今天整理了一下Touchlib这个库的Actionscript 3版本的源码注释,现在发布出来,希望和大家一起讨论修正。也欢迎大家指出其中的错误或者发表自己的意见。后续的as文件,会在我整理完成后慢慢发布出来。好了直接贴代码(本人很想办一个openframeworks的中文论坛,然后会发布一些ccv和openframeworks的个人心得,希望有这个兴趣的朋友一起来研究研究)
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/li_007/archive/2010/01/01/5118098.aspx
package com.touchlib {
import flash.events.DataEvent;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.geom.Point;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.XMLSocket;
//import flash.system.System;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
//import flash.events.MouseEvent;
import flash.display.*;
import app.core.element.Wrapper;
import flash.events.MouseEvent;
public class TUIO
{
static var FLOSCSocket:XMLSocket;
static var FLOSCSocketHost:String;
static var FLOSCSocketPort:Number;
static var thestage:Stage;
// 存储了所有可用TUIOObject实例
static var objectArray:Array;
// 存储了所有可用TUIOOject对象的ID号,但是在本源文件中并没有用到这个变量
static var idArray:Array;
public static var debugMode:Boolean;
static var debugText:TextField;
static var debugToggle:TextField;
static var recordedXML:XML;
static var bRecording:Boolean = false;
//static var xmlPlaybackURL:String = "www/xml/test.xml";
static var xmlPlaybackURL:String = "";
static var xmlPlaybackLoader:URLLoader;
static var playbackXML:XML;
static var bInitialized = false;
// s : 当然舞台,传递文档类的this即可
// host : 服务器IP地址
// port : 端口,CCV默认为3000
// debugXMLFile : 调试用xml文件路径
// debug : 一个Boolen值,表示当前是否为调试状态(不一定需要调试xml)
//
// 这个是TUIO AS 3 Library的初始化函数,在flash工程的文档类开始调用就可以。
//
public static function init (s:DisplayObjectContainer, host:String, port:Number, debugXMLFile:String, dbug:Boolean = true):void
{
if(bInitialized)
return;
debugMode = dbug;
FLOSCSocketHost=host;
FLOSCSocketPort=port;
bInitialized = true;
thestage = s.stage; // 获取当然文档类的舞台
thestage.align = StageAlign.TOP_LEFT;
thestage.displayState = StageDisplayState.FULL_SCREEN;
objectArray = new Array();
idArray = new Array();
try
{
// 与服务端建立xml socket连接,比如CCV。
// 关于flash的xmlsocket编程大家可以自己去查阅Actionscript 3的文档
FLOSCSocket = new XMLSocket();
FLOSCSocket.addEventListener(Event.CLOSE, closeHandler);
FLOSCSocket.addEventListener(Event.CONNECT, connectHandler);
FLOSCSocket.addEventListener(DataEvent.DATA, dataHandler);
FLOSCSocket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
FLOSCSocket.addEventListener(ProgressEvent.PROGRESS, progressHandler);
FLOSCSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
FLOSCSocket.connect(host, port);
} catch (e)
{
}
// 如果当前是调试状态,设置一些调试所需元件
if(debugMode)
{
var format:TextFormat = new TextFormat();
debugText = new TextField();
format.font = "Verdana";
format.color = 0xFFFFFF;
format.size = 10;
debugText.defaultTextFormat = format;
debugText.autoSize = TextFieldAutoSize.LEFT;
debugText.background = true;
debugText.backgroundColor = 0x000000;
debugText.border = true;
debugText.borderColor = 0x333333;
// 将一个动态文本对象加到显示列表,并且将它放在显示列表的最上层。
// 其实这个debugText对象是实时显示调试状态下,触摸点的ID号,x和y坐标
thestage.addChild( debugText );
thestage.setChildIndex(debugText, thestage.numChildren-1);
recordedXML = <OSCPackets></OSCPackets>;
// 创建一个Sprite对象,调试作用,稍后介绍
var buttonSprite = new Sprite();
buttonSprite.graphics.beginFill(0xFFFFFF,1.0);
buttonSprite.graphics.drawRoundRect(0, -10, 50, 60,10);
buttonSprite.addEventListener(MouseEvent.CLICK, toggleDebug);
// 创建一个Wrapper对象,Wrapper对象类在app.core.element包中
var WrapperObject:Wrapper = new Wrapper(buttonSprite);
thestage.addChild(WrapperObject);
thestage.setChildIndex(WrapperObject, thestage.numChildren-1);
//trace(thestage.numChildren);
// 调试xml文件处理
if(xmlPlaybackURL != "")
{
xmlPlaybackLoader = new URLLoader();
xmlPlaybackLoader.addEventListener("complete", xmlPlaybackLoaded);
xmlPlaybackLoader.load(new URLRequest(xmlPlaybackURL));
thestage.addEventListener(Event.ENTER_FRAME, frameUpdate);
}
} else {
recordedXML = <OSCPackets></OSCPackets>;
bRecording = false;
}
}
// 调试xml文件加载完成事件处理函数
private static function xmlPlaybackLoaded(evt:Event) {
trace("Loaded xml debug data");
playbackXML = new XML(xmlPlaybackLoader.data);
}
//
private static function frameUpdate(evt:Event)
{
if(playbackXML && playbackXML.OSCPACKET && playbackXML.OSCPACKET[0])
{
processMessage(playbackXML.OSCPACKET[0]);
delete playbackXML.OSCPACKET[0];
}
}
// 从名字就可以看出来函数功能。根据id来查找所有存储在objectArray数组中的TUIOObject实例
public static function getObjectById(id:Number): TUIOObject
{
for(var i=0; i<objectArray.length; i++)
{
if(objectArray[i].ID == id)
{
//trace("found " + id);
return objectArray[i];
}
}
//trace("Notfound");
return null;
}
// 这个函数要结合TUIOObject类来理解。
public static function listenForObject(id:Number, reciever:Object)
{
var tmpObj:TUIOObject = getObjectById(id);
if(tmpObj)
{
tmpObj.addListener(reciever);
}
}
// 这个是最重要的数据处理函数
public static function processMessage(msg:XML)
{
var fseq:String;
var node:XML;
// 处理fseq消息,格式如下:
//
// /tuio/[profileName] fseq int32
// profileName 代表定义好的常用可感知用户界面配置
// fseq 消息标示
// int32 一个类型为int32的fseq值
for each(node in msg.MESSAGE)
{
if(node.ARGUMENT[0] && node.ARGUMENT[0].@VALUE == "fseq")
fseq = node.ARGUMENT[1].@VALUE;
}
/// trace("fseq = " + fseq);
// 处理alive消息,格式如下:
//
// uio/[profileName] alive [list of active sessionIDs]
// profileName 代表定义好的常用可感知用户界面配置
// alive 消息标示
// [list of active sessionIDs] 一系列当前有用的目标对象的id号
for each(node in msg.MESSAGE)
{
if(node.ARGUMENT[0] && node.ARGUMENT[0].@VALUE == "alive")
{
// 重置objectArray数组中存储的所有TUIOOject实例的isAlive属性
for each (var obj1:TUIOObject in objectArray)
{
obj1.isAlive = false;
}
// 在这个地方重新定义了一个array,但是是无用的变量。
var newIdArray:Array = new Array();
// 循环获得alive消息所有id
//
// alive消息是配合set消息来确定哪些blobs点是有用,也就是哪些set消息中包含的数据是有效的
// 可以结合CCV中的源码来理解
for each(var aliveItem:XML in node.ARGUMENT.(@VALUE != "alive"))
{
// 根据alive消息中的id,相应的TUIOObject实例的isAlive属性设置为true,也即是当前点可用
if(getObjectById(aliveItem.@VALUE))
getObjectById(aliveItem.@VALUE).isAlive = true;
}
//trace(idArray);
idArray = newIdArray;
}
}
// 处理set消息
for each(node in msg.MESSAGE)
{
if(node.ARGUMENT[0])
{
var type:String;
// 在这里要注意区别2Dobj和2Dcur这两种profile的区别,结构如下,具体请阅读TUIO Protocol Specification
//
// /tuio/2Dobj set s i x y a X Y A m r
// /tuio/2Dcur set s x y X Y m
//
// 由于本人结合研究的CCV发送的是/tuio/2Dcur消息结构,所以我先注释/tuio/2Dcur结构消息处理
// 对于/tuio/2Dobj消息处理的注释在以后补上。
if(node.@NAME == "/tuio/2Dobj")
{
type = node.ARGUMENT[0].@VALUE;
if(type == "set")
{
var sID = node.ARGUMENT[1].@VALUE;
var id = node.ARGUMENT[2].@VALUE;
var x = Number(node.ARGUMENT[3].@VALUE) * thestage.stageWidth;
var y = Number(node.ARGUMENT[4].@VALUE) * thestage.stageHeight;
var a = Number(node.ARGUMENT[5].@VALUE);
var X = Number(node.ARGUMENT[6].@VALUE);
var Y = Number(node.ARGUMENT[7].@VALUE);
var A = Number(node.ARGUMENT[8].@VALUE);
var m = node.ARGUMENT[9].@VALUE;
var r = node.ARGUMENT[10].@VALUE;
// send object update event..
var objArray:Array = thestage.getObjectsUnderPoint(new Point(x, y));
var stagePoint:Point = new Point(x,y);
var displayObjArray:Array = thestage.getObjectsUnderPoint(stagePoint);
var dobj = null;
// if(displayObjArray.length > 0)
// dobj = displayObjArray[displayObjArray.length-1];
var tuioobj = getObjectById(id);
if(tuioobj == null)
{
tuioobj = new TUIOObject("2Dobj", id, x, y, X, Y, sID, a, dobj);
thestage.addChild(tuioobj.spr);
objectArray.push(tuioobj);
tuioobj.notifyCreated();
} else {
tuioobj.spr.x = x;
tuioobj.spr.y = y;
tuioobj.x = x;
tuioobj.y = y;
tuioobj.dX = X;
tuioobj.dY = Y;
tuioobj.setObjOver(dobj);
tuioobj.notifyMoved();
}
try
{
if(tuioobj.obj && tuioobj.obj.parent)
{
var localPoint:Point = tuioobj.obj.parent.globalToLocal(stagePoint);
tuioobj.obj.dispatchEvent(new TUIOEvent(TUIOEvent.TUIO_MOVE, true, false, x, y, localPoint.x, localPoint.y, tuioobj.oldX, tuioobj.oldY, tuioobj.obj, false,false,false, true, m, "2Dobj", id, sID, a));
}
} catch (e)
{
}
}
}
//
// /tuio/2Dcur set s x y X Y m
//
else if(node.@NAME == "/tuio/2Dcur")
{
// trace("2dcur");
type = node.ARGUMENT[0].@VALUE;
// 判断消息类型是否为set
if(type == "set")
{
// 当前点的id
var id = node.ARGUMENT[1].@VALUE;
// 将x,y分别乘以舞台宽度和高度转化为当前点全局舞台坐标中的水平和垂直坐标
// 注意在这里为什么是分别对应乘以舞台宽度和高度,需要认真理解
var x = Number(node.ARGUMENT[2].@VALUE) * thestage.stageWidth;
var y = Number(node.ARGUMENT[3].@VALUE) * thestage.stageHeight;
// 分别是当前点的位移量
var X = Number(node.ARGUMENT[4].@VALUE);
var Y = Number(node.ARGUMENT[5].@VALUE);
// 这个值根据TUIO Protocol Specification的解释和CCV中源码实现,我的理解产生了矛盾。
// 需要我后续的实验验证。故再次不做注释说明,也希望那位与我共同讨论(leezhm@126.com)
var m = node.ARGUMENT[6].@VALUE;
//var area = node.ARGUMENT[7].@VALUE;
var stagePoint:Point = new Point(x, y);
// 下面代码段是一个理解重点
// 根据当前点坐标得到舞台上该点下面所有显示对象。关于getObjectsUnderPoint函数
// 可以查阅Actionscript 3的Docs,它返回的包含所有对象的一个数组
var displayObjArray:Array = thestage.getObjectsUnderPoint(stagePoint);
var dobj = null;
// 根据返回的数组,得到最上层的显示对象
//
// 为什么要得到这个最上层的显示对象呢?怎么实现触摸响应的呢?
// 比如:舞台上有一个MovieClip,在这个MC上有一个Button。
// 当你的手触摸到这个button的时候,我们得到了当前点坐标(肯定是stageX和stageY),这样我们
// 用上面的方法获得这个点下面所有的显示对象,包括button,MovieClip等。这个时候我们就要获取
// 最上层这个button,然后让这个button发送一个TUIOEvent.TUIO_DOWN等这样的事件。然后我们只需
// 要在我们的flash中的button上监听这个TUIO_DOWN事件就可以了。
//
// 理解了么?这就是由屏幕上一个点,到flash舞台上元素响应事件的原理。好好学习下Actionscript 3
// 的事件机制后理解这些吧。因为这个让我也想起了Box2D这个库中实现鼠标事件的原理。
if(displayObjArray.length > 0)
dobj = displayObjArray[displayObjArray.length-1];
var sztmp:String="";
// for(var i=0; i<displayObjArray.length; i++)
// sztmp += (displayObjArray[i] is InteractiveObject) + ",";
// trace(sztmp);
// 根据当前id号在objectArray数组中查找是否存在对于的TUIOOjbect实例
var tuioobj = getObjectById(id);
if(tuioobj == null)
{
// 不存在,则创建响应TUIOObject对象,并加入到舞台和数组中(个人觉得没必要加载到舞台,
// 况且为了加载还重新定义了一个Sprite,真是有点多此一举)
//
// 注意这里创建TUIOObject实例所传递的参数中最后一个参数。当然这也要结合TUIOObject类
// 来理解。具体的将会在TUIOObject类中注释。
tuioobj = new TUIOObject("2Dcur", id, x, y, X, Y, -1, 0, dobj);
//tuioobj.area = area;
thestage.addChild(tuioobj.spr);
objectArray.push(tuioobj);
// 发送TUIO_OVER和TUIO_DOWN消息(请结合TUIOObject代码来理解)
tuioobj.notifyCreated();
}
else
{
// 存在,则更新当前点的信息
tuioobj.spr.x = x;
tuioobj.spr.y = y;
tuioobj.x = x;
tuioobj.y = y;
//tuioobj.area = area;
tuioobj.dX = X;
tuioobj.dY = Y;
tuioobj.setObjOver(dobj);
tuioobj.notifyMoved();
}
try
{
// 发送TUIO_MOVE消息
if(tuioobj.obj && tuioobj.obj.parent)
{
var localPoint:Point = tuioobj.obj.parent.globalToLocal(stagePoint);
tuioobj.obj.dispatchEvent(new TUIOEvent(TUIOEvent.TUIO_MOVE, true, false, x, y, localPoint.x, localPoint.y, tuioobj.oldX, tuioobj.oldY, tuioobj.obj, false,false,false, true, m, "2Dobj", id, sID, a));
}
} catch (e)
{
trace("Dispatch event failed " + tuioobj.name);
}
}
}
}
}
// 设置调试显示文本
if(debugMode)
{
debugText.text = "";
debugText.y = -2000;
debugText.x = -2000;
}
for (var i=0; i<objectArray.length; i++ )
{
// 如果当前点非alive,则总objectArray数组中去掉,并且清楚当前点。
if(objectArray[i].isAlive == false)
{
objectArray[i].kill();
thestage.removeChild(objectArray[i].spr);
objectArray.splice(i, 1);
i--;
}
else
{
// 调试状态下显示当前点的坐标(stageX和stageY)
if(debugMode)
{
debugText.appendText(" " + (i + 1) +" - " +objectArray[i].ID + " X:" + int(objectArray[i].x) + " Y:" + int(objectArray[i].y) + " \n");
debugText.x = thestage.stageWidth-160;
debugText.y = 40;
}
}
}
}
private static function toggleDebug(e:Event)
{
if(!debugMode){
debugMode=true;
FLOSCSocket.connect(FLOSCSocketHost, FLOSCSocketPort);
e.target.x=20;
}
else{
debugMode=false;
FLOSCSocket.connect(FLOSCSocketHost, FLOSCSocketPort);
e.target.x=0;
}
// show XML
//bRecording = false;
//debugMode = false;
//debugText.text = recordedXML.toString();
//debugText.x = 0;
//debugText.y = 0;
}
private static function closeHandler(event:Event):void {
//trace("closeHandler: " + event);
}
private static function connectHandler(event:Event):void {
// trace("connectHandler: " + event);
}
private static function dataHandler(event:DataEvent):void {
//trace("dataHandler: " + event);
if(bRecording)
recordedXML.appendChild( XML(event.data) );
processMessage(XML(event.data));
}
private static function ioErrorHandler(event:IOErrorEvent):void {
// thestage.tfDebug.appendText("ioError: " + event + "\n");
trace("ioErrorHandler: " + event);
}
private static function progressHandler(event:ProgressEvent):void {
//trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal);
}
private static function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
// thestage.tfDebug.appendText("securityError: " + event + "\n");
}
}
}
相关推荐
关于组织参加“第八届‘泰迪杯’数据挖掘挑战赛”的通知-4页
PyMySQL-1.1.0rc1.tar.gz
技术资料分享CC2530中文数据手册完全版非常好的技术资料.zip
docker构建php开发环境
VB程序实例,可供参考学习使用,希望对你有所帮助
pytz库的主要功能 时区转换:pytz库允许用户将时间从一个时区转换到另一个时区,这对于处理跨国业务或需要处理多地时间的数据分析尤为重要。 历史时区数据支持:pytz库不仅提供了当前的时区数据,还包含了历史上不同时期的时区信息,这使得它在处理历史数据时具有无与伦比的优势。 夏令时处理:pytz库能够自动处理夏令时的变化,当获取某个时区的时间时,它会自动考虑是否处于夏令时期间。 与datetime模块集成:pytz库可以与Python标准库中的datetime模块一起使用,以确保在涉及不同时区的场景中时间的准确性。
VB程序实例-为程序添加快捷键.zip
画2、3维的隐含数
pytz库的主要功能 时区转换:pytz库允许用户将时间从一个时区转换到另一个时区,这对于处理跨国业务或需要处理多地时间的数据分析尤为重要。 历史时区数据支持:pytz库不仅提供了当前的时区数据,还包含了历史上不同时期的时区信息,这使得它在处理历史数据时具有无与伦比的优势。 夏令时处理:pytz库能够自动处理夏令时的变化,当获取某个时区的时间时,它会自动考虑是否处于夏令时期间。 与datetime模块集成:pytz库可以与Python标准库中的datetime模块一起使用,以确保在涉及不同时区的场景中时间的准确性。
加载虚拟光驱并打开ma软件.
VB程序实例-图像的缩小.zip
Matlab领域上传的视频均有对应的完整代码,皆可运行,亲测可用,适合小白; 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作
yolo系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值
推荐几个国外 Java 大佬的优质博客.docx
Arduino一分钟快速在vs code 编译开发Arduino
强网杯objective-c可视化演示5中的常见排序算法,包括选择排序、气泡排序、插入排序、快速排序、堆排序等.zip
VB程序实例,可供参考学习使用,希望对你有所帮助
yolo系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值
强网杯
技术资料分享AT070TN92非常好的技术资料.zip