Browse Source

Update scripts

customisations
alemart 9 months ago
parent
commit
e5d0debc2d
2 changed files with 266 additions and 54 deletions
  1. 264
    52
      dist/encantar.js
  2. 2
    2
      dist/encantar.min.js

+ 264
- 52
dist/encantar.js View File

5
  * https://github.com/alemart/encantar-js
5
  * https://github.com/alemart/encantar-js
6
  *
6
  *
7
  * @license LGPL-3.0-or-later
7
  * @license LGPL-3.0-or-later
8
- * Date: 2024-11-25T01:46:40.728Z
8
+ * Date: 2024-12-17T18:08:41.979Z
9
  */
9
  */
10
 (function webpackUniversalModuleDefinition(root, factory) {
10
 (function webpackUniversalModuleDefinition(root, factory) {
11
 	if(typeof exports === 'object' && typeof module === 'object')
11
 	if(typeof exports === 'object' && typeof module === 'object')
19952
     'low-power': '&#x1F50B',
19952
     'low-power': '&#x1F50B',
19953
     'high-performance': '&#x26A1'
19953
     'high-performance': '&#x26A1'
19954
 });
19954
 });
19955
+/** Button icons (atlas) */
19956
+const BUTTON_ICONS = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAQCAYAAAB3AH1ZAAAAVUlEQVRIS2NkGGDAOMD2M4w6YDQE8IbAfyBgBAJSEipIDy712MzCaTiyQdRwBC4zsDoAmy8ocQQ+vRgOIDUI8UUPMVFIUvySkhaIVTvqgNEQGPAQAABSNiARgz5LggAAAABJRU5ErkJggg==';
19955
 /**
19957
 /**
19956
  * Stats panel used for development purposes
19958
  * Stats panel used for development purposes
19957
  */
19959
  */
19975
     /**
19977
     /**
19976
      * A method to be called in the update loop
19978
      * A method to be called in the update loop
19977
      * @param time current time in ms
19979
      * @param time current time in ms
19978
-     * @param trackers the trackers attached to the session
19979
      * @param sources the sources of media linked to the session
19980
      * @param sources the sources of media linked to the session
19981
+     * @param trackers the trackers attached to the session
19982
+     * @param viewport the viewport
19980
      * @param gpu GPU cycles per second
19983
      * @param gpu GPU cycles per second
19981
      * @param fps frames per second
19984
      * @param fps frames per second
19982
      */
19985
      */
19983
-    update(time, trackers, sources, gpu, fps) {
19986
+    update(time, sources, trackers, viewport, gpu, fps) {
19984
         if (time >= this._lastUpdate + stats_panel_UPDATE_INTERVAL) {
19987
         if (time >= this._lastUpdate + stats_panel_UPDATE_INTERVAL) {
19985
             this._lastUpdate = time;
19988
             this._lastUpdate = time;
19986
-            this._update(trackers, sources, fps, gpu);
19989
+            this._update(sources, trackers, viewport, fps, gpu);
19987
         }
19990
         }
19988
     }
19991
     }
19989
     /**
19992
     /**
20000
     }
20003
     }
20001
     /**
20004
     /**
20002
      * Update the contents of the panel
20005
      * Update the contents of the panel
20003
-     * @param trackers the trackers attached to the session
20004
      * @param sources the sources of media linked to the session
20006
      * @param sources the sources of media linked to the session
20007
+     * @param trackers the trackers attached to the session
20008
+     * @param viewport the viewport
20005
      * @param fps frames per second
20009
      * @param fps frames per second
20006
      * @param gpu GPU cycles per second
20010
      * @param gpu GPU cycles per second
20007
      */
20011
      */
20008
-    _update(trackers, sources, fps, gpu) {
20012
+    _update(sources, trackers, viewport, fps, gpu) {
20009
         // all sanitized
20013
         // all sanitized
20010
         const lfps = this._label('_ar_fps');
20014
         const lfps = this._label('_ar_fps');
20011
         if (lfps !== null) {
20015
         if (lfps !== null) {
20030
             const trackerStats = trackers.map(tracker => tracker._stats).join(', ');
20034
             const trackerStats = trackers.map(tracker => tracker._stats).join(', ');
20031
             lout.innerText = trackerStats;
20035
             lout.innerText = trackerStats;
20032
         }
20036
         }
20037
+        const lview = this._label('_ar_view');
20038
+        if (lview !== null) {
20039
+            const size = viewport.virtualSize;
20040
+            lview.innerText = `${size.width}x${size.height} rendering`;
20041
+        }
20033
     }
20042
     }
20034
     /**
20043
     /**
20035
      * Get a label of the panel
20044
      * Get a label of the panel
20071
      */
20080
      */
