package org.squidy.nodes.optitrack; import java.awt.Point; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlType; import javax.swing.KeyStroke; import javax.vecmath.*; import org.apache.poi.hwpf.usermodel.DateAndTime; 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.IData; import org.squidy.manager.data.IDataContainer; import org.squidy.manager.data.Processor; import org.squidy.manager.data.Property; import org.squidy.manager.data.domainprovider.DomainProvider; import org.squidy.manager.data.impl.DataButton; import org.squidy.manager.data.impl.DataDigital; import org.squidy.manager.data.impl.DataPosition2D; import org.squidy.manager.data.impl.DataPosition3D; import org.squidy.manager.data.impl.DataPosition6D; import org.squidy.manager.data.impl.DataString; import org.squidy.manager.model.AbstractNode; import org.squidy.manager.util.DataUtility; import org.squidy.manager.util.MathUtility; import org.squidy.nodes.Keyboard; import org.squidy.nodes.MouseIO; import org.squidy.nodes.Tracking; import org.squidy.nodes.optitrack.RigidBody.RB_MODEDomainProvider; import org.squidy.nodes.optitrack.intercept.FilterQueue; import org.squidy.nodes.optitrack.intercept.InterceptObject; import org.squidy.nodes.optitrack.intercept.Intersection; import org.squidy.nodes.optitrack.intercept.PointingDevice; import org.squidy.nodes.optitrack.utils.TrackingConstant; import org.squidy.nodes.optitrack.utils.TrackingUtility; import com.sun.opengl.util.Screenshot; /*<code>MultiIntersection</code>. * * <pre> * Date: Jan 29 2010 * Time: 1:35:05 AM * </pre> * * @author Simon Faeh, < href="mailto:simon.faeh@uni-konstanz.de">Simon.Faeh@uni-konstanz.de</>, University f Konstanz * * @version $Id$ */ @XmlType(name = "MultiIntersection") @Processor( name = "MultiIntersection", icon = "/org/squidy/nodes/image/48x48/intercept.png", description = "", types = {Processor.Type.OUTPUT, Processor.Type.INPUT }, tags = { "optitrack", "handtracking", "intersection" } ) public class MultiIntersection extends AbstractNode { // ################################################################################ // BEGIN OF ADJUSTABLES // ################################################################################ @XmlAttribute(name = "rbMode") @Property( name = "Force Pointingmode", description = "Forces the use of the same Pointingmode for any device" ) @ComboBox(domainProvider = RB_MODEDomainProvider.class) private int rbMode = TrackingConstant.RBMODE_NONE; public final int getRbMode() { return rbMode; } public final void setRbMode(int rbMode) { this.rbMode = rbMode; this.maxDirectPointRatio = (double)maxDPR / 100.0; this.minDirectPointRatio = (double)minDPR / 100.0; this.increasingSpeedThresold = (double)incSpeedThres / 100.0; pointingDevices = new ArrayList<PointingDevice>(); calcPoints = new FilterQueue(50); } // ################################################################################ @XmlAttribute(name = "minHybridSpeedThreshold") @Property( name = "Min Acceleration Threshold (Weighting)", description = "Min Acceleration Threshold (Weighting)", group ="Hybrid", suffix = "" ) @Slider( type = Integer.class, minimumValue = 0, maximumValue = 40, showLabels = true, showTicks = true, majorTicks = 10, minorTicks = 1, snapToTicks = true ) private int minHybridSpeedThreshold = 5; public int getMinHybridSpeedThreshold() { return minHybridSpeedThreshold; } public void setMinHybridSpeedThreshold(int minHybridSpeedThreshold) { this.minHybridSpeedThreshold = minHybridSpeedThreshold; } // ################################################################################ @XmlAttribute(name = "maxHybridSpeedThreshold") @Property( name = "Max Acceleration Threshold (Weighting)", description = "Max Acceleration Threshold (Weighting)", group ="Hybrid", suffix = "" ) @Slider( type = Integer.class, minimumValue = 0, maximumValue = 40, showLabels = true, showTicks = true, majorTicks = 10, minorTicks = 1, snapToTicks = true ) private int maxHybridSpeedThreshold = 11; public int getMaxHybridSpeedThreshold() { return maxHybridSpeedThreshold; } public void setMaxHybridSpeedThreshold(int maxHybridSpeedThreshold) { this.maxHybridSpeedThreshold = maxHybridSpeedThreshold; } // ################################################################################ @XmlAttribute(name = "maxDirectPointRatio") @Property( name = "Maximum DirectPointing Ratio", description = "Maximum ratio the directPionting value can get", group ="Hybrid", suffix = "%" ) @Slider( type = Integer.class, minimumValue = 50, maximumValue = 150, showLabels = true, showTicks = true, majorTicks = 50, minorTicks = 1, snapToTicks = true ) private int maxDPR = 80; private double maxDirectPointRatio; public int getMaxDPR() { return maxDPR; } public void setMaxDPR(int maxDirectPointRatio) { this.maxDPR = maxDirectPointRatio; this.maxDirectPointRatio = this.maxDPR / 100.0; } // ################################################################################ @XmlAttribute(name = "minDirectPointRatio") @Property( name = "Minimum DirectPointing Ratio", description = "Minimum ratio the directPionting value can get", group ="Hybrid", suffix = "%" ) @Slider( type = Integer.class, minimumValue = 0, maximumValue = 30, showLabels = true, showTicks = true, majorTicks = 15, minorTicks = 1, snapToTicks = true ) private int minDPR = 0; private double minDirectPointRatio = 0; public int getMinDPR() { return minDPR; } public void setMinDPR(int minDirectPointRatio) { this.minDirectPointRatio = minDirectPointRatio / 100.0; this.minDPR = minDirectPointRatio; } // ################################################################################ @XmlAttribute(name = "minHybAccelThreshold") @Property( name = "Min Speed Threshold (Relative Part)", description = "Min Speed Threshold (Relative Part)", group ="Hybrid", suffix = "" ) @Slider( type = Integer.class, minimumValue = 0, maximumValue = 60, showLabels = true, showTicks = true, majorTicks = 20, minorTicks = 1, snapToTicks = true ) private int minHybAccelThreshold = 5; public int getMinHybAccelThreshold() { return minHybAccelThreshold; } public void setMinHybAccelThreshold(int minHybAccelThreshold) { this.minHybAccelThreshold = minHybAccelThreshold; } // ################################################################################ @XmlAttribute(name = "maxHybAccelThreshold") @Property( name = "Max Speed Threshold (Relative Part)", description = "Max Speed Threshold (Relative Part)", group ="Hybrid", suffix = "" ) @Slider( type = Integer.class, minimumValue = 0, maximumValue = 100, showLabels = true, showTicks = true, majorTicks = 50, minorTicks = 1, snapToTicks = true ) private int maxHybAccelThreshold = 30; public int getMaxHybAccelThreshold() { return maxHybAccelThreshold; } public void setMaxHybAccelThreshold(int maxHybAccelThreshold) { this.maxHybAccelThreshold = maxHybAccelThreshold; } // ################################################################################ @XmlAttribute(name = "increasingSpeedThresold") @Property( name = "Threshold for prefetching direct pointnig", description = "Threshold for prefetching direct pointnig", group ="Hybrid", suffix = "%" ) @Slider( type = Integer.class, minimumValue = 50, maximumValue = 150, showLabels = true, showTicks = true, majorTicks = 50, minorTicks = 1, snapToTicks = true ) private int incSpeedThres = 75; private double increasingSpeedThresold; public int getIncSpeedThres() { return incSpeedThres; } public void setIncSpeedThres(int increasingSpeedThresold) { this.increasingSpeedThresold = increasingSpeedThresold / 100.0; this.incSpeedThres = increasingSpeedThresold; } // ################################################################################ @XmlAttribute(name = "minRelAccelThreshold") @Property( name = "Min Relative Acceleration Threshold", description = "Min Relative Acceleration Threshold", group ="Relative", suffix = "" ) @Slider( type = Integer.class, minimumValue = 0, maximumValue = 60, showLabels = true, showTicks = true, majorTicks = 20, minorTicks = 1, snapToTicks = true ) private int minRelAccelThreshold = 15; public int getMinRelAccelThreshold() { return minRelAccelThreshold; } public void setMinRelAccelThreshold(int minRelAccelThreshold) { this.minRelAccelThreshold = minRelAccelThreshold; } // ################################################################################ @XmlAttribute(name = "maxRelAccelThreshold") @Property( name = "Max Relative Acceleration Threshold", description = "Max Relative Acceleration Threshold", group ="Relative", suffix = "" ) @Slider( type = Integer.class, minimumValue = 40, maximumValue = 200, showLabels = true, showTicks = true, majorTicks = 20, minorTicks = 1, snapToTicks = true ) private int maxRelAccelThreshold = 120; public int getMaxRelAccelThreshold() { return maxRelAccelThreshold; } public void setMaxRelAccelThreshold(int maxRelAccelThreshold) { this.maxRelAccelThreshold = maxRelAccelThreshold; } // ################################################################################ // END OF ADJUSTABLES // ################################################################################ // ################################################################################ // BEGIN OF DOMAIN PROVIDERS // ################################################################################ public static class RB_MODEDomainProvider implements DomainProvider { /* * (non-Javadoc) * * @see org.squidy.manager.data.domainprovider.DomainProvider#getValues() */ public Object[] getValues() { ComboBoxItemWrapper[] values = new ComboBoxItemWrapper[4]; values[0] = new ComboBoxItemWrapper(TrackingConstant.RBMODE_NONE, "don't force"); values[1] = new ComboBoxItemWrapper(TrackingConstant.RBMODE_DIRECTPOINTING, "Direct Pointing"); values[2] = new ComboBoxItemWrapper(TrackingConstant.RBMODE_RELATIVEPIONTING, "Relative Pointing"); values[3] = new ComboBoxItemWrapper(TrackingConstant.RBMODE_HYBRIDPOINTING, "Hyprid Pointing"); return values; } } // ################################################################################ // END OF DOMAIN PROVIDERS // ################################################################################ private ArrayList<InterceptObject> interceptObjects; private ArrayList<PointingDevice> pointingDevices; private DataPosition6D trackedPerson; private PointingDevice relDevice; private InterceptObject humanVScreen; private DataButton lastButtonReceived; private double relativeWeight = 0; private FilterQueue calcPoints; @Override public void onStart() { this.maxDirectPointRatio = (double)maxDPR / 100.0; this.minDirectPointRatio = (double)minDPR / 100.0; this.increasingSpeedThresold = (double)incSpeedThres / 100.0; interceptObjects = new ArrayList(); pointingDevices = new ArrayList<PointingDevice>(); calcPoints = new FilterQueue(50); } @Override public IDataContainer preProcess(IDataContainer dataContainer) { return dataContainer; } private boolean sendDummyClick = false; /** * * @param dataPosition6d * @return */ public IData process (DataPosition6D dataPosition6d) { if (dataPosition6d.hasAttribute(TrackingConstant.RIGIDBODYROLE) == true && dataPosition6d.hasAttribute(DataConstant.IDENTIFIER) == true) { dataPosition6d = TrackingUtility.Norm2RoomCoordinates(Optitrack.class, dataPosition6d); /* * Mobile Display */ if (Integer.valueOf(dataPosition6d.getAttribute(TrackingConstant.RIGIDBODYROLE).toString()) == TrackingConstant.RBROLE_MOBILEDISPLAY) { InterceptObject iObject = getInterceptObject(dataPosition6d.getAttribute(DataConstant.IDENTIFIER).toString()); if (iObject == null) { iObject = new InterceptObject(dataPosition6d); interceptObjects.add(iObject); Collections.sort(interceptObjects); } else { iObject.updateMobileDisplay(dataPosition6d); } } /* * Tracked Person */ else if (Integer.valueOf(dataPosition6d.getAttribute(TrackingConstant.RIGIDBODYROLE).toString()) == TrackingConstant.RBROLE_PERSON) { trackedPerson = dataPosition6d; dataPosition6d.setAttribute(TrackingConstant.SCREENOVERSIZE, 0.0); dataPosition6d.setAttribute(TrackingConstant.REMOTEHOST, ""); dataPosition6d.setAttribute(TrackingConstant.REMOTEPORT, 0); dataPosition6d.setAttribute(TrackingConstant.BACKFACETRACKING, true); dataPosition6d.setAttribute(TrackingConstant.OBJECTWIDHT, 2000.0); dataPosition6d.setAttribute(TrackingConstant.OBJECTHEIGHT, 2000.0); if (humanVScreen == null) { humanVScreen = new InterceptObject(dataPosition6d); } else { humanVScreen.updateMobileDisplay(dataPosition6d); } } /* * Pointing device */ else if (Integer.valueOf(dataPosition6d.getAttribute(TrackingConstant.RIGIDBODYROLE).toString()) == TrackingConstant.RBROLE_POINTINGDEVICE) { PointingDevice pDevice = null; if (pointingDevices.size() > 0) pDevice = getDevice(TrackingUtility.getAttributesInteger(dataPosition6d, TrackingConstant.RIGIDBODYID)); if (pDevice == null) { pDevice = new PointingDevice(dataPosition6d); pointingDevices.add(pDevice); Collections.sort(pointingDevices); } else { if (!pDevice.updateDevice(dataPosition6d)) return null; } InterceptObject currentIObject = null; Intersection currentIntersection = null; if (pDevice.getPublishedIntersection() != null) { currentIObject = pDevice.getPublishedIntersection().getInterceptObject(); currentIntersection = pDevice.getPublishedIntersection(); } if (this.rbMode != TrackingConstant.RBMODE_NONE) pDevice.setPointingMode(this.rbMode); switch (pDevice.getPointingMode()) { case TrackingConstant.RBMODE_DIRECTPOINTING : { relativeWeight = 1.0; pDevice.setPublishedIntersection(directPointing(pDevice)); break; } case TrackingConstant.RBMODE_RELATIVEPIONTING : { relativeWeight = 0.0; if (TrackingUtility.getGestureBivariate(pDevice.getGesture()) != TrackingConstant.GESTURE_CLUTCH) { // System.out.println(pDevice.getGesture() +"=="+ TrackingConstant.GESTURE_SINGLEPOINT); if (pDevice.getGesture() == TrackingConstant.GESTURE_SINGLEPOINT || pDevice.getGesture() == TrackingConstant.GESTURE_SINGLEPOINTCLICK) { if (pDevice.getGesture() == TrackingConstant.GESTURE_SINGLEPOINTCLICK) { pDevice.setGesture(TrackingConstant.GESTURE_CLICK); } pDevice.setPublishedIntersection(directPointing(pDevice)); } else { if (pDevice.getPublishedIntersection() != null) pDevice.setPublishedIntersection(relativePointing(pDevice)); } } break; } case TrackingConstant.RBMODE_HYBRIDPOINTING: { if (pDevice.getGesture() == TrackingConstant.GESTURE_SINGLEPOINT) pDevice.setPublishedIntersection(directPointing(pDevice)); else pDevice.setPublishedIntersection(hybridPointing(pDevice)); break; } default : { pDevice.setPublishedIntersection(directPointing(pDevice)); } } Intersection intersection = pDevice.getPublishedIntersection(); if (intersection == null || intersection.getIntersectionPoint2d() == null) { for (Intersection is : pDevice.getAllOffScreenIntersections()) { if (is.getIsOffscreen()) { Point2d p2dOff = is.getIntersectionPoint2d(); DataPosition2D d2d = new DataPosition2D(Optitrack.class,p2dOff.x,p2dOff.y); d2d.setAttribute(TrackingConstant.REMOTEHOST, is.getInterceptObject().host); d2d.setAttribute(TrackingConstant.REMOTEPORT, is.getInterceptObject().port); d2d.setAttribute(TrackingConstant.SCREENOVERSIZE, is.getInterceptObject().screenOverSize); d2d.setAttribute(TrackingConstant.RIGIDBODYID, pDevice.rigidBodyID); d2d.setAttribute(DataConstant.GROUP_ID, pDevice.groupID); d2d.setAttribute(TrackingConstant.GESTUREID, pDevice.getGesture()); d2d.setAttribute(TrackingConstant.TUIOID, 0); if ((p2dOff.x > 0 && p2dOff.x < 1) || (p2dOff.y > 0 && p2dOff.y < 1)) { // System.out.println(p2dOff); d2d.setAttribute(TrackingConstant.KEYWORD, "SCREENOVERSIZE"); } publish(d2d); } } // System.out.println("NO INTERSECTION"); if (currentIObject != null) { // sending mouse buttons on object leave if (pDevice.hasMouseButtons && this.lastButtonReceived != null) { lastButtonReceived.setAttribute(TrackingConstant.REMOTEHOST, currentIObject.host); lastButtonReceived.setAttribute(TrackingConstant.REMOTEPORT, currentIObject.port); publish(lastButtonReceived); lastButtonReceived = null; } // release tuio finger // Point2d p = new Point2d(currentIntersection.getIntersectionPoint2d()); // System.out.println("last point " + p.toString()); // DataPosition2D d2dLast = new DataPosition2D(Optitrack.class, p.x, p.y); // d2dLast.setAttribute(TrackingConstant.SENDTUIO, "LASTONSCREEN"); // d2dLast.setAttribute(TrackingConstant.REMOTEHOST, currentIObject.host); // d2dLast.setAttribute(TrackingConstant.REMOTEPORT, currentIObject.port); // d2dLast.setAttribute(TrackingConstant.KEYWORD, "LASTONSCREEN"); // d2dLast.setAttribute(DataConstant.GROUP_ID, pDevice.groupID); // d2dLast.setAttribute(TrackingConstant.RIGIDBODYID, pDevice.rigidBodyID); // d2dLast.setAttribute(TrackingConstant.GESTUREID, TrackingConstant.GESTURE_DEFAULT); // d2dLast.setAttribute(TrackingConstant.TUIOID, pDevice.tuioID); // publish(d2dLast); // return null; Point2d p = new Point2d(currentIntersection.getIntersectionPoint2d()); DataPosition2D d2dOff = new DataPosition2D(Optitrack.class, p.x, p.y); d2dOff.setAttribute(TrackingConstant.SENDTUIO, "LAST"); d2dOff.setAttribute(TrackingConstant.REMOTEHOST, currentIObject.host); d2dOff.setAttribute(TrackingConstant.REMOTEPORT, currentIObject.port); d2dOff.setAttribute(TrackingConstant.KEYWORD, "OFFSCREEN"); d2dOff.setAttribute(DataConstant.GROUP_ID, pDevice.groupID); d2dOff.setAttribute(TrackingConstant.RIGIDBODYID, pDevice.rigidBodyID); d2dOff.setAttribute(TrackingConstant.GESTUREID, pDevice.getGesture()); if (pDevice.getGesture() == TrackingConstant.GESTURE_CLICK) { boolean noOtherIntersections = true; for (PointingDevice pd : pointingDevices) { try{ if (pd.getPublishedIntersection().getInterceptObject().host == currentIObject.host) { noOtherIntersections = false; break; } }catch (Exception ex) {} } if (noOtherIntersections) d2dOff.setAttribute(TrackingConstant.MERGEDIRECTLY, true); if (pDevice.tuioID > 0) { // System.out.println("LAST " +pDevice.tuioID + " " + currentIObject.host); d2dOff.setAttribute(TrackingConstant.TUIOID, pDevice.tuioID); } } publish(d2dOff); } currentIObject = null; return null; } Point2d p2d = intersection.getIntersectionPoint2d(); InterceptObject iObject = intersection.getInterceptObject(); //object changed? // System.out.println(iObject.objectName + " " + currentIObject.objectName); if (currentIObject== null || iObject != currentIObject) { if (currentIObject != null) { } if (iObject != null) { // sending mouse buttons on object enter if (pDevice.hasMouseButtons && this.lastButtonReceived != null) { lastButtonReceived.setAttribute(TrackingConstant.REMOTEHOST, iObject.host); lastButtonReceived.setAttribute(TrackingConstant.REMOTEPORT, iObject.port); publish(lastButtonReceived); lastButtonReceived = null; } if (pDevice.getGesture() == TrackingConstant.GESTURE_CLICK) { Point2d p = new Point2d(pDevice.getPublishedIntersection().getIntersectionPoint2d()); DataPosition2D d2dOn = new DataPosition2D(Optitrack.class,p.x, p.y); d2dOn.setAttribute(TrackingConstant.SENDTUIO, "FIRST"); d2dOn.setAttribute(TrackingConstant.REMOTEHOST, iObject.host); d2dOn.setAttribute(TrackingConstant.REMOTEPORT, iObject.port); d2dOn.setAttribute(TrackingConstant.KEYWORD, "ENTERSCREEN"); d2dOn.setAttribute(DataConstant.GROUP_ID, pDevice.groupID); d2dOn.setAttribute(TrackingConstant.RIGIDBODYID, pDevice.rigidBodyID); d2dOn.setAttribute(TrackingConstant.GESTUREID, pDevice.getGesture()); d2dOn.setAttribute(TrackingConstant.TUIOID, pDevice.tuioID); sendDummyClick = false; publish(d2dOn); } // System.out.println("object changed"); //relDevice = new PointingDevice(trackedPerson); // Vector3d body2Center = new Vector3d(iObject.screenCenter.x - pDevice.getPosition().x, // iObject.screenCenter.y - pDevice.getPosition().y, // iObject.screenCenter.z - pDevice.getPosition().z); // Vector3d xVec = new Vector3d(1,0,0); // Vector3d yVec = new Vector3d(0,1,0); // Vector3d zVec = new Vector3d(0,0,1); // double angleX = Math.toDegrees(body2Center.angle(xVec)); // double angleY = Math.toDegrees(body2Center.angle(yVec)); // double angleZ = Math.toDegrees(body2Center.angle(zVec)); // System.out.println("CENTER " + body2Center); } // click and gesture handling for enterscreen and leavesreen } Intersection dirIntersect = pDevice.getDPIntersection(); // pointer compare // if (dirIntersect!= null) // { // Point2d p2dir = dirIntersect.getIntersectionPoint2d(); // DataPosition2D d2d = new DataPosition2D(Optitrack.class,p2d.x,p2d.y); // d2d.setAttribute(TrackingConstant.REMOTEHOST, iObject.host); // d2d.setAttribute(TrackingConstant.REMOTEPORT, iObject.port); // d2d.setAttribute(TrackingConstant.KEYWORD, "OFFSCREEN"); // d2d.setAttribute(DataConstant.GROUP_ID, pDevice.groupID); // publish(d2d); // } if (p2d != null) { // System.out.println("MI GESTURE " + pDevice.getGesture()); // System.out.println(p2d.toString()); // calcPoints.add(p2d); // p2d = calcPoints.winsorize(0.25); DataPosition2D d2d = new DataPosition2D(Optitrack.class,p2d.x,p2d.y); d2d.setAttribute(TrackingConstant.REMOTEHOST, iObject.host); d2d.setAttribute(TrackingConstant.REMOTEPORT, iObject.port); d2d.setAttribute(TrackingConstant.DPRATIO, relativeWeight); d2d.setAttribute(TrackingConstant.KEYWORD, "ONSCREEN"); d2d.setAttribute(DataConstant.GROUP_ID, pDevice.groupID); d2d.setAttribute(TrackingConstant.GESTUREID, pDevice.getGesture()); if (pDevice.getGesture() == TrackingConstant.GESTURE_CLICK) { d2d.setAttribute(TrackingConstant.SENDTUIO, "TRUE"); if (pDevice.tuioID > 0) { d2d.setAttribute(TrackingConstant.TUIOID, pDevice.tuioID); // System.out.println("TUIO " + pDevice.tuioID); } if (p2d.x > 0.05 && p2d.x < 0.95 && p2d.y > 0.05 && p2d.y > 0.05 && p2d.y < 0.95 && sendDummyClick == false) { sendDummyClick = true; d2d.setAttribute(TrackingConstant.GESTUREID, TrackingConstant.GESTURE_DEFAULT); d2d.setAttribute(TrackingConstant.TUIOID, 0); } //d2d.setAttribute(TrackingConstant.HANDSIDE, dataPosition6d.getAttribute(TrackingConstant.HANDSIDE)); }else { if (pDevice.getGestureChanged()) { // d2d.setAttribute(TrackingConstant.SENDTUIO, "LAST"); // System.out.println("TUIO " + 0); } d2d.setAttribute(TrackingConstant.TUIOID, 0); } d2d.setAttribute(TrackingConstant.RIGIDBODYID, pDevice.rigidBodyID); publish(d2d); DataPosition3D d3d = new DataPosition3D(Optitrack.class,dataPosition6d.getX(),dataPosition6d.getY(),dataPosition6d.getZ()); d3d.setAttribute(TrackingConstant.REMOTEHOST, iObject.host); d3d.setAttribute(TrackingConstant.REMOTEPORT, iObject.port); publish(d3d); } // publish offscreen intersections for (Intersection is : pDevice.getAllOffScreenIntersections()) { if (is.getIsOffscreen()) { Point2d p2dOff = is.getIntersectionPoint2d(); // System.out.println("OFFSCREEM " + p2dOff.y); DataPosition2D d2d = new DataPosition2D(Optitrack.class,p2dOff.x,p2dOff.y); d2d.setAttribute(TrackingConstant.REMOTEHOST, is.getInterceptObject().host); d2d.setAttribute(TrackingConstant.REMOTEPORT, is.getInterceptObject().port); d2d.setAttribute(TrackingConstant.SCREENOVERSIZE, is.getInterceptObject().screenOverSize); d2d.setAttribute(TrackingConstant.RIGIDBODYID, pDevice.rigidBodyID); d2d.setAttribute(TrackingConstant.GESTUREID, TrackingConstant.GESTURE_DEFAULT); d2d.setAttribute(TrackingConstant.KEYWORD, "OFFSCREEN"); d2d.setAttribute(DataConstant.GROUP_ID, pDevice.groupID); publish(d2d); } } } } return null; } /** * * @param dataString creates a room object from string coordinates (see RoomObject.java) * @return */ public IData process (DataString dataString) { if (dataString.hasAttribute(TrackingConstant.OBJECTHEIGHT) == true) { InterceptObject iObject = getInterceptObject(dataString.getAttribute(DataConstant.IDENTIFIER).toString()); if (iObject == null) { iObject = new InterceptObject(dataString); interceptObjects.add(iObject); }else { interceptObjects.remove(iObject); iObject = new InterceptObject(dataString); interceptObjects.add(iObject); } } return dataString; } /** * * @param dataButton */ public void process(DataButton dataButton) { lastButtonReceived = dataButton; } /** * * @param pDevice * @return */ private Intersection relativePointing(PointingDevice pDevice) { Intersection currentIntersection = pDevice.getPublishedIntersection(); double relSpeed = 0.0; if (pDevice.getPointingMode() == TrackingConstant.RBMODE_HYBRIDPOINTING) { double maxThreshold = this.maxHybAccelThreshold;//30; double minThreshold = this.minHybAccelThreshold;//5; double minMaxSpeed = Math.max(minThreshold, pDevice.getInteractionSpeed()); minMaxSpeed = Math.min(maxThreshold, minMaxSpeed); // System.out.println(minMaxSpeed); relSpeed = TrackingUtility.minmax(minMaxSpeed, maxThreshold, minThreshold, 1, 0); relSpeed = Math.exp(relSpeed); // System.out.println(relSpeed); relSpeed = TrackingUtility.minmax(relSpeed, maxRelSpeed, 1, 1.9, 1); } else { double maxThreshold = this.maxRelAccelThreshold;//120; double minThreshold = this.minRelAccelThreshold;//15; double minMaxSpeed = Math.max(minThreshold, pDevice.getInteractionSpeed()); minMaxSpeed = Math.min(maxThreshold, minMaxSpeed); relSpeed = TrackingUtility.minmax(minMaxSpeed, maxThreshold, minThreshold, 1, 0); relSpeed = Math.exp(relSpeed); relSpeed = TrackingUtility.minmax(relSpeed, maxRelSpeed, 1, 2.9, 1.2); } Point2d iPoint; Vector3d normTurned = (Vector3d)currentIntersection.getInterceptObject().displayNorm.clone(); normTurned.scale(-1.0); Point2d pCurrent = currentIntersection.getInterceptObject().getOversizeIntersectionPoint2dSingle(pDevice.getPosition(), normTurned); Point2d pOld = currentIntersection.getInterceptObject().getOversizeIntersectionPoint2dSingle(pDevice.getPositionOld(),normTurned); // pCurrent.sub(pOld); // System.out.println(pCurrent); Point2d delta = new Point2d(); // if (relSpeed > 0.2) // System.out.println(Math.floor(relSpeed*100)); delta.x = (pCurrent.x - pOld.x) * currentIntersection.getInterceptObject().displayHeight * relSpeed; delta.y = (pCurrent.y - pOld.y) * currentIntersection.getInterceptObject().displayHeight * relSpeed; try { iPoint = currentIntersection.getIntersectionPoint2d(); } catch(Exception ex) { return null; } delta = currentIntersection.getInterceptObject().normalizeDistance(delta); iPoint.x += delta.x; iPoint.y += delta.y; if (iPoint.x < 0 || iPoint.y < 0 || iPoint.x > 1 || iPoint.y > 1) { pDevice.setRPIntersection(currentIntersection); Intersection offI = new Intersection(); offI.setIntersection(iPoint); offI.setIntercepObject(currentIntersection.getInterceptObject()); offI.setIsOffscreen(true); pDevice.addOffscreenIntersection(offI); currentIntersection = null; return null; } else { pDevice.setRPIntersection(currentIntersection); return currentIntersection; } } /** * * @param pDevice * @return */ private Intersection directPointing(PointingDevice pDevice) { Intersection currentIntersection = pDevice.getDPIntersection(); Point2d tmpIntersection; for (InterceptObject iObject : interceptObjects) { tmpIntersection = iObject.getIntersectionPoint2d(pDevice); Point2d oversize = iObject.getOversizeIntersectionPoint2d(pDevice, true); // pDevice.addOffscreenIntersection() //System.out.println("OVERSIZE " +oversize); if (tmpIntersection != null) { if (currentIntersection.getCenterDistance() < pDevice.getDPIntersection().getCenterDistance()) { currentIntersection = pDevice.getDPIntersection(); } } } // pDevice.setPublishedIntersection(currentIntersection); if (currentIntersection.getIntersectionPoint2d() != null) { pDevice.setDPIntersection(currentIntersection); return currentIntersection; } else { pDevice.setDPIntersection(currentIntersection); return null; } } private double maxRelSpeed = Math.exp(1); private LinkedList<Double> speeds = new LinkedList<Double>(); /** * * @param pDevice * @return */ private Intersection hybridPointing(PointingDevice pDevice) { Intersection currentIntersection = pDevice.getPublishedIntersection(); double maxThreshold = this.maxHybridSpeedThreshold;//11; double minThreshold = this.minHybridSpeedThreshold;//5; double minMaxSpeed = Math.max(minThreshold, pDevice.adapedRotationSpeed); minMaxSpeed = Math.min(maxThreshold, minMaxSpeed); double tmpMinRatio; double minRotThresh = 0.1; if (pDevice.rotationSpeed <= minRotThresh || this.minDirectPointRatio == 0) tmpMinRatio = 0; else { if (pDevice.rotationSpeed/100 < this.minDirectPointRatio-(minRotThresh/10)) tmpMinRatio = (pDevice.rotationSpeed-minRotThresh)/100; else tmpMinRatio = this.minDirectPointRatio-(minRotThresh/10); } // System.out.println(pDevice.rotationSpeed + "\t" + tmpMinRatio); double relSpeed = TrackingUtility.minmax(minMaxSpeed, maxThreshold, minThreshold, this.maxDirectPointRatio, tmpMinRatio); // System.out.println(relSpeed); relativeWeight = 1.0; if (currentIntersection == null || currentIntersection.getInterceptObject() == null) { directPointing(pDevice); currentIntersection = pDevice.getDPIntersection(); } else { Intersection dirIntersect; dirIntersect = directPointing(pDevice); Point2d currentPoint = currentIntersection.getInterceptObject().getOversizeIntersectionPoint2d(pDevice, true); if (currentPoint == null) { System.out.println("OUT OF AREA"); currentIntersection = null; return currentIntersection; } else { double screenOverSize = currentIntersection.getInterceptObject().screenOverSize; double x = TrackingUtility.minmax(currentPoint.x, 1, 0, 1 + screenOverSize, 0-screenOverSize); double y = TrackingUtility.minmax(currentPoint.y, 1, 0, 1 + screenOverSize, 0-screenOverSize); if (dirIntersect != null) { dirIntersect.setIntersection(new Point2d(x,y)); } else { dirIntersect = new Intersection(); dirIntersect.setIntercepObject(currentIntersection.getInterceptObject()); dirIntersect.setIntersection(new Point2d(x,y)); } } if (dirIntersect != null && dirIntersect.getIntersectionPoint2d() != null) { if (relativePointing(pDevice) != null && !Double.isNaN(pDevice.getRPIntersection().getIntersectionPoint2d().x)) { Intersection relIntersect = pDevice.getRPIntersection(); Point2d rel2d = null; // System.out.println("RELSPEED " + relSpeed); // rel2d = relIntersect.getWeightedIntersetionPoint2d(dirIntersect, relSpeed); relativeWeight = relSpeed; rel2d = relIntersect.getAdaptiveIntersection2d(dirIntersect, relSpeed, this.increasingSpeedThresold); // System.out.println(rel2d.toString()); if (rel2d != null) { currentIntersection.setIntersection(rel2d); pDevice.setRPIntersection(currentIntersection); } else { currentIntersection = dirIntersect; } } else { //System.out.println(dirIntersect); // System.out.println(dirIntersect.getInterceptObject().getOversizeIntersectionPoint2d(pDevice, false)); currentIntersection = null; } } // else // { // System.out.println("OFFSCREEN NULL"); // currentIntersection = pDevice.getDPIntersection(); // } } return currentIntersection; } /** * * @param name * @return */ private InterceptObject getInterceptObject(String name) { for (InterceptObject iObject : interceptObjects) { if (iObject.compareTo(name) == 0) { return iObject; } } return null; } /** * * @param id * @return */ private PointingDevice getDevice(int id) { for (PointingDevice pd : pointingDevices) { if (pd.compareTo(id) == 0) { return pd; } } return null; } }