summaryrefslogtreecommitdiffstats
path: root/core/java/android/gesture/Instance.java
blob: 7922faba3f981c2813bf0aaf55ded36b97871c40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
 * Copyright (C) 2008-2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.gesture;

import android.graphics.Matrix;

/**
 * An instance represents a sample if the label is available or a query if the
 * label is null.
 */
class Instance {
    private static final int SEQUENCE_SAMPLE_SIZE = 16;

    private static final int PATCH_SAMPLE_SIZE = 16;

    private final static float[] ORIENTATIONS = {
            0, 45, 90, 135, 180, -0, -45, -90, -135, -180
    };

    // the feature vector
    final float[] vector;

    // the label can be null
    final String label;

    // the id of the instance
    final long id;
    
    private Instance(long id, float[] sample, String sampleName) {
        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];
        }

        float magnitude = (float) Math.sqrt(sum);
        for (int i = 0; i < size; i++) {
            sample[i] /= magnitude;
        }
    }

    /**
     * create a learning instance for a single stroke gesture
     * 
     * @param gesture
     * @param label
     * @return the instance
     */
    static Instance createInstance(int samplingType, Gesture gesture, String label) {
        float[] pts;
        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 instance;
    }
    
    private static float[] spatialSampler(Gesture gesture) {
        return GestureUtilities.spatialSampling(gesture, PATCH_SAMPLE_SIZE);
    }

    private static float[] temporalSampler(int samplingType, Gesture gesture) {
        float[] pts = GestureUtilities.temporalSampling(gesture.getStrokes().get(0),
                SEQUENCE_SAMPLE_SIZE);
        float[] center = GestureUtilities.computeCentroid(pts);
        float orientation = (float) Math.atan2(pts[1] - center[1], pts[0] - center[0]);
        orientation *= 180 / Math.PI;

        float adjustment = -orientation;
        if (samplingType == GestureLibrary.ORIENTATION_SENSITIVE) {
            int count = ORIENTATIONS.length;
            for (int i = 0; i < count; i++) {
                float delta = ORIENTATIONS[i] - orientation;
                if (Math.abs(delta) < Math.abs(adjustment)) {
                    adjustment = delta;
                }
            }
        }

        Matrix m = new Matrix();
        m.setTranslate(-center[0], -center[1]);
        m.postRotate(adjustment);
        m.mapPoints(pts);

        return pts;
    }

}