/* Squidy Interaction 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 of the License,
* or (at your option) any later version.
*
* Squidy Interaction 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 Squidy Interaction Library. If not, see
* <http://www.gnu.org/licenses/>.
*
* 2009 Human-Computer Interaction Group, University of Konstanz.
* <http://hci.uni-konstanz.de>
*
* Please contact info@squidy-lib.de or visit our website
* <http://www.squidy-lib.de> for further information.
*/
package org.squidy.nodes;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.StringTokenizer;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import org.squidy.manager.controls.TextField;
import org.squidy.manager.data.DataConstant;
import org.squidy.manager.data.IData;
import org.squidy.manager.data.IDataContainer;
import org.squidy.manager.data.Processor;
import org.squidy.manager.data.Property;
import org.squidy.manager.data.Processor.Status;
import org.squidy.manager.data.impl.DataDigital;
import org.squidy.manager.data.impl.DataPosition2D;
import org.squidy.manager.model.AbstractNode;
/**
* <code>BlobToken</code>.
*
* <pre>
* Date: Apr 1, 2010
* Time: 10:38:23 PM
* </pre>
*
* @author Nicolas Hirrle, <a
* href="mailto:nihirrle@htwg-konstanz.de">nihirrle@htwg-
* konstanz.de</a>, University of Konstanz
* @version $Id: BlobToken.java 772 2011-09-16 15:39:44Z raedle $
* @since 1.1.0
*/
@XmlType(name = "BlobToken")
@Processor(
name = "BlobToken",
icon = "/org/squidy/nodes/image/48x48/blobtoken.png",
types = { Processor.Type.FILTER },
tags = {"BlobToken", "hci", "konstanz", "blob", "token" },
status = Status.UNSTABLE
)
public class BlobToken extends AbstractNode {
// ################################################################################
// BEGIN OF PROPERTIES
// ################################################################################
@XmlAttribute(name = "X-Resolution")
@Property(name = "X-Resolution", description = "X-Resolution (in pixel) of the screen")
@TextField
private int resolutionX = 1920;
public int getResolutionX() {
return resolutionX;
}
public void setResolutionX(int resolutionX) {
this.resolutionX = resolutionX;
}
@XmlAttribute(name = "Y-Resolution")
@Property(name = "Y-Resolution", description = "Y-Resolution (in pixel) of the screen")
@TextField
private int resolutionY = 1200;
public int getResolutionY() {
return resolutionY;
}
public void setResolutionY(int resolutionY) {
this.resolutionY = resolutionY;
}
@XmlAttribute(name = "Resolution_token_0")
@Property(name = "Resolution_token_0", description = "Resolution (in pixel) where blob is recogniezd as token 0 (has to be greater than Resolution finger)")
@TextField
private int treshholdT0 = 50;
public int getTreshholdT0() {
return treshholdT0;
}
public void setTreshholdT0(int treshholdT0) {
this.treshholdT0 = treshholdT0;
}
@XmlAttribute(name = "Resolution_token_1")
@Property(name = "Resolution_token_1", description = "Resolution (in pixel) where blob is recogniezd as token 1")
@TextField
private int treshholdT1 = 65;
public int getTreshholdT1() {
return treshholdT1;
}
public void setTreshholdT1(int treshholdT1) {
this.treshholdT1 = treshholdT1;
}
@XmlAttribute(name = "Resolution_token_2")
@Property(name = "Resolution_token_2", description = "Resolution (in pixel) where blob is recogniezd as token 2")
@TextField
private int treshholdT2 = 75;
public int getTreshholdT2() {
return treshholdT2;
}
public void setTreshholdT2(int treshholdT2) {
this.treshholdT2 = treshholdT2;
}
@XmlAttribute(name = "Resolution_token_3")
@Property(name = "Resolution_token_3", description = "Resolution (in pixel) where blob is recogniezd as token 3")
@TextField
private int treshholdT3 = 85;
public int getTreshholdT3() {
return treshholdT3;
}
public void setTreshholdT3(int treshholdT3) {
this.treshholdT3 = treshholdT3;
}
@XmlAttribute(name = "Resolution_token_4")
@Property(name = "Resolution_token_4", description = "Resolution (in pixel) where blob is recogniezd as token 4")
@TextField
private int treshholdT4 = 95;
public int getTreshholdT4() {
return treshholdT4;
}
public void setTreshholdT4(int treshholdT4) {
this.treshholdT4 = treshholdT4;
}
@XmlAttribute(name = "Resolution_token_5")
@Property(name = "Resolution_token_5", description = "Resolution (in pixel) where blob is recogniezd as token 5")
@TextField
private int treshholdT5 = 105;
public int getTreshholdT5() {
return treshholdT5;
}
public void setTreshholdT5(int treshholdT5) {
this.treshholdT5 = treshholdT5;
}
@XmlAttribute(name = "Resolution_finger")
@Property(name = "Resolution_finger", description = "Resolution (in pixel) where blob is recogniezd as a finger. IMPORTANT: Has to be smaller than Token 0!")
@TextField
private int treshholdFinger = 35;
public int getTreshholdFinger() {
return treshholdFinger;
}
public void setTreshholdFinger(int treshholdFinger) {
if (treshholdFinger > treshholdT0)
{
System.err.println("ERROR: TreshholdFinger has to be smaller than treshholdT0!");
treshholdFinger = treshholdT0 -1;
System.err.println("TreshholdFinger is set to" + treshholdFinger);
}
else
this.treshholdFinger = treshholdFinger;
}
@XmlAttribute(name = "TokenID_0")
@Property(name = "TokenID_0", description = "TokenID_for token 0")
@TextField
private int tokenID_0 = 0;
public int getTokenID_0() {
return tokenID_0;
}
public void setTokenID_0(int tokenID_0) {
this.tokenID_0 = tokenID_0;
}
@XmlAttribute(name = "TokenID_1")
@Property(name = "TokenID_1", description = "TokenID_for token 1")
@TextField
private int tokenID_1 = 1;
public int getTokenID_1() {
return tokenID_1;
}
public void setTokenID_1(int tokenID_1) {
this.tokenID_1 = tokenID_1;
}
@XmlAttribute(name = "TokenID_2")
@Property(name = "TokenID_2", description = "TokenID_for token 2")
@TextField
private int tokenID_2 = 2;
public int getTokenID_2() {
return tokenID_2;
}
public void setTokenID_2(int tokenID_2) {
this.tokenID_2 = tokenID_2;
}
@XmlAttribute(name = "TokenID_3")
@Property(name = "TokenID_3", description = "TokenID_for token 3")
@TextField
private int tokenID_3 = 3;
public int getTokenID_3() {
return tokenID_3;
}
public void setTokenID_3(int tokenID_3) {
this.tokenID_3 = tokenID_3;
}
@XmlAttribute(name = "TokenID_4")
@Property(name = "TokenID_4", description = "TokenID_for token 4")
@TextField
private int tokenID_4 = 4;
public int getTokenID_4() {
return tokenID_4;
}
public void setTokenID_4(int tokenID_4) {
this.tokenID_4 = tokenID_4;
}
@XmlAttribute(name = "TokenID_5")
@Property(name = "TokenID_5", description = "TokenID_for token 5")
@TextField
private int tokenID_5 = 5;
public int getTokenID_5() {
return tokenID_5;
}
public void setTokenID_5(int tokenID_5) {
this.tokenID_5 = tokenID_5;
}
// ################################################################################
// END OF PROPERTIES
// ################################################################################
// ################################################################################
// BEGIN OF PROCESSABLE
// ################################################################################
private HashSet<Integer> allTrackedTokens;
public void onStart() {
super.onStart();
allTrackedTokens = new HashSet<Integer>();
}
@Override
public void onStop() {
super.onStop();
allTrackedTokens.clear();
}
public IDataContainer preProcess(IDataContainer dataContainer) {
IData data[] = dataContainer.getData();
HashSet<Integer> currentAlives;
for (int i=0; i<data.length; i++)
{
if (data[i] instanceof DataDigital){
if (data[i].hasAttribute(DataConstant.SESSION_ID)){
int id = (Integer) data[i].getAttribute(DataConstant.SESSION_ID);
if (((DataDigital) data[i]).getFlag() == false){
allTrackedTokens.remove(id);
}
}
}
}
if (data[0] instanceof DataPosition2D) {
DataPosition2D dataPosition2D = (DataPosition2D) data[0];
if (dataPosition2D.hasAttribute(DreaMTouch.TUIO_ALIVE)) {
currentAlives = setHashSetAlives(dataPosition2D);
ArrayList<DataPosition2D> dataFinger = new ArrayList<DataPosition2D>();
ArrayList<DataPosition2D> dataToken = new ArrayList<DataPosition2D>();
DataPosition2D dataFingerAlive = new DataPosition2D(
BlobToken.class, 0, 0);
dataFingerAlive.setAttribute(TUIO.ORIGIN_ADDRESS,
"/tuio/2Dblb");
DataPosition2D dataTokenAlive = new DataPosition2D(
BlobToken.class, 0, 0);
dataTokenAlive.setAttribute(TUIO.ORIGIN_ADDRESS,
"/tuio/2Dobj");
String aliveFinger = new String();
String aliveToken = new String();
for (int i = 1; i < data.length; i++) {
if (data[i] instanceof DataPosition2D) {
DataPosition2D dataTmp = (DataPosition2D) data[i];
if (dataTmp.hasAttribute(TUIO.ORIGIN_ADDRESS)) {
if (dataTmp
.getAttribute(TUIO.ORIGIN_ADDRESS)
.equals("/tuio/2Dblb")) {
DataPosition2D data2D = checkIfToken((DataPosition2D) data[i]);
if (data2D.getAttribute(
TUIO.ORIGIN_ADDRESS).equals(
"/tuio/2Dblb")) {
dataFinger.add(data2D);
} else if (data2D.getAttribute(
TUIO.ORIGIN_ADDRESS).equals(
"/tuio/2Dobj")) {
//System.out.println("published token id: " + data2D.getAttribute(DataConstant.SESSION_ID) + "width: " + data2D.getAttribute(DreaMTouch.TUIO_WIDTH));
dataToken.add(data2D);
}
}
}
}
}
Iterator<Integer> itr = currentAlives.iterator();
while (itr.hasNext()) {
int id = (Integer) itr.next();
if (allTrackedTokens.contains(id)) {
aliveToken = aliveToken + id + " ";
} else {
aliveFinger = aliveFinger + id + " ";
}
}
dataFingerAlive.setAttribute(DreaMTouch.TUIO_ALIVE, aliveFinger);
dataTokenAlive.setAttribute(DreaMTouch.TUIO_ALIVE, aliveToken);
dataFinger.add(0, dataFingerAlive);
dataToken.add(0, dataTokenAlive);
publish(dataFinger);
publish(dataToken);
}
}
return null;
}
// ################################################################################
// END OF PROCESSABLE
// ################################################################################
// ################################################################################
// BEGIN OF USERDEFINED FUNCTIONS
// ################################################################################
private DataPosition2D checkIfToken(DataPosition2D dataPosition2D) {
dataPosition2D = setResolution(dataPosition2D);
float width = (Float) dataPosition2D.getAttribute(TUIO.WIDTH);
// float height = (Float)
// dataPosition2D.getAttribute(DreaMTouch.TUIO_HEIGHT);
// float area = (Float) dataPosition2D.getAttribute(DreaMTouch.TUIO_AREA);
int id = (Integer) dataPosition2D.getAttribute(DataConstant.SESSION_ID);
System.out.println("width: " + width);
DataPosition2D dataToken = null;
if (width < 35) {
// System.out.println("tracked Finger");
dataPosition2D = setResolutionBack(dataPosition2D);
dataPosition2D.setAttribute(TUIO.ORIGIN_ADDRESS,
"/tuio/2Dblb");
return dataPosition2D;
} else {
dataToken = new DataPosition2D(BlobToken.class, dataPosition2D
.getX(), dataPosition2D.getY());
dataToken.setAttribute(TUIO.ORIGIN_ADDRESS, "/tuio/2Dobj");
dataToken.setAttribute(DataConstant.SESSION_ID,
(Integer) dataPosition2D
.getAttribute(DataConstant.SESSION_ID));
dataToken.setAttribute(TUIO.MOVEMENT_VECTOR_X, dataPosition2D
.getAttribute(TUIO.MOVEMENT_VECTOR_X));
dataToken.setAttribute(TUIO.MOVEMENT_VECTOR_Y, dataPosition2D
.getAttribute(TUIO.MOVEMENT_VECTOR_Y));
dataToken.setAttribute(TUIO.ROTATION_VECTOR_A, dataPosition2D
.getAttribute(TUIO.ROTATION_VECTOR_A));
dataToken.setAttribute(TUIO.ANGLE_A, 0f);
dataToken.setAttribute(TUIO.ROTATION_ACCELERATION, dataPosition2D
.getAttribute(TUIO.ROTATION_ACCELERATION));
dataToken.setAttribute(TUIO.MOTION_ACCELERATION, dataPosition2D
.getAttribute(TUIO.ROTATION_ACCELERATION));
if (width < treshholdT0) {
dataToken.setAttribute(TUIO.FIDUCIAL_ID, tokenID_0);
} else if (width < treshholdT1) {
dataToken.setAttribute(TUIO.FIDUCIAL_ID, tokenID_1);
} else if (width < treshholdT2) {
dataToken.setAttribute(TUIO.FIDUCIAL_ID, tokenID_2);
} else if (width < treshholdT3) {
dataToken.setAttribute(TUIO.FIDUCIAL_ID, tokenID_3);
} else if (width < treshholdT4) {
dataToken.setAttribute(TUIO.FIDUCIAL_ID, tokenID_4);
} else if (width < treshholdT5) {
dataToken.setAttribute(TUIO.FIDUCIAL_ID, tokenID_5);
}
// System.out.println("tracked token with id: " + dataToken.getAttribute(TUIO.FIDUCIAL_ID));
}
System.out.println("width: " + width + "tokenid" + dataToken.getAttribute(TUIO.FIDUCIAL_ID));
DataPosition2D Pos2DTmp = setResolutionBack(dataPosition2D);
width = (Float) Pos2DTmp.getAttribute(TUIO.WIDTH);
double x = Pos2DTmp.getX();
double y = Pos2DTmp.getY();
dataToken.setX(x);
dataToken.setY(y);
dataToken.setAttribute(TUIO.WIDTH, width);
dataToken.setAttribute(DataConstant.SESSION_ID, id);
allTrackedTokens.add(id);
return dataToken;
}
private HashSet<Integer> setHashSetAlives(DataPosition2D dataPosition2D) {
HashSet<Integer> alives = new HashSet<Integer>();
String alivestr = (String) dataPosition2D
.getAttribute(DreaMTouch.TUIO_ALIVE);
if (alivestr != null) {
StringTokenizer st = new StringTokenizer(alivestr, " ");
String sid = new String();
while (st.hasMoreElements()) {
sid = st.nextToken();
int id = Integer.parseInt(sid);
alives.add(id);
}
}
return alives;
}
private DataPosition2D setResolutionBack(DataPosition2D dataPosition2D) {
double x = dataPosition2D.getX();
if (x > 1) {
x = x / resolutionX;
dataPosition2D.setX(x);
}
double y = dataPosition2D.getY();
if (y > 1) {
y = y / resolutionY;
dataPosition2D.setY(y);
}
float width = (Float) dataPosition2D.getAttribute(TUIO.WIDTH);
width = width / resolutionY;
dataPosition2D.setAttribute(TUIO.WIDTH, width);
return dataPosition2D;
}
private DataPosition2D setResolution(DataPosition2D dataPosition2D) {
double x = dataPosition2D.getX();
x = Math.round(x * resolutionX);
double y = dataPosition2D.getY();
y = Math.round(y * resolutionY);
dataPosition2D.setX(x);
dataPosition2D.setY(y);
float width = (Float) dataPosition2D.getAttribute(TUIO.WIDTH);
width = Math.round(width * resolutionY);
dataPosition2D.setAttribute(TUIO.WIDTH, width);
return dataPosition2D;
}
// ################################################################################
// END OF USERDEFINED FUNCTIONS
// ################################################################################
}