/**
* 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.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.squidy.manager.controls.CheckBox;
import org.squidy.manager.controls.TextField;
import org.squidy.manager.data.DataConstant;
import org.squidy.manager.data.Processor;
import org.squidy.manager.data.Property;
import org.squidy.manager.data.Throughput;
import org.squidy.manager.data.impl.DataButton;
import org.squidy.manager.data.impl.DataObject;
import org.squidy.manager.data.impl.DataPosition2D;
import org.squidy.manager.model.AbstractNode;
/**
* <code>ContactGestures</code>.
*
* <pre>
* Date: June 13, 2008
* Time: 1:34:36 AM
* </pre>
*
* @author Werner Koenig, werner.koenig@uni-konstanz.de, University of Konstanz
* @author Roman Rädle, <a
* href="mailto:Roman.Raedle@uni-konstanz.de">Roman.Raedle@uni-konstanz.de</a>, University
* of Konstanz
* @version $Id: ContactGestures.java 772 2011-09-16 15:39:44Z raedle $
* @since 1.0.0
*/
@XmlType(name = "Contact Gestures")
@Processor(
name = "Contact Gestures",
icon = "/org/squidy/nodes/image/48x48/tactilefinger.png",
description = "/org/squidy/nodes/html/ContactGestures.html",
types = { Processor.Type.FILTER },
tags = {"touch", "gesture", "contact", "button", "click", "multitouch"}
)
public class ContactGestures extends AbstractNode {
// Logger to log info, error, debug,... messages.
private static Log LOG = LogFactory.getLog(ContactGestures.class);
// ################################################################################
// BEGIN OF ADJUSTABLES
// ################################################################################
@XmlAttribute(name = "timeout")
@Property(
name = "Timeout",
suffix = "ms"
)
@TextField
private int timeout = 80;
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
@XmlAttribute(name = "maximum-distance")
@Property(
name = "Maximum distance"
)
@TextField
private double maximumDistance = 0.05;
public double getMaximumDistance() {
return maximumDistance;
}
public void setMaximumDistance(double maximumDistance) {
this.maximumDistance = maximumDistance;
}
@XmlAttribute(name = "first-hit")
@Property(
name = "First hit"
)
@CheckBox
private boolean firstHit = false;
public boolean getFirstHit() {
return firstHit;
}
public void setFirstHit(boolean firstHit) {
this.firstHit = firstHit;
}
// ################################################################################
// END OF ADJUSTABLES
// ################################################################################
private Map<Object, DataPosition2D[]> contacts;
/**
* {@inheritDoc}
*/
public DataPosition2D process(DataPosition2D data2d) {
Object sessionID = data2d.getAttribute(DataConstant.SESSION_ID);
if(sessionID==null) return data2d;
// System.out.println(contacts.size());
DataPosition2D[] data = contacts.get(sessionID);
if (data == null) {
// System.out.println("new session id: "+sessionID);
DataPosition2D data2dClone = data2d.getClone();
contacts.put(sessionID,
new DataPosition2D[] { data2dClone, data2dClone });
if(firstHit){
DataButton dataButtonTrue = new DataButton(ContactGestures.class, DataButton.BUTTON_1, true);
//TODO DeepClone!!!
dataButtonTrue.setAttribute(DataConstant.SESSION_ID,sessionID);
dataButtonTrue.setAttribute(DataConstant.DEVICE_ID, data2d.getAttribute(DataConstant.DEVICE_ID));
DataButton dataButtonFalse = new DataButton(ContactGestures.class, DataButton.BUTTON_1, false);
//TODO DeepClone!!!
dataButtonFalse.setAttribute(DataConstant.SESSION_ID,sessionID);
dataButtonFalse.setAttribute(DataConstant.DEVICE_ID, data2d.getAttribute(DataConstant.DEVICE_ID));
publish(data2d, dataButtonTrue);
publish(data2d, dataButtonFalse);
}
// for (Map.Entry<Object, DataPosition2D[]> contact : contacts.entrySet()) {
// DataPosition2D[] pos = contact.getValue();
// System.out.println(pos[0].getAttribute(DataConstant.SESSION_ID));
// }
}
else {
// System.out.println("old session id: "+sessionID);
data[1] = data2d.getClone();
// System.out.println(data2d.getAttribute(DataConstant.SESSION_ID));
contacts.put(sessionID, data);
}
return data2d;
}
/* (non-Javadoc)
* @see org.squidy.manager.ReflectionProcessable#onStart()
*/
@Override
public void onStart() {
contacts = new ConcurrentHashMap<Object, DataPosition2D[]>();
Thread t = new Thread(new Runnable() {
/*
* (non-Javadoc)
*
* @see java.lang.Runnable#run()
*/
public void run() {
while (isProcessing()) {
long timestamp = System.currentTimeMillis();
// System.out.println(contacts.size());
for (Map.Entry<Object, DataPosition2D[]> contact : contacts.entrySet()) {
DataPosition2D[] data = contact.getValue();
if (timestamp - data[1].getTimestamp() > timeout) {
double x1 = data[0].getX();
double x2 = data[1].getX();
double y1 = data[0].getY();
double y2 = data[1].getY();
double distX = x1-x2;
double distY = y1-y2;
double distAbs = Math.sqrt(distX * distX + distY * distY);
if (distAbs <= maximumDistance) {
if(!firstHit){
DataButton dataButtonTrue = new DataButton(ContactGestures.class, DataButton.BUTTON_1, true);
//TODO DeepClone!!!
dataButtonTrue.setAttribute(DataConstant.SESSION_ID, data[1].getAttribute(DataConstant.SESSION_ID));
dataButtonTrue.setAttribute(DataConstant.DEVICE_ID, data[1].getAttribute(DataConstant.DEVICE_ID));
DataButton dataButtonFalse = new DataButton(ContactGestures.class, DataButton.BUTTON_1, false);
//TODO DeepClone!!!
dataButtonFalse.setAttribute(DataConstant.SESSION_ID, data[1].getAttribute(DataConstant.SESSION_ID));
dataButtonFalse.setAttribute(DataConstant.DEVICE_ID, data[1].getAttribute(DataConstant.DEVICE_ID));
publish(data[1], dataButtonTrue);
publish(data[1], dataButtonFalse);
}
// System.out.println(contact.getKey()+" removed");
contacts.remove(contact.getKey());
}
}
}
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
if (LOG.isErrorEnabled()) {
LOG.error(e.getMessage(), e);
}
}
}
}
});
// t.setPriority(Thread.MIN_PRIORITY);
t.start();
}
}