View Javadoc

1   /*
2    * @(#)$Id: FeatureTool.java 689 2009-07-22 00:10:27Z bsigner $
3    *
4    * Author       :   Ueli Kurmann, igesture@uelikurmann.ch
5    *
6    * Purpose      :   Some feature tools.
7    *
8    * -----------------------------------------------------------------------
9    *
10   * Revision Information:
11   *
12   * Date             Who         Reason
13   *
14   * Dec 26, 2006     ukurmann    Initial Release
15   * Mar 15, 2007     bsigner     Cleanup
16   *
17   * -----------------------------------------------------------------------
18   *
19   * Copyright 1999-2009 ETH Zurich. All Rights Reserved.
20   *
21   * This software is the proprietary information of ETH Zurich.
22   * Use is subject to license terms.
23   * 
24   */
25  
26  
27  package org.ximtec.igesture.algorithm.feature;
28  
29  import java.util.ArrayList;
30  import java.util.List;
31  import java.util.StringTokenizer;
32  import java.util.logging.Level;
33  import java.util.logging.Logger;
34  
35  import org.sigtec.ink.Note;
36  import org.sigtec.ink.Point;
37  import org.sigtec.ink.Trace;
38  import org.sigtec.util.Constant;
39  import org.ximtec.igesture.util.DoubleVector;
40  
41  
42  /**
43   * Some feature tools.
44   * 
45   * @version 1.0 Dec 2006
46   * @author Ueli Kurmann, igesture@uelikurmann.ch
47   * @author Beat Signer, signer@inf.ethz.ch
48   */
49  public class FeatureTool {
50  
51     private static final Logger LOGGER = Logger.getLogger(FeatureTool.class
52           .getName());
53  
54  
55     /**
56      * Takes a note and returns a single trace containing all points.
57      * 
58      * @param note the note whose points have to be extracted.
59      * @return the trace containing all points of the note.
60      */
61     public static Trace createTrace(Note note) {
62        final Trace result = new Trace();
63  
64        for (final Trace trace : note.getTraces()) {
65           result.addAll(trace.getPoints());
66        }
67  
68        return result;
69     } // createTrace
70  
71  
72     /**
73      * Returns the distance in respect to the X axis between point i and i+1.
74      * 
75      * @param i the ith point.
76      * @param points the array of points.
77      * @return the distance in respect to the X axis between point i and i+1.
78      */
79     public static double getDeltaX(int i, Point[] points) {
80        return points[i + 1].getX() - points[i].getX();
81     } // getDeltaX
82  
83  
84     /**
85      * Returns the distance in respect to the Y axis between point i and i+1.
86      * 
87      * @param i the ith point.
88      * @param points the array of points.
89      * @return the distance in respect to the Y axis between point i and i+1.
90      */
91     public static double getDeltaY(int i, Point[] points) {
92        return points[i + 1].getY() - points[i].getY();
93     } // getDeltaY
94  
95  
96     /**
97      * Returns the difference of the timestamps in point i and i + 1.
98      * 
99      * @param i the ith point.
100     * @param points the array of points.
101     * @return the time between two points.
102     */
103    public static double getDeltaT(int i, Point[] points) {
104       return points[i + 1].getTimestamp() - points[i].getTimestamp();
105    } // getDeltaT
106 
107 
108    /**
109     * Returns the difference of the timestamps in point p1 and p2.
110     * 
111     * @param p1 the point p1.
112     * @param p2 the point p2.
113     * @return the time passes between the two given points.
114     */
115    public static double getDeltaT(Point p1, Point p2) {
116       return p2.getTimestamp() - p1.getTimestamp();
117    } // getDeltaT
118 
119 
120    /**
121     * Computes the angle in respect to the x axis in point i and i-1.
122     * 
123     * @param i the index of the point to be used in the computation.
124     * @param points the set of points.
125     * @return the angle relative to the x axis for point i and i-1.
126     */
127    public static double roh(int i, Point[] points) {
128       final double divisor = getDeltaX(i, points) * getDeltaY(i - 1, points)
129             - getDeltaX(i - 1, points) * getDeltaY(i, points);
130       final double dividend = getDeltaX(i, points) * getDeltaX(i - 1, points)
131             + getDeltaY(i, points) * getDeltaY(i - 1, points);
132       final double result = Math.atan(divisor / dividend);
133 
134       if (Double.isNaN(result)) {
135          return 1;
136       }
137       else {
138          return result;
139       }
140 
141    } // roh
142 
143 
144    /**
145     * Computes the angle of the line p1-p2 in the unit circle.
146     * 
147     * @param p1 start point of the line.
148     * @param p2 end point of the line.
149     * @return the angle.
150     */
151    public static double getAngle(Point p1, Point p2) {
152       final double r = p1.distance(p2);
153       final double x = p2.getX() - p1.getX();
154 
155       double alpha = Math.toDegrees(Math.acos(x / r));
156 
157       if (p2.getY() - p1.getY() < 0) {
158          alpha = 360 - alpha;
159       }
160 
161       return alpha;
162    } // getAngle
163 
164 
165    /**
166     * Removes traces from the list with less than minNumOfPoints.
167     * 
168     * @param traces the list of traces.
169     * @param minNumOfPoints the minimal number of points a trace must contain.
170     * @return the filtered list of traces.
171     */
172    public static List<Trace> removeShortTraces(List<Trace> traces,
173          int minNumOfPoints) {
174       final List<Trace> result = new ArrayList<Trace>();
175 
176       for (final Trace trace : traces) {
177 
178          if (trace.size() >= minNumOfPoints) {
179             result.add(trace);
180          }
181 
182       }
183       return result;
184    } // removeShortTraces
185 
186 
187    /**
188     * Creates a list of instantiated features out of a comma delimited list of
189     * full qualified feature classnames.
190     * 
191     * @param featureList a comma delimited list of full qualified class names.
192     * @return list of feature instances.
193     */
194    public static List<Feature> createFeatureList(String featureList) {
195       final ArrayList<Feature> result = new ArrayList<Feature>();
196       final StringTokenizer tokenizer = new StringTokenizer(featureList,
197             Constant.COMMA);
198 
199       while (tokenizer.hasMoreElements()) {
200          result.add(createFeature(tokenizer.nextToken()));
201       }
202 
203       return result;
204    } // createFeatureList
205 
206 
207    /**
208     * Instantiates a feature of the given full qualified classname.
209     * 
210     * @param classname the full qualified class name.
211     * @return the instance of the feature.
212     */
213    public static Feature createFeature(String classname) {
214       try {
215          return (Feature)Class.forName(classname.trim()).newInstance();
216       }
217       catch (final InstantiationException e) {
218          LOGGER.log(Level.SEVERE, Constant.EMPTY_STRING, e);
219       }
220       catch (final IllegalAccessException e) {
221          LOGGER.log(Level.SEVERE, Constant.EMPTY_STRING, e);
222       }
223       catch (final ClassNotFoundException e) {
224          LOGGER.log(Level.SEVERE, Constant.EMPTY_STRING, e);
225       }
226 
227       return null;
228    } // createFeature
229 
230 
231    /**
232     * Computes the feature vector.
233     * 
234     * @param note the note the feature vector has to be computed of.
235     * @param minDistance the minimal distance between two points.
236     * @param featureList an array of features.
237     * @return the feature vector.
238     * @throws FeatureException if the feature vector cannot be computed.
239     */
240    public static DoubleVector computeFeatureVector(Note note, int minDistance,
241          Feature[] featureList) throws FeatureException {
242 
243       // clone the note to avoid side effects
244       final Note clone = (Note)note.clone();
245 
246       // filter the note using the min distance
247       clone.filter(minDistance);
248 
249       // create the feature vector
250       final DoubleVector featureVector = new DoubleVector(featureList.length);
251 
252       for (int i = 0; i < featureList.length; i++) {
253          featureVector.set(i, featureList[i].compute(clone));
254       }
255 
256       return featureVector;
257    } // computeFeatureVector
258 
259 
260    /**
261     * Returns the minimal number of points a note must contain to be processed.
262     * @param list the list of features.
263     * @return the minimal number of points a note must contain.
264     */
265    public static int computeMinimalNumberOfRequiredPoints(Feature[] list) {
266       int result = 0;
267       for (Feature feature : list) {
268          result = Math.max(result, feature.getMinimalNumberOfPoints());
269       }
270       return result;
271    }
272 
273 
274    public static double computeD1(Note note) {
275       Trace trace = createTrace(note);
276       double a = Math.pow(trace.get(trace.size() / 2).getX()
277             - trace.getStartPoint().getX(), 2);
278       double b = Math.pow(trace.get(trace.size() / 2).getY()
279             - trace.getStartPoint().getY(), 2);
280       return Math.sqrt(a + b);
281    } // computeD1
282 
283 
284    public static double computeD2(Note note) {
285       Trace trace = createTrace(note);
286       double a = Math.pow(trace.getEndPoint().getX()
287             - trace.get(trace.size() / 2).getX(), 2);
288       double b = Math.pow(trace.getEndPoint().getY()
289             - trace.get(trace.size() / 2).getY(), 2);
290       return Math.sqrt(a + b);
291    } // computeD2
292 
293 
294    public static double computeD3(Note note) {
295       Trace trace = createTrace(note);
296       double a = Math.pow(trace.getEndPoint().getX()
297             - trace.getStartPoint().getX(), 2);
298       double b = Math.pow(trace.getEndPoint().getY()
299             - trace.getStartPoint().getY(), 2);
300       return Math.sqrt(a + b);
301    } // computeD3
302 
303 }