Instance.java revision e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886
135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li/*
235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * Copyright (C) 2008-2009 The Android Open Source Project
335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li *
435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * Licensed under the Apache License, Version 2.0 (the "License");
535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * you may not use this file except in compliance with the License.
635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * You may obtain a copy of the License at
735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li *
835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li *      http://www.apache.org/licenses/LICENSE-2.0
935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li *
1035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * Unless required by applicable law or agreed to in writing, software
1135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * distributed under the License is distributed on an "AS IS" BASIS,
1235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * See the License for the specific language governing permissions and
1435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * limitations under the License.
1535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */
1635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
1735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Lipackage com.android.gesture;
1835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
1935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li/**
2035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * An instance represents a sample if the label is available or a query if the
2135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li * label is null.
2235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li */
2335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Liclass Instance {
2435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private static final int SEQUENCE_SAMPLE_SIZE = 16;
2535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
26e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li    private static final int PATCH_SAMPLE_SIZE = 16;
2735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
2835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private final static float[] ORIENTATIONS = {
2935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            0, 45, 90, 135, 180, -0, -45, -90, -135, -180
3035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    };
3135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
3235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    // the feature vector
3335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    final float[] vector;
3435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
3535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    // the label can be null
3635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    final String label;
3735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
3835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    // the id of the instance
39c534727972c3835ed997e84a349f259915ef2cddRomain Guy    final long id;
40e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li
4135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private Instance(long id, float[] sample, String sampleName) {
42c534727972c3835ed997e84a349f259915ef2cddRomain Guy        this.id = id;
4335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        vector = sample;
4435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        label = sampleName;
45e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li    }
46e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li
47e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li    private void normalize() {
48e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        float[] sample = vector;
4935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        float sum = 0;
5035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        int size = sample.length;
5135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        for (int i = 0; i < size; i++) {
5235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            sum += sample[i] * sample[i];
5335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        }
54e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        float magnitude = (float) Math.sqrt(sum);
55e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        for (int i = 0; i < size; i++) {
56e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li            sample[i] /= magnitude;
57e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        }
5835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    }
5935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
6035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    /**
6135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * create a learning instance for a single stroke gesture
6235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     *
6335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param gesture
6435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @param label
6535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     * @return the instance
6635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li     */
67e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li    static Instance createInstance(int samplingType, Gesture gesture, String label) {
6835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        float[] pts;
69e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        Instance instance;
70e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        if (samplingType == GestureLibrary.SEQUENCE_SENSITIVE) {
71e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li            pts = temporalSampler(samplingType, gesture);
72e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li            instance = new Instance(gesture.getID(), pts, label);
73e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li            instance.normalize();
7435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        } else {
7535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            pts = spatialSampler(gesture);
76e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li            instance = new Instance(gesture.getID(), pts, label);
7735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        }
78e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        return instance;
7935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    }
80e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li
8135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    private static float[] spatialSampler(Gesture gesture) {
82c534727972c3835ed997e84a349f259915ef2cddRomain Guy        return GestureUtilities.spatialSampling(gesture, PATCH_SAMPLE_SIZE);
8335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    }
8435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
85e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li    private static float[] temporalSampler(int samplingType, Gesture gesture) {
86c534727972c3835ed997e84a349f259915ef2cddRomain Guy        float[] pts = GestureUtilities.temporalSampling(gesture.getStrokes().get(0),
8735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li                SEQUENCE_SAMPLE_SIZE);
88c534727972c3835ed997e84a349f259915ef2cddRomain Guy        float[] center = GestureUtilities.computeCentroid(pts);
8935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        float orientation = (float) Math.atan2(pts[1] - center[1], pts[0] - center[0]);
9035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        orientation *= 180 / Math.PI;
9135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
9235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        float adjustment = -orientation;
93e6ea003ab66ea8bd91bed8aaf5c3b4cd75555886Yang Li        if (samplingType == GestureLibrary.ORIENTATION_SENSITIVE) {
9435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            int count = ORIENTATIONS.length;
9535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            for (int i = 0; i < count; i++) {
9635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li                float delta = ORIENTATIONS[i] - orientation;
9735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li                if (Math.abs(delta) < Math.abs(adjustment)) {
9835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li                    adjustment = delta;
9935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li                }
10035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li            }
10135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        }
10235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
10335aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        android.graphics.Matrix m = new android.graphics.Matrix();
10435aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        m.setTranslate(-center[0], -center[1]);
10535aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        android.graphics.Matrix rotation = new android.graphics.Matrix();
10635aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        rotation.setRotate(adjustment);
10735aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        m.postConcat(rotation);
10835aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        m.mapPoints(pts);
10935aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li        return pts;
11035aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li    }
11135aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li
11235aa84b1f9f5e42dd00cb66df993ed1628c8963bYang Li}
113