20072
     _createTitle() {
20081
     _createTitle() {
20073
         const title = document.createElement('div');
20082
         const title = document.createElement('div');
20083
+        const button = document.createElement('button');
20084
+        title.style.display = 'flex';
20074
         title.style.backgroundColor = '#7e56c2';
20085
         title.style.backgroundColor = '#7e56c2';
20075
         title.style.color = 'white';
20086
         title.style.color = 'white';
20076
         title.style.fontFamily = 'monospace';
20087
         title.style.fontFamily = 'monospace';
20077
         title.style.fontSize = '14px';
20088
         title.style.fontSize = '14px';
20078
         title.style.fontWeight = 'bold';
20089
         title.style.fontWeight = 'bold';
20079
-        title.style.padding = '2px';
20090
+        title.style.paddingRight = '4px';
20080
         title.innerText = 'encantar.js ' + AR.version;
20091
         title.innerText = 'encantar.js ' + AR.version;
20092
+        button.style.width = '18px';
20093
+        button.style.height = '18px';
20094
+        button.style.marginRight = '4px';
20095
+        button.style.backgroundColor = '#7e56c2';
20096
+        button.style.backgroundImage = 'url(' + BUTTON_ICONS + ')';
20097
+        button.style.backgroundRepeat = 'no-repeat';
20098
+        button.style.backgroundPosition = '0 0';
20099
+        button.style.borderWidth = '2px';
20100
+        button.style.borderColor = '#b588fb #46346a #46346a #b588fb';
20101
+        title.insertBefore(button, title.firstChild);
20102
+        button.addEventListener('click', () => {
20103
+            const container = title.parentNode;
20104
+            const details = container && container.querySelector('._ar_details');
20105
+            if (!details)
20106
+                return;
20107
+            details.hidden = !details.hidden;
20108
+            button.style.backgroundPosition = details.hidden ? '0 0 ' : '-16px 0';
20109
+        });
20081
         return title;
20110
         return title;
20082
     }
20111
     }
20083
     /**
20112
     /**
20086
      */
20115
      */
20087
     _createContent() {
20116
     _createContent() {
20088
         const content = document.createElement('div');
20117
         const content = document.createElement('div');
20089
-        const print = (html) => content.insertAdjacentHTML('beforeend', html);
20118
+        const details = document.createElement('div');
20090
         content.style.backgroundColor = 'rgba(0,0,0,0.5)';
20119
         content.style.backgroundColor = 'rgba(0,0,0,0.5)';
20091
         content.style.color = 'white';
20120
         content.style.color = 'white';
20092
         content.style.fontFamily = 'monospace';
20121
         content.style.fontFamily = 'monospace';
20093
         content.style.fontSize = '14px';
20122
         content.style.fontSize = '14px';
20094
         content.style.padding = '2px';
20123
         content.style.padding = '2px';
20095
         content.style.whiteSpace = 'pre-line';
20124
         content.style.whiteSpace = 'pre-line';
20125
+        details.classList.add('_ar_details');
20126
+        details.hidden = true;
20096
         // all sanitized
20127
         // all sanitized
20097
-        print('FPS: <span class="_ar_fps"></span> | ');
20098
-        print('GPU: <span class="_ar_gpu"></span> ');
20099
-        print('<span class="_ar_power"></span>');
20100
-        print('<br>');
20101
-        print('IN: <span class="_ar_in"></span>');
20102
-        print('<br>');
20103
-        print('OUT: <span class="_ar_out"></span>');
20128
+        const append = (div, html) => div.insertAdjacentHTML('beforeend', html);
20129
+        append(content, 'FPS: <span class="_ar_fps"></span> | ');
20130
+        append(content, 'GPU: <span class="_ar_gpu"></span> ');
20131
+        append(content, '<span class="_ar_power"></span>');
20132
+        append(details, 'IN: <span class="_ar_in"></span><br>');
20133
+        append(details, 'OUT: <span class="_ar_out"></span><br>');
20134
+        append(details, 'VIEW: <span class="_ar_view"></span>');
20135
+        // done!
20136
+        content.appendChild(details);
20104
         return content;
20137
         return content;
20105
     }
20138
     }
20106
 }
20139
 }
20148
 /** When in the scanning state, we require the image to be matched during a few consecutive frames before accepting it */
20181
 /** When in the scanning state, we require the image to be matched during a few consecutive frames before accepting it */
20149
 const SCAN_CONSECUTIVE_FRAMES = 30; //15;//45;
20182
 const SCAN_CONSECUTIVE_FRAMES = 30; //15;//45;
20150
 /** Reprojection error, in NIS pixels, used when estimating a motion model (scanning state) */
20183
 /** Reprojection error, in NIS pixels, used when estimating a motion model (scanning state) */
20151
-const SCAN_RANSAC_REPROJECTIONERROR_NIS = (NIS_SIZE * 0.02) | 0;
20184
+const SCAN_RANSAC_REPROJECTIONERROR_NIS = (NIS_SIZE * 0.0125) | 0;
20152
 /** Reprojection error, in NDC, used when estimating a motion model (scanning state) */
20185
 /** Reprojection error, in NDC, used when estimating a motion model (scanning state) */
20153
 const SCAN_RANSAC_REPROJECTIONERROR_NDC = SCAN_RANSAC_REPROJECTIONERROR_NIS / (NIS_SIZE / 2);
20186
 const SCAN_RANSAC_REPROJECTIONERROR_NDC = SCAN_RANSAC_REPROJECTIONERROR_NIS / (NIS_SIZE / 2);
20154
 /** Number of tables used in the LSH-based keypoint matching */
20187
 /** Number of tables used in the LSH-based keypoint matching */
20177
 const SUBPIXEL_METHOD = 'bilinear-upsample'; // 'quadratic1d';
20210
 const SUBPIXEL_METHOD = 'bilinear-upsample'; // 'quadratic1d';
20178
 /** Minimum acceptable number of matched keypoints when in a pre-tracking state */
20211
 /** Minimum acceptable number of matched keypoints when in a pre-tracking state */
