Browse Source

PointerTracker: introduce the adjusted space

customisations
alemart 9 months ago
parent
commit
9bbfb73a5a

+ 26
- 3
docs/api/pointer-tracker.md View File

8
 
8
 
9
 ### AR.Tracker.Pointer
9
 ### AR.Tracker.Pointer
10
 
10
 
11
-`AR.Tracker.Pointer(): PointerTracker`
11
+`AR.Tracker.Pointer(options: object): PointerTracker`
12
 
12
 
13
-Create a new `PointerTracker`.
13
+Create a new `PointerTracker` with the specified `options`.
14
+
15
+**Arguments**
16
+
17
+* `options: object, optional`. An object with the following keys (all are optional):
18
+    * `space: string`. The [space](#space) in which pointers will be located. Defaults to `"normalized"`.
14
 
19
 
15
 **Returns**
20
 **Returns**
16
 
21
 
19
 **Example**
24
 **Example**
20
 
25
 
21
 ```js
26
 ```js
27
+// Use default settings
22
 const pointerTracker = AR.Tracker.Pointer();
28
 const pointerTracker = AR.Tracker.Pointer();
29
+
30
+// Track pointers in adjusted space
31
+const pointerTracker = AR.Tracker.Pointer({ space: 'adjusted' });
23
 ```
32
 ```
24
 
33
 
25
 ## Properties
34
 ## Properties
28
 
37
 
29
 `tracker.type: string, read-only`
38
 `tracker.type: string, read-only`
30
 
39
 
31
-The string `"pointer-tracker"`.
40
+The string `"pointer-tracker"`.
41
+
42
+### space
43
+
44
+`tracker.space: string, read-only`
45
+
46
+The space in which pointers are located. You may set it when instantiating the tracker. Possible values: `"normalized"` or `"adjusted"`.
47
+
48
+- In `"normalized"` space, pointers are located in [-1,1]x[-1,1]. The origin of the space is at the center of the [viewport](viewport.md). The x-axis points to the right and the y-axis points up. This is the default space.
49
+
50
+- The `"adjusted"` space is similar to the normalized space, except that it is scaled so that it matches the [aspect ratio](viewport.md#aspectratio) of the viewport.
51
+
52
+    Pointers in adjusted space are contained in normalized space, but unless the viewport is a square, one of their coordinates, x or y, will no longer range from -1 to +1. It will range from *-s* to *+s*, where *s = min(a, 1/a)*. In this expression, *a* is the aspect ratio of the viewport and *s* is less than or equal to 1.
53
+
54
+    Selecting the adjusted space is useful for making sure that pointer speeds are equivalent in both axes and for preserving movement curves. Speeds are not equivalent and movement curves are not preserved by default because the normalized space is a square, whereas the viewport is a rectangle.

+ 4
- 4
docs/api/trackable-pointer.md View File

4
 
4
 
5
 A pointer is an abstraction that represents an instance of user input that targets one or more coordinates on a screen. For example, each point of contact between fingers and a multitouch screen generate a pointer. Devices such as a mouse and a pen/stylus also generate pointers.
5
 A pointer is an abstraction that represents an instance of user input that targets one or more coordinates on a screen. For example, each point of contact between fingers and a multitouch screen generate a pointer. Devices such as a mouse and a pen/stylus also generate pointers.
6
 
6
 
7
-Pointers are positioned in the [viewport](viewport.md). Their positions are given in normalized units, which range from -1 to +1. The center of the viewport is at (0,0). The top right corner is at (1,1). The bottom left corner is at (-1,-1).
7
+Pointers are located in the [viewport](viewport.md). Their positions are given in [space units](pointer-tracker.md#space). By default, space units are normalized units, which range from -1 to +1. In normalized space, the center of the viewport is at (0,0). The top right corner is at (1,1). The bottom left corner is at (-1,-1).
8
 
8
 
9
 *Since:* 0.4.0
9
 *Since:* 0.4.0
10
 
10
 
32
 
32
 
33
 `pointer.position: Vector2, read-only`
33
 `pointer.position: Vector2, read-only`
34
 
34
 
35
-The current position of the pointer, given in normalized units. See also: [Viewer.raycast](viewer.md#raycast), [Viewport.convertToPixels](viewport.md#converttopixels).
35
+The current position of the pointer, given in space units. See also: [PointerTracker.space](pointer-tracker.md#space), [Viewer.raycast](viewer.md#raycast), [Viewport.convertToPixels](viewport.md#converttopixels).
36
 
36
 
37
 ### initialPosition
37
 ### initialPosition
38
 
38
 
50
 
50
 
51
 `pointer.velocity: Vector2, read-only`
51
 `pointer.velocity: Vector2, read-only`
52
 
52
 
53
-The current velocity of the pointer, given in normalized units per second. You can get the current speed of motion by calculating the [magnitude](vector2.md#length) of this vector.
53
+The current velocity of the pointer, given in space units per second. You can get the current speed of motion by calculating the [magnitude](vector2.md#length) of this vector.
54
 
54
 
55
 ### elapsedTime
55
 ### elapsedTime
56
 
56
 
62
 
62
 
63
 `pointer.totalDistance: number, read-only`
63
 `pointer.totalDistance: number, read-only`
64
 
64
 
65
-How much this pointer has moved, in normalized units, since its tracking began. You can get the average speed of motion by calculating the ratio `totalDistance / elapsedTime`.
65
+How much this pointer has moved, in space units, since its tracking began. You can get the average speed of motion by calculating the ratio `totalDistance / elapsedTime`.
66
 
66
 
67
 ### isPrimary
67
 ### isPrimary
68
 
68
 

+ 88
- 3
src/trackers/pointer-tracker/pointer-tracker.ts View File

27
 import { PointerSource } from '../../sources/pointer-source';
27
 import { PointerSource } from '../../sources/pointer-source';
28
 import { Vector2 } from '../../geometry/vector2';
28
 import { Vector2 } from '../../geometry/vector2';
29
 import { Utils, Nullable } from '../../utils/utils';
29
 import { Utils, Nullable } from '../../utils/utils';
30
-import { IllegalOperationError } from '../../utils/errors';
30
+import { IllegalOperationError, IllegalArgumentError } from '../../utils/errors';
31
 import { Session } from '../../core/session';
31
 import { Session } from '../../core/session';
32
 import { Viewport } from '../../core/viewport';
32
 import { Viewport } from '../../core/viewport';
33
 
33
 
52
     readonly exports: PointerTrackerResult;
52
     readonly exports: PointerTrackerResult;
53
 }
53
 }
54
 
54
 
55
+/**
56
+ * The space in which pointers are located.
57
+ *
58
+ * - In "normalized" space, pointers are located in [-1,1]x[-1,1]. The origin
59
+ *   of the space is at the center of the viewport. The x-axis points to the
60
+ *   right and the y-axis points up. This is the default space.
61
+ *
62
+ * - The "adjusted" space is similar to the normalized space, except that it is
63
+ *   scaled so that it matches the aspect ratio of the viewport.
64
+ *
65
+ *   Pointers in adjusted space are contained in normalized space, but unless
66
+ *   the viewport is a square, one of their coordinates, x or y, will no longer
67
+ *   range from -1 to +1. It will range from -s to +s, where s = min(a, 1/a).
68
+ *   In this expression, a is the aspect ratio of the viewport and s is less
69
+ *   than or equal to 1.
70
+ *
71
+ *   Selecting the adjusted space is useful for making sure that pointer speeds
72
+ *   are equivalent in both axes and for preserving movement curves. Speeds are
73
+ *   not equivalent and movement curves are not preserved by default because
74
+ *   the normalized space is a square, whereas the viewport is a rectangle.
75
+ */
76
+export type PointerSpace = 'normalized' | 'adjusted'; // | 'viewport';
77
+
78
+/**
79
+ * Options for instantiating a PointerTracker
80
+ */
81
+export interface PointerTrackerOptions
82
+{
83
+    /** the space in which pointers will be located */
84
+    space?: PointerSpace;
85
+}
86
+
55
 /** Convert event type to trackable pointer phase */
87
 /** Convert event type to trackable pointer phase */
56
 const EVENTTYPE2PHASE: Record<string, TrackablePointerPhase> = {
88
 const EVENTTYPE2PHASE: Record<string, TrackablePointerPhase> = {
57
     'pointerdown': 'began',
89
     'pointerdown': 'began',
62
     'pointerenter': 'began',
94
     'pointerenter': 'began',
63
 };
95
 };
64
 
96
 
97
+/** Default options for instantiating a PointerTracker */
98
+const DEFAULT_OPTIONS: Readonly<Required<PointerTrackerOptions>> = {
99
+    space: 'normalized'
100
+};
101
+
65
 
102
 
66
 
103
 
67
 
104
 
76
     /** the viewport */
113
     /** the viewport */
77
     private _viewport: Nullable<Viewport>;
114
     private _viewport: Nullable<Viewport>;
78
 
115
 
116
+    /** pointer space */
117
+    private _space: PointerSpace;
118
+
79
     /** active pointers */
119
     /** active pointers */
80
     private _activePointers: Map<number, TrackablePointer>;
120
     private _activePointers: Map<number, TrackablePointer>;
81
 
121
 
99
 
139
 
100
 
140
 
101
 
141
 
142
+
143
+
144
+
102
     /**
145
     /**
103
      * Constructor
146
      * Constructor
147
+     * @param options
104
      */
148
      */
105
-    constructor()
149
+    constructor(options: PointerTrackerOptions)
106
     {
150
     {
151
+        const settings = this._buildSettings(options);
152
+
107
         this._source = null;
153
         this._source = null;
108
         this._viewport = null;
154
         this._viewport = null;
155
+        this._space = settings.space;
109
         this._activePointers = new Map();
156
         this._activePointers = new Map();
110
         this._newPointers = new Map();
157
         this._newPointers = new Map();
111
         this._idMap = new Map();
158
         this._idMap = new Map();
117
     }
164
     }
118
 
165
 
119
     /**
166
     /**
167
+     * Build a full and validated options object
168
+     * @param options
169
+     * @returns validated options with defaults
170
+     */
171
+    private _buildSettings(options: PointerTrackerOptions): Required<PointerTrackerOptions>
172
+    {
173
+        const settings: Required<PointerTrackerOptions> = Object.assign({}, DEFAULT_OPTIONS, options);
174
+
175
+        if(settings.space != 'normalized' && settings.space != 'adjusted')
176
+            throw new IllegalArgumentError(`Invalid pointer space: "${settings.space}"`);
177
+
178
+        return settings;
179
+    }
180
+
181
+    /**
120
      * The type of the tracker
182
      * The type of the tracker
121
      */
183
      */
122
     get type(): string
184
     get type(): string
283
                     continue;
345
                     continue;
284
             }
346
             }
285
 
347
 
286
-            // determine the current position
348
+            // determine the current position in normalized space
287
             const absX = event.pageX - (rect.left + window.scrollX);
349
             const absX = event.pageX - (rect.left + window.scrollX);
288
             const absY = event.pageY - (rect.top + window.scrollY);
350
             const absY = event.pageY - (rect.top + window.scrollY);
289
             const relX = 2 * absX / rect.width - 1; // convert to [-1,1]
351
             const relX = 2 * absX / rect.width - 1; // convert to [-1,1]
290
             const relY = -(2 * absY / rect.height - 1); // flip Y axis
352
             const relY = -(2 * absY / rect.height - 1); // flip Y axis
291
             const position = new Vector2(relX, relY);
353
             const position = new Vector2(relX, relY);
292
 
354
 
355
+            // scale the normalized space so that it matches the aspect ratio of the viewport
356
+            if(this._space == 'adjusted') {
357
+                const a = this._viewport!.aspectRatio;
358
+
359
+                if(a >= 1) {
360
+                    // landscape
361
+                    position._set(relX, relY / a);
362
+                }
363
+                else {
364
+                    // portrait
365
+                    position._set(relX * a, relY);
366
+                }
367
+            }
368
+
293
             // determine the position delta
369
             // determine the position delta
294
             const deltaPosition = !previous ? Vector2.ZERO :
370
             const deltaPosition = !previous ? Vector2.ZERO :
295
                                   position._clone()._subtract(previous.position);
371
                                   position._clone()._subtract(previous.position);
360
     }
436
     }
361
 
437
 
362
     /**
438
     /**
439
+     * The space in which pointers are located.
440
+     * You may set it when instantiating the tracker.
441
+     */
442
+    get space(): PointerSpace
443
+    {
444
+        return this._space;
445
+    }
446
+
447
+    /**
363
      * Generate tracker output
448
      * Generate tracker output
364
      * @returns a new PointerTrackerOutput object
449
      * @returns a new PointerTrackerOutput object
365
      */
450
      */

+ 3
- 3
src/trackers/pointer-tracker/trackable-pointer.ts View File

44
     /** the phase of the pointer */
44
     /** the phase of the pointer */
45
     readonly phase: TrackablePointerPhase;
45
     readonly phase: TrackablePointerPhase;
46
 
46
 
47
-    /** current position in normalized units [-1,1]x[-1,1] */
47
+    /** current position, given in space units */
48
     readonly position: Vector2;
48
     readonly position: Vector2;
49
 
49
 
50
     /** the difference between the position of the pointer in this and in the previous frame */
50
     /** the difference between the position of the pointer in this and in the previous frame */
53
     /** the position of the pointer when its tracking began */
53
     /** the position of the pointer when its tracking began */
54
     readonly initialPosition: Vector2;
54
     readonly initialPosition: Vector2;
55
 
55
 
56
-    /** current velocity, given in normalized units per second */
56
+    /** current velocity, given in space units per second */
57
     readonly velocity: Vector2;
57
     readonly velocity: Vector2;
58
 
58
 
59
     /** elapsed time, in seconds, since the tracking of this pointer began */
59
     /** elapsed time, in seconds, since the tracking of this pointer began */
60
     readonly elapsedTime: number;
60
     readonly elapsedTime: number;
61
 
61
 
62
-    /** how much this pointer has moved, in normalized units, since its tracking began */
62
+    /** how much this pointer has moved, in space units, since its tracking began */
63
     readonly totalDistance: number;
63
     readonly totalDistance: number;
64
 
64
 
65
     /** whether or not this is the primary pointer for this type */
65
     /** whether or not this is the primary pointer for this type */

+ 4
- 3
src/trackers/tracker-factory.ts View File

21
  */
21
  */
22
 
22
 
23
 import { ImageTracker, ImageTrackerOptions } from './image-tracker/image-tracker';
23
 import { ImageTracker, ImageTrackerOptions } from './image-tracker/image-tracker';
24
-import { PointerTracker } from './pointer-tracker/pointer-tracker';
24
+import { PointerTracker, PointerTrackerOptions } from './pointer-tracker/pointer-tracker';
25
 
25
 
26
 /**
26
 /**
27
  * Tracker factory
27
  * Tracker factory
48
 
48
 
49
     /**
49
     /**
50
      * Create a Pointer Tracker
50
      * Create a Pointer Tracker
51
+     * @param options
51
      */
52
      */
52
-    static Pointer(): PointerTracker
53
+    static Pointer(options: PointerTrackerOptions = {}): PointerTracker
53
     {
54
     {
54
-        return new PointerTracker();
55
+        return new PointerTracker(options);
55
     }
56
     }
56
 }
57
 }

Loading…
Cancel
Save