PageRenderTime 198ms CodeModel.GetById 153ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/src/org/mt4j/input/inputProcessors/componentProcessors/panProcessor/PanProcessorTwoFingers.java

http://mt4j.googlecode.com/
Java | 273 lines | 161 code | 47 blank | 65 comment | 16 complexity | 780dce8c6714d60004fbeb289dce4bc6 MD5 | raw file
  1/***********************************************************************
  2 * mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
  3 *  
  4 *   This program is free software: you can redistribute it and/or modify
  5 *   it under the terms of the GNU General Public License as published by
  6 *   the Free Software Foundation, either version 3 of the License, or
  7 *   (at your option) any later version.
  8 *
  9 *   This program is distributed in the hope that it will be useful,
 10 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 *   GNU General Public License for more details.
 13 *
 14 *   You should have received a copy of the GNU General Public License
 15 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 16 *
 17 ***********************************************************************/
 18package org.mt4j.input.inputProcessors.componentProcessors.panProcessor;
 19
 20import java.util.List;
 21
 22import org.mt4j.components.interfaces.IMTComponent3D;
 23import org.mt4j.input.inputData.AbstractCursorInputEvt;
 24import org.mt4j.input.inputData.InputCursor;
 25import org.mt4j.input.inputProcessors.IInputProcessor;
 26import org.mt4j.input.inputProcessors.MTGestureEvent;
 27import org.mt4j.input.inputProcessors.componentProcessors.AbstractComponentProcessor;
 28import org.mt4j.input.inputProcessors.componentProcessors.AbstractCursorProcessor;
 29import org.mt4j.util.math.Tools3D;
 30import org.mt4j.util.math.ToolsGeometry;
 31import org.mt4j.util.math.Vector3D;
 32
 33import processing.core.PApplet;
 34
 35/**
 36 * The Class PanProcessorTwoFingers. Multi-touch gesture processor for panning the
 37 * canvas by moving the scene's camera. Should only be registered with MTCanvas components.
 38 * Fires PanEvent gesture events.
 39 * <br><strong>NOTE:</strong> Should be only used in combination with a MTCanvas component. 
 40 * @author Christopher Ruff
 41 */
 42public class PanProcessorTwoFingers extends AbstractCursorProcessor {
 43	
 44	/** The detect radius. */
 45	private float detectRadius;
 46	
 47	/** The applet. */
 48	private PApplet applet;
 49	
 50	/** The point in plane. */
 51	private Vector3D pointInPlane;
 52	
 53	/** The plane normal. */
 54	private Vector3D planeNormal;
 55	
 56	
 57	/**
 58	 * Instantiates a new pan processor two fingers.
 59	 * 
 60	 * @param app the app
 61	 */
 62	public PanProcessorTwoFingers(PApplet app) {
 63		this(app, app.width/2);
 64	}
 65	
 66	/**
 67	 * Instantiates a new pan processor two fingers.
 68	 * 
 69	 * @param applet the applet
 70	 * @param panDetectRadius the pan detect radius
 71	 */
 72	public PanProcessorTwoFingers(PApplet applet, float panDetectRadius){
 73		this.applet = applet;
 74		this.detectRadius = panDetectRadius;
 75		this.pointInPlane = new Vector3D(0,0,0); 
 76		this.planeNormal = new Vector3D(0,0,1); 
 77		this.setLockPriority(2);
 78	}
 79	
 80
 81	@Override
 82	public void cursorStarted(InputCursor c, AbstractCursorInputEvt positionEvent) {
 83		InputCursor[] locked = getLockedCursorsArray();
 84		if (locked.length >= 2){ //gesture with 2 fingers already in progress
 85			logger.debug(this.getName() + " has already enough cursors for this gesture - adding to unused ID:" + c.getId());
 86		}else{//not in progress yet
 87			List<InputCursor> availableCursors = getFreeComponentCursors();
 88			logger.debug(this.getName() + " Available cursors: " + availableCursors.size());
 89			
 90			if (availableCursors.size() >= 2){
 91				InputCursor otherCursor = (availableCursors.get(0).equals(c))? availableCursors.get(1) : availableCursors.get(0);
 92				//See if we can obtain a lock on both cursors
 93				if (this.canLock(otherCursor, c)){
 94					float newDistance = Vector3D.distance(otherCursor.getPosition(), c.getPosition());
 95					if (newDistance < detectRadius) {
 96						this.getLock(otherCursor, c);
 97						logger.debug(this.getName() + " we could lock both cursors! And fingers in zoom distance!");
 98						this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_STARTED, positionEvent.getCurrentTarget(), otherCursor, c, new Vector3D(0,0,0), positionEvent.getCurrentTarget().getViewingCamera()));
 99					}else{
100						logger.debug(this.getName() + " cursors not close enough to start gesture. Distance: " + newDistance);
101					}
102				}else{
103					logger.debug(this.getName() + " we could NOT lock both cursors!");
104				}
105			}
106		}
107	}
108
109	@Override
110	public void cursorUpdated(InputCursor c, AbstractCursorInputEvt positionEvent) {
111		List<InputCursor> locked = getLockedCursors();
112		if (locked.contains(c)){ //in progress with this cursors
113			InputCursor firstCursor = locked.get(0);
114			InputCursor secondCursor = locked.get(1);
115			Vector3D distance = (c.equals(firstCursor))? getNewTranslation(positionEvent.getTarget(), firstCursor, secondCursor) : getNewTranslation(positionEvent.getTarget(), secondCursor, firstCursor);
116			if (c.equals(firstCursor)){
117				this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_UPDATED, positionEvent.getCurrentTarget(), firstCursor, secondCursor, new Vector3D(distance.getX(),distance.getY(),0), positionEvent.getCurrentTarget().getViewingCamera()));
118			}else{
119				this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_UPDATED, positionEvent.getCurrentTarget(), firstCursor, secondCursor, new Vector3D(distance.getX(),distance.getY(),0), positionEvent.getCurrentTarget().getViewingCamera()));
120			}
121		}
122	}
123	
124	
125	@Override
126	public void cursorEnded(InputCursor c, AbstractCursorInputEvt positionEvent) {
127		logger.debug(this.getName() + " INPUT_ENDED RECIEVED - cursor: " + c.getId());
128		List<InputCursor> locked = getLockedCursors();
129		if (locked.contains(c)){
130			InputCursor leftOverCursor = (locked.get(0).equals(c))? locked.get(1) : locked.get(0);
131			InputCursor futureCursor = getFarthestFreeCursorToLimited(leftOverCursor, detectRadius);
132			if (futureCursor != null){
133				float newDistance = Vector3D.distance(leftOverCursor.getPosition(), futureCursor.getPosition());
134				if (newDistance < detectRadius) {//Check if other cursor is in distance 
135					this.getLock(futureCursor);
136					logger.debug(this.getName() + " we could lock another cursor! (ID:" + futureCursor.getId() +")");
137					logger.debug(this.getName() + " continue with different cursors (ID: " + futureCursor.getId() + ")" + " " + "(ID: " + leftOverCursor.getId() + ")");
138				}else{
139					this.endGesture(c, leftOverCursor, positionEvent.getCurrentTarget());
140				}
141			}else{
142				this.endGesture(c, leftOverCursor, positionEvent.getCurrentTarget());
143			}
144		}
145	}
146	
147	
148	/**
149	 * End gesture.
150	 * 
151	 * @param inputEndedCursor the input ended cursor
152	 * @param leftOverCursor the left over cursor
153	 * @param comp the comp
154	 */
155	private void endGesture(InputCursor inputEndedCursor, InputCursor leftOverCursor, IMTComponent3D comp){
156		this.unLock(leftOverCursor);
157		this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_ENDED, comp, inputEndedCursor, leftOverCursor, new Vector3D(0,0,0), comp.getViewingCamera()));
158	}
159	
160	
161
162	@Override
163	public void cursorLocked(InputCursor c, IInputProcessor lockingProcessor) {
164		if (lockingProcessor instanceof AbstractComponentProcessor){
165			logger.debug(this.getName() + " Recieved cursor LOCKED by (" + ((AbstractComponentProcessor)lockingProcessor).getName()  + ") - cursor ID: " + c.getId());
166		}else{
167			logger.debug(this.getName() + " Recieved cursor LOCKED by higher priority signal - cursor ID: " + c.getId());
168		}
169		
170		List<InputCursor> locked = getLockedCursors();
171		if (locked.contains(c)){
172			InputCursor leftOverCursor = (locked.get(0).equals(c))? locked.get(1) : locked.get(0);
173			this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_CANCELED, c.getCurrentTarget(), c, leftOverCursor, new Vector3D(0,0,0), c.getCurrentTarget().getViewingCamera()));			
174			this.unLockAllCursors();
175			logger.debug(this.getName() + " cursor:" + c.getId() + " cursor LOCKED. Was an active cursor in this gesture - we therefor have to stop this gesture!");
176		}
177	}
178
179	
180	
181	@Override
182	public void cursorUnlocked(InputCursor c) {
183		logger.debug(this.getName() + " Recieved UNLOCKED signal for cursor ID: " + c.getId());
184		
185		if (getLockedCursors().size() >= 2){ //we dont need the unlocked cursor, gesture still in progress
186			return;
187		}
188		
189		this.unLockAllCursors();
190		
191		List<InputCursor> availableCursors = getFreeComponentCursors();
192		if (availableCursors.size() >= 2){ //we can try to resume the gesture
193			InputCursor firstCursor = availableCursors.get(0);
194			InputCursor secondCursor = getFarthestFreeCursorToLimited(firstCursor, detectRadius);
195
196			//See if we can obtain a lock on both cursors
197			if (this.canLock(firstCursor, secondCursor)){
198				float newDistance = Vector3D.distance(firstCursor.getPosition(), secondCursor.getPosition());
199				if (newDistance < detectRadius) {//Check if other cursor is in distance 
200					this.getLock(firstCursor, secondCursor);
201					logger.debug(this.getName() + " we could lock cursors: " + firstCursor.getId() +", " + secondCursor.getId());
202					logger.debug(this.getName() + " continue with different cursors (ID: " + firstCursor.getId() + ")" + " " + "(ID: " + secondCursor.getId() + ")");
203					this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_RESUMED, c.getCurrentTarget(), firstCursor, secondCursor, new Vector3D(0,0,0), c.getCurrentTarget().getViewingCamera()));
204				}else{
205					logger.debug(this.getName() + " distance was too great between cursors: " + firstCursor.getId() +", " + secondCursor.getId() + " distance: " + newDistance);
206				}
207			}else{
208				logger.debug(this.getName() + " we could NOT lock cursors: " + firstCursor.getId() +", " + secondCursor.getId());
209			}
210		}
211	}
212	
213	
214	
215	
216	/**
217	 * Gets the new translation.
218	 * 
219	 * @param comp the comp
220	 * @param movingCursor the moving cursor
221	 * @param otherCursor the other cursor
222	 * 
223	 * @return the new translation
224	 */
225	private Vector3D getNewTranslation(IMTComponent3D comp, InputCursor movingCursor, InputCursor otherCursor){
226		Vector3D fromFirstFinger = ToolsGeometry.getRayPlaneIntersection(
227				Tools3D.getCameraPickRay(applet, comp.getViewingCamera(), movingCursor.getPreviousEvent().getX(), movingCursor.getPreviousEvent().getY()), 
228				planeNormal, 
229				pointInPlane);
230		
231		Vector3D fromSecondFinger = ToolsGeometry.getRayPlaneIntersection(
232				Tools3D.getCameraPickRay(applet, comp.getViewingCamera(), otherCursor.getCurrentEvent().getX(), otherCursor.getCurrentEvent().getY()), 
233				planeNormal, 
234				pointInPlane);
235		
236		Vector3D oldMiddlePoint = getMiddlePointBetweenFingers(fromSecondFinger, fromFirstFinger);
237		
238		Vector3D toFirstFinger = ToolsGeometry.getRayPlaneIntersection(
239				Tools3D.getCameraPickRay(applet, comp.getViewingCamera(), movingCursor.getCurrentEvent().getX(), movingCursor.getCurrentEvent().getY()), 
240				planeNormal, 
241				pointInPlane);
242		
243		Vector3D newMiddlePoint = getMiddlePointBetweenFingers(toFirstFinger ,  fromSecondFinger);
244		Vector3D distance = newMiddlePoint.getSubtracted(oldMiddlePoint);
245		return distance;
246	}
247	
248	
249	/**
250	 * Gets the middle point between fingers.
251	 * 
252	 * @param firstFinger the first finger
253	 * @param secondFinger the second finger
254	 * 
255	 * @return the middle point between fingers
256	 */
257	private Vector3D getMiddlePointBetweenFingers(Vector3D firstFinger, Vector3D secondFinger){
258		Vector3D bla = secondFinger.getSubtracted(firstFinger); //= direction vector of 1. to 2. finger
259		bla.scaleLocal(0.5f); //take the half
260		return (new Vector3D(firstFinger.getX() + bla.getX(), firstFinger.getY() + bla.getY(), firstFinger.getZ() + bla.getZ()));
261	}
262	
263	
264	
265	@Override
266	public String getName() {
267		return "two finger pan detector";
268	}
269
270
271	
272
273}