1 /* 2 * Copyright (C) 2008-2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.gesture; 18 19 20 /** 21 * An instance represents a sample if the label is available or a query if the 22 * label is null. 23 */ 24 class Instance { 25 private static final int SEQUENCE_SAMPLE_SIZE = 16; 26 27 private static final int PATCH_SAMPLE_SIZE = 16; 28 29 private final static float[] ORIENTATIONS = { 30 0, (float) (Math.PI / 4), (float) (Math.PI / 2), (float) (Math.PI * 3 / 4), 31 (float) Math.PI, -0, (float) (-Math.PI / 4), (float) (-Math.PI / 2), 32 (float) (-Math.PI * 3 / 4), (float) -Math.PI 33 }; 34 35 // the feature vector 36 final float[] vector; 37 38 // the label can be null 39 final String label; 40 41 // the id of the instance 42 final long id; 43 44 private Instance(long id, float[] sample, String sampleName) { 45 this.id = id; 46 vector = sample; 47 label = sampleName; 48 } 49 50 private void normalize() { 51 float[] sample = vector; 52 float sum = 0; 53 54 int size = sample.length; 55 for (int i = 0; i < size; i++) { 56 sum += sample[i] * sample[i]; 57 } 58 59 float magnitude = (float)Math.sqrt(sum); 60 for (int i = 0; i < size; i++) { 61 sample[i] /= magnitude; 62 } 63 } 64 65 /** 66 * create a learning instance for a single stroke gesture 67 * 68 * @param gesture 69 * @param label 70 * @return the instance 71 */ 72 static Instance createInstance(int sequenceType, int orientationType, Gesture gesture, String label) { 73 float[] pts; 74 Instance instance; 75 if (sequenceType == GestureStore.SEQUENCE_SENSITIVE) { 76 pts = temporalSampler(orientationType, gesture); 77 instance = new Instance(gesture.getID(), pts, label); 78 instance.normalize(); 79 } else { 80 pts = spatialSampler(gesture); 81 instance = new Instance(gesture.getID(), pts, label); 82 } 83 return instance; 84 } 85 86 private static float[] spatialSampler(Gesture gesture) { 87 return GestureUtils.spatialSampling(gesture, PATCH_SAMPLE_SIZE, false); 88 } 89 90 private static float[] temporalSampler(int orientationType, Gesture gesture) { 91 float[] pts = GestureUtils.temporalSampling(gesture.getStrokes().get(0), 92 SEQUENCE_SAMPLE_SIZE); 93 float[] center = GestureUtils.computeCentroid(pts); 94 float orientation = (float)Math.atan2(pts[1] - center[1], pts[0] - center[0]); 95 96 float adjustment = -orientation; 97 if (orientationType != GestureStore.ORIENTATION_INVARIANT) { 98 int count = ORIENTATIONS.length; 99 for (int i = 0; i < count; i++) { 100 float delta = ORIENTATIONS[i] - orientation; 101 if (Math.abs(delta) < Math.abs(adjustment)) { 102 adjustment = delta; 103 } 104 } 105 } 106 107 GestureUtils.translate(pts, -center[0], -center[1]); 108 GestureUtils.rotate(pts, adjustment); 109 110 return pts; 111 } 112 113 } 114