MicroGestureDetectionStrategyPrediction.java :  » UnTagged » ba10-bsha-1 » ch » zhaw » ba10_bsha_1 » strategies » Android Open Source

Android Open Source » UnTagged » ba10 bsha 1 
ba10 bsha 1 » ch » zhaw » ba10_bsha_1 » strategies » MicroGestureDetectionStrategyPrediction.java
package ch.zhaw.ba10_bsha_1.strategies;


import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import ch.zhaw.ba10_bsha_1.StrategyArgument;
import ch.zhaw.ba10_bsha_1.TouchPoint;
import ch.zhaw.ba10_bsha_1.service.MicroGesture;


/**
 * Implementation of {@link IMicroGestureDetectionStrategy} which tries to distinguish between the different
 * {@link MicroGesture}s by using a prediction of the next point's position and starting a new {@link MicroGesture}
 * if the actual next point is not within a certain tolerance of the predicted position.
 * (Deprecated because the strategy was found ineffective and because it was not adjusted to changes in the overall 
 * design of the application)
 * 
 * @author Julian Hanhart, Dominik Giger
 */
@Deprecated
public class MicroGestureDetectionStrategyPrediction extends BaseStrategy implements IMicroGestureDetectionStrategy {

  
  //---------------------------------------------------------------------------
  // Attributes
  //---------------------------------------------------------------------------
  
  
  private float predictionTolerance = 5;
  private float fieldHeight = 0;
  private boolean mergeMicroGestures = true;


  //---------------------------------------------------------------------------
  // Implementation of BaseStrategy's abstract methods
  //---------------------------------------------------------------------------
  
  
  @Override
  public void initialize() {
    if (!hasArgument("FieldHeight")) {
      addArgument(new StrategyArgument(getStrategyName(), "FieldHeight", "Height of input field"));
    }
  }

  @Override
  protected String getStrategyName() {
    return "Prediction";
  }
  
  @Override
  protected String getStrategyDescription() {
    return "Detect MicroGestures by predicting the expected position of the next point";
  } 


  //---------------------------------------------------------------------------
  // Implementation of IMicroGestureDetectionStrategy
  //---------------------------------------------------------------------------
  

  /**
   * Detect {@link MicroGesture}s in the {@link TouchPoint}s of the given {@link MicroGesture}s
   * 
   * @param micro_gestures
   * @return
   */
  @Override
  public Collection<MicroGesture> detectMicroGestures(Collection<MicroGesture> micro_gestures) {
    fieldHeight = Float.parseFloat(getArgument("FieldHeight").getArgumentValue());
    ArrayList<MicroGesture> result = new ArrayList<MicroGesture>();
    Iterator<MicroGesture> itr = micro_gestures.iterator();
    while (itr.hasNext()) {
      MicroGesture mg = itr.next();
      ArrayList<TouchPoint> points = mg.getPoints();
      MicroGesture curr_mg = new MicroGesture();
      if ((points != null) && (points.size() > 0)) {
        TouchPoint[] pts = new TouchPoint[points.size()];
        pts = points.toArray(pts);
        boolean first = true;
        TouchPoint prev = null;
        TouchPoint curr;
        TouchPoint next;
        for (int i = 0; i < pts.length; i++) {
          curr = pts[i];
          //Add point to current MicroGesture if it's the first one
          if (first) {
            first = false;
            curr_mg.addPoint(curr);
            prev = curr;
          //Make prediction if there's a next point
          } else if (i < (pts.length - 2)) {
            next = pts[i + 1];
            //Predict position of next point
            float pred_x = curr.x + (curr.x - prev.x);
            float pred_y = curr.y + (curr.y - prev.y);
            //Complete current MicroGesture and start new one if prediction is not met
            if ((Math.abs(next.x - pred_x) > predictionTolerance) 
                && (Math.abs(next.y - pred_y) > predictionTolerance)) {
              prev = curr;
              curr_mg.addPoint(next);
              curr_mg = analyseMicroGesture(result, curr_mg);
              if (!result.contains(curr_mg)) {
                result.add(curr_mg);
              }
              curr_mg = new MicroGesture();
              first = true;
            //Continue with next point otherwise
            } else if (curr.distanceTo(prev) >= (2 * predictionTolerance)) {
              curr_mg.addPoint(curr);
              prev = curr;
            }
          //Add point to current MicroGesture and complete it if it's the last point
          } else {
            curr_mg.addPoint(curr);
            curr_mg = analyseMicroGesture(result, curr_mg);
            if (!result.contains(curr_mg)) {
              result.add(curr_mg);
            }
          }
        }
      } else {
        curr_mg = new MicroGesture(points);
        result.add(curr_mg);
      }
    }
    return result;
  }


