diff options
Diffstat (limited to 'tests/sketch/src')
14 files changed, 544 insertions, 1852 deletions
diff --git a/tests/sketch/src/com/android/gesture/Gesture.java b/tests/sketch/src/com/android/gesture/Gesture.java deleted file mode 100755 index 29c07ad..0000000 --- a/tests/sketch/src/com/android/gesture/Gesture.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * 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 com.android.gesture; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PointF; -import android.graphics.RectF; -import android.os.Parcel; -import android.os.Parcelable; - -import com.android.gesture.recognizer.RecognitionUtil; - -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.StringTokenizer; - -/** - * A single stroke gesture. - */ - -public class Gesture implements Parcelable { - - private RectF mBBX; - private float mLength = 0; - private int mColor; - private float mWidth; - private ArrayList<PointF> mPtsBuffer = new ArrayList<PointF>(); - private long mTimestamp = 0; - private long mID; - - private static final long systemStartupTime = System.currentTimeMillis(); - private static int instanceCount = 0; - - public Gesture() { - mID = systemStartupTime + instanceCount++; - } - - public void setColor(int c) { - mColor = c; - } - - public void setStrokeWidth(float w) { - mWidth = w; - } - - public int getColor() { - return mColor; - } - - public float getStrokeWidth() { - return mWidth; - } - - public ArrayList<PointF> getPoints() { - return this.mPtsBuffer; - } - - public int numOfPoints() { - return this.mPtsBuffer.size(); - } - - public void addPoint(float x, float y) { - mPtsBuffer.add(new PointF(x, y)); - if (mBBX == null) { - mBBX = new RectF(); - mBBX.top = y; - mBBX.left = x; - mBBX.right = x; - mBBX.bottom = y; - mLength = 0; - } - else { - PointF lst = mPtsBuffer.get(mPtsBuffer.size()-2); - mLength += Math.sqrt(Math.pow(x-lst.x, 2)+Math.pow(y-lst.y, 2)); - mBBX.union(x, y); - } - mTimestamp = System.currentTimeMillis(); - } - - /** - * @return the length of the gesture - */ - public float getLength() { - return this.mLength; - } - - public RectF getBBX() { - return mBBX; - } - - public void setID(long id) { - mID = id; - } - - public long getID() { - return mID; - } - - public long getTimeStamp() { - return mTimestamp; - } - - public void setTimestamp(long t) { - this.mTimestamp = t; - } - - /** - * draw the gesture - * @param canvas - */ - public void draw(Canvas canvas) { - Paint paint = new Paint(); - paint.setAntiAlias(true); - paint.setDither(true); - paint.setColor(mColor); - paint.setStyle(Paint.Style.STROKE); - paint.setStrokeJoin(Paint.Join.ROUND); - paint.setStrokeCap(Paint.Cap.ROUND); - paint.setStrokeWidth(mWidth); - - Path path = null; - float mX = 0, mY = 0; - Iterator<PointF> it = mPtsBuffer.iterator(); - while (it.hasNext()) { - PointF p = it.next(); - float x = p.x; - float y = p.y; - if (path == null) { - path = new Path(); - path.moveTo(x, y); - mX = x; - mY = y; - } else { - float dx = Math.abs(x - mX); - float dy = Math.abs(y - mY); - if (dx >= 3 || dy >= 3) { - path.quadTo(mX, mY, (x + mX)/2, (y + mY)/2); - mX = x; - mY = y; - } - } - } - - canvas.drawPath(path, paint); - } - - /** - * convert the gesture to a Path - * @param width the width of the bounding box of the target path - * @param height the height of the bounding box of the target path - * @param numSample the num of points needed - * @return the path - */ - public Path toPath(float width, float height, int numSample) { - float[] pts = RecognitionUtil.resample(this, numSample); - RectF rect = this.getBBX(); - float scale = height / rect.height(); - Matrix matrix = new Matrix(); - matrix.setTranslate(-rect.left, -rect.top); - Matrix scalem = new Matrix(); - scalem.setScale(scale, scale); - matrix.postConcat(scalem); - Matrix translate = new Matrix(); - matrix.postConcat(translate); - matrix.mapPoints(pts); - - Path path = null; - float mX = 0, mY = 0; - for (int i=0; i<pts.length-1; i+=2) { - float x = pts[i]; - float y = pts[i+1]; - if (path == null) { - path = new Path(); - path.moveTo(x, y); - mX = x; - mY = y; - } else { - float dx = Math.abs(x - mX); - float dy = Math.abs(y - mY); - if (dx >= 3 || dy >= 3) { - path.quadTo(mX, mY, (x + mX)/2, (y + mY)/2); - mX = x; - mY = y; - } - } - } - return path; - } - - /** - * get a bitmap thumbnail of the gesture with a transparent background - * @param w - * @param h - * @param edge - * @param numSample - * @param foreground - * @return - */ - public Bitmap toBitmap(int w, int h, - int edge, int numSample) { - RectF bbx = this.getBBX(); - Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - Path path = this.toPath(w - 2 * edge, h - 2 * edge, numSample); - Canvas c = new Canvas(bitmap); - //c.drawColor(background); - c.translate(edge, edge); - Paint paint = new Paint(); - paint.setAntiAlias(true); - paint.setDither(true); - paint.setColor(mColor); - paint.setStyle(Paint.Style.STROKE); - paint.setStrokeJoin(Paint.Join.ROUND); - paint.setStrokeCap(Paint.Cap.ROUND); - paint.setStrokeWidth(2); - c.drawPath(path, paint); - return bitmap; - } - - /** - * save the gesture as XML - * @param namespace - * @param serializer - * @throws IOException - */ - public void toXML(String namespace, XmlSerializer serializer) throws IOException { - serializer.startTag(namespace, "stroke"); - serializer.attribute(namespace, "timestamp", Long.toString(mTimestamp)); - serializer.attribute(namespace, "id", Long.toString(mID)); - serializer.attribute(namespace, "color", Integer.toString(mColor)); - serializer.attribute(namespace, "width", Float.toString(mWidth)); - Iterator it = this.mPtsBuffer.iterator(); - String pts = ""; - while (it.hasNext()) { - PointF fp = (PointF)it.next(); - if (pts.length() > 0) - pts += ","; - pts += fp.x + "," + fp.y; - } - serializer.text(pts); - serializer.endTag(namespace, "stroke"); - } - - - public void createFromString(String str) { - StringTokenizer st = new StringTokenizer(str, "#"); - - String para = st.nextToken(); - StringTokenizer innerst = new StringTokenizer(para, ","); - this.mBBX = new RectF(); - this.mBBX.left = Float.parseFloat(innerst.nextToken()); - this.mBBX.top = Float.parseFloat(innerst.nextToken()); - this.mBBX.right = Float.parseFloat(innerst.nextToken()); - this.mBBX.bottom = Float.parseFloat(innerst.nextToken()); - - para = st.nextToken(); - innerst = new StringTokenizer(para, ","); - while (innerst.hasMoreTokens()) { - String s = innerst.nextToken().trim(); - if (s.length()==0) - break; - float x = Float.parseFloat(s); - float y = Float.parseFloat(innerst.nextToken()); - this.mPtsBuffer.add(new PointF(x, y)); - } - - para = st.nextToken(); - this.mColor = Integer.parseInt(para); - - para = st.nextToken(); - this.mWidth = Float.parseFloat(para); - - para = st.nextToken(); - this.mLength = Float.parseFloat(para); - - para = st.nextToken(); - this.mTimestamp = Long.parseLong(para); - } - - @Override - public String toString() { - String str = ""; - - str += "#" + this.mBBX.left + "," + this.mBBX.top + "," + - this.mBBX.right + "," + this.mBBX.bottom; - - str += "#"; - Iterator<PointF> it = this.mPtsBuffer.iterator(); - while (it.hasNext()) { - PointF fp = it.next(); - str += fp.x + "," + fp.y + ","; - } - - str += "#"; - str += this.mColor; - - str += "#"; - str += this.mWidth; - - str += "#"; - str += this.mLength; - - str += "#"; - str += this.mTimestamp; - - return str; - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public Gesture createFromParcel(Parcel in) { - String str = in.readString(); - Gesture stk = new Gesture(); - stk.createFromString(str); - return stk; - } - - public Gesture[] newArray(int size) { - return new Gesture[size]; - } - }; - - public static Gesture buildFromArray(byte[] bytes) { - String str = new String(bytes); - Gesture stk = new Gesture(); - stk.createFromString(str); - return stk; - } - - public static byte[] saveToArray(Gesture stk) { - String str = stk.toString(); - return str.getBytes(); - } - - public void writeToParcel(Parcel out, int flags) { - out.writeString(this.toString()); - } - - public int describeContents() { - return CONTENTS_FILE_DESCRIPTOR; - } -} diff --git a/tests/sketch/src/com/android/gesture/GestureLib.java b/tests/sketch/src/com/android/gesture/GestureLib.java deleted file mode 100755 index d0a25f2..0000000 --- a/tests/sketch/src/com/android/gesture/GestureLib.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * 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 com.android.gesture; - -import android.util.Log; -import android.util.Xml; -import android.util.Xml.Encoding; - -import com.android.gesture.recognizer.Classifier; -import com.android.gesture.recognizer.Instance; -import com.android.gesture.recognizer.NearestNeighbor; -import com.android.gesture.recognizer.Prediction; - -import org.xml.sax.Attributes; -import org.xml.sax.ContentHandler; -import org.xml.sax.Locator; -import org.xml.sax.SAXException; -import org.xmlpull.v1.XmlSerializer; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Set; -import java.util.StringTokenizer; - -public class GestureLib { - - private static final String LOGTAG = "GestureLib"; - private static String namespace = "ink"; - private final String datapath; - private HashMap<String, ArrayList<Gesture>> name2gestures = - new HashMap<String, ArrayList<Gesture>>(); - private Classifier mClassifier; - - public GestureLib(String path) { - datapath = path; - mClassifier = new NearestNeighbor(); - } - - public Classifier getClassifier() { - return mClassifier; - } - - /** - * get all the labels in the library - * @return a set of strings - */ - public Set<String> getLabels() { - return name2gestures.keySet(); - } - - public ArrayList<Prediction> recognize(Gesture gesture) { - Instance instance = Instance.createInstance(gesture, null); - return mClassifier.classify(instance); - } - - public void addGesture(String name, Gesture gesture) { - Log.v(LOGTAG, "add an example for gesture: " + name); - ArrayList<Gesture> gestures = name2gestures.get(name); - if (gestures == null) { - gestures = new ArrayList<Gesture>(); - name2gestures.put(name, gestures); - } - gestures.add(gesture); - mClassifier.addInstance( - Instance.createInstance(gesture, name)); - } - - public void removeGesture(String name, Gesture gesture) { - ArrayList<Gesture> gestures = name2gestures.get(name); - if (gestures == null) { - return; - } - - gestures.remove(gesture); - - // if there are no more samples, remove the entry automatically - if (gestures.isEmpty()) { - name2gestures.remove(name); - } - - mClassifier.removeInstance(gesture.getID()); - } - - public ArrayList<Gesture> getGestures(String label) { - ArrayList<Gesture> gestures = name2gestures.get(label); - if (gestures != null) - return (ArrayList<Gesture>)gestures.clone(); - else - return null; - } - - public void load() { - String filename = datapath - + File.separator + "gestures.xml"; - File f = new File(filename); - if (f.exists()) { - try { - loadInk(filename, null); - } - catch (SAXException ex) { - ex.printStackTrace(); - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - - public void save() { - try { - compactSave(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - private void compactSave() throws IOException { - File f = new File(datapath); - if (f.exists() == false) { - f.mkdirs(); - } - String filename = datapath + File.separator + "gestures.xml"; - Log.v(LOGTAG, "save to " + filename); - BufferedOutputStream fos = new BufferedOutputStream( - new FileOutputStream(filename)); - - PrintWriter writer = new PrintWriter(fos); - XmlSerializer serializer = Xml.newSerializer(); - serializer.setOutput(writer); - serializer.startDocument(Encoding.ISO_8859_1.name(), null); - serializer.startTag(namespace, "gestures"); - Iterator<String> it = name2gestures.keySet().iterator(); - while (it.hasNext()) { - String key = it.next(); - ArrayList<Gesture> gestures = name2gestures.get(key); - saveGestures(serializer, key, gestures); - } - - serializer.endTag(namespace, "gestures"); - serializer.endDocument(); - serializer.flush(); - writer.close(); - fos.close(); - } - - private static void saveGestures(XmlSerializer serializer, - String name, ArrayList<Gesture> strokes) throws IOException { - serializer.startTag(namespace, "gesture"); - serializer.startTag(namespace, "name"); - serializer.text(name); - serializer.endTag(namespace, "name"); - Iterator<Gesture> it = strokes.iterator(); - while (it.hasNext()) { - Gesture stk = it.next(); - stk.toXML(namespace, serializer); - } - serializer.endTag(namespace, "gesture"); - } - - private void loadInk(String filename, String label) throws SAXException, IOException { - Log.v(LOGTAG, "load from " + filename); - BufferedInputStream in = new BufferedInputStream( - new FileInputStream(filename)); - Xml.parse(in, Encoding.ISO_8859_1, new CompactInkHandler()); - in.close(); - } - - class CompactInkHandler implements ContentHandler { - - Gesture currentGesture = null; - StringBuffer buffer = null; - String gestureName; - ArrayList<Gesture> gestures; - - CompactInkHandler() { - } - - // Receive notification of character data. - public void characters(char[] ch, int start, int length) { - buffer.append(ch, start, length); - } - - //Receive notification of the end of a document. - public void endDocument() { - } - - // Receive notification of the end of an element. - public void endElement(String uri, String localName, String qName) { - if (localName.equals("gesture")) { - name2gestures.put(gestureName, gestures); - gestures = null; - } else if (localName.equals("name")) { - gestureName = buffer.toString(); - } else if (localName.equals("stroke")) { - StringTokenizer tokenizer = new StringTokenizer(buffer.toString(), ","); - while (tokenizer.hasMoreTokens()) { - String str = tokenizer.nextToken(); - float x = Float.parseFloat(str); - str = tokenizer.nextToken(); - float y = Float.parseFloat(str); - try - { - currentGesture.addPoint(x, y); - } - catch(Exception ex) { - ex.printStackTrace(); - } - } - gestures.add(currentGesture); - mClassifier.addInstance( - Instance.createInstance(currentGesture, gestureName)); - currentGesture = null; - } - } - - // End the scope of a prefix-URI mapping. - public void endPrefixMapping(String prefix) { - } - - //Receive notification of ignorable whitespace in element content. - public void ignorableWhitespace(char[] ch, int start, int length) { - } - - //Receive notification of a processing instruction. - public void processingInstruction(String target, String data) { - } - - // Receive an object for locating the origin of SAX document events. - public void setDocumentLocator(Locator locator) { - } - - // Receive notification of a skipped entity. - public void skippedEntity(String name) { - } - - // Receive notification of the beginning of a document. - public void startDocument() { - } - - // Receive notification of the beginning of an element. - public void startElement(String uri, String localName, String qName, Attributes atts) { - if (localName.equals("gesture")) { - gestures = new ArrayList<Gesture>(); - } else if (localName.equals("name")) { - buffer = new StringBuffer(); - } else if (localName.equals("stroke")) { - currentGesture = new Gesture(); - currentGesture.setTimestamp(Long.parseLong(atts.getValue(namespace, "timestamp"))); - currentGesture.setColor(Integer.parseInt(atts.getValue(namespace, "color"))); - currentGesture.setStrokeWidth(Float.parseFloat(atts.getValue(namespace, "width"))); - buffer = new StringBuffer(); - } - } - - public void startPrefixMapping(String prefix, String uri) { - } - } -} diff --git a/tests/sketch/src/com/android/gesture/GesturePad.java b/tests/sketch/src/com/android/gesture/GesturePad.java deleted file mode 100755 index 45a09e6..0000000 --- a/tests/sketch/src/com/android/gesture/GesturePad.java +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (C) 2008 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 com.android.gesture; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PointF; -import android.os.Handler; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import java.util.ArrayList; -import java.util.Iterator; - -/** - * A view for rendering and processing gestures - */ - -public class GesturePad extends View { - - public static final float TOUCH_TOLERANCE = 4; - public static final int default_foreground = Color.argb(255, 255, 255, 0); - private int background = Color.argb(0, 0, 0, 0); - private int foreground = default_foreground; - private int uncertain_foreground = Color.argb(55, 255, 255, 0); - private Bitmap mBitmap; - private Canvas mCanvas; - private Path mPath; - private Paint mBitmapPaint; - private Paint mPaint; - private Paint mDebugPaint; - private float mX, mY; - private boolean mEnableInput = true; - private boolean mEnableRendering = true; - private boolean mCacheGesture = true; - private Gesture mCurrentGesture = null; - ArrayList<GestureListener> mGestureListeners = new ArrayList<GestureListener>(); - - private boolean mShouldFadingOut = true; - private boolean mIsFadingOut = false; - private float mFadingAlpha = 1; - - private boolean reconstruct = false; - - private ArrayList<Path> debug = new ArrayList<Path>(); - private Handler mHandler = new Handler(); - - private Runnable mFadingOut = new Runnable() { - public void run() { - mFadingAlpha -= 0.03f; - if (mFadingAlpha <= 0) { - mIsFadingOut = false; - mPath.reset(); - } else { - mHandler.postDelayed(this, 100); - } - invalidate(); - } - }; - - public GesturePad(Context context) { - super(context); - init(); - } - - public GesturePad(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - public boolean isEnableRendering() { - return this.mEnableRendering; - } - - public Gesture getCurrentGesture() { - return mCurrentGesture; - } - - public Paint getPaint() { - return mPaint; - } - - public void setColor(int c) { - this.foreground = c; - } - - public void setFadingAlpha(float f) { - mFadingAlpha = f; - } - - public void setCurrentGesture(Gesture stk) { - this.mCurrentGesture = stk; - reconstruct = true; - } - - private void init() { - mDebugPaint = new Paint(); - mDebugPaint.setColor(Color.WHITE); - mDebugPaint.setStrokeWidth(4); - mDebugPaint.setAntiAlias(true); - mDebugPaint.setStyle(Paint.Style.STROKE); - - mPaint = new Paint(); - mPaint.setAntiAlias(true); - mPaint.setDither(true); - mPaint.setColor(foreground); - mPaint.setStyle(Paint.Style.STROKE); - mPaint.setStrokeJoin(Paint.Join.ROUND); - mPaint.setStrokeCap(Paint.Cap.ROUND); - mPaint.setStrokeWidth(12); - - mBitmapPaint = new Paint(Paint.DITHER_FLAG); - mPath = new Path(); - - reconstruct = false; - } - - public void cacheGesture(boolean b) { - mCacheGesture = b; - } - - public void enableRendering(boolean b) { - mEnableRendering = b; - } - - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - // TODO Auto-generated method stub - super.onSizeChanged(w, h, oldw, oldh); - - if (w <=0 || h <=0) - return; - - int width = w>oldw? w : oldw; - int height = h>oldh? h : oldh; - Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - mCanvas = new Canvas(newBitmap); - - if (mBitmap != null) { - mCanvas.drawColor(background); - mCanvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); - mCanvas.drawPath(mPath, mPaint); - } - - mBitmap = newBitmap; - } - - public void addGestureListener(GestureListener l) { - this.mGestureListeners.add(l); - } - - public void removeGestureListener(GestureListener l) { - this.mGestureListeners.remove(l); - } - - @Override - protected void onDraw(Canvas canvas) { - canvas.drawColor(background); - - if (mCacheGesture) - canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); - - if (mIsFadingOut) { - int color = foreground; - int alpha = (int)(Color.alpha(color) * mFadingAlpha); - mPaint.setColor(Color.argb(alpha, - Color.red(color), - Color.green(color), - Color.blue(color))); - } else if (mEnableRendering == false) { - mPaint.setColor(uncertain_foreground); - } else { - mPaint.setColor(foreground); - } - - if (reconstruct) { - - if (this.mCurrentGesture != null) { - float xedge = 30; - float yedge = 30; - float w = this.getWidth() - 2 * xedge; - float h = this.getHeight() - 2 * yedge; - float sx = w / this.mCurrentGesture.getBBX().width(); - float sy = h / mCurrentGesture.getBBX().height(); - float scale = sx>sy?sy:sx; - convertFromStroke(mCurrentGesture); - Matrix matrix = new Matrix(); - matrix.preTranslate(-mCurrentGesture.getBBX().centerX(), -mCurrentGesture.getBBX().centerY()); - matrix.postScale(scale, scale); - matrix.postTranslate(this.getWidth()/2, this.getHeight()/2); - this.mPath.transform(matrix); - } else { - mPath.reset(); - } - - reconstruct = false; - } - - canvas.drawPath(mPath, mPaint); - - Iterator<Path> it = debug.iterator(); - while (it.hasNext()) { - Path path = it.next(); - canvas.drawPath(path, mDebugPaint); - } - } - - public void clearDebugPath() { - debug.clear(); - } - - public void addDebugPath(Path path) { - debug.add(path); - } - - public void addDebugPath(ArrayList<Path> paths) { - debug.addAll(paths); - } - - public void clear() { - mPath = new Path(); - this.mCurrentGesture = null; - mCanvas.drawColor(background); - this.invalidate(); - } - - private void convertFromStroke(Gesture stk) { - mPath = null; - Iterator it = stk.getPoints().iterator(); - while (it.hasNext()) { - PointF p = (PointF) it.next(); - if (mPath == null) { - mPath = new Path(); - mPath.moveTo(p.x, p.y); - mX = p.x; - mY = p.y; - } else { - float dx = Math.abs(p.x - mX); - float dy = Math.abs(p.y - mY); - if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { - mPath.quadTo(mX, mY, (p.x + mX)/2, (p.y + mY)/2); - mX = p.x; - mY = p.y; - } - } - } - mPath.lineTo(mX, mY); - } - - public void setEnableInput(boolean b) { - mEnableInput = b; - } - - public boolean isEnableInput() { - return mEnableInput; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - - if(mEnableInput == false) - return true; - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - touch_start(event); - invalidate(); - break; - case MotionEvent.ACTION_MOVE: - touch_move(event); - invalidate(); - break; - case MotionEvent.ACTION_UP: - touch_up(event); - invalidate(); - break; - } - return true; - } - - private void touch_start(MotionEvent event) { - mIsFadingOut = false; - mHandler.removeCallbacks(mFadingOut); - - float x = event.getX(); - float y = event.getY(); - - mCurrentGesture = new Gesture(); - mCurrentGesture.addPoint(x, y); - - mPath.reset(); - mPath.moveTo(x, y); - mX = x; - mY = y; - - Iterator<GestureListener> it = mGestureListeners.iterator(); - while (it.hasNext()) { - it.next().onStartGesture(this, event); - } - } - - private void touch_move(MotionEvent event) { - float x = event.getX(); - float y = event.getY(); - - float dx = Math.abs(x - mX); - float dy = Math.abs(y - mY); - if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { - mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2); - mX = x; - mY = y; - } - - mCurrentGesture.addPoint(x, y); - - Iterator<GestureListener> it = mGestureListeners.iterator(); - while (it.hasNext()) { - it.next().onGesture(this, event); - } - } - - public void setFadingOut(boolean b) { - mShouldFadingOut = b; - mIsFadingOut = false; - } - - public boolean shouldFadingOut() { - return mShouldFadingOut; - } - - private void touch_up(MotionEvent event) { - mPath.lineTo(mX, mY); - - if (mCacheGesture) - mCanvas.drawPath(mPath, mPaint); - - // kill this so we don't double draw - if (shouldFadingOut()) { - mFadingAlpha = 1; - mIsFadingOut = true; - mHandler.removeCallbacks(mFadingOut); - mHandler.postDelayed(mFadingOut, 100); - } - - Iterator<GestureListener> it = mGestureListeners.iterator(); - while (it.hasNext()) { - it.next().onFinishGesture(this, event); - } - } - -} diff --git a/tests/sketch/src/com/android/gesture/example/ContactAdapter.java b/tests/sketch/src/com/android/gesture/example/ContactAdapter.java new file mode 100644 index 0000000..008a972 --- /dev/null +++ b/tests/sketch/src/com/android/gesture/example/ContactAdapter.java @@ -0,0 +1,100 @@ +/* + * 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 com.android.gesture.example; + +import android.app.Activity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import java.util.ArrayList; + +class ContactAdapter extends ArrayAdapter<ContactItem> { + + private LayoutInflater mInflater; + + public ContactAdapter(Activity activity, ArrayList<ContactItem> contacts) { + super(activity, 0, contacts); + mInflater = activity.getLayoutInflater(); + } + + @Override + public ContactItem getItem(int position) { + return super.getItem(position); + } + + @Override + public long getItemId(int position) { + return getItem(position).itemID; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final ContactItem info = getItem(position); + + View view = convertView; + if (view == null) { + view = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false); + view.setTag(view.findViewById(android.R.id.text1)); + } + + final TextView textView = (TextView)view.getTag(); + textView.setText(info.toString()); + + return view; + } + + public int search(String query) { + if (query != null && query.length() > 0) { + int start = 0; + int end = getCount() - 1; + int index = binarySearch(query, start, end); + for (index = index - 1; index >= 0; index--) { + String str = getItem(index).toString().toLowerCase(); + if (!str.startsWith(query)) { + return index + 1; + } + if (index == 0) { + return 0; + } + } + return -1; + } else { + return -1; + } + } + + private int binarySearch(String prefix, int start, int end) { + if (start > end) { + return -1; + } + int mid = (start + end) / 2; + String str = getItem(mid).toString().toLowerCase(); + if (prefix.compareTo(str) <= 0) { + if (str.startsWith(prefix)) { + return mid; + } else { + return binarySearch(prefix, start, mid - 1); + } + } else { + return binarySearch(prefix, mid + 1, end); + } + } + +} diff --git a/tests/sketch/src/com/android/gesture/GestureListener.java b/tests/sketch/src/com/android/gesture/example/ContactItem.java index ebb4149..557c4d9 100755..100644 --- a/tests/sketch/src/com/android/gesture/GestureListener.java +++ b/tests/sketch/src/com/android/gesture/example/ContactItem.java @@ -14,12 +14,21 @@ * limitations under the License. */ -package com.android.gesture; +package com.android.gesture.example; -import android.view.MotionEvent; -public interface GestureListener { - public void onStartGesture(GesturePad pad, MotionEvent event); - public void onGesture(GesturePad pad, MotionEvent event); - public void onFinishGesture(GesturePad pad, MotionEvent event); +class ContactItem { + final String itemName; + + final long itemID; + + public ContactItem(long id, String name) { + itemID = id; + itemName = name; + } + + @Override + public String toString() { + return itemName; + } } diff --git a/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java b/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java new file mode 100644 index 0000000..eda4224 --- /dev/null +++ b/tests/sketch/src/com/android/gesture/example/ContactListGestureOverlay.java @@ -0,0 +1,119 @@ +/* + * 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 com.android.gesture.example; + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.Intent; +import android.database.Cursor; +import android.os.Bundle; +import android.provider.Contacts.People; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.AdapterView; +import android.widget.ListView; + +import android.gesture.Gesture; +import android.gesture.GestureOverlayView; +import android.gesture.LetterRecognizer; +import android.gesture.Prediction; +import android.gesture.TouchThroughGestureListener; + +import java.util.ArrayList; + +public class ContactListGestureOverlay extends Activity { + + private static final String LOGTAG = "ContactListGestureOverlay"; + + private static final String SORT_ORDER = People.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; + + private static final String[] CONTACTS_PROJECTION = new String[] { + People._ID, // 0 + People.DISPLAY_NAME, // 1 + }; + + private ContactAdapter mContactAdapter; + + private TouchThroughGestureListener mGestureProcessor; + + private LetterRecognizer mRecognizer; + + private ListView mContactList; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); + setContentView(R.layout.overlaydemo); + + setProgressBarIndeterminateVisibility(true); + + // create a letter recognizer + mRecognizer = LetterRecognizer.getLetterRecognizer(this, LetterRecognizer.RECOGNIZER_LATIN_LOWERCASE); + + // load the contact list + mContactList = (ListView) findViewById(R.id.list); + registerForContextMenu(mContactList); + mContactList.setTextFilterEnabled(true); + mContactList.setOnItemClickListener(new AdapterView.OnItemClickListener() { + public void onItemClick(AdapterView<?> parent, View v, int position, long id) { + if (!mGestureProcessor.isGesturing()) { + Intent intent = new Intent(Intent.ACTION_VIEW, ContentUris.withAppendedId( + People.CONTENT_URI, id)); + startActivity(intent); + } + } + }); + ContentResolver resolver = getContentResolver(); + Cursor cursor = resolver.query(People.CONTENT_URI, CONTACTS_PROJECTION, null, null, + SORT_ORDER); + ArrayList<ContactItem> list = new ArrayList<ContactItem>(); + while (cursor.moveToNext()) { + list.add(new ContactItem(cursor.getLong(0), cursor.getString(1))); + } + mContactAdapter = new ContactAdapter(this, list); + mContactList.setAdapter(mContactAdapter); + + setProgressBarIndeterminateVisibility(false); + + // add a gesture overlay on top of the ListView + GestureOverlayView overlay = new GestureOverlayView(this); + mGestureProcessor = new TouchThroughGestureListener(mContactList); + mGestureProcessor.setGestureType(TouchThroughGestureListener.MULTIPLE_STROKE); + mGestureProcessor.addOnGestureActionListener(new TouchThroughGestureListener.OnGesturePerformedListener() { + public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) { + ArrayList<Prediction> predictions = mRecognizer.recognize(gesture); + if (!predictions.isEmpty()) { + Log.v(LOGTAG, "1st Prediction : " + predictions.get(0).name); + Log.v(LOGTAG, "2nd Prediction : " + predictions.get(1).name); + Log.v(LOGTAG, "3rd Prediction : " + predictions.get(2).name); + int index = mContactAdapter.search(predictions.get(0).name); + if (index != -1) { + mContactList.setSelection(index); + } + } + } + }); + overlay.addOnGestureListener(mGestureProcessor); + ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT); + this.addContentView(overlay, params); + } +} diff --git a/tests/sketch/src/com/android/gesture/example/GestureEntry.java b/tests/sketch/src/com/android/gesture/example/GestureEntry.java new file mode 100644 index 0000000..200f89f --- /dev/null +++ b/tests/sketch/src/com/android/gesture/example/GestureEntry.java @@ -0,0 +1,206 @@ +/* + * 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 com.android.gesture.example; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.os.Environment; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.AdapterView.OnItemSelectedListener; +import android.gesture.Gesture; + +import android.gesture.GestureLibrary; +import android.gesture.GestureOverlayView; +import android.gesture.Prediction; + +import java.io.File; +import java.util.ArrayList; + +public class GestureEntry extends Activity { + + private static final String PARCEL_KEY = "gesture"; + + static final String GESTURE_FILE_NAME = Environment.getExternalStorageDirectory().getAbsolutePath() + + File.separator + "demo_library.gestures"; + + private static final int DIALOG_NEW_ENTRY = 1; + + private static final int NEW_ID = Menu.FIRST; + + private static final int VIEW_ID = Menu.FIRST + 1; + + private GestureOverlayView mGesturePad; + + private Spinner mRecognitionResult; + + private GestureLibrary mGestureLibrary; + + private boolean mChangedByRecognizer = false; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.demo); + + // init the gesture library + mGestureLibrary = new GestureLibrary(GESTURE_FILE_NAME); + mGestureLibrary.load(); + + // create the spinner for showing the recognition results + // the spinner also allows a user to correct a prediction + mRecognitionResult = (Spinner) findViewById(R.id.spinner); + mRecognitionResult.setOnItemSelectedListener(new OnItemSelectedListener() { + + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + // correct the recognition result by adding the new example + if (!mChangedByRecognizer) { + mGestureLibrary.addGesture(parent.getSelectedItem().toString(), mGesturePad + .getCurrentGesture()); + } else { + mChangedByRecognizer = false; + } + } + + public void onNothingSelected(AdapterView<?> parent) { + + } + + }); + + // create the area for drawing a gesture + mGesturePad = (GestureOverlayView) findViewById(R.id.drawingpad); + mGesturePad.setBackgroundColor(Color.BLACK); + mGesturePad.addOnGestureListener(new GestureOverlayView.OnGestureListener() { + public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) { + recognize(overlay.getCurrentGesture()); + } + + public void onGesture(GestureOverlayView overlay, MotionEvent event) { + } + + public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) { + overlay.clear(false); + } + }); + + if (savedInstanceState != null) { + Gesture gesture = (Gesture) savedInstanceState.getParcelable(PARCEL_KEY); + if (gesture != null) { + mGesturePad.setCurrentGesture(gesture); + } + } + } + + @Override + protected Dialog onCreateDialog(int id) { + LayoutInflater factory = LayoutInflater.from(this); + final View textEntryView = factory.inflate(R.layout.newgesture_dialog, null); + return new AlertDialog.Builder(GestureEntry.this).setTitle( + R.string.newgesture_text_entry).setView(textEntryView).setPositiveButton( + R.string.newgesture_dialog_ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + EditText edittext = (EditText) ((AlertDialog) dialog) + .findViewById(R.id.gesturename_edit); + String text = edittext.getText().toString().trim(); + if (text.length() > 0) { + mGestureLibrary.addGesture(text, mGesturePad.getCurrentGesture()); + } + } + }).setNegativeButton(R.string.newgesture_dialog_cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + } + }).create(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + menu.add(0, NEW_ID, 0, R.string.newgesture).setShortcut('0', 'n').setIcon( + android.R.drawable.ic_menu_add); + menu.add(0, VIEW_ID, 0, R.string.viewgesture).setShortcut('1', 'v').setIcon( + android.R.drawable.ic_menu_view); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case NEW_ID: + if (mGesturePad.getCurrentGesture() != null) { + showDialog(DIALOG_NEW_ENTRY); + } + break; + + case VIEW_ID: + startActivityForResult(new Intent(this, GestureLibViewer.class), VIEW_ID); + break; + } + + return super.onOptionsItemSelected(item); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + mGestureLibrary.load(); + mGesturePad.clear(false); + } + + @Override + protected void onPause() { + super.onPause(); + mGestureLibrary.save(); + } + + @Override + protected void onPrepareDialog(int id, Dialog dialog) { + super.onPrepareDialog(id, dialog); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + Gesture gesture = mGesturePad.getCurrentGesture(); + if (gesture != null) { + outState.putParcelable(PARCEL_KEY, gesture); + } + mGestureLibrary.save(); + } + + private void recognize(Gesture gesture) { + mChangedByRecognizer = true; + ArrayList<Prediction> predictions = mGestureLibrary.recognize(gesture); + ArrayAdapter<Prediction> adapter = new ArrayAdapter<Prediction>(this, + android.R.layout.simple_spinner_item, predictions); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mRecognitionResult.setAdapter(adapter); + } + +} diff --git a/tests/sketch/src/com/android/gesture/example/GestureEntryDemo.java b/tests/sketch/src/com/android/gesture/example/GestureEntryDemo.java deleted file mode 100755 index 8fee21a..0000000 --- a/tests/sketch/src/com/android/gesture/example/GestureEntryDemo.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2008 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 com.android.gesture.example; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.AdapterView.OnItemSelectedListener; - -import com.android.gesture.Gesture; -import com.android.gesture.GestureLib; -import com.android.gesture.GestureListener; -import com.android.gesture.GesturePad; -import com.android.gesture.R; -import com.android.gesture.recognizer.Prediction; - -import java.util.ArrayList; - -/** - * The demo shows how to construct a gesture-based user interface on Android. - */ - -public class GestureEntryDemo extends Activity { - - private static final int DIALOG_NEW_ENTRY = 1; - private static final int NEW_ID = Menu.FIRST; - private static final int VIEW_ID = Menu.FIRST + 1; - - GesturePad mView; - Spinner mResult; - GestureLib mRecognizer; - boolean mChangedByRecognizer = false; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.demo); - - // init the recognizer - mRecognizer = new GestureLib("/sdcard/gestureentry"); - mRecognizer.load(); - - // create the spinner for showing the recognition results - // the spinner also allows a user to correct a prediction - mResult = (Spinner) findViewById(R.id.spinner); - mResult.setOnItemSelectedListener(new OnItemSelectedListener() { - - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - // TODO Auto-generated method stub - // correct the recognition result by adding the new example - if (mChangedByRecognizer == false) { - mRecognizer.addGesture(parent.getSelectedItem().toString(), - mView.getCurrentGesture()); - } else { - mChangedByRecognizer = false; - } - } - - public void onNothingSelected(AdapterView<?> parent) { - // TODO Auto-generated method stub - - } - - }); - - // create the area for drawing a gesture - mView = (GesturePad)this.findViewById(R.id.drawingpad); - mView.cacheGesture(false); - mView.setFadingOut(false); - mView.addGestureListener(new GestureListener() { - public void onFinishGesture(GesturePad patch, MotionEvent event) { - // TODO Auto-generated method stub - recognize(patch.getCurrentGesture()); - } - public void onGesture(GesturePad patch, MotionEvent event) { - // TODO Auto-generated method stub - - } - public void onStartGesture(GesturePad patch, MotionEvent event) { - // TODO Auto-generated method stub - - } - }); - - - if (savedInstanceState != null) { - mView.setCurrentGesture( - (Gesture)savedInstanceState.getParcelable("gesture")); - } - } - - @Override - protected Dialog onCreateDialog(int id) { - // create the dialog for adding a new entry - LayoutInflater factory = LayoutInflater.from(this); - final View textEntryView = - factory.inflate(R.layout.newgesture_dialog, null); - return new AlertDialog.Builder(GestureEntryDemo.this) - .setTitle(R.string.newgesture_text_entry) - .setView(textEntryView) - .setPositiveButton(R.string.newgesture_dialog_ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - /* User clicked OK so do some stuff */ - EditText edittext = - (EditText)((AlertDialog)dialog).findViewById(R.id.gesturename_edit); - String text = edittext.getText().toString().trim(); - if (text.length() > 0) { - mRecognizer.addGesture(text, mView.getCurrentGesture()); - } - } - }) - .setNegativeButton(R.string.newgesture_dialog_cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - /* User clicked cancel so do some stuff */ - } - }) - .create(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // TODO Auto-generated method stub - super.onCreateOptionsMenu(menu); - menu.add(0, NEW_ID, 0, R.string.newgesture) - .setShortcut('0', 'n') - .setIcon(android.R.drawable.ic_menu_add); - menu.add(0, VIEW_ID, 0, R.string.viewgesture) - .setShortcut('1', 'v') - .setIcon(android.R.drawable.ic_menu_view); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle all of the possible menu actions. - switch (item.getItemId()) { - case NEW_ID: - // if there has been a gesture on the canvas - if (mView.getCurrentGesture() != null) { - showDialog(DIALOG_NEW_ENTRY); - } - break; - - case VIEW_ID: - startActivityForResult( - new Intent(this, GestureLibViewer.class), VIEW_ID); - break; - } - - return super.onOptionsItemSelected(item); - } - - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - mRecognizer.load(); - mView.clear(); - } - - @Override - protected void onPause() { - // TODO Auto-generated method stub - super.onPause(); - mRecognizer.save(); - } - - - @Override - protected void onPrepareDialog(int id, Dialog dialog) { - // TODO Auto-generated method stub - super.onPrepareDialog(id, dialog); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - // TODO Auto-generated method stub - super.onSaveInstanceState(outState); - outState.putParcelable("gesture", mView.getCurrentGesture()); - mRecognizer.save(); - } - - public void recognize(Gesture ink) { - mChangedByRecognizer = true; - ArrayList<Prediction> predictions = mRecognizer.recognize(ink); - ArrayAdapter adapter = new ArrayAdapter(this, - android.R.layout.simple_spinner_item, predictions); - adapter.setDropDownViewResource( - android.R.layout.simple_spinner_dropdown_item); - mResult.setAdapter(adapter); - } - -} diff --git a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java index 7ae7fc5..aa07e7b 100755 --- a/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java +++ b/tests/sketch/src/com/android/gesture/example/GestureLibViewer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * 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. @@ -17,8 +17,6 @@ package com.android.gesture.example; import android.app.Activity; -import android.graphics.Matrix; -import android.graphics.Path; import android.os.Bundle; import android.view.KeyEvent; import android.view.View; @@ -28,230 +26,158 @@ import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.Spinner; import android.widget.AdapterView.OnItemSelectedListener; +import android.gesture.Gesture; -import com.android.gesture.Gesture; -import com.android.gesture.GestureLib; -import com.android.gesture.GesturePad; -import com.android.gesture.R; -import com.android.gesture.recognizer.Instance; +import android.gesture.GestureLibrary; +import android.gesture.GestureOverlayView; import java.util.ArrayList; import java.util.Collections; /** - * GestureLibViewer is for viewing existing gestures and + * GestureLibViewer gives an example on how to browse existing gestures and * removing unwanted gestures. */ -public class GestureLibViewer extends Activity { - - GesturePad mView; - Spinner mResult; - GestureLib mRecognizer; - ArrayList<Gesture> mSamples; - int mCurrentGestureIndex; +public class GestureLibViewer extends Activity { + + private GestureOverlayView mGesturePad; + + private Spinner mGestureCategory; + + private GestureLibrary mGesureLibrary; + + private ArrayList<Gesture> mGestures; + + private int mCurrentGestureIndex; + + private class RemoveGestureListener implements OnClickListener { + public void onClick(View v) { + if (mGestures.isEmpty()) { + return; + } + + String name = (String) mGestureCategory.getSelectedItem(); + Gesture gesture = mGestures.get(mCurrentGestureIndex); + mGesureLibrary.removeGesture(name, gesture); + + mGestures = mGesureLibrary.getGestures(name); + + if (mGestures == null) { + // delete the entire entry + mCurrentGestureIndex = 0; + ArrayList<String> list = new ArrayList<String>(); + list.addAll(mGesureLibrary.getGestureEntries()); + Collections.sort(list); + ArrayAdapter<String> adapter = new ArrayAdapter<String>(GestureLibViewer.this, + android.R.layout.simple_spinner_item, list); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mGestureCategory.setAdapter(adapter); + } else { + if (mCurrentGestureIndex > mGestures.size() - 1) { + mCurrentGestureIndex--; + } + gesture = mGestures.get(mCurrentGestureIndex); + mGesturePad.setCurrentGesture(gesture); + mGesturePad.invalidate(); + } + } + } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.gestureviewer); - - // create the area for drawing a glyph - mView = (GesturePad)this.findViewById(R.id.drawingpad); - mView.cacheGesture(false); - mView.setFadingOut(false); - mView.setEnableInput(false); - - // init the recognizer - mRecognizer = new GestureLib("/sdcard/gestureentry"); - mRecognizer.load(); - mResult = (Spinner) findViewById(R.id.spinner); + // create the area for drawing a gesture + mGesturePad = (GestureOverlayView) findViewById(R.id.drawingpad); + mGesturePad.setEnabled(false); + + // init the gesture library + mGesureLibrary = new GestureLibrary(GestureEntry.GESTURE_FILE_NAME); + mGesureLibrary.load(); + + mGestureCategory = (Spinner) findViewById(R.id.spinner); ArrayList<String> list = new ArrayList<String>(); - list.addAll(mRecognizer.getLabels()); - Collections.sort(list); - ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, - android.R.layout.simple_spinner_item, - list); - adapter.setDropDownViewResource( - android.R.layout.simple_spinner_dropdown_item); - mResult.setAdapter(adapter); - mSamples = mRecognizer.getGestures(list.get(0)); - if (mSamples.isEmpty() == false) { + if (!mGesureLibrary.getGestureEntries().isEmpty()) { + list.addAll(mGesureLibrary.getGestureEntries()); + Collections.sort(list); + ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, + android.R.layout.simple_spinner_item, list); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mGestureCategory.setAdapter(adapter); + mGestures = mGesureLibrary.getGestures(list.get(0)); mCurrentGestureIndex = 0; - Gesture gesture = mSamples.get(mCurrentGestureIndex); - mView.setCurrentGesture(gesture); - mView.clearDebugPath(); - mView.addDebugPath( - toPath(mRecognizer.getClassifier().getInstance(gesture.getID()))); + Gesture gesture = mGestures.get(mCurrentGestureIndex); + mGesturePad.setCurrentGesture(gesture); } - - mResult.setOnItemSelectedListener(new OnItemSelectedListener() { + + mGestureCategory.setOnItemSelectedListener(new OnItemSelectedListener() { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - // TODO Auto-generated method stub - mSamples = mRecognizer.getGestures( - (String)mResult.getSelectedItem()); - if (mSamples.isEmpty() == false) { + mGestures = mGesureLibrary.getGestures((String) mGestureCategory.getSelectedItem()); + if (!mGestures.isEmpty()) { mCurrentGestureIndex = 0; - Gesture gesture = mSamples.get(mCurrentGestureIndex); - mView.setCurrentGesture(gesture); - mView.clearDebugPath(); - mView.addDebugPath( - toPath(mRecognizer.getClassifier().getInstance(gesture.getID()))); + Gesture gesture = mGestures.get(mCurrentGestureIndex); + mGesturePad.setCurrentGesture(gesture); } - mView.invalidate(); + mGesturePad.invalidate(); } - + public void onNothingSelected(AdapterView<?> parent) { - // TODO Auto-generated method stub - - } - - }); - - Button remove = (Button)this.findViewById(R.id.remove); - remove.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - // TODO Auto-generated method stub - if (mSamples.isEmpty()) - return; - - String name = (String)mResult.getSelectedItem(); - Gesture gesture = mSamples.get(mCurrentGestureIndex); - mRecognizer.removeGesture(name, gesture); - - mSamples = mRecognizer.getGestures(name); - - if (mSamples == null) { - // delete the entire entry - mCurrentGestureIndex = 0; - ArrayList<String> list = new ArrayList<String>(); - list.addAll(mRecognizer.getLabels()); - Collections.sort(list); - ArrayAdapter<String> adapter = new ArrayAdapter<String>( - GestureLibViewer.this, - android.R.layout.simple_spinner_item, - list); - adapter.setDropDownViewResource( - android.R.layout.simple_spinner_dropdown_item); - mResult.setAdapter(adapter); - } else { - if (mCurrentGestureIndex > mSamples.size()-1) { - mCurrentGestureIndex--; - } - gesture = mSamples.get(mCurrentGestureIndex); - mView.setCurrentGesture(gesture); - mView.clearDebugPath(); - mView.addDebugPath( - toPath(mRecognizer.getClassifier().getInstance(gesture.getID()))); - mView.invalidate(); - } } + }); - - Button next = (Button)this.findViewById(R.id.next); + + Button remove = (Button) findViewById(R.id.remove); + remove.setOnClickListener(new RemoveGestureListener()); + + Button next = (Button) findViewById(R.id.next); next.setOnClickListener(new OnClickListener() { public void onClick(View v) { - // TODO Auto-generated method stub - if (mCurrentGestureIndex >= mSamples.size()-1) + if (mCurrentGestureIndex >= mGestures.size() - 1) { return; - + } mCurrentGestureIndex++; - Gesture gesture = mSamples.get(mCurrentGestureIndex); - mView.setCurrentGesture(gesture); - mView.clearDebugPath(); - mView.addDebugPath( - toPath(mRecognizer.getClassifier().getInstance(gesture.getID()))); - mView.invalidate(); + Gesture gesture = mGestures.get(mCurrentGestureIndex); + mGesturePad.setCurrentGesture(gesture); + mGesturePad.invalidate(); } }); - Button previous = (Button)this.findViewById(R.id.previous); + Button previous = (Button) findViewById(R.id.previous); previous.setOnClickListener(new OnClickListener() { public void onClick(View v) { - // TODO Auto-generated method stub - if (mCurrentGestureIndex >= 1 && - mSamples.isEmpty() == false) { + if (mCurrentGestureIndex >= 1 && !mGestures.isEmpty()) { mCurrentGestureIndex--; - Gesture gesture = mSamples.get(mCurrentGestureIndex); - mView.setCurrentGesture(gesture); - mView.clearDebugPath(); - mView.addDebugPath( - toPath(mRecognizer.getClassifier().getInstance(gesture.getID()))); - mView.invalidate(); + Gesture gesture = mGestures.get(mCurrentGestureIndex); + mGesturePad.setCurrentGesture(gesture); + mGesturePad.invalidate(); } } }); } - - public static ArrayList<Path> toPath(Instance instance) { - ArrayList<Path> paths = new ArrayList(); - Path path = null; - float minx = 0, miny = 0; - float mX = 0, mY = 0; - for (int i=0; i<instance.vector.length; i+=2) { - float x = instance.vector[i]; - float y = instance.vector[i+1]; - if (x < minx) - minx = x; - if (y < miny) - miny = y; - if (path == null) { - path = new Path(); - path.moveTo(x, y); - mX = x; - mY = y; - } else { - float dx = Math.abs(x - mX); - float dy = Math.abs(y - mY); - if (dx >= 3 || dy >= 3) { - path.quadTo(mX, mY, (x + mX)/2, (y + mY)/2); - mX = x; - mY = y; - } - } - } - Matrix matrix = new Matrix(); - matrix.setTranslate(-minx + 10, -miny + 10); - path.transform(matrix); - paths.add(path); - - path = new Path(); - path.moveTo(instance.vector[0]-5, instance.vector[1]-5); - path.lineTo(instance.vector[0]-5, instance.vector[1]+5); - path.lineTo(instance.vector[0]+5, instance.vector[1]+5); - path.lineTo(instance.vector[0]+5, instance.vector[1]-5); - path.close(); - path.transform(matrix); - paths.add(path); - - return paths; - } - + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - // TODO Auto-generated method stub - if (keyCode == KeyEvent.KEYCODE_BACK) { - mRecognizer.save(); - this.setResult(RESULT_OK); - finish(); - return true; - } - else - return false; + if (keyCode == KeyEvent.KEYCODE_BACK) { + mGesureLibrary.save(); + setResult(RESULT_OK); + finish(); + return true; + } else { + return false; + } } - + @Override protected void onPause() { - // TODO Auto-generated method stub super.onPause(); - mRecognizer.save(); + mGesureLibrary.save(); } @Override protected void onSaveInstanceState(Bundle outState) { - // TODO Auto-generated method stub super.onSaveInstanceState(outState); - mRecognizer.save(); + mGesureLibrary.save(); } } diff --git a/tests/sketch/src/com/android/gesture/recognizer/Classifier.java b/tests/sketch/src/com/android/gesture/recognizer/Classifier.java deleted file mode 100755 index 584e0a5..0000000 --- a/tests/sketch/src/com/android/gesture/recognizer/Classifier.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2008 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 com.android.gesture.recognizer; - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * The abstract class of Classifier - */ -public abstract class Classifier { - - HashMap<Long, Instance> mInstances = new HashMap<Long, Instance>(); - - public void addInstance(Instance instance) { - mInstances.put(instance.id, instance); - } - - public Instance getInstance(long id) { - return mInstances.get(id); - } - - public void removeInstance(long id) { - mInstances.remove(id); - } - - public abstract ArrayList<Prediction> classify(Instance instance); -} diff --git a/tests/sketch/src/com/android/gesture/recognizer/Instance.java b/tests/sketch/src/com/android/gesture/recognizer/Instance.java deleted file mode 100755 index 2eaa1c2..0000000 --- a/tests/sketch/src/com/android/gesture/recognizer/Instance.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2008 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 com.android.gesture.recognizer; - -import android.graphics.PointF; - -import com.android.gesture.Gesture; - -/** - * An instance represents a sample if the label is available or a query if - * the label is null. - */ -public class Instance { - - private final static float[] targetOrientations = { - 0, 45, 90, 135, 180, -0, -45, -90, -135, -180 - }; - - // the feature vector - public final float[] vector; - // the label can be null - public final String label; - // the length of the vector - public final float length; - // the id of the instance - public final long id; - - Instance(long d, float[] v, String l) { - id = d; - vector = v; - label = l; - float sum = 0; - for (int i = 0; i < vector.length; i++) { - sum += vector[i] * vector[i]; - } - length = (float)Math.sqrt(sum); - } - - public static Instance createInstance(Gesture gesture, String label) { - float[] pts = RecognitionUtil.resample(gesture, 64); - PointF center = RecognitionUtil.computeCentroid(pts); - float inductiveOrientation = (float)Math.atan2(pts[1] - center.y, - pts[0] - center.x); - inductiveOrientation *= 180 / Math.PI; - - float minDeviation = Float.MAX_VALUE; - for (int i=0; i<targetOrientations.length; i++) { - float delta = targetOrientations[i] - inductiveOrientation; - if (Math.abs(delta) < Math.abs(minDeviation)) { - minDeviation = delta; - } - } - - android.graphics.Matrix m = new android.graphics.Matrix(); - m.setTranslate(-center.x, -center.y); - android.graphics.Matrix rotation = new android.graphics.Matrix(); - rotation.setRotate(minDeviation); - m.postConcat(rotation); - m.mapPoints(pts); - - return new Instance(gesture.getID(), pts, label); - } -} diff --git a/tests/sketch/src/com/android/gesture/recognizer/NearestNeighbor.java b/tests/sketch/src/com/android/gesture/recognizer/NearestNeighbor.java deleted file mode 100755 index cb8a9d3..0000000 --- a/tests/sketch/src/com/android/gesture/recognizer/NearestNeighbor.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2008 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 com.android.gesture.recognizer; - -import android.util.Log; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.TreeMap; - -public class NearestNeighbor extends Classifier { - - private static final String LOGTAG = "NearestNeighbor"; - private static final double variance = 0.25; // std = 0.5 - - public ArrayList<Prediction> classify(Instance instance) { - - ArrayList<Prediction> list = new ArrayList<Prediction>(); - Iterator<Instance> it = mInstances.values().iterator(); - Log.v(LOGTAG, mInstances.size() + " instances found"); - TreeMap<String, Double> label2score = new TreeMap<String, Double>(); - while (it.hasNext()) { - Instance sample = it.next(); - double dis = RecognitionUtil.cosineDistance(sample, instance); - double weight = Math.exp(-dis*dis/(2 * variance)); - Log.v(LOGTAG, sample.label + " = " + dis + " weight = " + weight); - Double score = label2score.get(sample.label); - if (score == null) { - score = weight; - } - else { - score += weight; - } - label2score.put(sample.label, score); - } - - double sum = 0; - Iterator it2 = label2score.keySet().iterator(); - while (it2.hasNext()) { - String name = (String)it2.next(); - double score = label2score.get(name); - sum += score; - list.add(new Prediction(name, score)); - } - - it2 = list.iterator(); - while (it2.hasNext()) { - Prediction name = (Prediction)it2.next(); - name.score /= sum; - } - - - Collections.sort(list, new Comparator<Prediction>() { - public int compare(Prediction object1, Prediction object2) { - // TODO Auto-generated method stub - double score1 = object1.score; - double score2 = object2.score; - if (score1 > score2) - return -1; - else if (score1 < score2) - return 1; - else - return 0; - } - }); - - it2 = list.iterator(); - while (it2.hasNext()) { - Prediction name = (Prediction)it2.next(); - Log.v(LOGTAG, "prediction [" + name.label + " = " + name.score + "]"); - } - - return list; - } -} diff --git a/tests/sketch/src/com/android/gesture/recognizer/Prediction.java b/tests/sketch/src/com/android/gesture/recognizer/Prediction.java deleted file mode 100755 index c318754..0000000 --- a/tests/sketch/src/com/android/gesture/recognizer/Prediction.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2008 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 com.android.gesture.recognizer; - -/** - * - * A recognition result that includes the label and its score - */ -public class Prediction { - public final String label; - public double score; - - public Prediction(String l, double s) { - label = l; - score = s; - } - - @Override - public String toString() { - return label; - } -} diff --git a/tests/sketch/src/com/android/gesture/recognizer/RecognitionUtil.java b/tests/sketch/src/com/android/gesture/recognizer/RecognitionUtil.java deleted file mode 100755 index 9146b95..0000000 --- a/tests/sketch/src/com/android/gesture/recognizer/RecognitionUtil.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * 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 com.android.gesture.recognizer; - -import android.graphics.PointF; - -import com.android.gesture.Gesture; - -import java.util.Iterator; - -/** - * - * Utilities for recognition. - */ - -public class RecognitionUtil { - - /** - * Re-sample a list of points to a given number - * @param stk - * @param num - * @return - */ - public static float[] resample(Gesture gesture, int num) { - final float increment = gesture.getLength()/(num - 1); - float[] newstk = new float[num*2]; - float distanceSoFar = 0; - Iterator<PointF> it = gesture.getPoints().iterator(); - PointF lstPoint = it.next(); - int index = 0; - PointF currentPoint = null; - try - { - newstk[index] = lstPoint.x; - index++; - newstk[index] = lstPoint.y; - index++; - while (it.hasNext()) { - if (currentPoint == null) - currentPoint = it.next(); - float deltaX = currentPoint.x - lstPoint.x; - float deltaY = currentPoint.y - lstPoint.y; - float distance = (float)Math.sqrt(deltaX*deltaX+deltaY*deltaY); - if (distanceSoFar+distance >= increment) { - float ratio = (increment - distanceSoFar) / distance; - float nx = lstPoint.x + ratio * deltaX; - float ny = lstPoint.y + ratio * deltaY; - newstk[index] = nx; - index++; - newstk[index] = ny; - index++; - lstPoint = new PointF(nx, ny); - distanceSoFar = 0; - } - else { - lstPoint = currentPoint; - currentPoint = null; - distanceSoFar += distance; - } - } - } - catch(Exception ex) { - ex.printStackTrace(); - } - - for(int i = index; i < newstk.length -1; i+=2) { - newstk[i] = lstPoint.x; - newstk[i+1] = lstPoint.y; - } - return newstk; - } - - /** - * Calculate the centroid of a list of points - * @param points - * @return the centroid - */ - public static PointF computeCentroid(float[] points) { - float centerX = 0; - float centerY = 0; - for(int i=0; i<points.length; i++) - { - centerX += points[i]; - i++; - centerY += points[i]; - } - centerX = 2 * centerX/points.length; - centerY = 2 * centerY/points.length; - return new PointF(centerX, centerY); - } - - /** - * calculate the variance-covariance matrix, treat each point as a sample - * @param points - * @return - */ - public static double[][] computeCoVariance(float[] points) { - double[][] array = new double[2][2]; - array[0][0] = 0; - array[0][1] = 0; - array[1][0] = 0; - array[1][1] = 0; - for(int i=0; i<points.length; i++) - { - float x = points[i]; - i++; - float y = points[i]; - array[0][0] += x * x; - array[0][1] += x * y; - array[1][0] = array[0][1]; - array[1][1] += y * y; - } - array[0][0] /= (points.length/2); - array[0][1] /= (points.length/2); - array[1][0] /= (points.length/2); - array[1][1] /= (points.length/2); - - return array; - } - - - public static float computeTotalLength(float[] points) { - float sum = 0; - for (int i=0; i<points.length - 4; i+=2) { - float dx = points[i+2] - points[i]; - float dy = points[i+3] - points[i+1]; - sum += Math.sqrt(dx*dx + dy*dy); - } - return sum; - } - - public static double computeStraightness(float[] points) { - float totalLen = computeTotalLength(points); - float dx = points[2] - points[0]; - float dy = points[3] - points[1]; - return Math.sqrt(dx*dx + dy*dy) / totalLen; - } - - public static double computeStraightness(float[] points, float totalLen) { - float dx = points[2] - points[0]; - float dy = points[3] - points[1]; - return Math.sqrt(dx*dx + dy*dy) / totalLen; - } - - public static double averageEuclidDistance(float[] stk1, float[] stk2) { - double distance = 0; - for (int i = 0; i < stk1.length; i += 2) { - distance += PointF.length(stk1[i] - stk2[i], stk1[i+1] - stk2[i+1]); - } - return distance/stk1.length; - } - - public static double squaredEuclidDistance(float[] stk1, float[] stk2) { - double squaredDistance = 0; - for (int i = 0; i < stk1.length; i++) { - float difference = stk1[i] - stk2[i]; - squaredDistance += difference * difference; - } - return squaredDistance/stk1.length; - } - - /** - * Calculate the cosine distance between two instances - * @param in1 - * @param in2 - * @return the angle between 0 and Math.PI - */ - public static double cosineDistance(Instance in1, Instance in2) { - float sum = 0; - for (int i = 0; i < in1.vector.length; i++) { - sum += in1.vector[i] * in2.vector[i]; - } - return Math.acos(sum / (in1.length * in2.length)); - } - -} |