org.squidy.nodes.ReacTIVision.java Source code

Java tutorial

Introduction

Here is the source code for org.squidy.nodes.ReacTIVision.java

Source

/**
 * 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.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.xml.bind.Unmarshaller;
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.ProcessException;
import org.squidy.manager.controls.CheckBox;
import org.squidy.manager.controls.ComboBox;
import org.squidy.manager.controls.Slider;
import org.squidy.manager.controls.TextField;
import org.squidy.manager.controls.ComboBoxControl.ComboBoxItemWrapper;
import org.squidy.manager.data.DataConstant;
import org.squidy.manager.data.Processor;
import org.squidy.manager.data.Property;
import org.squidy.manager.data.Processor.Status;
import org.squidy.manager.data.domainprovider.DomainProvider;
import org.squidy.manager.data.impl.DataPosition2D;
import org.squidy.manager.model.AbstractNode;
import org.squidy.nodes.reactivision.TuioClient;
import org.squidy.nodes.reactivision.TuioCursor;
import org.squidy.nodes.reactivision.TuioListener;
import org.squidy.nodes.reactivision.TuioObject;
import org.squidy.nodes.reactivision.remote.CalibrationWindow;
import org.squidy.nodes.reactivision.remote.control.CameraSettingsContainer;
import org.squidy.nodes.reactivision.remote.control.ControlServer;
import org.squidy.nodes.reactivision.remote.control.FiducialSet;
import org.squidy.nodes.reactivision.remote.image.ImageServer;

/**
 * <code>ReacTIVision</code>.
 * 
 * <pre>
 * Date: Okt 30, 2009
 * Time: 15:08:41 PM
 * </pre>
 * 
 * @author Andreas Ergenzinger, <a
 *         href="mailto:andreas.ergenzinger@uni-konstanz.de">andreas.ergenzinger@uni-konstanz.de</a>
 *         Human-Computer Interaction Group University of Konstanz
 * 
 * @version $Id: ReacTIVision.java 772 2011-09-16 15:39:44Z raedle $
 * @since 1.1.0
 */
@XmlType(name = "reacTIVision")
@Processor(name = "reacTIVision", icon = "/org/squidy/nodes/image/48x48/reactivision.png", description = "/org/squidy/nodes/html/ReacTIVision.html", types = {
        Processor.Type.INPUT }, tags = { "reactivision", "fiducial", "id", "token" })
public class ReacTIVision extends AbstractNode implements TuioListener {

    // Logger to log info, error, debug,... messages.
    private static final Log LOG = LogFactory.getLog(ReacTIVision.class);

    public static final DataConstant TUIO_TOKEN = DataConstant.get(String.class, "TUIO_TOKEN");
    public static final DataConstant TUIO_CURSOR = DataConstant.get(String.class, "TUIO_CURSOR");
    public static final DataConstant TUIO_ALIVE = DataConstant.get(Vector.class, "TUIO_ALIVE");