20179
 const PRE_TRACK_MIN_MATCHES = 4;
20212
 const PRE_TRACK_MIN_MATCHES = 4;
20213
+/** Maximum number of iterations in Pre-tracking B */
20214
+const PRE_TRACK_MAX_ITERATIONS = 3;
20215
+/** Reprojection error, in NIS pixels, used when pre-tracking */
20216
+const PRE_TRACK_RANSAC_REPROJECTIONERROR_NIS = (NIS_SIZE * 0.0125 * 0.5) | 0;
20217
+/** Reprojection error, in NDC, used when pre-tracking */
20218
+const PRE_TRACK_RANSAC_REPROJECTIONERROR_NDC = PRE_TRACK_RANSAC_REPROJECTIONERROR_NIS / (NIS_SIZE / 2);
20180
 /** Minimum acceptable number of matched keypoints when in the tracking state */
20219
 /** Minimum acceptable number of matched keypoints when in the tracking state */
20181
 const TRACK_MIN_MATCHES = 4; //10; //20;
20220
 const TRACK_MIN_MATCHES = 4; //10; //20;
20182
 /** Maximum number of keypoints to be analyzed in the tracking state */
20221
 /** Maximum number of keypoints to be analyzed in the tracking state */
21124
                     rafQueue[i][1].call(undefined, time, frame);
21163
                     rafQueue[i][1].call(undefined, time, frame);
21125
                 // update internals
21164
                 // update internals
21126
                 this._renderStats.update();
21165
                 this._renderStats.update();
21127
-                this._statsPanel.update(time, this._trackers, this._sources, this._updateStats.cyclesPerSecond, this._renderStats.cyclesPerSecond);
21166
+                this._statsPanel.update(time, this._sources, this._trackers, this._viewport, this._updateStats.cyclesPerSecond, this._renderStats.cyclesPerSecond);
21128
                 this._frameReady = false;
21167
                 this._frameReady = false;
21129
             }
21168
             }
21130
             else {
21169
             else {
22524
         return ImageTrackerUtils.findPerspectiveWarpNDC(points, {
22563
         return ImageTrackerUtils.findPerspectiveWarpNDC(points, {
22525
             method: 'pransac',
22564
             method: 'pransac',
22526
             reprojectionError: SCAN_RANSAC_REPROJECTIONERROR_NDC,
22565
             reprojectionError: SCAN_RANSAC_REPROJECTIONERROR_NDC,
22527
-            numberOfHypotheses: 512,
22566
+            numberOfHypotheses: 512 * 2,
22528
             bundleSize: 128,
22567
             bundleSize: 128,
22529
         });
22568
         });
22530
     }
22569
     }
22850
 
22889
 
22851
 
22890
 
22852
 
22891
 
