001: /*
002: * $RCSfile: Sensor.java,v $
003: *
004: * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.6 $
028: * $Date: 2008/02/28 20:17:29 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import javax.vecmath.*;
035:
036: /**
037: * The Sensor Class encapsulates an object that provides real-time
038: * data. Examples include six-degree-of-freedom tracking, a joystick,
039: * or a data file being read back during a program. A sensor must be
040: * used in conjuction with an implementation of the InputDevice
041: * interface.<P>
042: *
043: * The Sensor object provides an abstract concept of a hardware
044: * input device. A Sensor consists of a timestamped sequence of
045: * input values and the state of buttons or switches at the time
046: * that Java 3D sampled the value. A sensor also contains a hotspot
047: * offset specified in the sensor's local coordinate system. If not
048: * specified, the hotspot is (0.0, 0.0, 0.0).<P>
049: *
050: * Since a typical hardware environment may contain multiple sensing
051: * elements, Java 3D maintains an array of sensors. Users can access
052: * a sensor directly from their Java code or they can assign a sensor
053: * to one of Java 3D's predefined 6DOF entities, such as UserHead.<P>
054: *
055: * Using a sensor is as easy as accessing an object. Write your
056: * Java code to extract the associated sensor value from the array of
057: * sensors. You can then directly apply that value to an element in a
058: * scene graph or process the sensor values in whatever way necessary.<P>
059: *
060: * Java 3D includes three special six-degrees-of-freedom (6DOF) entities.
061: * These include UserHead, DominantHand, and NondominantHand. You
062: * can assign or change which sensor drives one
063: * of these predefined entities. Java 3D uses the specified sensor to
064: * drive the 6DOF entity - most visibly the View.<P>
065: *
066: * Java 3D does not provide raw tracker or joystick-generated data in
067: * a sensor. At a minimum, Java 3D normalizes the raw data using the
068: * registration and calibration parameters either provided by or
069: * provided for the end user. It additionally may filter and process
070: * the data to remove noise and improve latency.
071: * The application programmer can suppress this latter effect on a
072: * sensor-by-sensor basis.<P>
073: *
074: * @see SensorRead
075: */
076:
077: public class Sensor {
078:
079: /**
080: * Set predictor type to do no prediction; this is the default.
081: *
082: * @deprecated As of Java 3D version 1.4, prediction is not a
083: * supported feature.
084: */
085: public static final int PREDICT_NONE = 1;
086:
087: /**
088: * @deprecated As of Java 3D version 1.4, prediction is not a
089: * supported feature.
090: */
091: public static final int PREDICT_NEXT_FRAME_TIME = 2;
092:
093: /**
094: * Use no prediction policy; this is the default.
095: *
096: * @deprecated As of Java 3D version 1.4, prediction is not a
097: * supported feature.
098: */
099: public static final int NO_PREDICTOR = 16;
100:
101: /**
102: * @deprecated As of Java 3D version 1.4, prediction is not a
103: * supported feature.
104: */
105: public static final int HEAD_PREDICTOR = 32;
106:
107: /**
108: * @deprecated As of Java 3D version 1.4, prediction is not a
109: * supported feature.
110: */
111: public static final int HAND_PREDICTOR = 64;
112:
113: /**
114: * Default SensorRead object count (30); the number of SensorRead
115: * objects constructed if no count is specified.
116: */
117: public static final int DEFAULT_SENSOR_READ_COUNT = 30;
118:
119: /**
120: * SENSOR_READ_COUNT_BUFFER is the number of extra sensor reading
121: * values to store at the end of the circular list. It helps provide
122: * MT-safeness. This is necessary if someone asks for the last
123: * k sensor values and k is close to sensor read count.
124: * This helps avoid some synchronization statements in getRead
125: * and setNextSensorRead.
126: */
127: static final int SENSOR_READ_COUNT_BUFFER = 15;
128:
129: static int num_reads_so_far = 0;
130:
131: // specifies whether a DEMAND_DRIVEN device has been added that
132: // manages this sensor
133: boolean demand_driven = false;
134:
135: // size of the sensor read buffer
136: int sensorReadCount;
137:
138: // Prediction policy -- unused
139: private int predictionPolicy = NO_PREDICTOR;
140:
141: // Predictor type -- unused
142: private int predictorType = PREDICT_NONE;
143:
144: // This sensor's associated device
145: InputDevice device;
146:
147: SensorRead readings[];
148: int currentIndex;
149: int lastIndex;
150: Point3d hotspot;
151: int MaxSensorReadIndex;
152:
153: // The count of the number of buttons associated with this sensor.
154: int sensorButtonCount;
155:
156: // These matrices used as a temporary workspace for the local SVD
157: // calculations (thus minimimizing garbage collection).
158: Matrix3d orig_rot = new Matrix3d();
159: Matrix3d orig_rot_transpose = new Matrix3d();
160: Matrix3d temp_rot = new Matrix3d();
161: Matrix3d local_svd = new Matrix3d();
162:
163: /**
164: * Constructs a Sensor object for the specified input device using
165: * default parameters. The default values are as follows:
166: * <ul>
167: * sensor read count : 30<br>
168: * sensor button count : 0<br>
169: * hot spot : (0,0,0)<br>
170: * predictor : PREDICT_NONE — <i>this attribute is unused</i><br>
171: * prediction policy : NO_PREDICTOR — <i>this attribute is unused</i><br>
172: * </ul>
173: * @param device the Sensor's associated device.
174: */
175: public Sensor(InputDevice device) {
176: this (device, DEFAULT_SENSOR_READ_COUNT, 0, new Point3d(0.0,
177: 0.0, 0.0));
178: }
179:
180: /**
181: * Constructs a Sensor object for the specified input device using
182: * the specified number of SensorRead objects.
183: * Default values are used for all other parameters.
184: * @param device the Sensor's associated device
185: * @param sensorReadCount the number of SensorReads to associate with
186: * this sensor
187: */
188: public Sensor(InputDevice device, int sensorReadCount) {
189: this (device, sensorReadCount, 0, new Point3d(0.0, 0.0, 0.0));
190: }
191:
192: /**
193: * Constructs a Sensor object for the specified input device using
194: * the specified number of SensorRead objects and number of buttons.
195: * Default values are used for all other parameters.
196: * @param device the Sensor's associated device
197: * @param sensorReadCount the number of SensorReads to associate with
198: * this sensor
199: * @param sensorButtonCount the number of buttons associated with each
200: * sensor read
201: */
202: public Sensor(InputDevice device, int sensorReadCount,
203: int sensorButtonCount) {
204: this (device, sensorReadCount, sensorButtonCount, new Point3d(
205: 0.0, 0.0, 0.0));
206: }
207:
208: /**
209: * Constructs a Sensor object for the specified input device using
210: * the specified hotspot.
211: * Default values are used for all other parameters.
212: * @param device the Sensor's associated device
213: * @param hotspot the Sensor's hotspot defined in its local coordinate
214: * system
215: */
216: public Sensor(InputDevice device, Point3d hotspot) {
217: this (device, DEFAULT_SENSOR_READ_COUNT, 0, hotspot);
218: }
219:
220: /**
221: * Constructs a Sensor object for the specified input device using
222: * the specified number of SensorRead objects and hotspot.
223: * Default values are used for all other parameters.
224: * @param device the Sensor's associated device
225: * @param sensorReadCount the number of SensorReads to associate with
226: * this sensor
227: * @param hotspot the Sensor's hotspot defined in its local coordinate
228: * system
229: */
230: public Sensor(InputDevice device, int sensorReadCount,
231: Point3d hotspot) {
232: this (device, sensorReadCount, 0, hotspot);
233: }
234:
235: /**
236: * Constructs a Sensor object for the specified input device using
237: * the specified number of SensorRead objects, number of buttons, and
238: * hotspot.
239: * Default values are used for all other parameters.
240: * @param device the Sensor's associated device
241: * @param sensorReadCount the number of SensorReads to associate with
242: * this sensor
243: * @param sensorButtonCount the number of buttons associated with each
244: * sensor read
245: * @param hotspot the Sensor's hotspot defined in its local coordinate
246: * system
247: */
248: public Sensor(InputDevice device, int sensorReadCount,
249: int sensorButtonCount, Point3d hotspot) {
250: this .device = device;
251: this .sensorReadCount = sensorReadCount;
252: this .MaxSensorReadIndex = sensorReadCount
253: + SENSOR_READ_COUNT_BUFFER - 1;
254: this .sensorButtonCount = sensorButtonCount;
255: readings = new SensorRead[MaxSensorReadIndex + 1];
256: for (int i = 0; i < MaxSensorReadIndex + 1; i++) {
257: readings[i] = new SensorRead(sensorButtonCount);
258: }
259: currentIndex = 0;
260: this .hotspot = new Point3d(hotspot);
261: }
262:
263: // argument of 0 is last reading (ie, currentIndex), argument
264: // of 1 means next to last index, etc.
265: int previousIndex(int k) {
266: int temp = currentIndex - k;
267: return (temp >= 0 ? temp : MaxSensorReadIndex + temp + 1);
268: }
269:
270: /**
271: * Sets the type of predictor to use with this sensor.
272: * Since prediction is not implemented (and never has been), this
273: * attribute has no effect.
274: * @param predictor predictor type one of PREDICT_NONE or
275: * PREDICT_NEXT_FRAME_TIME
276: * @exception IllegalArgumentException if an invalid predictor type
277: * is specified.
278: *
279: * @deprecated As of Java 3D version 1.4, prediction is not a
280: * supported feature.
281: */
282: public void setPredictor(int predictor) {
283: if (predictor != PREDICT_NONE
284: && predictor != PREDICT_NEXT_FRAME_TIME) {
285: throw new IllegalArgumentException(J3dI18N
286: .getString("Sensor0"));
287: } else {
288: predictorType = predictor;
289: }
290: }
291:
292: /**
293: * Returns the type of predictor used by this sensor.
294: * @return the predictor type.
295: *
296: * @deprecated As of Java 3D version 1.4, prediction is not a
297: * supported feature.
298: */
299: public int getPredictor() {
300: return predictorType;
301: }
302:
303: /**
304: * Sets the prediction policy use by this sensor.
305: * Since prediction is not implemented (and never has been), this
306: * attribute has no effect.
307: * @param policy prediction policy one of NO_PREDICTOR, HEAD_PREDICTOR,
308: * or HAND_PREDICTOR
309: * @exception IllegalArgumentException if an invalid prediction policy
310: * is specified.
311: *
312: * @deprecated As of Java 3D version 1.4, prediction is not a
313: * supported feature.
314: */
315: public void setPredictionPolicy(int policy) {
316: if (policy != NO_PREDICTOR && policy != HEAD_PREDICTOR
317: && policy != HAND_PREDICTOR)
318: throw new IllegalArgumentException(J3dI18N
319: .getString("Sensor1"));
320: else
321: predictionPolicy = policy;
322: }
323:
324: /**
325: * Returns the prediction policy used by this sensor.
326: * @return the prediction policy.
327: *
328: * @deprecated As of Java 3D version 1.4, prediction is not a
329: * supported feature.
330: */
331: public int getPredictionPolicy() {
332: return predictionPolicy;
333: }
334:
335: /**
336: * Set the sensor's hotspot in this sensor's coordinate system.
337: * @param hotspot the sensor's new hotspot
338: */
339: public void setHotspot(Point3d hotspot) {
340: this .hotspot.set(hotspot);
341: }
342:
343: /**
344: * Get the sensor's hotspot in this sensor's coordinate system.
345: * @param hotspot the variable to receive the sensor's hotspot
346: */
347: public void getHotspot(Point3d hotspot) {
348: hotspot.set(this .hotspot);
349: }
350:
351: /**
352: * Set the sensor's associated input device.
353: * @param device the sensor's new device
354: */
355: public void setDevice(InputDevice device) {
356: this .device = device;
357: }
358:
359: /**
360: * Retrieves the sensor's associated input device.
361: * @return the sensor's device
362: */
363: public InputDevice getDevice() {
364: return device;
365: }
366:
367: /**
368: * Retrieves the last sensor reading and copies that value into
369: * the specified argument.
370: *
371: * @param read the matrix that will receive the sensor reading
372: */
373: public void getRead(Transform3D read) {
374: if (demand_driven == true)
375: device.pollAndProcessInput();
376:
377: read.set(readings[currentIndex].read);
378: }
379:
380: /**
381: * Retrieves the last sensor reading and copies that value into
382: * the specified argument.
383: *
384: * @param read the matrix that will receive the sensor reading
385: * @param deltaT this parameter is ignored
386: *
387: * @deprecated As of Java 3D version 1.4, prediction is not a
388: * supported feature; use <code>getRead(Transform3D)</code> instead.
389: */
390: public void getRead(Transform3D read, long deltaT) {
391: getRead(read);
392: }
393:
394: /**
395: * Extracts the most recent sensor reading and copies that value into
396: * the specified argument.
397: * @param read the matrix that will receive the most recent sensor reading
398: */
399: public void lastRead(Transform3D read) {
400: read.set(readings[currentIndex].read);
401: }
402:
403: /**
404: * Extracts the kth-most recent sensor reading and copies that value into
405: * the specified argument; where 0 is the most recent sensor reading, 1 is
406: * the next most recent sensor reading, etc.
407: * @param read the matrix that will receive the most recent sensor reading
408: * @param kth the kth previous sensor reading
409: */
410: public void lastRead(Transform3D read, int kth) {
411: if (kth >= sensorReadCount) {
412: throw new IllegalArgumentException(J3dI18N
413: .getString("Sensor3"));
414: }
415: read.set(readings[previousIndex(kth)].read);
416: }
417:
418: /**
419: * Returns the time associated with the most recent sensor reading.
420: * @return the time associated with the most recent sensor reading.
421: */
422: public long lastTime() {
423: return readings[currentIndex].time;
424: }
425:
426: /**
427: * Returns the time associated with the kth-most recent sensor reading;
428: * where 0 is the most recent sensor reading, 1 is the next most recent
429: * sensor reading, etc.
430: * @return the time associated with the kth-most recent sensor reading.
431: */
432: public long lastTime(int k) {
433: if (k >= sensorReadCount) {
434: throw new IllegalArgumentException(J3dI18N
435: .getString("Sensor4"));
436: }
437: return readings[previousIndex(k)].time;
438: }
439:
440: /**
441: * Places the most recent sensor reading value for each button into
442: * the array parameter; will throw an ArrayIndexOutOfBoundsException
443: * if values.length is less than the number of buttons.
444: * @param values the array into which the button values will be
445: * placed
446: */
447: public void lastButtons(int[] values) {
448: System.arraycopy(readings[currentIndex].buttonValues, 0,
449: values, 0, sensorButtonCount);
450: }
451:
452: /**
453: * Places the kth-most recent sensor reading value for each button into
454: * the array parameter; where k=0 is the most recent sensor reading, k=1
455: * is the next most recent sensor reading, etc.; will throw an
456: * ArrayIndexOutOfBoundsException if values.length is less than
457: * the number of buttons.
458: * @param k the time associated with the most recent sensor reading
459: * @param values the array into which the button values will be
460: * placed.
461: */
462: public void lastButtons(int k, int[] values) {
463: if (k >= sensorReadCount) {
464: throw new IllegalArgumentException(J3dI18N
465: .getString("Sensor5"));
466: }
467: System.arraycopy(readings[previousIndex(k)].buttonValues, 0,
468: values, 0, sensorButtonCount);
469: }
470:
471: /**
472: * Returns the number of SensorRead objects associated with
473: * this sensor.
474: * @return the number of SensorReadObjects associated with this sensor
475: */
476: public int getSensorReadCount() {
477: return this .sensorReadCount;
478: }
479:
480: /**
481: * Set the number of sensor read objects per Sensor. This is a
482: * calibration parameter that should normally be set in this
483: * object's constructor. Calling this method resets all of this
484: * sensor's values that are already in the buffer.
485: * It is illegal to change this value after the device has been
486: * added to the scheduler.
487: * @param count the new sensor read count
488: */
489: public void setSensorReadCount(int count) {
490: sensorReadCount = count;
491: MaxSensorReadIndex = sensorReadCount + SENSOR_READ_COUNT_BUFFER
492: - 1;
493: readings = new SensorRead[MaxSensorReadIndex + 1];
494: for (int i = 0; i < MaxSensorReadIndex + 1; i++) {
495: readings[i] = new SensorRead(sensorButtonCount);
496: }
497: currentIndex = 0;
498: }
499:
500: /**
501: * Returns the number of buttons associated with this sensor.
502: * @return the number of buttons associated with this sensor.
503: */
504: public int getSensorButtonCount() {
505: return sensorButtonCount;
506: }
507:
508: /**
509: * Gets the current sensor read.
510: * @return the current sensor read object
511: */
512: public SensorRead getCurrentSensorRead() {
513: // not sure if this should return a reference or a copy
514: SensorRead read = new SensorRead(sensorButtonCount);
515: read.set(readings[currentIndex]);
516: return read;
517: }
518:
519: /**
520: * Sets the next sensor read to the specified values; once these
521: * values are set via this method they become the current values
522: * returned by methods such as lastRead(), lastTime(), and
523: * lastButtons(); note that if there are no buttons associated with
524: * this sensor, values can just be an empty array.
525: * @param time the next SensorRead's associated time
526: * @param transform the next SensorRead's transformation
527: * @param values the next SensorRead's buttons' states
528: */
529: public void setNextSensorRead(long time, Transform3D transform,
530: int[] values) {
531:
532: int temp = currentIndex + 1;
533: if (temp > MaxSensorReadIndex)
534: temp = 0;
535:
536: readings[temp].setTime(time);
537: readings[temp].set(transform);
538: if (sensorButtonCount > 0)
539: readings[temp].setButtons(values);
540: currentIndex = temp;
541: }
542:
543: /**
544: * Sets the next sensor read to the specified values; once these
545: * values are set via this method they become the current values
546: * returned by methods such as lastRead(), lastTime(), and
547: * lastButtons().
548: * @param read the next SensorRead's values
549: */
550: public void setNextSensorRead(SensorRead read) {
551: int temp = currentIndex + 1;
552: if (temp > MaxSensorReadIndex)
553: temp = 0;
554: readings[temp].set(read);
555: currentIndex = temp;
556: }
557:
558: }
|