  //---------------------------------------------------------------------------
  // Helper methods
  //---------------------------------------------------------------------------
  

  /**
   * Determine a found {@link MicroGesture}'s direction, type and merge it with the last one if needed
   * 
   * @param list
   * @param mg
   * @return
   */
  private MicroGesture analyseMicroGesture(ArrayList<MicroGesture> list, MicroGesture mg) {
    mg.setDirection(analyseMicroGestureDirection(mg));
    mg.setType(analyseMicroGestureType(mg));
    mg.enableStubMerging(true);
    if (mergeMicroGestures && (list.size() > 0)) {
      MicroGesture last = list.get(list.size() - 1);
      if ((last != null) && last.canMergeWith(mg)) {
        mg = last.merge(mg);
      }
    }
    return mg;
  }
  
  /**
   * Determine a {@link MicroGesture}'s direction
   * 
   * @param mg
   * @return
   */
  private int analyseMicroGestureDirection(MicroGesture mg) {
    float result = 0;
    if (mg.getPoints().size() > 1) {
      TouchPoint first  = mg.getPoints().get(0);
      TouchPoint second = mg.getPoints().get(1);
      float dx = first.x - second.x;
      float dy = first.y - second.y;
      result = (float) (Math.atan2(dy, dx));
    }
    int dir;
    if (directionIsUp(result)) {
      dir = 2;
    }
    else if (directionIsDown(result)) {
      dir = 3;
    }
    else if (directionIsRight(result)) {
      dir = 1;
    }
    else if (directionIsLeft(result)) {
      dir = 0;
    }
    else {
      dir = -1;
    }
    return dir;
  }
  
  private boolean directionIsUp(double direction) {
    return (Math.abs(direction) <= Math.PI) 
        ? (direction > 0) : false;
  }
  
  private boolean directionIsDown(double direction) {
    return (Math.abs(direction) <= Math.PI) 
        ? (direction < 0) : false;
  }
  
  private boolean directionIsRight(double direction) {
    return (Math.abs(direction) <= Math.PI) 
        ? (Math.abs(direction) > (Math.PI / 2)) : false;
  }
  
  private boolean directionIsLeft(double direction) {
    return (Math.abs(direction) <= Math.PI) 
        ? (Math.abs(direction) < (Math.PI / 2)) : false;
  }
  
  /**
   * Determine a {@link MicroGesture}'s type
   * 
   * @param mg
   * @return
   */
  private int analyseMicroGestureType(MicroGesture mg) {
    int type = MicroGesture.TYPE_UNKNOWN;
    TouchPoint[] pts = new TouchPoint[mg.getPoints().size()];
    mg.getPoints().toArray(pts);
    int nop = pts.length; //number of points
    float mg_length = mg.getLength();
    float start_end_distance = pts[0].distanceTo(pts[nop - 1]);
    if ((nop < 3) || (mg_length <= (start_end_distance + predictionTolerance))) {
      if (fieldHeight > 0) {
        if ((start_end_distance - predictionTolerance) <= (fieldHeight / 3)) {
          type = MicroGesture.TYPE_SHORT_LINE;
        } else {
          type = MicroGesture.TYPE_LONG_LINE;
        }
      } else {
        type = MicroGesture.TYPE_LONG_LINE;
      }
    } else {
      type = (calcAngle(pts[0], pts[1], pts[2]) < 2)
          ? MicroGesture.TYPE_NARROW_CURVE : MicroGesture.TYPE_WIDE_CURVE;
    }
    return type;
  }
  
  /**
   * Calculate the angle between three {@link TouchPoint}s
   * 
   * @param first
   * @param second
   * @param third
   * @return
   */
  private float calcAngle(TouchPoint first, TouchPoint second, TouchPoint third) {
    float a = first.distanceTo(second);
    float b = second.distanceTo(third);
    float c = first.distanceTo(third);
    return ((float) Math.acos((Math.pow(a, 2) + Math.pow(b, 2) - Math.pow(c, 2)) / (2 * a * b)));
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.