22892
+/** Port of the source image multiplexer: get data from the portal */
22893
+const PORT_PORTAL = 0;
22894
+/** Port of the source image multiplexer: get data from the camera */
22895
+const pre_tracking_b_PORT_CAMERA = 1;
22853
 /**
22896
 /**
22854
  * In Pre-Tracking B, we refine the homography obtained at the scanning state.
22897
  * In Pre-Tracking B, we refine the homography obtained at the scanning state.
22855
  * We find a transformation that warps the snapshot obtained from the scanning
22898
  * We find a transformation that warps the snapshot obtained from the scanning
22866
         this._referenceImage = null;
22909
         this._referenceImage = null;
22867
         this._snapshot = null;
22910
         this._snapshot = null;
22868
         this._referenceKeypointPortalSink = null;
22911
         this._referenceKeypointPortalSink = null;
22912
+        this._iterations = 0;
22869
     }
22913
     }
22870
     /**
22914
     /**
22871
      * Called as soon as this becomes the active state, just before update() runs for the first time
22915
      * Called as soon as this becomes the active state, just before update() runs for the first time
22876
         const referenceImage = settings.referenceImage;
22920
         const referenceImage = settings.referenceImage;
22877
         const snapshot = settings.snapshot;
22921
         const snapshot = settings.snapshot;
22878
         const referenceKeypointPortalSink = settings.referenceKeypointPortalSink;
22922
         const referenceKeypointPortalSink = settings.referenceKeypointPortalSink;
22923
+        const sourceMux = this._pipeline.node('sourceMux');
22924
+        const sourceBuffer = this._pipeline.node('sourceBuffer');
22879
         // set attributes
22925
         // set attributes
22880
         this._homography = homography;
22926
         this._homography = homography;
22881
         this._referenceImage = referenceImage;
22927
         this._referenceImage = referenceImage;
22882
         this._snapshot = snapshot;
22928
         this._snapshot = snapshot;
22883
         this._referenceKeypointPortalSink = referenceKeypointPortalSink;
22929
         this._referenceKeypointPortalSink = referenceKeypointPortalSink;
22930
+        this._iterations = 0;
22931
+        // reset nodes
22932
+        sourceMux.port = PORT_PORTAL;
22933
+        sourceBuffer.frozen = false;
22884
     }
22934
     }
22885
     /**
22935
     /**
22886
      * Called just before the GPU processing
22936
      * Called just before the GPU processing
22922
         const keypoints = result.keypoints; // from Pre-Tracking B
22972
         const keypoints = result.keypoints; // from Pre-Tracking B
22923
         const image = result.image;
22973
         const image = result.image;
22924
         const keypointPortalSink = this._pipeline.node('keypointPortalSink');
22974
         const keypointPortalSink = this._pipeline.node('keypointPortalSink');
22975
+        const sourceMux = this._pipeline.node('sourceMux');
22976
+        const sourceBuffer = this._pipeline.node('sourceBuffer');
22925
         // tracker output
22977
         // tracker output
22926
         const trackerOutput = {
22978
         const trackerOutput = {
22927
             keypointsNIS: image !== undefined ? keypoints : undefined,
22979
             keypointsNIS: image !== undefined ? keypoints : undefined,
22936
                 throw new TrackingError('Not enough data points');
22988
                 throw new TrackingError('Not enough data points');
22937
             // find a warp
22989
             // find a warp
22938
             const points = ImageTrackerUtils.compilePairsOfKeypointsNDC(pairs);
22990
             const points = ImageTrackerUtils.compilePairsOfKeypointsNDC(pairs);
22939
-            return this._findAffineMotionNDC(points);
22991
+            return this._findMotionNDC(points);
22940
         })
22992
         })
22941
             .then(warp => {
22993
             .then(warp => {
22994
+            // get the camera image in the next iteration
22995
+            // the warped snapshot from the scanning state is occasionally very blurry
22996
+            sourceMux.port = pre_tracking_b_PORT_CAMERA;
22997
+            sourceBuffer.frozen = true;
22942
             // refine the homography
22998
             // refine the homography
22943
             return this._homography.setTo(warp.times(this._homography));
22999
             return this._homography.setTo(warp.times(this._homography));
22944
         })
23000
         })
22945
             .then(_ => ({
23001
             .then(_ => ({
22946
-            nextState: 'tracking',
22947
-            //nextState: 'pre-tracking-b',
23002
+            nextState: (++this._iterations < PRE_TRACK_MAX_ITERATIONS) ? 'pre-tracking-b' : 'tracking',
22948
             trackerOutput: trackerOutput,
23003
             trackerOutput: trackerOutput,
22949
             nextStateSettings: {
23004
             nextStateSettings: {
22950
                 // we export keypoints obtained in Pre-Tracking B, not in A.
23005
                 // we export keypoints obtained in Pre-Tracking B, not in A.
22951
-                // lighting conditions match, but what if the snapshot is too blurry?
22952
                 templateKeypoints: keypoints,
23006
                 templateKeypoints: keypoints,
22953
                 templateKeypointPortalSink: keypointPortalSink,
23007
                 templateKeypointPortalSink: keypointPortalSink,
22954
                 referenceImage: this._referenceImage,
23008
                 referenceImage: this._referenceImage,
22965
         });
23019
         });
22966
     }
23020
     }
22967
     /**
23021
     /**
22968
-     * Find an affine motion model in NDC between pairs of keypoints in NDC
23022
+     * Find a motion model in NDC between pairs of keypoints in NDC
22969
      * given as a 2 x 2n [ src | dest ] matrix
23023
      * given as a 2 x 2n [ src | dest ] matrix
22970
      * @param points compiled pairs of keypoints in NDC
23024
      * @param points compiled pairs of keypoints in NDC
22971
      * @returns a promise that resolves to a 3x3 warp in NDC that maps source to destination
23025
      * @returns a promise that resolves to a 3x3 warp in NDC that maps source to destination
22972
      */
23026
      */
