Package org.pollux3d.gesture

Source Code of org.pollux3d.gesture.GestureSystem$CursorStore

package org.pollux3d.gesture;

import java.util.ArrayList;
import java.util.List;

import org.pollux3d.tuio.TuioInputListener;

import com.jme3.math.FastMath;
import com.jme3.math.Vector2f;
public class GestureSystem implements TuioInputListener {
 
  private static float SingelTouchTimout = 1f;
  private static int longClickMaxDelta = 1;
  private float timer = 0;
  private boolean twoCursors = false;
  class CursorStore {
   
    int x;
    int y;
    int xDelta;
    int yDelta;
    boolean isNew;
   
    public CursorStore (int xDelta, int yDelta, int x, int y, boolean isNew) {
      this.x = x;
      this.y = y;
      this.xDelta = xDelta;
      this.yDelta = yDelta;
      this.isNew = isNew;
    }
   
    public CursorStore (int xDelta, int yDelta, int x, int y) {
      this(xDelta, yDelta, x, y, false);
    }
   
    public CursorStore (int x, int y) {
      this(0, 0, x, y, true);
    }
   
    public Vector2f getVector() {
      return new Vector2f(x, y);
    }
   
    public Vector2f getPreVector() {
      return new Vector2f(x+xDelta, y-yDelta);
    }
   
    public boolean hasNotMoved() {
      return (xDelta == 0 && yDelta == 0);
    }
   
    public boolean isNew() {
      return isNew;
    }
  }
 
  private CursorStore cursor1 = null;
  private CursorStore cursor2 = null;
 
  private CursorStore lastCursor1 = null;
  private CursorStore lastCursor2 = null;
 
  /**
   * Singleton instance
   */
  private static GestureSystem instance = new GestureSystem();
 
  /**
   * List of active listeners
   */
  protected List<GestureListener> listeners;
 
  private GestureSystem() {};
 
  public static GestureSystem get() {
    return instance;
  }
 
  private boolean isTimerExpired() {
    return timer <= 0;
  }
 
  private void tickTimer(float tpf) {
    if (timer < 0) return;
    timer -= tpf;
  }
 
  private void resetTimer() {
    timer = SingelTouchTimout;
  }
 
  public void update(float tpf) {
    // check if we have one or two cursors
    if (cursor1 == null || cursor2 == null) {
      tickTimer(tpf);
      // update single touch system
      updateSingleTouch(twoCursors);
    } else if (cursor1 != null && cursor2 != null) {
      resetTimer();
      // update multi touch system
      updateMultiTouch();
      // set the two cursor flag to ignore click events
      twoCursors = true;
    }
    // no cursors then reset the twoCursors flag
    if (cursor1 == null && cursor2 == null && twoCursors) {
      twoCursors = false;
    }
  }
 
  private void updateSingleTouch(boolean twoCursors) {
    //TODO: fix click event when two fingers a released at the same time
   
    // get the cursors for long click event
    CursorStore cursor = null;
    if (cursor1 != null) {
      cursor = cursor1;
    } else if (cursor2 != null){
      cursor = cursor2;
    }
    // if we have an cursor and the timer expired
    if (cursor != null && !twoCursors) {
      // if time is expired reset timer and trigger event
      if (isTimerExpired()) {
        resetTimer();
        Vector2f longClick = cursor.getVector();
        for (int i = 0; i < listeners.size(); i++) {
          GestureListener listener = listeners.get(i);
          listener.longClick(longClick);
        }
      } else {
        // if the cursor has move over the longClickMaxDelta reset the Timer
        if (FastMath.abs(cursor.xDelta) > longClickMaxDelta ||
          FastMath.abs(cursor.yDelta) > longClickMaxDelta ) {
          resetTimer();
        }
      }
    }
   
   
    // get the last cursor for up and click event
    CursorStore lastCursor = null;
    if (lastCursor1 != null && lastCursor2 == null) {
      lastCursor = lastCursor1;
      lastCursor1 = null;
    } else if (lastCursor2 != null && lastCursor1 == null){
      lastCursor = lastCursor2;
      lastCursor2 = null;
    } else {
      // no last cursor or multitouch event ended
      return;
    }
    // we know we have an up event -> reset long click timer
    resetTimer();
   
    Vector2f up = lastCursor.getVector();
    // loop through listeners and trigger up and click events
    for (int i = 0; i < listeners.size(); i++) {
      GestureListener listener = listeners.get(i);
      listener.up(up);
      if (cursor1 == null && cursor2 == null && !twoCursors) {
        listener.click(up);
      }
    }
   
  }
 