    public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
        if (enableRemoteConfiguration)
            startCommServers();
    }

    // ################################################################################
    // BEGIN OF ADJUSTABLES
    // ################################################################################

    @XmlAttribute(name = "reactivision-identifier")
    @Property(name = "ReacTIVision Identifier", description = "Information about which camera and ReacTIVision instance will connect to this node.")
    @TextField
    private String reactivisionIdentifier = "id";

    /**
     * @return the port
     */
    public final String getReactivisionIdentifier() {
        return reactivisionIdentifier;
    }

    public void setReactivisionIdentifier(String reactivisionIdentifier) {
        this.reactivisionIdentifier = reactivisionIdentifier;
    }

    @XmlAttribute(name = "tuio-port")
    @Property(name = "TUIO Port", description = "The port on which the reacTIVision node receives TUIO messages.")
    @TextField
    private int tuioPort = 4444;

    /**
     * @return the port
     */
    public final int getTuioPort() {
        return tuioPort;
    }

    /**
     * Makes the following changes:
     * <ul>
     * <li>tuioPort = port</li>
     * <li>controlServerPort = port + 1</li>
     * <li>imageServerPort = port + 2</li>
     * </ul>
     * @param port the new value for the tuioPort variable
     */
    public final void setTuioPort(int port) {
        //set all affected port numbers
        tuioPort = port;
        refreshControlServerPort(port + CONTROL_SERVER_OFFSET);
        refreshImageServerPort(port + IMAGE_SERVER_OFFSET);

        if (tuioClient != null) {
            stop();
            start();
        }
    }

    // ################################################################################

    @XmlAttribute(name = "periodic-messages")
    @Property(name = "Periodic messages", description = "Sends a periodic update every second just to indicate that the tracker is still available and to correct eventually lost packets in between")
    @CheckBox
    private boolean periodicMessages = false;

    public synchronized boolean isPeriodicMessages() {
        return periodicMessages;
    }

    public synchronized void setPeriodicMessages(boolean periodicMessages) {
        this.periodicMessages = periodicMessages;

        if (isProcessing() && periodicMessages) {
            startPeriodicMessages();
        }
    }

    // ################################################################################

    @XmlAttribute(name = "counter-clockwise-angle")
    @Property(name = "Counter clockwise angle", description = "Returns the object angle in a counter clockwise manner.")
    @CheckBox
    private boolean counterClockwiseAngle = false;

    public boolean isCounterClockwiseAngle() {
        return counterClockwiseAngle;

    }

    public void setCounterClockwiseAngle(boolean counterClockwiseAngle) {
        this.counterClockwiseAngle = counterClockwiseAngle;

    }

    //REMOTE CONFIGURATION

    private ControlServer controlServer;
    private ImageServer imageServer;
    private CalibrationWindow calibrationWindow;

    @XmlAttribute(name = "enable-remote-configuration")
    @Property(name = "Enable remote configuration", group = "Camera Configuration")
    @CheckBox
    private boolean enableRemoteConfiguration = false;

    public boolean isEnableRemoteConfiguration() {
        return enableRemoteConfiguration;
    }

    public void setEnableRemoteConfiguration(boolean enableRemoteConfiguration) {
        if (enableRemoteConfiguration == true) {
            int result = startCommServers();
            switch (result) {
            case 0:
                //everything is fine
                this.enableRemoteConfiguration = enableRemoteConfiguration;
                break;
            case 1:
                showErrorPopUp(
                        "Could not create ControlServer, since port " + (tuioPort + 1) + " is already in use.");
                break;
            case 2:
                showErrorPopUp(
                        "Could not create ImageServer, since port " + (tuioPort + 2) + " is already in use.");
                break;
            case 3:
                showErrorPopUp("Could not create ControlServer and ImageServer, since " + "ports " + (tuioPort + 1)
                        + " and " + (tuioPort + 2) + " are already in use.");
            }
        } else {
            this.enableRemoteConfiguration = enableRemoteConfiguration;
            if (calibrationWindow != null)
                calibrationWindow.dispose();
            this.refreshGridCalibration(MODE_OFF);
            stopCommServers();
        }
    }

    private int startCommServers() {
        stopCommServers();
        controlServer = new ControlServer(this, tuioPort + CONTROL_SERVER_OFFSET);
        imageServer = new ImageServer(tuioPort + IMAGE_SERVER_OFFSET);
        int i = 0;
        if (!controlServer.start())
            i += 1;
        if (!imageServer.start())
            i += 2;
        return i;
    }

    private void stopCommServers() {
        if (controlServer != null)
            controlServer.stop();
        if (imageServer != null)
            imageServer.stop();
    }

    public static void showErrorPopUp(String errorMessage) {
        //get screen size
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        //create pop up
        final JFrame frame = new JFrame();
        frame.setResizable(false);
        frame.setAlwaysOnTop(true);
        frame.setUndecorated(true);
        JLabel text = new JLabel(" " + errorMessage + " ");
        frame.getContentPane().setBackground(Color.RED);
        text.setForeground(Color.WHITE);
        frame.add(text);
        frame.pack();
        frame.setLocation((dim.width - frame.getWidth()) / 2, (dim.height - frame.getHeight()) / 2);
        frame.setVisible(true);
        frame.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent arg0) {
                frame.dispose();
            }
        });
    }

    //############################################################################
    /**
     * controlServerPort - tuioPort = ...
     */
    private static final int CONTROL_SERVER_OFFSET = 1;

    @XmlAttribute(name = "control-server-port")
    @Property(name = "ControlServer Port", group = "Camera Configuration", description = "The port ReacTIVision will connect to in order to receive control messages.")
    @TextField
    private int controlServerPort = tuioPort + CONTROL_SERVER_OFFSET;

    public final int getControlServerPort() {
        return controlServerPort;
    }

    public final void setControlServerPort(int controlServerPort) {
        if (controlServerPort != this.controlServerPort) {
            //do not change port number
            //but show message ...
            publishNotification("ControlServer port number depends on TUIO port number.");
            //... and reset displayed value
            refreshControlServerPort(tuioPort + CONTROL_SERVER_OFFSET);
        }
    }

    public final void refreshControlServerPort(int controlServerPort) {
        fireStatusChange("controlServerPort", "", ((Integer) controlServerPort).toString());
        this.controlServerPort = controlServerPort;
    }

    //############################################################################

    private static final int IMAGE_SERVER_OFFSET = 2;

    @XmlAttribute(name = "image-server-port")
    @Property(name = "ImageServer Port", group = "Camera Configuration", description = "The port ReacTIVision will connect to in order to send image data to Squidy.")
    @TextField
    private int imageServerPort = tuioPort + IMAGE_SERVER_OFFSET;

    public final int getImageServerPort() {
        return imageServerPort;
    }

    public final void setImageServerPort(int imageServerPort) {
        if (imageServerPort != this.imageServerPort) {
            //do not change port number
            //but show message ...
            publishNotification("ImageServer port number depends on TUIO port number.");
            //... and reset displayed value
            refreshImageServerPort(tuioPort + IMAGE_SERVER_OFFSET);
        }
    }

    public final void refreshImageServerPort(int imageServerPort) {
        fireStatusChange("imageServerPort", "", ((Integer) imageServerPort).toString());
        this.imageServerPort = imageServerPort;
    }

    //############################################################################

    public final static int MODE_OFF = 0;
    public final static int MODE_ON = 1;

    @XmlAttribute(name = "grid-calibration")
    @Property(name = "Grid Calibration", group = "Camera Configuration")
    @ComboBox(domainProvider = OnOffModeDomainProvider.class)
    private int gridCalibration = MODE_OFF;

    public int getGridCalibration() {
        return gridCalibration;
    }

    public void setGridCalibration(int mode) {
        this.gridCalibration = mode;
        if (enableRemoteConfiguration) {
            if (mode == MODE_ON) {
                calibrationWindow = new CalibrationWindow(this, controlServer, imageServer);
                calibrationWindow.setVisible(true);
            } else {
                if (calibrationWindow != null)
                    calibrationWindow.dispose();
            }
        } else if (mode == MODE_ON) {
            //prevent setting mode to MODE_ON
            fireStatusChange("gridCalibration", MODE_ON, MODE_OFF);
        }
    }

    public void refreshGridCalibration(int mode) {
        fireStatusChange("gridCalibration", getGridCalibration(), mode);
    }

    @XmlAttribute(name = "framerate")
    @Property(name = "Framerate", group = "Camera Configuration", description = "Camera framerate")
    @Slider(type = Integer.class, minimumValue = 0, maximumValue = 80, showLabels = true, showTicks = true, majorTicks = 20, minorTicks = 10, snapToTicks = false)
    private int framerate = 20;

    public int getFramerate() {
        return framerate;
    }

    public void setFramerate(int framerate) {
        this.framerate = framerate;
        if (enableRemoteConfiguration) {
            controlServer.setFramerate((float) framerate);
            refreshCameraSettings();
        }
    }

    public void refreshFramerate(int framerate) {
        fireStatusChange("framerate", getFramerate(), framerate);
        this.framerate = framerate;
    }

    @XmlAttribute(name = "exposure-time")
    @Property(name = "Exposure Time", group = "Camera Configuration", description = "Camera exposure time")
    @Slider(type = Integer.class, minimumValue = 0, maximumValue = 50, showLabels = true, showTicks = true, majorTicks = 10, minorTicks = 5, snapToTicks = false)
    private int exposureTime = 20;

    public int getExposureTime() {
        return exposureTime;
    }

    public void setExposureTime(int exposureTime) {
        this.exposureTime = exposureTime;
        if (enableRemoteConfiguration) {
            controlServer.setExposureTime((float) exposureTime);
            refreshCameraSettings();
        }
    }

    public void refreshExposureTime(int exposureTime) {
        fireStatusChange("exposureTime", getExposureTime(), exposureTime);
        this.exposureTime = exposureTime;
    }

    @XmlAttribute(name = "pixel-clock")
    @Property(name = "Pixel Clock", group = "Camera Configuration", description = "Camera pixel clock value")
    @Slider(type = Integer.class, minimumValue = 0, maximumValue = 60, showLabels = true, showTicks = true, majorTicks = 10, minorTicks = 1, snapToTicks = false)
    private int pixelClock = 30;

    public int getPixelClock() {
        return pixelClock;
    }

    public void setPixelClock(int pixelClock) {
        this.pixelClock = pixelClock;
        if (enableRemoteConfiguration) {
            controlServer.setPixelClock(pixelClock);
            refreshCameraSettings();
        }
    }

    public void refreshPixelClock(int pixelClock) {
        fireStatusChange("pixelClock", getPixelClock(), pixelClock);
        this.pixelClock = pixelClock;
    }

    @XmlAttribute(name = "hardware-gain")
    @Property(name = "Hardware Gain", group = "Camera Configuration", description = "Hardware gain")
    @Slider(type = Integer.class, minimumValue = 0, maximumValue = 100, showLabels = true, showTicks = true, majorTicks = 20, minorTicks = 5, snapToTicks = false)
    private int hardwareGain = 30;

    public int getHardwareGain() {
        return hardwareGain;
    }

    public void setHardwareGain(int hardwareGain) {
        this.hardwareGain = hardwareGain;
        if (enableRemoteConfiguration) {
            controlServer.setHardwareGain(hardwareGain);
            refreshCameraSettings();
        }
    }

    public void refreshHardwareGain(int hardwareGain) {
        fireStatusChange("hardwareGain", getHardwareGain(), hardwareGain);
        this.hardwareGain = hardwareGain;
    }

    @XmlAttribute(name = "edge-enhancement")
    @Property(name = "Edge Enhancement", group = "Camera Configuration", description = "Edge enhancement")
    @Slider(type = Integer.class, minimumValue = 0, maximumValue = 2, showLabels = true, showTicks = true, majorTicks = 1, minorTicks = 1, snapToTicks = true)
    private int edgeEnhancement = 0;

    public int getEdgeEnhancement() {
        return edgeEnhancement;
    }

    public void setEdgeEnhancement(int edgeEnhancement) {
        this.edgeEnhancement = edgeEnhancement;
        if (enableRemoteConfiguration) {
            controlServer.setEdgeEnhancement(edgeEnhancement);
            refreshCameraSettings();
        }
    }

    public void refreshEdgeEnhancement(int edgeEnhancement) {
        fireStatusChange("edgeEnhancement", getEdgeEnhancement(), edgeEnhancement);
        this.edgeEnhancement = edgeEnhancement;
    }

    @XmlAttribute(name = "gamma")
    @Property(name = "Gamma", group = "Camera Configuration", description = "Gamma. Default value is 100.")
    @Slider(type = Integer.class, minimumValue = 0, maximumValue = 1000, showLabels = true, showTicks = true, majorTicks = 250, minorTicks = 50, snapToTicks = false)
    private int gamma = 100;

    public int getGamma() {
        return gamma;
    }

    public void setGamma(int gamma) {
        this.gamma = gamma;
        if (enableRemoteConfiguration) {
            controlServer.setGamma(gamma);
            refreshCameraSettings();
        }
    }

    public void refreshGamma(int gamma) {
        fireStatusChange("gamma", getGamma(), gamma);
        this.gamma = gamma;
    }

    public void refreshCameraSettings() {
        final CameraSettingsContainer container = controlServer.getCameraSettings();
        if (container == null)
            return;
        //else

        refreshFramerate(Math.round(container.framerate));
        refreshExposureTime(Math.round(container.exposureTime));
        refreshPixelClock(container.pixelClock);
        refreshHardwareGain(container.hardwareGain);
        refreshEdgeEnhancement(container.edgeEnhancement);
        refreshGamma(container.gamma);

    }

    @XmlAttribute(name = "fiducial-set")
    @Property(name = "Fiducial Set", group = "Camera Configuration")
    @ComboBox(domainProvider = FiducialSetDomainProvider.class)
    private FiducialSet fiducialSet = FiducialSet.AMOEBA_DEFAULT;

    public FiducialSet getFiducialSet() {
        return fiducialSet;
    }

    public void setFiducialSet(FiducialSet fiducialSet) {
        this.fiducialSet = fiducialSet;

        //make ReacTIVision write the desired set into its configuration file,
        //terminate and restart ReacTIVision 
        if (enableRemoteConfiguration)
            controlServer.setFiducialSet(fiducialSet);
    }

    public void refreshFiducialSet(FiducialSet fiducialSet) {
        fireStatusChange("fiducialSet", getFiducialSet(), fiducialSet);
        this.fiducialSet = fiducialSet;
    }

    // ################################################################################
    // END OF ADJUSTABLES
    // ################################################################################

    private TuioClient tuioClient;

    private Thread activePeriodicThread = null;
    private boolean needPeriodicMessage = false;

    /*
     * (non-Javadoc)
     * 
     * @see org.squidy.manager.ReflectionProcessable#onStart()
     */
    @Override
    public void onStart() throws ProcessException {

        if (isPeriodicMessages()) {
            startPeriodicMessages();
        }

        tuioClient = new TuioClient(tuioPort);

        tuioClient.addTuioListener(this);
        tuioClient.connect();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.squidy.manager.ReflectionProcessable#onStop()
     */
    @Override
    public void onStop() throws ProcessException {
        if (tuioClient != null) {
            tuioClient.disconnect();
            tuioClient = null;
        }
        activePeriodicThread = null;
    }

    public static class OnOffModeDomainProvider implements DomainProvider {

        /*
         * (non-Javadoc)
         * 
         * @see
         * org.squidy.manager.data.domainprovider.DomainProvider#getValues
         * ()
         */
        public Object[] getValues() {
            ComboBoxItemWrapper[] values = new ComboBoxItemWrapper[2];
            values[0] = new ComboBoxItemWrapper(MODE_OFF, "Off");
            values[1] = new ComboBoxItemWrapper(MODE_ON, "On");

            return values;
        }
    }

    public static class FiducialSetDomainProvider implements DomainProvider {

        public Object[] getValues() {
            ComboBoxItemWrapper[] values = new ComboBoxItemWrapper[FiducialSet.size()];
            FiducialSet[] fSetValues = FiducialSet.values();
            for (int i = 0; i < values.length; ++i)
                values[i] = new ComboBoxItemWrapper(fSetValues[i], fSetValues[i].name().toLowerCase());

            return values;
        }
    }

    /**
     * 
     */
    private void startPeriodicMessages() {

        if (activePeriodicThread == null) {
            activePeriodicThread = new Thread(new Runnable() {

                /* (non-Javadoc)
                 * @see java.lang.Runnable#run()
                 */
                public void run() {
                    while (isPeriodicMessages()) {
                        needPeriodicMessage = true;
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            stop();
                        }

                        if (isPeriodicMessages() && needPeriodicMessage) {
                            publishObject(null, "periodic");
                        }
                    }
                    activePeriodicThread = null;
                }
            });
            activePeriodicThread.start();
        }
    }

    // ################################################################################
    // BEGIN OF TuioListener
    // ################################################################################

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.squidy.manager.input.impl.reactivision.TuioListener
     * #addTuioObject
     * (org.squidy.manager.input.impl.reactivision.TuioObject)
     */
    public void addTuioObject(TuioObject tuioObject) {
        publishObject(tuioObject, "add");
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.squidy.manager.input.impl.reactivision.TuioListener
     * #updateTuioObject
     * (org.squidy.manager.input.impl.reactivision.TuioObject)
     */
    public void updateTuioObject(TuioObject tuioObject) {
        publishObject(tuioObject, "update");
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.squidy.manager.input.impl.reactivision.TuioListener
     * #removeTuioObject
     * (org.squidy.manager.input.impl.reactivision.TuioObject)
     */
    public void removeTuioObject(TuioObject tuioObject) {
        publishObject(tuioObject, "remove");
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.squidy.manager.input.impl.reactivision.TuioListener
     * #addTuioCursor
     * (org.squidy.manager.input.impl.reactivision.TuioCursor)
     */
    public void addTuioCursor(TuioCursor tuioCursor) {
        // ignore
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.squidy.manager.input.impl.reactivision.TuioListener
     * #updateTuioCursor
     * (org.squidy.manager.input.impl.reactivision.TuioCursor)
     */
    public void updateTuioCursor(TuioCursor tuioCursor) {
        // ignore
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.squidy.manager.input.impl.reactivision.TuioListener
     * #removeTuioCursor
     * (org.squidy.manager.input.impl.reactivision.TuioCursor)
     */
    public void removeTuioCursor(TuioCursor tuioCursor) {
        // ignore
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.squidy.manager.input.impl.reactivision.TuioListener
     * #refresh(long)
     */
    public void refresh(long timestamp) {
        // ignore
    }

    /**
     * @param tuioObject
     * @param objectState
     */
    private void publishObject(TuioObject tuioObject, String objectState) {
        needPeriodicMessage = false;

        DataPosition2D dataPosition2D;
        if (tuioObject != null) {
            dataPosition2D = new DataPosition2D(ReacTIVision.class, tuioObject.getX(), tuioObject.getY());
            dataPosition2D.setAttribute(TUIO.ORIGIN_ADDRESS, "/tuio/2Dobj");
            dataPosition2D.setAttribute(DataConstant.SESSION_ID, ((Long) tuioObject.getSessionID()).intValue());
            dataPosition2D.setAttribute(TUIO.FIDUCIAL_ID, tuioObject.getFiducialID());
            dataPosition2D.setAttribute(TUIO.MOVEMENT_VECTOR_X, tuioObject.getSpeedX());
            dataPosition2D.setAttribute(TUIO.MOVEMENT_VECTOR_Y, tuioObject.getSpeedY());
            dataPosition2D.setAttribute(TUIO.ROTATION_VECTOR_A, tuioObject.getRotationSpeed());
            dataPosition2D.setAttribute(TUIO.ANGLE_A,
                    counterClockwiseAngle ? ((float) ((2 * Math.PI) - tuioObject.getAngle()))
                            : tuioObject.getAngle());
            dataPosition2D.setAttribute(TUIO.ROTATION_ACCELERATION, tuioObject.getRotationAccel());
            dataPosition2D.setAttribute(TUIO.MOTION_ACCELERATION, tuioObject.getMotionAccel());
            dataPosition2D.setAttribute(TUIO.OBJECT_STATE, objectState);
        } else {
            dataPosition2D = new DataPosition2D(ReacTIVision.class, 0, 0);
            dataPosition2D.setAttribute(TUIO.OBJECT_STATE, objectState);
        }

        publish(dataPosition2D);
    }

    // ################################################################################
    // END OF TuioListener
    // ################################################################################
}