22973
-    _findAffineMotionNDC(points) {
22974
-        return ImageTrackerUtils.findAffineWarpNDC(points, {
23027
+    _findMotionNDC(points) {
23028
+        //return ImageTrackerUtils.findAffineWarpNDC(points, {
23029
+        return ImageTrackerUtils.findPerspectiveWarpNDC(points, {
22975
             method: 'pransac',
23030
             method: 'pransac',
22976
-            reprojectionError: TRACK_RANSAC_REPROJECTIONERROR_NDC,
22977
-            numberOfHypotheses: 512 * 4,
23031
+            reprojectionError: PRE_TRACK_RANSAC_REPROJECTIONERROR_NDC,
23032
+            numberOfHypotheses: 512 * 8,
22978
             bundleSize: 128,
23033
             bundleSize: 128,
22979
             mask: undefined // score is not needed
23034
             mask: undefined // score is not needed
22980
         }).then(([warp, score]) => {
23035
         }).then(([warp, score]) => {
23023
         const pipeline = speedy_vision_default().Pipeline();
23078
         const pipeline = speedy_vision_default().Pipeline();
23024
         const source = speedy_vision_default().Image.Source('source');
23079
         const source = speedy_vision_default().Image.Source('source');
23025
         const imagePortalSource = speedy_vision_default().Image.Portal.Source('imagePortalSource');
23080
         const imagePortalSource = speedy_vision_default().Image.Portal.Source('imagePortalSource');
23081
+        const sourceMux = speedy_vision_default().Image.Multiplexer('sourceMux');
23082
+        const sourceBuffer = speedy_vision_default().Image.Buffer('sourceBuffer');
23026
         const referenceKeypointPortalSource = speedy_vision_default().Keypoint.Portal.Source('referenceKeypointPortalSource');
23083
         const referenceKeypointPortalSource = speedy_vision_default().Keypoint.Portal.Source('referenceKeypointPortalSource');
23027
         const screen = speedy_vision_default().Transform.Resize('screen');
23084
         const screen = speedy_vision_default().Transform.Resize('screen');
23028
         const greyscale = speedy_vision_default().Filter.Greyscale();
23085
         const greyscale = speedy_vision_default().Filter.Greyscale();
23044
         //const imageSink = Speedy.Image.Sink('image');
23101
         //const imageSink = Speedy.Image.Sink('image');
23045
         source.media = null;
23102
         source.media = null;
23046
         imagePortalSource.source = null;
23103
         imagePortalSource.source = null;
23104
+        sourceMux.port = PORT_PORTAL;
23105
+        sourceBuffer.frozen = false;
23047
         referenceKeypointPortalSource.source = null;
23106
         referenceKeypointPortalSource.source = null;
23048
         imageRectifier.transform = speedy_vision_default().Matrix.Eye(3);
23107
         imageRectifier.transform = speedy_vision_default().Matrix.Eye(3);
23049
         screen.size = speedy_vision_default().Size(0, 0);
23108
         screen.size = speedy_vision_default().Size(0, 0);
23066
         keypointScaler.transform = speedy_vision_default().Matrix.Eye(3);
23125
         keypointScaler.transform = speedy_vision_default().Matrix.Eye(3);
23067
         keypointSink.turbo = false;
23126
         keypointSink.turbo = false;
23068
         // prepare input
23127
         // prepare input
23069
-        //source.output(); // ignore, but keep it in the pipeline
23070
-        imagePortalSource.output().connectTo(screen.input());
23128
+        imagePortalSource.output().connectTo(sourceMux.input('in0'));
23129
+        source.output().connectTo(sourceBuffer.input());
23130
+        sourceBuffer.output().connectTo(sourceMux.input('in1'));
23131
+        sourceMux.output().connectTo(screen.input());
23071
         screen.output().connectTo(greyscale.input());
23132
         screen.output().connectTo(greyscale.input());
23072
         // preprocess images
23133
         // preprocess images
23073
         greyscale.output().connectTo(imageRectifier.input());
23134
         greyscale.output().connectTo(imageRectifier.input());
23097
         referenceKeypointPortalSource.output().connectTo(referenceKeypointSink.input());
23158
         referenceKeypointPortalSource.output().connectTo(referenceKeypointSink.input());
23098
         //imageRectifier.output().connectTo(imageSink.input());
23159
         //imageRectifier.output().connectTo(imageSink.input());
23099
         // done!
23160
         // done!
23100
-        pipeline.init(source, screen, imagePortalSource, referenceKeypointPortalSource, greyscale, imageRectifier, nightvision, nightvisionMux, detector, borderClipper, clipper, denoiser, subpixel, blur, descriptor, matcher, keypointScaler, keypointSink, keypointPortalSink, referenceKeypointSink);
23161
+        pipeline.init(source, imagePortalSource, sourceBuffer, sourceMux, screen, referenceKeypointPortalSource, greyscale, imageRectifier, nightvision, nightvisionMux, detector, borderClipper, clipper, denoiser, subpixel, blur, descriptor, matcher, keypointScaler, keypointSink, keypointPortalSink, referenceKeypointSink);
23101
         return pipeline;
23162
         return pipeline;
23102
     }
23163
     }
23103
 }
23164
 }
23599
         return new Vector3(x, y, z);
23660
         return new Vector3(x, y, z);
23600
     }
23661
     }
23601
     /**
23662
     /**
23663
+     * Compute a unit vector with the same direction as this
23664
+     * @returns a new unit vector with the same direction as this
23665
+     */
23666
+    normalized() {
23667
+        return this._clone()._normalize();
23668
+    }
23669
+    /**
23670
+     * Compute the sum between this vector and v
23671
+     * @param v a vector
23672
+     * @returns a new vector equal to the sum between this and v
23673
+     */
23674
+    plus(v) {
23675
+        return this._clone()._add(v);
23676
+    }
23677
+    /**
23678
+     * Compute the difference between this vector and v
23679
+     * @param v a vector
23680
+     * @returns a new vector equal to the difference this - v
23681
+     */
23682
+    minus(v) {
23683
+        return this._clone()._subtract(v);
23684
+    }
23685
+    /**
23686
+     * Compute the multiplication between this vector and a scale factor
23687
+     * @param scale scalar quantity
23688
+     * @returns a new vector equal to the multiplication between this and the scale factor
23689
+     */
23690
+    times(scale) {
23691
+        return this._clone()._scale(scale);
23692
+    }
23693
+    /**
23602
      * Check if this and v have the same coordinates
23694
      * Check if this and v have the same coordinates
23603
      * @param v a vector
23695
      * @param v a vector
23604
      * @returns true if this and v have the same coordinates
23696
      * @returns true if this and v have the same coordinates
25508
                only affect the rendering of virtual elements positioned at the
25600
                only affect the rendering of virtual elements positioned at the
25509
                local space linked to the target ("ar.root").
25601
                local space linked to the target ("ar.root").
25510
 
25602
 
25603
+               (that's right, and movements of the real camera in physical space
25604
+               shouldn't affect the world space either. Note: the real camera is
25605
+               expected to be shaky. Example: a user holding a mobile phone.)
25606
+
25511
             */
25607
             */
25512
             // the target moves and the camera stays fixed at the origin
25608
             // the target moves and the camera stays fixed at the origin
