/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. ***********************************************************************/
  18. package org.mt4j.input.inputProcessors.componentProcessors.panProcessor;
  19. import java.util.List;
  20. import org.mt4j.components.interfaces.IMTComponent3D;
  21. import org.mt4j.input.inputData.AbstractCursorInputEvt;
  22. import org.mt4j.input.inputData.InputCursor;
  23. import org.mt4j.input.inputProcessors.IInputProcessor;
  24. import org.mt4j.input.inputProcessors.MTGestureEvent;
  25. import org.mt4j.input.inputProcessors.componentProcessors.AbstractComponentProcessor;
  26. import org.mt4j.input.inputProcessors.componentProcessors.AbstractCursorProcessor;
  27. import org.mt4j.util.math.Tools3D;
  28. import org.mt4j.util.math.ToolsGeometry;
  29. import org.mt4j.util.math.Vector3D;
  30. import processing.core.PApplet;
  31. /**
  32. * The Class PanProcessorTwoFingers. Multi-touch gesture processor for panning the
  33. * canvas by moving the scene's camera. Should only be registered with MTCanvas components.
  34. * Fires PanEvent gesture events.
  35. * <br><strong>NOTE:</strong> Should be only used in combination with a MTCanvas component.
  36. * @author Christopher Ruff
  37. */
  38. public class PanProcessorTwoFingers extends AbstractCursorProcessor {
  39. /** The detect radius. */
  40. private float detectRadius;
  41. /** The applet. */
  42. private PApplet applet;
  43. /** The point in plane. */
  44. private Vector3D pointInPlane;
  45. /** The plane normal. */
  46. private Vector3D planeNormal;
  47. /**
  48. * Instantiates a new pan processor two fingers.
  49. *
  50. * @param app the app
  51. */
  52. public PanProcessorTwoFingers(PApplet app) {
  53. this(app, app.width/2);
  54. }
  55. /**
  56. * Instantiates a new pan processor two fingers.
  57. *
  58. * @param applet the applet
  59. * @param panDetectRadius the pan detect radius
  60. */
  61. public PanProcessorTwoFingers(PApplet applet, float panDetectRadius){
  62. this.applet = applet;
  63. this.detectRadius = panDetectRadius;
  64. this.pointInPlane = new Vector3D(0,0,0);
  65. this.planeNormal = new Vector3D(0,0,1);
  66. this.setLockPriority(2);
  67. }
  68. @Override
  69. public void cursorStarted(InputCursor c, AbstractCursorInputEvt positionEvent) {
  70. InputCursor[] locked = getLockedCursorsArray();
  71. if (locked.length >= 2){ //gesture with 2 fingers already in progress
  72. logger.debug(this.getName() + " has already enough cursors for this gesture - adding to unused ID:" + c.getId());
  73. }else{//not in progress yet
  74. List<InputCursor> availableCursors = getFreeComponentCursors();
  75. logger.debug(this.getName() + " Available cursors: " + availableCursors.size());
  76. if (availableCursors.size() >= 2){
  77. InputCursor otherCursor = (availableCursors.get(0).equals(c))? availableCursors.get(1) : availableCursors.get(0);
  78. //See if we can obtain a lock on both cursors
  79. if (this.canLock(otherCursor, c)){
  80. float newDistance = Vector3D.distance(otherCursor.getPosition(), c.getPosition());
  81. if (newDistance < detectRadius) {
  82. this.getLock(otherCursor, c);
  83. logger.debug(this.getName() + " we could lock both cursors! And fingers in zoom distance!");
  84. this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_STARTED, positionEvent.getCurrentTarget(), otherCursor, c, new Vector3D(0,0,0), positionEvent.getCurrentTarget().getViewingCamera()));
  85. }else{
  86. logger.debug(this.getName() + " cursors not close enough to start gesture. Distance: " + newDistance);
  87. }
  88. }else{
  89. logger.debug(this.getName() + " we could NOT lock both cursors!");
  90. }
  91. }
  92. }
  93. }
  94. @Override
  95. public void cursorUpdated(InputCursor c, AbstractCursorInputEvt positionEvent) {
  96. List<InputCursor> locked = getLockedCursors();
  97. if (locked.contains(c)){ //in progress with this cursors
  98. InputCursor firstCursor = locked.get(0);
  99. InputCursor secondCursor = locked.get(1);
  100. Vector3D distance = (c.equals(firstCursor))? getNewTranslation(positionEvent.getTarget(), firstCursor, secondCursor) : getNewTranslation(positionEvent.getTarget(), secondCursor, firstCursor);
  101. if (c.equals(firstCursor)){
  102. this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_UPDATED, positionEvent.getCurrentTarget(), firstCursor, secondCursor, new Vector3D(distance.getX(),distance.getY(),0), positionEvent.getCurrentTarget().getViewingCamera()));
  103. }else{
  104. this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_UPDATED, positionEvent.getCurrentTarget(), firstCursor, secondCursor, new Vector3D(distance.getX(),distance.getY(),0), positionEvent.getCurrentTarget().getViewingCamera()));
  105. }
  106. }
  107. }
  108. @Override
  109. public void cursorEnded(InputCursor c, AbstractCursorInputEvt positionEvent) {
  110. logger.debug(this.getName() + " INPUT_ENDED RECIEVED - cursor: " + c.getId());
  111. List<InputCursor> locked = getLockedCursors();
  112. if (locked.contains(c)){
  113. InputCursor leftOverCursor = (locked.get(0).equals(c))? locked.get(1) : locked.get(0);
  114. InputCursor futureCursor = getFarthestFreeCursorToLimited(leftOverCursor, detectRadius);
  115. if (futureCursor != null){
  116. float newDistance = Vector3D.distance(leftOverCursor.getPosition(), futureCursor.getPosition());
  117. if (newDistance < detectRadius) {//Check if other cursor is in distance
  118. this.getLock(futureCursor);
  119. logger.debug(this.getName() + " we could lock another cursor! (ID:" + futureCursor.getId() +")");
  120. logger.debug(this.getName() + " continue with different cursors (ID: " + futureCursor.getId() + ")" + " " + "(ID: " + leftOverCursor.getId() + ")");
  121. }else{
  122. this.endGesture(c, leftOverCursor, positionEvent.getCurrentTarget());
  123. }
  124. }else{
  125. this.endGesture(c, leftOverCursor, positionEvent.getCurrentTarget());
  126. }
  127. }
  128. }
  129. /**
  130. * End gesture.
  131. *
  132. * @param inputEndedCursor the input ended cursor
  133. * @param leftOverCursor the left over cursor
  134. * @param comp the comp
  135. */
  136. private void endGesture(InputCursor inputEndedCursor, InputCursor leftOverCursor, IMTComponent3D comp){
  137. this.unLock(leftOverCursor);
  138. this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_ENDED, comp, inputEndedCursor, leftOverCursor, new Vector3D(0,0,0), comp.getViewingCamera()));
  139. }
  140. @Override
  141. public void cursorLocked(InputCursor c, IInputProcessor lockingProcessor) {
  142. if (lockingProcessor instanceof AbstractComponentProcessor){
  143. logger.debug(this.getName() + " Recieved cursor LOCKED by (" + ((AbstractComponentProcessor)lockingProcessor).getName() + ") - cursor ID: " + c.getId());
  144. }else{
  145. logger.debug(this.getName() + " Recieved cursor LOCKED by higher priority signal - cursor ID: " + c.getId());
  146. }
  147. List<InputCursor> locked = getLockedCursors();
  148. if (locked.contains(c)){
  149. InputCursor leftOverCursor = (locked.get(0).equals(c))? locked.get(1) : locked.get(0);
  150. this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_CANCELED, c.getCurrentTarget(), c, leftOverCursor, new Vector3D(0,0,0), c.getCurrentTarget().getViewingCamera()));
  151. this.unLockAllCursors();
  152. logger.debug(this.getName() + " cursor:" + c.getId() + " cursor LOCKED. Was an active cursor in this gesture - we therefor have to stop this gesture!");
  153. }
  154. }
  155. @Override
  156. public void cursorUnlocked(InputCursor c) {
  157. logger.debug(this.getName() + " Recieved UNLOCKED signal for cursor ID: " + c.getId());
  158. if (getLockedCursors().size() >= 2){ //we dont need the unlocked cursor, gesture still in progress
  159. return;
  160. }
  161. this.unLockAllCursors();
  162. List<InputCursor> availableCursors = getFreeComponentCursors();
  163. if (availableCursors.size() >= 2){ //we can try to resume the gesture
  164. InputCursor firstCursor = availableCursors.get(0);
  165. InputCursor secondCursor = getFarthestFreeCursorToLimited(firstCursor, detectRadius);
  166. //See if we can obtain a lock on both cursors
  167. if (this.canLock(firstCursor, secondCursor)){
  168. float newDistance = Vector3D.distance(firstCursor.getPosition(), secondCursor.getPosition());
  169. if (newDistance < detectRadius) {//Check if other cursor is in distance
  170. this.getLock(firstCursor, secondCursor);
  171. logger.debug(this.getName() + " we could lock cursors: " + firstCursor.getId() +", " + secondCursor.getId());
  172. logger.debug(this.getName() + " continue with different cursors (ID: " + firstCursor.getId() + ")" + " " + "(ID: " + secondCursor.getId() + ")");
  173. this.fireGestureEvent(new PanTwoFingerEvent(this, MTGestureEvent.GESTURE_RESUMED, c.getCurrentTarget(), firstCursor, secondCursor, new Vector3D(0,0,0), c.getCurrentTarget().getViewingCamera()));
  174. }else{
  175. logger.debug(this.getName() + " distance was too great between cursors: " + firstCursor.getId() +", " + secondCursor.getId() + " distance: " + newDistance);
  176. }
  177. }else{
  178. logger.debug(this.getName() + " we could NOT lock cursors: " + firstCursor.getId() +", " + secondCursor.getId());
  179. }
  180. }
  181. }
  182. /**
  183. * Gets the new translation.
  184. *
  185. * @param comp the comp
  186. * @param movingCursor the moving cursor
  187. * @param otherCursor the other cursor
  188. *
  189. * @return the new translation
  190. */
  191. private Vector3D getNewTranslation(IMTComponent3D comp, InputCursor movingCursor, InputCursor otherCursor){
  192. Vector3D fromFirstFinger = ToolsGeometry.getRayPlaneIntersection(
  193. Tools3D.getCameraPickRay(applet, comp.getViewingCamera(), movingCursor.getPreviousEvent().getX(), movingCursor.getPreviousEvent().getY()),
  194. planeNormal,
  195. pointInPlane);
  196. Vector3D fromSecondFinger = ToolsGeometry.getRayPlaneIntersection(
  197. Tools3D.getCameraPickRay(applet, comp.getViewingCamera(), otherCursor.getCurrentEvent().getX(), otherCursor.getCurrentEvent().getY()),
  198. planeNormal,
  199. pointInPlane);
  200. Vector3D oldMiddlePoint = getMiddlePointBetweenFingers(fromSecondFinger, fromFirstFinger);
  201. Vector3D toFirstFinger = ToolsGeometry.getRayPlaneIntersection(
  202. Tools3D.getCameraPickRay(applet, comp.getViewingCamera(), movingCursor.getCurrentEvent().getX(), movingCursor.getCurrentEvent().getY()),
  203. planeNormal,
  204. pointInPlane);
  205. Vector3D newMiddlePoint = getMiddlePointBetweenFingers(toFirstFinger , fromSecondFinger);
  206. Vector3D distance = newMiddlePoint.getSubtracted(oldMiddlePoint);
  207. return distance;
  208. }
  209. /**
  210. * Gets the middle point between fingers.
  211. *
  212. * @param firstFinger the first finger
  213. * @param secondFinger the second finger
  214. *
  215. * @return the middle point between fingers
  216. */
  217. private Vector3D getMiddlePointBetweenFingers(Vector3D firstFinger, Vector3D secondFinger){
  218. Vector3D bla = secondFinger.getSubtracted(firstFinger); //= direction vector of 1. to 2. finger
  219. bla.scaleLocal(0.5f); //take the half
  220. return (new Vector3D(firstFinger.getX() + bla.getX(), firstFinger.getY() + bla.getY(), firstFinger.getZ() + bla.getZ()));
  221. }
  222. @Override
  223. public String getName() {
  224. return "two finger pan detector";
  225. }
  226. }