Loading tests/sketch/src/com/android/gesture/GestureLibrary.java +8 −8 Original line number Diff line number Diff line Loading @@ -49,11 +49,11 @@ public class GestureLibrary { private static final String NAMESPACE = ""; public static final int SEQUENCE_INVARIANT = 1; // when SEQUENCE_SENSITIVE is used, only single stroke gestures are allowed // when SEQUENCE_SENSITIVE is used, only single stroke gestures are currently allowed public static final int SEQUENCE_SENSITIVE = 2; // ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures public static final int ORIENTATION_INVARIANT = 1; // ORIENTATION_SENSITIVE is only available for single stroke gestures public static final int ORIENTATION_SENSITIVE = 2; private int mSequenceType = SEQUENCE_SENSITIVE; Loading @@ -77,8 +77,8 @@ public class GestureLibrary { } /** * Specify whether the gesture library will handle orientation sensitive * gestures. Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE * Specify how the gesture library will handle orientation. * Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE * * @param style */ Loading Loading @@ -114,8 +114,8 @@ public class GestureLibrary { * @return a list of predictions of possible entries for a given gesture */ public ArrayList<Prediction> recognize(Gesture gesture) { Instance instance = Instance.createInstance(this, gesture, null); return mClassifier.classify(this, instance); Instance instance = Instance.createInstance(mSequenceType, gesture, null); return mClassifier.classify(mSequenceType, instance.vector); } /** Loading @@ -134,7 +134,7 @@ public class GestureLibrary { mEntryName2gestures.put(entryName, gestures); } gestures.add(gesture); mClassifier.addInstance(Instance.createInstance(this, gesture, entryName)); mClassifier.addInstance(Instance.createInstance(mSequenceType, gesture, entryName)); mChanged = true; } Loading Loading @@ -300,7 +300,7 @@ public class GestureLibrary { mGestures = null; } else if (localName.equals(GestureConstants.XML_TAG_GESTURE)) { mGestures.add(mCurrentGesture); mClassifier.addInstance(Instance.createInstance(GestureLibrary.this, mClassifier.addInstance(Instance.createInstance(mSequenceType, mCurrentGesture, mEntryName)); mCurrentGesture = null; } else if (localName.equals(GestureConstants.XML_TAG_STROKE)) { Loading tests/sketch/src/com/android/gesture/GestureStroke.java +8 −0 Original line number Diff line number Diff line Loading @@ -244,4 +244,12 @@ public class GestureStroke { public void invalidate() { mCachedPath = null; } /** * Compute an oriented bounding box of the stroke * @return OrientedBoundingBox */ public OrientedBoundingBox computeOrientedBoundingBox() { return GestureUtilities.computeOrientedBoundingBox(points); } } tests/sketch/src/com/android/gesture/GestureUtilities.java +8 −10 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ import java.io.IOException; import static com.android.gesture.GestureConstants.*; public final class GestureUtilities { final class GestureUtilities { private static final int TEMPORAL_SAMPLING_RATE = 16; private GestureUtilities() { Loading Loading @@ -348,33 +348,31 @@ public final class GestureUtilities { /** * Calculate the cosine distance between two instances * * @param in1 * @param in2 * @param vector1 * @param vector2 * @return the distance between 0 and Math.PI */ static double cosineDistance(Instance in1, Instance in2) { static double cosineDistance(float[] vector1, float[] vector2) { float sum = 0; float[] vector1 = in1.vector; float[] vector2 = in2.vector; int len = vector1.length; for (int i = 0; i < len; i++) { sum += vector1[i] * vector2[i]; } return Math.acos(sum / (in1.magnitude * in2.magnitude)); return Math.acos(sum); } public static OrientedBoundingBox computeOrientedBoundingBox(ArrayList<GesturePoint> pts) { static OrientedBoundingBox computeOrientedBoundingBox(ArrayList<GesturePoint> pts) { GestureStroke stroke = new GestureStroke(pts); float[] points = temporalSampling(stroke, TEMPORAL_SAMPLING_RATE); return computeOrientedBoundingBox(points); } public static OrientedBoundingBox computeOrientedBoundingBox(float[] points) { static OrientedBoundingBox computeOrientedBoundingBox(float[] points) { float[] meanVector = computeCentroid(points); return computeOrientedBoundingBox(points, meanVector); } public static OrientedBoundingBox computeOrientedBoundingBox(float[] points, float[] centroid) { static OrientedBoundingBox computeOrientedBoundingBox(float[] points, float[] centroid) { Matrix tr = new Matrix(); tr.setTranslate(-centroid[0], -centroid[1]); tr.mapPoints(points); Loading tests/sketch/src/com/android/gesture/Instance.java +21 −13 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ package com.android.gesture; class Instance { private static final int SEQUENCE_SAMPLE_SIZE = 16; private static final int PATCH_SAMPLE_SIZE = 8; private static final int PATCH_SAMPLE_SIZE = 16; private final static float[] ORIENTATIONS = { 0, 45, 90, 135, 180, -0, -45, -90, -135, -180 Loading @@ -35,9 +35,6 @@ class Instance { // the label can be null final String label; // the length of the vector final float magnitude; // the id of the instance final long id; Loading @@ -45,12 +42,19 @@ class Instance { this.id = id; vector = sample; label = sampleName; } private void normalize() { float[] sample = vector; float sum = 0; int size = sample.length; for (int i = 0; i < size; i++) { sum += sample[i] * sample[i]; } magnitude = (float) Math.sqrt(sum); float magnitude = (float) Math.sqrt(sum); for (int i = 0; i < size; i++) { sample[i] /= magnitude; } } /** Loading @@ -60,21 +64,25 @@ class Instance { * @param label * @return the instance */ static Instance createInstance(GestureLibrary gesturelib, Gesture gesture, String label) { static Instance createInstance(int samplingType, Gesture gesture, String label) { float[] pts; if (gesturelib.getGestureType() == GestureLibrary.SEQUENCE_SENSITIVE) { pts = temporalSampler(gesturelib, gesture); Instance instance; if (samplingType == GestureLibrary.SEQUENCE_SENSITIVE) { pts = temporalSampler(samplingType, gesture); instance = new Instance(gesture.getID(), pts, label); instance.normalize(); } else { pts = spatialSampler(gesture); instance = new Instance(gesture.getID(), pts, label); } return new Instance(gesture.getID(), pts, label); return instance; } private static float[] spatialSampler(Gesture gesture) { return GestureUtilities.spatialSampling(gesture, PATCH_SAMPLE_SIZE); } private static float[] temporalSampler(GestureLibrary gesturelib, Gesture gesture) { private static float[] temporalSampler(int samplingType, Gesture gesture) { float[] pts = GestureUtilities.temporalSampling(gesture.getStrokes().get(0), SEQUENCE_SAMPLE_SIZE); float[] center = GestureUtilities.computeCentroid(pts); Loading @@ -82,7 +90,7 @@ class Instance { orientation *= 180 / Math.PI; float adjustment = -orientation; if (gesturelib.getOrientationStyle() == GestureLibrary.ORIENTATION_SENSITIVE) { if (samplingType == GestureLibrary.ORIENTATION_SENSITIVE) { int count = ORIENTATIONS.length; for (int i = 0; i < count; i++) { float delta = ORIENTATIONS[i] - orientation; Loading tests/sketch/src/com/android/gesture/InstanceLearner.java +5 −5 Original line number Diff line number Diff line Loading @@ -34,21 +34,21 @@ class InstanceLearner extends Learner { private static final String LOGTAG = "InstanceLearner"; @Override ArrayList<Prediction> classify(GestureLibrary lib, Instance instance) { ArrayList<Prediction> classify(int gestureType, float[] vector) { ArrayList<Prediction> predictions = new ArrayList<Prediction>(); ArrayList<Instance> instances = getInstances(); int count = instances.size(); TreeMap<String, Double> label2score = new TreeMap<String, Double>(); for (int i = 0; i < count; i++) { Instance sample = instances.get(i); if (sample.vector.length != instance.vector.length) { if (sample.vector.length != vector.length) { continue; } double distance; if (lib.getGestureType() == GestureLibrary.SEQUENCE_SENSITIVE) { distance = GestureUtilities.cosineDistance(sample, instance); if (gestureType == GestureLibrary.SEQUENCE_SENSITIVE) { distance = GestureUtilities.cosineDistance(sample.vector, vector); } else { distance = GestureUtilities.squaredEuclideanDistance(sample.vector, instance.vector); distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector); } double weight; if (distance == 0) { Loading Loading
tests/sketch/src/com/android/gesture/GestureLibrary.java +8 −8 Original line number Diff line number Diff line Loading @@ -49,11 +49,11 @@ public class GestureLibrary { private static final String NAMESPACE = ""; public static final int SEQUENCE_INVARIANT = 1; // when SEQUENCE_SENSITIVE is used, only single stroke gestures are allowed // when SEQUENCE_SENSITIVE is used, only single stroke gestures are currently allowed public static final int SEQUENCE_SENSITIVE = 2; // ORIENTATION_SENSITIVE and ORIENTATION_INVARIANT are only for SEQUENCE_SENSITIVE gestures public static final int ORIENTATION_INVARIANT = 1; // ORIENTATION_SENSITIVE is only available for single stroke gestures public static final int ORIENTATION_SENSITIVE = 2; private int mSequenceType = SEQUENCE_SENSITIVE; Loading @@ -77,8 +77,8 @@ public class GestureLibrary { } /** * Specify whether the gesture library will handle orientation sensitive * gestures. Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE * Specify how the gesture library will handle orientation. * Use ORIENTATION_INVARIANT or ORIENTATION_SENSITIVE * * @param style */ Loading Loading @@ -114,8 +114,8 @@ public class GestureLibrary { * @return a list of predictions of possible entries for a given gesture */ public ArrayList<Prediction> recognize(Gesture gesture) { Instance instance = Instance.createInstance(this, gesture, null); return mClassifier.classify(this, instance); Instance instance = Instance.createInstance(mSequenceType, gesture, null); return mClassifier.classify(mSequenceType, instance.vector); } /** Loading @@ -134,7 +134,7 @@ public class GestureLibrary { mEntryName2gestures.put(entryName, gestures); } gestures.add(gesture); mClassifier.addInstance(Instance.createInstance(this, gesture, entryName)); mClassifier.addInstance(Instance.createInstance(mSequenceType, gesture, entryName)); mChanged = true; } Loading Loading @@ -300,7 +300,7 @@ public class GestureLibrary { mGestures = null; } else if (localName.equals(GestureConstants.XML_TAG_GESTURE)) { mGestures.add(mCurrentGesture); mClassifier.addInstance(Instance.createInstance(GestureLibrary.this, mClassifier.addInstance(Instance.createInstance(mSequenceType, mCurrentGesture, mEntryName)); mCurrentGesture = null; } else if (localName.equals(GestureConstants.XML_TAG_STROKE)) { Loading
tests/sketch/src/com/android/gesture/GestureStroke.java +8 −0 Original line number Diff line number Diff line Loading @@ -244,4 +244,12 @@ public class GestureStroke { public void invalidate() { mCachedPath = null; } /** * Compute an oriented bounding box of the stroke * @return OrientedBoundingBox */ public OrientedBoundingBox computeOrientedBoundingBox() { return GestureUtilities.computeOrientedBoundingBox(points); } }
tests/sketch/src/com/android/gesture/GestureUtilities.java +8 −10 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ import java.io.IOException; import static com.android.gesture.GestureConstants.*; public final class GestureUtilities { final class GestureUtilities { private static final int TEMPORAL_SAMPLING_RATE = 16; private GestureUtilities() { Loading Loading @@ -348,33 +348,31 @@ public final class GestureUtilities { /** * Calculate the cosine distance between two instances * * @param in1 * @param in2 * @param vector1 * @param vector2 * @return the distance between 0 and Math.PI */ static double cosineDistance(Instance in1, Instance in2) { static double cosineDistance(float[] vector1, float[] vector2) { float sum = 0; float[] vector1 = in1.vector; float[] vector2 = in2.vector; int len = vector1.length; for (int i = 0; i < len; i++) { sum += vector1[i] * vector2[i]; } return Math.acos(sum / (in1.magnitude * in2.magnitude)); return Math.acos(sum); } public static OrientedBoundingBox computeOrientedBoundingBox(ArrayList<GesturePoint> pts) { static OrientedBoundingBox computeOrientedBoundingBox(ArrayList<GesturePoint> pts) { GestureStroke stroke = new GestureStroke(pts); float[] points = temporalSampling(stroke, TEMPORAL_SAMPLING_RATE); return computeOrientedBoundingBox(points); } public static OrientedBoundingBox computeOrientedBoundingBox(float[] points) { static OrientedBoundingBox computeOrientedBoundingBox(float[] points) { float[] meanVector = computeCentroid(points); return computeOrientedBoundingBox(points, meanVector); } public static OrientedBoundingBox computeOrientedBoundingBox(float[] points, float[] centroid) { static OrientedBoundingBox computeOrientedBoundingBox(float[] points, float[] centroid) { Matrix tr = new Matrix(); tr.setTranslate(-centroid[0], -centroid[1]); tr.mapPoints(points); Loading
tests/sketch/src/com/android/gesture/Instance.java +21 −13 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ package com.android.gesture; class Instance { private static final int SEQUENCE_SAMPLE_SIZE = 16; private static final int PATCH_SAMPLE_SIZE = 8; private static final int PATCH_SAMPLE_SIZE = 16; private final static float[] ORIENTATIONS = { 0, 45, 90, 135, 180, -0, -45, -90, -135, -180 Loading @@ -35,9 +35,6 @@ class Instance { // the label can be null final String label; // the length of the vector final float magnitude; // the id of the instance final long id; Loading @@ -45,12 +42,19 @@ class Instance { this.id = id; vector = sample; label = sampleName; } private void normalize() { float[] sample = vector; float sum = 0; int size = sample.length; for (int i = 0; i < size; i++) { sum += sample[i] * sample[i]; } magnitude = (float) Math.sqrt(sum); float magnitude = (float) Math.sqrt(sum); for (int i = 0; i < size; i++) { sample[i] /= magnitude; } } /** Loading @@ -60,21 +64,25 @@ class Instance { * @param label * @return the instance */ static Instance createInstance(GestureLibrary gesturelib, Gesture gesture, String label) { static Instance createInstance(int samplingType, Gesture gesture, String label) { float[] pts; if (gesturelib.getGestureType() == GestureLibrary.SEQUENCE_SENSITIVE) { pts = temporalSampler(gesturelib, gesture); Instance instance; if (samplingType == GestureLibrary.SEQUENCE_SENSITIVE) { pts = temporalSampler(samplingType, gesture); instance = new Instance(gesture.getID(), pts, label); instance.normalize(); } else { pts = spatialSampler(gesture); instance = new Instance(gesture.getID(), pts, label); } return new Instance(gesture.getID(), pts, label); return instance; } private static float[] spatialSampler(Gesture gesture) { return GestureUtilities.spatialSampling(gesture, PATCH_SAMPLE_SIZE); } private static float[] temporalSampler(GestureLibrary gesturelib, Gesture gesture) { private static float[] temporalSampler(int samplingType, Gesture gesture) { float[] pts = GestureUtilities.temporalSampling(gesture.getStrokes().get(0), SEQUENCE_SAMPLE_SIZE); float[] center = GestureUtilities.computeCentroid(pts); Loading @@ -82,7 +90,7 @@ class Instance { orientation *= 180 / Math.PI; float adjustment = -orientation; if (gesturelib.getOrientationStyle() == GestureLibrary.ORIENTATION_SENSITIVE) { if (samplingType == GestureLibrary.ORIENTATION_SENSITIVE) { int count = ORIENTATIONS.length; for (int i = 0; i < count; i++) { float delta = ORIENTATIONS[i] - orientation; Loading
tests/sketch/src/com/android/gesture/InstanceLearner.java +5 −5 Original line number Diff line number Diff line Loading @@ -34,21 +34,21 @@ class InstanceLearner extends Learner { private static final String LOGTAG = "InstanceLearner"; @Override ArrayList<Prediction> classify(GestureLibrary lib, Instance instance) { ArrayList<Prediction> classify(int gestureType, float[] vector) { ArrayList<Prediction> predictions = new ArrayList<Prediction>(); ArrayList<Instance> instances = getInstances(); int count = instances.size(); TreeMap<String, Double> label2score = new TreeMap<String, Double>(); for (int i = 0; i < count; i++) { Instance sample = instances.get(i); if (sample.vector.length != instance.vector.length) { if (sample.vector.length != vector.length) { continue; } double distance; if (lib.getGestureType() == GestureLibrary.SEQUENCE_SENSITIVE) { distance = GestureUtilities.cosineDistance(sample, instance); if (gestureType == GestureLibrary.SEQUENCE_SENSITIVE) { distance = GestureUtilities.cosineDistance(sample.vector, vector); } else { distance = GestureUtilities.squaredEuclideanDistance(sample.vector, instance.vector); distance = GestureUtilities.squaredEuclideanDistance(sample.vector, vector); } double weight; if (distance == 0) { Loading