package advanced.gestureSound.gestures.qualities; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.List; import advanced.gestureSound.Geometry; import org.mt4j.input.inputData.AbstractCursorInputEvt; import org.mt4j.input.inputData.InputCursor; import Jama.Matrix; import advanced.gestureSound.gestures.GestureEngine; import advanced.gestureSound.gestures.filters.KalmanFilter; public class Curvature extends Quality { public static String name="curvature"; KalmanFilter filter; double currentValue=0f; ArrayList<double[]> pastValues; public static Quality cursorDetected(GestureEngine engine) { return new Curvature(engine); } public Curvature(GestureEngine engine) { super(engine); pastValues = new ArrayList<double[]>(); filter = KalmanFilter.buildKF(0.2, 5, 10); filter.setX(new Matrix(new double[][]{{0.01}, {0.01}, {0.01}})); filter.predict(); } @Override public void update(InputCursor in) { double val=0.0f; val = (float) (findCurvature(in)/(Math.PI)); pastValues.add(new double[]{val}); //filter, no. average? Yes. // float pastEvtCount = in.getEvents(10).size(); // val = (currentValue*pastEvtCount + val)/(pastEvtCount+1); // int size = in.getEvents(200).size(); // //if (size > 2) { //this is the.... other method. using least squares. // if (size < 0) { //nonsense, for now. // //size=3; // double[][] b = new double[size][2]; // double[][] a = new double[size][2]; // int pastValuesSize = pastValues.size(); // System.out.println("Size of pastValuesL: "+pastValuesSize+" Size of b:"+size); // for (int x = 0; x < size; x++) { // b[x][0] = pastValues.get(pastValuesSize-x-1)[0]; // b[x][1] = size-x; // a[x][0] = 1; // a[x][1] = x+1; // } // // // Matrix A = new Matrix(a); // Matrix B = new Matrix(b); // System.out.println("A: "+A+" B:"+B); // Matrix sol = A.solve(B); // System.out.println(sol); // for (double[] row : sol.getArray()) // System.out.println("Row: ["+row[0]+","+row[1]+"]"); // val = (float) sol.getArray()[0][0]; // } // if (size > 2) { // // } //this is the spline method http://www.faculty.idc.ac.il/arik/Java/ex2/index.html int n=15; List<AbstractCursorInputEvt> past = in.getEvents(); int sizeofpast = in.getEvents().size(); if (sizeofpast > n) { Point2D[] s = new Point2D[n+1]; for (int i=0;i<n+1;i++) { AbstractCursorInputEvt p = past.get(sizeofpast-i-1); s[i] = new Point2D.Double(p.getPosX(),p.getPosY()); } Point2D p2,p1,p0; p0 = s[0]; p1 = Geometry.evalBezier(s,0.1); p2 = Geometry.evalBezier(s,0.2); val = findCurvature(p0.getX(), p0.getY(), p1.getX(), p1.getY(), p2.getX(), p2.getY()); } //System.out.println("Curvature: "+val); //filter.correct(new Matrix(new double[][]{{val}})); //filter.predict(); //System.out.println("0:"+filter.getX().get(0,0)); //System.out.println("1:"+filter.getX().get(1,0)); //System.out.println("2:"+filter.getX().get(2,0)); //val = (float) filter.getX().get(0,0); //System.out.println("Curvature: "+val); currentValue = val; engine.gestureQualityChange(name, (float)val, in); } private double findCurvature(InputCursor in) { if (in.getEventCount() < 3) return 0.0f; List<AbstractCursorInputEvt> events = in.getEvents(); AbstractCursorInputEvt posEvt = events.get(events.size()-1); AbstractCursorInputEvt prev = events.get(events.size()-2); AbstractCursorInputEvt prev2 = events.get(events.size()-3); if (prev == null) return 0; if (prev2 == null) return 0; return findCurvature(posEvt.getPosX(), posEvt.getPosY(), prev.getPosX(), prev.getPosY(), prev2.getPosX(), prev2.getPosY()); } public static double findCurvature(double x1, double y1, double x2, double y2, double x3, double y3) { double angle1 = getAngle(x1,y1,x2,y2); double angle2 = getAngle(x2,y2,x3,y3); if (angle1 == 0.0f || angle2 == 0.0f) { return 0.0f; } double result = angle1-angle2; if (result > Math.PI) { //System.out.println("Result too big! taking other atan2: "+result+" New: "+(2*Math.PI-result)); result = (2*Math.PI-result); } else if (result < -1*Math.PI) { //System.out.println("Result too small! taking other atan2: "+result+" New: "+(2*Math.PI+result)); result = (2*Math.PI+result); } //System.out.println("Curvature: "+result+" First Angle:"+angle1+" Second Angle: "+angle2); return result; } public static double getAngle(AbstractCursorInputEvt ev1, AbstractCursorInputEvt ev2) { return getAngle(ev1.getPosX(),ev1.getPosY(),ev2.getPosX(), ev2.getPosY()); } public static double getAngle(double x1, double y1, double x2, double y2) { return Math.atan2(x1-x2, y1-y2); } @Override public float getCurrentValue() { return (float)currentValue; } }