/***********************************************************************
* mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
***********************************************************************/
package org.mt4j.input.inputProcessors.componentProcessors.dragProcessor;
import org.mt4j.components.interfaces.IMTComponent3D;
import org.mt4j.input.inputData.InputCursor;
import org.mt4j.input.inputData.MTFingerInputEvt;
import org.mt4j.input.inputProcessors.IInputProcessor;
import org.mt4j.input.inputProcessors.MTGestureEvent;
import org.mt4j.input.inputProcessors.componentProcessors.AbstractComponentProcessor;
import org.mt4j.input.inputProcessors.componentProcessors.AbstractCursorProcessor;
import org.mt4j.util.math.Tools3D;
import org.mt4j.util.math.ToolsGeometry;
import org.mt4j.util.math.Vector3D;
import processing.core.PApplet;
/**
* The Class DragProcessor. For multi touch drag behaviour on components.
* Fires DragEvent gesture events.
* @author Christopher Ruff
*/
public class DragProcessor extends AbstractCursorProcessor {
/** The applet. */
private PApplet applet;
/** The dc. */
private DragContext dc;
/**
* Instantiates a new drag processor.
*
* @param graphicsContext the graphics context
*/
public DragProcessor(PApplet graphicsContext){
this.applet = graphicsContext;
this.setLockPriority(1);
this.setDebug(false);
// logger.setLevel(Level.DEBUG);
}
/* (non-Javadoc)
* @see org.mt4j.input.inputProcessors.componentProcessors.AbstractCursorProcessor#cursorStarted(org.mt4j.input.inputData.InputCursor, org.mt4j.input.inputData.MTFingerInputEvt)
*/
@Override
public void cursorStarted(InputCursor cursor, MTFingerInputEvt fe) {
IMTComponent3D comp = fe.getTargetComponent();
InputCursor[] theLockedCursors = getLockedCursorsArray();
//if gesture isnt started and no other cursor on comp is locked by higher priority gesture -> start
if (theLockedCursors.length == 0 && this.canLock(getCurrentComponentCursorsArray())){
dc = new DragContext(cursor, comp);
if (!dc.isGestureAborted()){ //See if the drag couldnt start (i.e. cursor doesent hit component anymore etc)
//Lock this cursor with our priority
this.getLock(cursor);
logger.debug(this.getName() + " successfully locked cursor (id:" + cursor.getId() + ")");
this.fireGestureEvent(new DragEvent(this,MTGestureEvent.GESTURE_DETECTED, comp, cursor, dc.getLastPosition(), dc.getNewPosition()));
}else{
logger.debug(this.getName() + " gesture aborted, probably finger not on component!");
dc = null;
}
}
}
/* (non-Javadoc)
* @see org.mt4j.input.inputProcessors.componentProcessors.AbstractCursorProcessor#cursorUpdated(org.mt4j.input.inputData.InputCursor, org.mt4j.input.inputData.MTFingerInputEvt)
*/
@Override
public void cursorUpdated(InputCursor c, MTFingerInputEvt fe) {
IMTComponent3D comp = fe.getTargetComponent();
if (getLockedCursors().contains(c)){
dc.updateDragPosition();
this.fireGestureEvent(new DragEvent(this, MTGestureEvent.GESTURE_UPDATED, comp, c, dc.getLastPosition(), dc.getNewPosition()));
}
}
/* (non-Javadoc)
* @see org.mt4j.input.inputProcessors.componentProcessors.AbstractCursorProcessor#cursorEnded(org.mt4j.input.inputData.InputCursor, org.mt4j.input.inputData.MTFingerInputEvt)
*/
@Override
public void cursorEnded(InputCursor c, MTFingerInputEvt fe) {
IMTComponent3D comp = fe.getTargetComponent();
logger.debug(this.getName() + " INPUT_ENDED RECIEVED - MOTION: " + c.getId());
if (getLockedCursors().contains(c)){ //cursors was a actual gesture cursors
dc.updateDragPosition();
//Check if we can resume the gesture with another cursor
InputCursor[] availableCursors = getFreeComponentCursorsArray();
if (availableCursors.length > 0 && this.canLock(getCurrentComponentCursorsArray())){
InputCursor otherCursor = availableCursors[0];
DragContext newContext = new DragContext(otherCursor, comp);
if (!newContext.isGestureAborted()){
dc = newContext;
this.getLock(otherCursor);
}else{
this.fireGestureEvent(new DragEvent(this, MTGestureEvent.GESTURE_ENDED, comp, c, dc.getLastPosition(), dc.getNewPosition()));
}
}else{
this.fireGestureEvent(new DragEvent(this, MTGestureEvent.GESTURE_ENDED, comp, c, dc.getLastPosition(), dc.getNewPosition()));
}
}
}
/* (non-Javadoc)
* @see org.mt4j.input.inputProcessors.componentProcessors.AbstractCursorProcessor#cursorLocked(org.mt4j.input.inputData.InputCursor, org.mt4j.input.inputProcessors.IInputProcessor)
*/
@Override
public void cursorLocked(InputCursor c, IInputProcessor p) {
if (p instanceof AbstractComponentProcessor){
logger.debug(this.getName() + " Recieved MOTION LOCKED by (" + ((AbstractComponentProcessor)p).getName() + ") - cursors ID: " + c.getId());
}else{
logger.debug(this.getName() + " Recieved MOTION LOCKED by higher priority signal - cursors ID: " + c.getId());
}
if (dc != null && dc.getCursor().equals(c)){
dc = null;
logger.debug(this.getName() + " cursors:" + c.getId() + " CURSOR LOCKED. Was an locked cursor in this gesture!");
}
}
/* (non-Javadoc)
* @see org.mt4j.input.inputProcessors.componentProcessors.AbstractCursorProcessor#cursorUnlocked(org.mt4j.input.inputData.InputCursor)
*/
@Override
public void cursorUnlocked(InputCursor c) {
logger.debug(this.getName() + " Recieved UNLOCKED signal for cursors ID: " + c.getId());
if (getLockedCursors().size() >= 1){ //we dont need the unlocked cursors, gesture still in progress
return;
}
if (getFreeComponentCursors().size() > 0 && this.canLock(getCurrentComponentCursorsArray())){
DragContext newContext = new DragContext(c, c.getTarget());
if (!newContext.isGestureAborted()){
dc = newContext;
this.getLock(c);
logger.debug(this.getName() + " can resume its gesture with cursors: " + c.getId());
}else{
dc = null;
logger.debug(this.getName() + " we could NOT start gesture - cursors not on component: " + c.getId());
}
}else{
logger.debug(this.getName() + " still in progress - we dont need the unlocked cursors" );
}
}
/**
* The Class DragContext.
* @author Christopher Ruff
*/
private class DragContext {
/** The start position. */
private Vector3D startPosition;
/** The last position. */
private Vector3D lastPosition;
/** The new position. */
private Vector3D newPosition;
/** The drag object. */
private IMTComponent3D dragObject;
/** The m. */
private InputCursor m;
/** The gesture aborted. */
private boolean gestureAborted;
/** The drag plane normal. */
private Vector3D dragPlaneNormal;
/**
* Instantiates a new drag context.
*
* @param m the m
* @param dragObject the drag object
*/
public DragContext(InputCursor m, IMTComponent3D dragObject){
this.dragObject = dragObject;
this.m = m;
gestureAborted = false;
//Calculate the normal of the plane we will be dragging at (useful if camera isnt default)
this.dragPlaneNormal = dragObject.getViewingCamera().getPosition().getSubtracted(dragObject.getViewingCamera().getViewCenterPos()).normalizeLocal();
//Set the Drag Startposition
Vector3D interSectP = getIntersection(applet, dragObject, m);
if (interSectP != null)
this.startPosition = interSectP;
else{
logger.warn(getName() + " Drag StartPoint Null -> aborting drag");
gestureAborted = true;
this.startPosition = new Vector3D(0,0,0); //TODO ABORT GESTURE!
//abortGesture(m); //TODO in anderen analyzern auch machen
}
this.newPosition = startPosition.getCopy();
this.updateDragPosition();
//Set the Drags lastPostition (the last one before the new one)
this.lastPosition = startPosition.getCopy();
}
public void updateDragPosition(){
if (dragObject == null || dragObject.getViewingCamera() == null){ //IF component was destroyed while gesture still active
this.gestureAborted = true;
return ;
}
Vector3D newPos = ToolsGeometry.getRayPlaneIntersection(
Tools3D.getCameraPickRay(applet, dragObject, m.getCurrentEvtPosX(), m.getCurrentEvtPosY()),
dragPlaneNormal,
startPosition);
if (newPos != null){
lastPosition = newPosition;
newPosition = newPos;
}
}
public Vector3D getLastPosition() {
return lastPosition;
}
public Vector3D getNewPosition() {
return newPosition;
}
public boolean isGestureAborted() {
return gestureAborted;
}
public InputCursor getCursor(){
return this.m;
}
}
/* (non-Javadoc)
* @see org.mt4j.input.inputProcessors.componentProcessors.AbstractComponentProcessor#getName()
*/
@Override
public String getName() {
return "Drag Processor";
}
}