View Javadoc

1   /**
2    * 
3    */
4   package org.ximtec.igesture;
5   
6   import java.util.ArrayList;
7   import java.util.Arrays;
8   import java.util.Calendar;
9   import java.util.Iterator;
10  import java.util.Map;
11  import java.util.PriorityQueue;
12  
13  import org.ximtec.igesture.core.Gesture;
14  import org.ximtec.igesture.core.GestureSample;
15  import org.ximtec.igesture.core.GestureSample3D;
16  import org.ximtec.igesture.core.ResultSet;
17  
18  /**
19   * This class represents the input queue of the multi-modal gesture recogniser.
20   * 
21   * @author Bjorn Puype, bpuype@gmail.com
22   *
23   */
24  public class MultimodalGestureQueue {
25  
26  	private PriorityQueue<QueueElement> queue;
27  	private Map<String, String> characterMapping;
28  	private Map<String, Calendar> timeWindowMapping;
29  	private MultimodalGestureRecogniser recogniser;
30  	
31  	public MultimodalGestureQueue(Map<String, String> charMapping, Map<String, Calendar> timeWindows, MultimodalGestureRecogniser owner)
32  	{
33  		queue = new PriorityQueue<QueueElement>();
34  		characterMapping = charMapping;
35  		timeWindowMapping = timeWindows;
36  		recogniser = owner;
37  	}
38  	
39  	/**
40  	 * Push an element in the queue
41  	 * @param resultSet	The recognised gesture as a ResultSet
42  	 */
43  	public synchronized void push(ResultSet resultSet)
44  	{
45  		//put in gesture queue
46  		queue.add(new QueueElement(resultSet,characterMapping.get(resultSet.getGesture().getName())));
47  		//execute a recognition step
48  		if(recogniser.isRunning())
49  		{
50  			//avoid java.util.concurrent.RejectedExecutionException by asking the thread pool to execute something 
51  			//if the pool is not running
52  			recogniser.recognise(getWindowOfQueue());
53  		}
54  	}
55  	
56  	/**
57  	 * Remove an element from the queue
58  	 * @return true if the element was removed
59  	 */
60  //	public synchronized boolean remove()
61  //	{
62  //		boolean sleep = false;
63  //		//remove head from gesture queue
64  //		QueueElement elem = queue.peek();
65  //		if(elem != null && elem.getWindows() == 0)
66  //		{
67  //			queue.poll();
68  //			sleep = true;
69  //		}	
70  //		return sleep;
71  //	}
72  	
73  	/**
74  	 * Retrieves but does not remove the head of the queue, <i>null</i> if empty
75  	 * @return
76  	 */
77  	public synchronized QueueElement peek()
78  	{
79  		return queue.peek();
80  	}
81  	
82  	/**
83  	 * Retrieves and removes the head of the queue, <i>null</i> if empty
84  	 * @return
85  	 */
86  	public synchronized QueueElement poll()
87  	{
88  		return queue.poll();
89  	}
90  	
91  	/**
92  	 * Get a part of the queue that fits within the time window of element last put in the queue
93  	 * @return
94  	 */
95  	private QueueElement[] getWindowOfQueue()
96  	{
97  		QueueElement[] arr = new QueueElement[1]; 
98  		arr = queue.toArray(arr);
99  	
100 		// calculate time window
101 		Calendar cal = timeWindowMapping.get(arr[arr.length-1].getGesture().getName());
102 		int millis = cal.get(Calendar.MILLISECOND);
103 		int seconds = cal.get(Calendar.SECOND);
104 		int minutes = cal.get(Calendar.MINUTE);
105 		int hours = cal.get(Calendar.HOUR);
106 		millis += seconds*1000+minutes*60*1000+hours*60*60*1000;
107 
108 //		System.out.println(millis);
109 		
110 		// calculate start time of window
111 		long time = arr[arr.length-1].getTime() - millis;
112 		
113 		//TODO think that because of current time window implementation, there will not be a lot of correctly recognised gestures
114 		
115 		//get all gestures performed after time 'time'
116 		int index = 0;
117 		for (int i = 0; i < arr.length; i++) {
118 			if(arr[i].getTime() >= time)
119 			{
120 				index = i;
121 				break;
122 			}
123 		}
124 		
125 		// remove all identified gestures
126 //		List<QueueElement> list = Arrays.asList(Arrays.copyOfRange(arr, index, arr.length));
127 		ArrayList<QueueElement> elements = new ArrayList<QueueElement>();
128 		elements.addAll(Arrays.asList(Arrays.copyOfRange(arr, index, arr.length)));
129 		for (Iterator iterator = elements.iterator(); iterator.hasNext();) {
130 			QueueElement queueElement = (QueueElement) iterator.next();
131 			if(queueElement.isIdentified())
132 				iterator.remove();
133 		}
134 		return elements.toArray(new QueueElement[1]);
135 		//return Arrays.copyOfRange(arr, index, arr.length);
136 	}
137 	
138 	public synchronized boolean isEmpty()
139 	{
140 		return queue.isEmpty();
141 	}
142 	
143 	public synchronized int size()
144 	{
145 		return queue.size();
146 	}	
147 	
148 	/**
149 	 * This class represents an element in the queue and encapsulates different information.
150 	 * @author Bjönöype, bpuype@gmail.com
151 	 *
152 	 */
153 	public class QueueElement implements Comparable<QueueElement>//TODO different locks
154 	{
155 		private int windows; // the number of time windows overlapping this gesture
156 		private boolean identified; // is the element part of a recognised and validated composite?
157 		private Gesture<?> gs; // the gesture sample
158 		private ResultSet result; // the resultset, is used to fire a single gesture if is not identified as part of a composite
159 		private String ch; // the character representation of the gesture
160 		private long time; // the start time stamp of the gesture
161 		
162 		/**
163 		 * Constructor
164 		 */
165 		public QueueElement(ResultSet resultSet, String character)
166 		{
167 			result = resultSet;
168 			gs = resultSet.getGesture();
169 			windows = 0;
170 			identified = false;
171 			ch = character;
172 			if(gs instanceof GestureSample)
173 			{
174 				time = ((GestureSample)gs).getGesture().getStartPoint().getTimestamp();
175 //				System.out.println("QueueElement: GestureSample");
176 			} 
177 			else if(gs instanceof GestureSample3D)
178 			{
179 				time = ((GestureSample3D)gs).getGesture().getStartPoint().getTimeStamp();
180 //				System.out.println("QueueElement: GestureSample3D");
181 			}			
182 		}
183 
184 		/**
185 		 * @return the identified
186 		 */
187 		public synchronized boolean isIdentified() {
188 			return identified;
189 		}
190 
191 		/**
192 		 * @param identified the identified to set
193 		 */
194 		public synchronized void setIdentified(boolean identified) {
195 			this.identified = identified;
196 		}
197 
198 		/**
199 		 * The number of time windows overlapping this gesture.
200 		 * @return the windows
201 		 */
202 		public synchronized int getWindows() {
203 			return windows;
204 		}
205 		
206 		/**
207 		 * Increment the number of time windows by 1.
208 		 */
209 		public synchronized void incrementWindows()
210 		{
211 			windows++;
212 		}
213 		
214 		/**
215 		 * Decrement the number of time windows by 1.
216 		 */
217 		public synchronized void decrementWindows()
218 		{
219 			windows--;
220 		}
221 
222 		/**
223 		 * @return the gs
224 		 */
225 		public Gesture<?> getGesture() {
226 			return gs;
227 		}
228 
229 		/**
230 		 * @return the ch
231 		 */
232 		public String getCharacterRepresentation() {
233 			return ch;
234 		}
235 
236 		/**
237 		 * @return the time
238 		 */
239 		public long getTime() {
240 			return time;
241 		}
242 
243 		/* (non-Javadoc)
244 		 * @see java.lang.Comparable#compareTo(java.lang.Object)
245 		 */
246 		@Override
247 		public int compareTo(QueueElement o) {// for the ordering in the priority queue, time based
248 			if(getTime() > o.getTime())
249 				return 1;
250 			else if(getTime() < o.getTime())
251 				return -1;
252 			else
253 				return 0; 
254 		}
255 		
256 		public ResultSet getResultSet()
257 		{
258 			return result;
259 		}
260 		
261 		public String toString()
262 		{
263 			return "[QueueElement ["+gs.getName() + " "+ getTime()+"]]";
264 		}
265 	}
266 }