  private void updateMultiTouch()  {
    if (cursor1.hasNotMoved() && cursor2.hasNotMoved()) return;
    if (cursor1.isNew() || cursor2.isNew()) return;
   
    float distancePre = FastMath.abs(cursor1.getPreVector().distance(cursor2.getPreVector()));
    float distanceNow = FastMath.abs(cursor1.getVector().distance(cursor2.getVector()));
   
    float zoom = distanceNow - distancePre;
 
    Vector2f nPre = cursor1.getPreVector().subtract(cursor2.getPreVector()).normalize();
    Vector2f nNow = cursor1.getVector().subtract(cursor2.getVector()).normalize();
   
    // scalar product  -> angle
    float angle = FastMath.acos(nPre.x * nNow.x + nPre.y * nNow.y);
   
    //TODO: Find a better calculation
    if (!isPosRotation(nPre, nNow, angle)) angle = -angle;
 
    Vector2f pre = cursor1.getVector().subtract(cursor1.getPreVector());
    Vector2f now = cursor2.getVector().subtract(cursor2.getPreVector());
   
    Vector2f move = pre.add(now).divide(2f);
   
    for (int i = 0; i < listeners.size(); i++) {
      GestureListener listener = listeners.get(i);
      listener.zoom(zoom);
      listener.rotate(angle);
      listener.move(move);
    }
   
  }
 
  public void move(Vector2f move) {
    for (int i = 0; i < listeners.size(); i++) {
      GestureListener listener = listeners.get(i);
      listener.move(move);
    }
  }
 
  public void zoom(float zoom) {
    for (int i = 0; i < listeners.size(); i++) {
      GestureListener listener = listeners.get(i);
      listener.zoom(zoom);
    }
  }
 
  private boolean isPosRotation(Vector2f v1, Vector2f v2, float angle) {
   
    float calculationError = 0.01f;
   
    float posRotX = FastMath.cos(FastMath.atan2(v1.y, v1.x)+angle);
    float posRotY = FastMath.sin(FastMath.atan2(v1.y, v1.x)+angle);
   
    float divX = FastMath.abs(v2.x - posRotX);
    float divY = FastMath.abs(v2.y- posRotY);
   
    if (divX > calculationError || divY > calculationError) {
      return true;
    }    
    return false;
  }

  public void onMove(int cursorId, int xDelta, int yDelta, int x, int y) {
    if (cursorId == 1) {
      cursor1 = new CursorStore(xDelta, yDelta, x, y);
    } else {
      cursor2 = new CursorStore(xDelta, yDelta, x, y);
    }
  }

  public void onNew(int cursorId, int x, int y) {
    if (cursorId == 1) {
      cursor1 = new CursorStore(x, y);
      lastCursor1 = null;
    } else {
      cursor2 = new CursorStore(x, y);
      lastCursor2 = null;
    }
  }

  public void onRelease(int cursorId) {
    if (cursorId == 1) {
      lastCursor1 = cursor1;
      cursor1 = null;
    } else {
      lastCursor2 = cursor2;
      cursor2 = null;
    }
  }
 
    public void addListener( GestureListener listener ) {
        if ( listeners == null ) {
            listeners = new ArrayList<GestureListener>();
        }
        listeners.add( listener );
    }

    /**
     * Unsubscribe a listener. Disable event generation if no more listeners.
     *
     * @param listener to be unsubscribed
     */
    public void removeListener( GestureListener listener ) {
        if ( listeners != null ) {
            listeners.remove( listener );
            if (listeners.size() == 0) listeners = null;
        }
    }

    /**
     * Remove all listeners and disable event generation.
     */
    public void removeListeners() {
        if ( listeners != null ) {
            listeners.clear();
            listeners = null;
        }
    }
}
TOP

Related Classes of org.pollux3d.gesture.GestureSystem$CursorStore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.