25513
             const modelMatrix = this._camera.computeViewMatrix(); // p_view = V M p_model
25609
             const modelMatrix = this._camera.computeViewMatrix(); // p_view = V M p_model
25595
         return ImageTrackerUtils.findAffineWarpNDC(points, {
25691
         return ImageTrackerUtils.findAffineWarpNDC(points, {
25596
             method: 'pransac',
25692
             method: 'pransac',
25597
             reprojectionError: TRACK_RANSAC_REPROJECTIONERROR_NDC,
25693
             reprojectionError: TRACK_RANSAC_REPROJECTIONERROR_NDC,
25598
-            numberOfHypotheses: 512 * 4,
25694
+            numberOfHypotheses: 512 * 2,
25599
             bundleSize: 128,
25695
             bundleSize: 128,
25600
             mask: undefined // score is not needed
25696
             mask: undefined // score is not needed
25601
         }).then(([warp, score]) => {
25697
         }).then(([warp, score]) => {
25812
 
25908
 
25813
 
25909
 
25814
 
25910
 
25815
-/** A helper */
25816
-const formatSize = (size) => `${size.width}x${size.height}`;
25817
 /** Default options for instantiating an ImageTracker */
25911
 /** Default options for instantiating an ImageTracker */
25818
 const image_tracker_DEFAULT_OPTIONS = {
25912
 const image_tracker_DEFAULT_OPTIONS = {
25819
     resolution: 'sm'
25913
     resolution: 'sm'
25867
         return this._database;
25961
         return this._database;
25868
     }
25962
     }
25869
     /**
25963
     /**
25870
-     * Resolution of the AR screen space
25964
+     * Resolution of the tracker
25871
      */
25965
      */
25872
     get resolution() {
25966
     get resolution() {
25873
         return this._resolution;
25967
         return this._resolution;
25874
     }
25968
     }
25875
     /**
25969
     /**
25876
-     * Resolution of the AR screen space
25970
+     * Resolution of the tracker
25971
+     * @readonly
25877
      */
25972
      */
25878
     set resolution(resolution) {
25973
     set resolution(resolution) {
25879
-        this._resolution = resolution;
25974
+        // this property is readonly, but this setter has been kept because
25975
+        // it wasn't readonly in previous versions of the engine. FIXME
25880
     }
25976
     }
25881
     /**
25977
     /**
25882
      * Size of the AR screen space, in pixels
25978
      * Size of the AR screen space, in pixels
25897
      * @internal
25993
      * @internal
25898
      */
25994
      */
25899
     get _stats() {
25995
     get _stats() {
25900
-        return `${formatSize(this.screenSize)} ${this.state}`;
25996
+        const screenSize = this.screenSize;
25997
+        return `${screenSize.width}x${screenSize.height} ${this.state}`;
25901
     }
25998
     }
25902
     /**
25999
     /**
25903
      * Initialize this tracker
26000
      * Initialize this tracker
26110
         return v._clone()._subtract(this)._normalize();
26207
         return v._clone()._subtract(this)._normalize();
26111
     }
26208
     }
26112
     /**
26209
     /**
26210
+     * Compute a unit vector with the same direction as this
26211
+     * @returns a new unit vector with the same direction as this
26212
+     */
26213
+    normalized() {
26214
+        return this._clone()._normalize();
26215
+    }
26216
+    /**
26217
+     * Compute the sum between this vector and v
26218
+     * @param v a vector
26219
+     * @returns a new vector equal to the sum between this and v
26220
+     */
26221
+    plus(v) {
26222
+        return this._clone()._add(v);
26223
+    }
26224
+    /**
26225
+     * Compute the difference between this vector and v
26226
+     * @param v a vector
26227
+     * @returns a new vector equal to the difference this - v
26228
+     */
26229
+    minus(v) {
26230
+        return this._clone()._subtract(v);
26231
+    }
26232
+    /**
26233
+     * Compute the multiplication between this vector and a scale factor
26234
+     * @param scale scalar quantity
26235
+     * @returns a new vector equal to the multiplication between this and the scale factor
26236
+     */
26237
+    times(scale) {
26238
+        return this._clone()._scale(scale);
26239
+    }
26240
+    /**
26113
      * Check if this and v have the same coordinates
26241
      * Check if this and v have the same coordinates
26114
      * @param v a vector
26242
      * @param v a vector
26115
      * @returns true if this and v have the same coordinates
26243
      * @returns true if this and v have the same coordinates
26240
     'pointerleave': 'ended',
26368
     'pointerleave': 'ended',
26241
     'pointerenter': 'began',
26369
     'pointerenter': 'began',
26242
 };
26370
 };
26371
+/** Default options for instantiating a PointerTracker */
26372
+const pointer_tracker_DEFAULT_OPTIONS = {
26373
+    space: 'normalized'
26374
+};
26243
 /**
26375
 /**
26244
  * A tracker of pointer-based input such as mouse, touch or pen
26376
  * A tracker of pointer-based input such as mouse, touch or pen
26245
  */
26377
  */
26246
 class PointerTracker {
26378
 class PointerTracker {
26247
     /**
26379
     /**
26248
      * Constructor
26380
      * Constructor
26381
+     * @param options
26249
      */
26382
      */
26250
-    constructor() {
26383
+    constructor(options) {
26384
+        const settings = this._buildSettings(options);
26251
         this._source = null;
26385
         this._source = null;
26252
         this._viewport = null;
26386
         this._viewport = null;
26387
+        this._space = settings.space;
26253
         this._activePointers = new Map();
26388
         this._activePointers = new Map();
26254
         this._newPointers = new Map();
26389
         this._newPointers = new Map();
26255
         this._idMap = new Map();
26390
         this._idMap = new Map();
26260
         this._resetInTheNextUpdate = this._resetInTheNextUpdate.bind(this);
26395
         this._resetInTheNextUpdate = this._resetInTheNextUpdate.bind(this);
26261
     }
26396
     }
26262
     /**
26397
     /**
26398
+     * Build a full and validated options object
26399
+     * @param options
26400
+     * @returns validated options with defaults
26401
+     */
26402
+    _buildSettings(options) {
26403
+        const settings = Object.assign({}, pointer_tracker_DEFAULT_OPTIONS, options);
26404
+        if (settings.space != 'normalized' && settings.space != 'adjusted')
26405
+            throw new IllegalArgumentError(`Invalid pointer space: "${settings.space}"`);
26406
+        return settings;
26407
+    }
26408
+    /**
26263
      * The type of the tracker
26409
      * The type of the tracker
26264
      */
26410
      */
26265
     get type() {
26411
     get type() {
26394
                     this._newPointers.clear();
26540
                     this._newPointers.clear();
26395
                     continue;
26541
                     continue;
26396
             }
26542
             }
26397
-            // determine the current position
26543
+            // determine the current position in normalized space
26398
             const absX = event.pageX - (rect.left + window.scrollX);
26544
             const absX = event.pageX - (rect.left + window.scrollX);
26399
             const absY = event.pageY - (rect.top + window.scrollY);
26545
             const absY = event.pageY - (rect.top + window.scrollY);
26400
             const relX = 2 * absX / rect.width - 1; // convert to [-1,1]
26546
             const relX = 2 * absX / rect.width - 1; // convert to [-1,1]
26401
             const relY = -(2 * absY / rect.height - 1); // flip Y axis
26547
             const relY = -(2 * absY / rect.height - 1); // flip Y axis
26402
             const position = new Vector2(relX, relY);
26548
             const position = new Vector2(relX, relY);
26549
+            // scale the normalized space so that it matches the aspect ratio of the viewport
26550
+            if (this._space == 'adjusted') {
26551
+                const a = this._viewport.aspectRatio;
26552
+                if (a >= 1) {
26553
+                    // landscape
26554
+                    position._set(relX, relY / a);
26555
+                }
26556
+                else {
26557
+                    // portrait
26558
+                    position._set(relX * a, relY);
26559
+                }
26560
+            }
26403
             // determine the position delta
26561
             // determine the position delta
26404
             const deltaPosition = !previous ? Vector2.ZERO :
26562
             const deltaPosition = !previous ? Vector2.ZERO :
26405
                 position._clone()._subtract(previous.position);
26563
                 position._clone()._subtract(previous.position);
26410
             const velocity = deltaPosition._clone()._scale(inverseDeltaTime);
26568
             const velocity = deltaPosition._clone()._scale(inverseDeltaTime);
26411
             // determine the elapsed time since the tracking began
26569
             // determine the elapsed time since the tracking began
26412
             const elapsedTime = previous ? previous.elapsedTime + deltaTime : 0;
26570
             const elapsedTime = previous ? previous.elapsedTime + deltaTime : 0;
26571
+            // determine how much this pointer has moved since its tracking began
26572
+            const totalDistance = previous ? previous.totalDistance + deltaPosition.length() : 0;
26413
             // determine whether or not this is the primary pointer for this type
26573
             // determine whether or not this is the primary pointer for this type
26414
             const isPrimary = event.isPrimary;
26574
             const isPrimary = event.isPrimary;
26415
             // determine the type of the originating device
26575
             // determine the type of the originating device
26416
             const kind = event.pointerType;
26576
             const kind = event.pointerType;
26417
             // we create new trackable instances on each frame;
26577
             // we create new trackable instances on each frame;
26418
             // these will be exported and consumed by the user
26578
             // these will be exported and consumed by the user
26419
-            this._newPointers.set(id, { id, phase, position, deltaPosition, initialPosition, velocity, elapsedTime, isPrimary, kind });
26579
+            this._newPointers.set(id, { id, phase, position, deltaPosition, initialPosition, velocity, elapsedTime, totalDistance, isPrimary, kind });
26420
         }
26580
         }
26421
         // update trackables
26581
         // update trackables
26422
         this._newPointers.forEach((trackable, id) => this._activePointers.set(id, trackable));
26582
         this._newPointers.forEach((trackable, id) => this._activePointers.set(id, trackable));
26449
         return n + ' pointer' + s;
26609
         return n + ' pointer' + s;
26450
     }
26610
     }
26451
     /**
26611
     /**
26612
+     * The space in which pointers are located.
26613
+     * You may set it when instantiating the tracker.
26614
+     */
26615
+    get space() {
26616
+        return this._space;
26617
+    }
26618
+    /**
26452
      * Generate tracker output
26619
      * Generate tracker output
26453
      * @returns a new PointerTrackerOutput object
26620
      * @returns a new PointerTrackerOutput object
26454
      */
26621
      */
26628
     }
26795
     }
