View Javadoc

1   /*
2    * @(#)$Id: Parser.java 689 2009-07-22 00:10:27Z bsigner $
3    *
4    * Author       :   Ueli Kurmann, igesture@uelikurmann.ch
5    *
6    * Purpose      :	Parses the textual description of a gesture class.
7    *
8    * -----------------------------------------------------------------------
9    *
10   * Revision Information:
11   *
12   * Date             Who         Reason
13   *
14   * Dec 26, 2006     ukurmann    Initial Release
15   * Mar 16, 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.siger;
28  
29  import java.util.StringTokenizer;
30  import java.util.regex.Pattern;
31  
32  import org.sigtec.util.Constant;
33  
34  
35  /**
36   * Parses the textual description of a gesture class.
37   * 
38   * @version 1.0 Dec 2006
39   * @author Ueli Kurmann, igesture@uelikurmann.ch
40   * @author Beat Signer, signer@inf.ethz.ch
41   */
42  public class Parser {
43  
44     /**
45      * Tokens of SiGeR's description language.
46      * 
47      */
48     enum Tokens {
49        N, NE, E, SE, S, SW, W, NW, STRAIGHT, DIAGONAL, PROXIMITY;
50     }
51  
52     /**
53      * Operators of Siger's description language.
54      * 
55      */
56     public enum Operator {
57        EQ, GT, LT, GTE, LTE;
58     }
59  
60     /**
61      * Boolean operators.
62      */
63     // TODO: other operators should be implemented to enhance the description
64     // language
65     public enum BooleanOperators {
66        AND;
67     }
68  
69     private String expression;
70  
71     private String regexExpression;
72  
73     private String constraintExpression;
74  
75     private Pattern pattern;
76  
77  
78     /**
79      * Parses a string containing a description.
80      * @param expression the string to be parsed.
81      */
82     public Parser(String expression) {
83        this.expression = expression.trim();
84  
85        if (this.expression.indexOf(Constant.SEMICOLON) > 0) {
86           regexExpression = this.expression.substring(0, this.expression
87                 .indexOf(Constant.SEMICOLON));
88           constraintExpression = this.expression.substring(this.expression
89                 .indexOf(Constant.SEMICOLON) + 1);
90        }
91        else {
92           regexExpression = this.expression;
93           constraintExpression = Constant.EMPTY_STRING;
94        }
95  
96     }
97  
98  
99     /**
100     * Returns the pattern.
101     * @return the pattern.
102     */
103    public Pattern getPattern() {
104       if (pattern == null) {
105          final StringTokenizer tokenizer = new StringTokenizer(regexExpression,
106                Constant.COMMA);
107          final StringBuilder sb = new StringBuilder();
108          sb.append(Constants.START);
109 
110          while (tokenizer.hasMoreTokens()) {
111             final String token = tokenizer.nextToken();
112             final Direction d = Direction.parse(token);
113 
114             if (d != null) {
115                sb.append(Constants.getRegex(d));
116             }
117 
118          }
119          sb.append(Constants.END);
120          pattern = Pattern.compile(sb.toString());
121       }
122 
123       return pattern;
124    } // getPattern
125 
126 
127    /**
128     * Evaluates the constraints.
129     * @param strokeStatistic the stroke statistics.
130     * @return true if the constraint is satisfied.
131     */
132    public boolean evaluateConstraints(Statistics strokeStatistic) {
133       final String tmpExpression = constraintExpression.replace(
134             BooleanOperators.AND.name(), Constant.HASH);
135       final StringTokenizer expressionTokenizer = new StringTokenizer(
136             tmpExpression, Constant.HASH);
137 
138       while (expressionTokenizer.hasMoreTokens()) {
139          final String thisExpression = expressionTokenizer.nextToken().trim();
140          final StringTokenizer tokenizer = new StringTokenizer(thisExpression);
141 
142          if (tokenizer.countTokens() == 3) {
143             final double left = parseDoubleToken(tokenizer.nextToken().trim(),
144                   strokeStatistic);
145             final Operator op = Operator.valueOf(tokenizer.nextToken().trim());
146             final double right = parseDoubleToken(tokenizer.nextToken().trim(),
147                   strokeStatistic);
148 
149             if (!evaluateComparison(op, left, right)) {
150                return false;
151             }
152 
153          }
154 
155       }
156       return true;
157    } // evaluateConstraints
158 
159 
160    /**
161     * Parses a double token.
162     * @param token a string holding the double.
163     * @param statistic the statistic.
164     * @return the double value.
165     */
166    private double parseDoubleToken(String token, Statistics statistic) {
167       final double d = 0;
168 
169       if (isDouble(token)) {
170          return Double.parseDouble(token);
171       }
172       else {
173          final Tokens t = Tokens.valueOf(token);
174 
175          if (t != null) {
176             return evaluateFunction(t, statistic);
177          }
178 
179       }
180       return d;
181    } // parseDoubleToken
182 
183 
184    /**
185     * Returns true if the input represents a double value.
186     * @param s the string to checked.
187     * @return true if the input is a double value.
188     */
189    private static boolean isDouble(String s) {
190       try {
191          Double.parseDouble(s);
192          return true;
193       }
194       catch (final Exception e) {
195          return false;
196       }
197 
198    } // isDouble
199 
200 
201    /**
202     * Evaluates the given function.
203     * @param token the token to be used.
204     * @param strokeStatistic the statistics to be used.
205     * @return the function's result.
206     */
207    public static double evaluateFunction(Tokens token, Statistics strokeStatistic) {
208       switch (token) {
209          case N:
210             return strokeStatistic.getNorth();
211          case NE:
212             return strokeStatistic.getNorthEast();
213          case E:
214             return strokeStatistic.getEast();
215          case SE:
216             return strokeStatistic.getSouthEast();
217          case S:
218             return strokeStatistic.getSouth();
219          case SW:
220             return strokeStatistic.getSouthWest();
221          case W:
222             return strokeStatistic.getWest();
223          case NW:
224             return strokeStatistic.getNorthWest();
225          case STRAIGHT:
226             return strokeStatistic.getStraight();
227          case DIAGONAL:
228             return strokeStatistic.getDiagonal();
229          case PROXIMITY:
230             return strokeStatistic.getProximity();
231       }
232 
233       return 0;
234    } // evaluateFunction
235 
236 
237    /**
238     * Evaluates a comparison
239     * @param operator the comparison operator.
240     * @param left the value of the left operand.
241     * @param right the value of the right operand.
242     * @return true if the condition defined by the operator is true.
243     */
244    public static boolean evaluateComparison(Operator operator, double left,
245          double right) {
246 
247       switch (operator) {
248          case EQ:
249             return left == right;
250          case GT:
251             return left > right;
252          case GTE:
253             return left >= right;
254          case LT:
255             return left < right;
256          case LTE:
257             return left <= right;
258       }
259 
260       return false;
261    } // evaluateComparison
262 
263 }