26629
     /**
26796
     /**
26630
      * Create a Pointer Tracker
26797
      * Create a Pointer Tracker
26798
+     * @param options
26631
      */
26799
      */
26632
-    static Pointer() {
26633
-        return new PointerTracker();
26800
+    static Pointer(options = {}) {
26801
+        return new PointerTracker(options);
26634
     }
26802
     }
26635
 }
26803
 }
26636
 
26804
 
27984
     resize(viewport) {
28152
     resize(viewport) {
27985
         const subContainer = viewport._subContainer;
28153
         const subContainer = viewport._subContainer;
27986
         const windowAspectRatio = window.innerWidth / window.innerHeight;
28154
         const windowAspectRatio = window.innerWidth / window.innerHeight;
27987
-        const viewportAspectRatio = viewport._realSize.width / viewport._realSize.height;
28155
+        const viewportAspectRatio = viewport.aspectRatio;
27988
         let width = 1, height = 1, left = '0px', top = '0px';
28156
         let width = 1, height = 1, left = '0px', top = '0px';
27989
         if (viewportAspectRatio <= windowAspectRatio) {
28157
         if (viewportAspectRatio <= windowAspectRatio) {
27990
             height = window.innerHeight;
28158
             height = window.innerHeight;
28093
      * on which the virtual scene will be drawn
28261
      * on which the virtual scene will be drawn
28094
      */
28262
      */
28095
     get virtualSize() {
28263
     get virtualSize() {
28264
+        return Utils.resolution(this._resolution, this.aspectRatio);
28265
+    }
28266
+    /**
28267
+     * Aspect ratio of the viewport
28268
+     */
28269
+    get aspectRatio() {
28096
         const size = this._realSize;
28270
         const size = this._realSize;
28097
-        const aspectRatio = size.width / size.height;
28098
-        return Utils.resolution(this._resolution, aspectRatio);
28271
+        return size.width / size.height;
28099
     }
28272
     }
28100
     /**
28273
     /**
28101
      * Is the viewport currently being displayed in fullscreen mode?
28274
      * Is the viewport currently being displayed in fullscreen mode?
28151
         return this._fullscreen.exit();
28324
         return this._fullscreen.exit();
28152
     }
28325
     }
28153
     /**
28326
     /**
28154
-     * Convert a position given in normalized units to a corresponding pixel
28155
-     * position in canvas space. Normalized units range from -1 to +1. The
28156
-     * center of the canvas is at (0,0). The top right corner is at (1,1).
28327
+     * Convert a position given in space units to a corresponding pixel
28328
+     * position in canvas space. Units in normalized space range from -1 to +1.
28329
+     * The center of the canvas is at (0,0). The top right corner is at (1,1).
28157
      * The bottom left corner is at (-1,-1).
28330
      * The bottom left corner is at (-1,-1).
28158
-     * @param position in normalized units
28331
+     * @param position in space units
28332
+     * @param space either "normalized" (default) or "adjusted"; @see PointerSpace
28159
      * @returns an equivalent pixel position in canvas space
28333
      * @returns an equivalent pixel position in canvas space
28160
      */
28334
      */
28161
-    convertToPixels(position) {
28335
+    convertToPixels(position, space = 'normalized') {
28162
         const canvas = this.canvas;
28336
         const canvas = this.canvas;
28163
-        const x = 0.5 * (1 + position.x) * canvas.width;
28164
-        const y = 0.5 * (1 - position.y) * canvas.height;
28337
+        let px = position.x, py = position.y;
28338
+        if (space == 'adjusted') {
28339
+            // convert from adjusted to normalized space
28340
+            const a = canvas.width / canvas.height;
28341
+            if (a >= 1)
28342
+                py *= a;
28343
+            else
28344
+                px /= a;
28345
+        }
28346
+        else if (space != 'normalized')
28347
+            throw new IllegalArgumentError(`Invalid space: "${space}"`);
28348
+        // convert from normalized to canvas space
28349
+        const x = 0.5 * (1 + px) * canvas.width;
28350
+        const y = 0.5 * (1 - py) * canvas.height;
28351
+        // done!
28352
+        return new Vector2(x, y);
28353
+    }
28354
+    /**
28355
+     * Convert a pixel position given in canvas space to a corresponding
28356
+     * position in space units. This is the inverse of convertToPixels().
28357
+     * @param position in canvas space
28358
+     * @space either "normalized" (default) or "adjusted"; see @PointerSpace
28359
+     * @returns an equivalent position in space units
28360
+     */
28361
+    convertFromPixels(position, space = 'normalized') {
28362
+        const canvas = this.canvas;
28363
+        // convert from canvas to normalized space
28364
+        let x = 2 * position.x / canvas.width - 1;
28365
+        let y = -2 * position.y / canvas.height + 1;
28366
+        if (space == 'adjusted') {
28367
+            // convert from normalized to adjusted space
28368
+            const a = canvas.width / canvas.height;
28369
+            if (a >= 1)
28370
+                y /= a;
28371
+            else
28372
+                x *= a;
28373
+        }
28374
+        else if (space != 'normalized')
28375
+            throw new IllegalArgumentError(`Invalid space: "${space}"`);
28376
+        // done!
28165
         return new Vector2(x, y);
28377
         return new Vector2(x, y);
28166
     }
28378
     }
28167
     /**
28379
     /**

+ 2
- 2
dist/encantar.min.js
File diff suppressed because it is too large
View File


Loading…
Cancel
Save