UNPKG

nativescript-ar

Version:

NativeScript Augmented Reality plugin. ARKit on iOS and (with the help of Sceneform) ARCore on Android.

572 lines (571 loc) 25.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var application = require("tns-core-modules/application"); var utils = require("tns-core-modules/utils/utils"); var ar_common_1 = require("./ar-common"); var imagefragment_android_1 = require("./imagefragment.android"); var arbox_1 = require("./nodes/android/arbox"); var argroup_1 = require("./nodes/android/argroup"); var arimage_1 = require("./nodes/android/arimage"); var armodel_1 = require("./nodes/android/armodel"); var arplane_1 = require("./nodes/android/arplane"); var arsphere_1 = require("./nodes/android/arsphere"); var artube_1 = require("./nodes/android/artube"); var aruiview_1 = require("./nodes/android/aruiview"); var arvideo_1 = require("./nodes/android/arvideo"); var screengrab_android_1 = require("./screengrab-android"); var videorecorder_android_1 = require("./videorecorder.android"); var _fragment, _origin, _videoRecorder; var AppPackageName = useAndroidX() ? global.androidx.core.app : android.support.v4.app; var ContentPackageName = useAndroidX() ? global.androidx.core.content : android.support.v4.content; function useAndroidX() { return global.androidx && global.androidx.appcompat; } var addNode = function (options, parentNode) { return new Promise(function (resolve, reject) { argroup_1.ARGroup.create(options, _fragment) .then(function (group) { group.android.setParent(parentNode); resolve(group); }).catch(reject); }); }; var addVideo = function (options, parentNode) { return new Promise(function (resolve, reject) { arvideo_1.ARVideo.create(options, _fragment) .then(function (video) { video.android.setParent(parentNode); resolve(video); }).catch(reject); }); }; var addImage = function (options, parentNode) { return new Promise(function (resolve, reject) { arimage_1.ARImage.create(options, _fragment) .then(function (image) { image.android.setParent(parentNode); resolve(image); }).catch(reject); }); }; var addPlane = function (options, parentNode) { return new Promise(function (resolve, reject) { arplane_1.ARPlane.create(options, _fragment) .then(function (plane) { plane.android.setParent(parentNode); resolve(plane); }).catch(reject); }); }; var addModel = function (options, parentNode) { return new Promise(function (resolve, reject) { armodel_1.ARModel.create(options, _fragment) .then(function (model) { if (parentNode) { model.android.setParent(parentNode); } resolve(model); }).catch(reject); }); }; var addBox = function (options, parentNode) { return new Promise(function (resolve, reject) { arbox_1.ARBox.create(options, _fragment) .then(function (box) { box.android.setParent(parentNode); if (parentNode && parentNode.getRenderable()) { parentNode.getRenderable().setRenderPriority(Math.max(0, box.android.getRenderable().getRenderPriority() - 1)); } resolve(box); }).catch(reject); }); }; var addSphere = function (options, parentNode) { return new Promise(function (resolve, reject) { arsphere_1.ARSphere.create(options, _fragment) .then(function (sphere) { sphere.android.setParent(parentNode); if (parentNode && parentNode.getRenderable()) { parentNode.getRenderable().setRenderPriority(Math.max(0, sphere.android.getRenderable().getRenderPriority() - 1)); } resolve(sphere); }).catch(reject); }); }; var addUIView = function (options, parentNode) { return new Promise(function (resolve, reject) { aruiview_1.ARUIView.create(options, _fragment) .then(function (view) { view.android.setParent(parentNode); resolve(view); }).catch(reject); }); }; var addTube = function (options, parentNode) { return new Promise(function (resolve, reject) { artube_1.ARTube.create(options, _fragment) .then(function (tube) { tube.android.setParent(parentNode); resolve(tube); }).catch(reject); }); }; var resolveParentNode = function (options) { if (options.parentNode && options.parentNode.android) { return options.parentNode.android; } return getOriginAnchor(); }; var getOriginAnchor = function () { if (!_origin) { var session = _fragment.getArSceneView().getSession(); var pose = com.google.ar.core.Pose.IDENTITY; var anchor = session.createAnchor(pose); var anchorNode = new com.google.ar.sceneform.AnchorNode(anchor); anchorNode.setParent(_fragment.getArSceneView().getScene()); _origin = anchorNode; } return _origin; }; var TNSArFragmentForFaceDetection = (function (_super) { __extends(TNSArFragmentForFaceDetection, _super); function TNSArFragmentForFaceDetection() { var _this = _super.call(this) || this; return global.__native(_this); } TNSArFragmentForFaceDetection.prototype.getSessionConfiguration = function (session) { var config = new com.google.ar.core.Config(session); config.setAugmentedFaceMode(com.google.ar.core.Config.AugmentedFaceMode.MESH3D); return config; }; TNSArFragmentForFaceDetection.prototype.getSessionFeatures = function () { return java.util.EnumSet.of(com.google.ar.core.Session.Feature.FRONT_CAMERA); }; TNSArFragmentForFaceDetection.prototype.onCreateView = function (inflater, container, savedInstanceState) { var frameLayout = _super.prototype.onCreateView.call(this, inflater, container, savedInstanceState); _super.prototype.getPlaneDiscoveryController.call(this).hide(); _super.prototype.getPlaneDiscoveryController.call(this).setInstructionView(null); return frameLayout; }; return TNSArFragmentForFaceDetection; }(com.google.ar.sceneform.ux.ArFragment)); var ARImageTrackingActionsImpl = (function () { function ARImageTrackingActionsImpl(anchor, planeNode) { this.anchor = anchor; this.planeNode = planeNode; this.video; } ARImageTrackingActionsImpl.prototype.playVideo = function (url, loop) { var _this = this; addVideo({ dimensions: { x: this.anchor.getExtentX(), y: this.anchor.getExtentZ() }, position: { x: 0, y: 0, z: 0 }, scale: 1 / this.planeNode.getLocalScale().x, video: url, loop: loop }, this.planeNode).then(function (video) { return _this.video = video; }).catch(console.error); }; ARImageTrackingActionsImpl.prototype.stopVideoLoop = function () { if (this.video) { this.video.pause(); } }; ARImageTrackingActionsImpl.prototype.addBox = function (options) { return addBox(options, this.planeNode); }; ARImageTrackingActionsImpl.prototype.addModel = function (options) { return addModel(options, this.planeNode); }; ARImageTrackingActionsImpl.prototype.addImage = function (options) { return addImage(options, this.planeNode); }; ARImageTrackingActionsImpl.prototype.addUIView = function (options) { return addUIView(options, this.planeNode); }; ARImageTrackingActionsImpl.prototype.addNode = function (options) { return addNode(options, this.planeNode); }; return ARImageTrackingActionsImpl; }()); var ARFaceTrackingActionsImpl = (function () { function ARFaceTrackingActionsImpl(faceNode) { this.faceNode = faceNode; } ARFaceTrackingActionsImpl.prototype.addModel = function (options) { var _this = this; return new Promise(function (resolve, reject) { addModel(options) .then(function (model) { _this.faceNode.setParent(_fragment.getArSceneView().getScene()); _this.faceNode.setFaceRegionsRenderable(model.android.getRenderable()); resolve(model); }) .catch(function (err) { return reject; }); }); }; ARFaceTrackingActionsImpl.prototype.addText = function (options) { return Promise.reject("addText not implemented for ARFaceTrackingActions"); }; ARFaceTrackingActionsImpl.prototype.addUIView = function (options) { return Promise.reject("addUIView not implemented for ARFaceTrackingActions"); }; return ARFaceTrackingActionsImpl; }()); var AR = (function (_super) { __extends(AR, _super); function AR() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.faceNodeMap = new Map(); return _this; } AR.prototype.initNativeView = function () { _super.prototype.initNativeView.call(this); this.initAR(); }; AR.prototype.disposeNativeView = function () { _super.prototype.disposeNativeView.call(this); if (_origin) { _origin.setParent(null); _origin = null; } var supportFragmentManager = (application.android.foregroundActivity || application.android.startActivity).getSupportFragmentManager(); supportFragmentManager.beginTransaction().remove(_fragment).commit(); }; AR.prototype.getCameraPosition = function () { var p = Array.create("float", 3); _fragment.getArSceneView().getArFrame().getCamera().getPose().getTranslation(p, 0); return { x: p[0], y: p[1], z: p[2] }; }; AR.prototype.getCameraRotation = function () { var q1 = Array.create("float", 4); _fragment.getArSceneView().getArFrame().getCamera().getPose().getRotationQuaternion(q1, 0); var q = { x: q1[2], y: q1[0], z: q1[1], w: q1[3] }; var rot = { z: 0, x: 0, y: 0 }; var sinr_cosp = +2.0 * (q.w * q.x + q.y * q.z); var cosr_cosp = +1.0 - 2.0 * (q.x * q.x + q.y * q.y); rot.z = -(Math.atan2(sinr_cosp, cosr_cosp) + Math.PI / 2); var sinp = +2.0 * (q.w * q.y - q.z * q.x); if (Math.abs(sinp) >= 1) { rot.x = -(sinp / Math.abs(sinp)) * (Math.PI / 2); } else { rot.x = -Math.asin(sinp); } var siny_cosp = +2.0 * (q.w * q.z + q.x * q.y); var cosy_cosp = +1.0 - 2.0 * (q.y * q.y + q.z * q.z); rot.y = Math.atan2(siny_cosp, cosy_cosp) + Math.PI; var toDeg = function (rad) { return ((rad * (180.0 / Math.PI)) + 360) % 360; }; return { x: toDeg(rot.x), y: toDeg(rot.y), z: toDeg(rot.z) }; }; AR.prototype.initAR = function () { var _this = this; this.nativeView.setId(android.view.View.generateViewId()); if (this.trackingMode === "FACE") { _fragment = new TNSArFragmentForFaceDetection(); } else { if (this.trackingMode === "IMAGE") { _fragment = new imagefragment_android_1.TNSArFragmentForImageDetection(); _fragment.getImageDetectionSceneView().then(function (sceneView) { if (_this.trackingImagesBundle) { _fragment.addImagesInFolder(_this.trackingImagesBundle); } var scene = sceneView.getScene(); var augmentedImages = []; scene.addOnUpdateListener(new com.google.ar.sceneform.Scene.OnUpdateListener({ onUpdate: function (frameTime) { var frame = sceneView.getArFrame(); if (frame == null) { return; } var updatedAugmentedImages = frame.getUpdatedTrackables(com.google.ar.core.AugmentedImage.class).toArray(); for (var i = 0; i < updatedAugmentedImages.length; i++) { var augmentedImage = updatedAugmentedImages[i]; var state = augmentedImage.getTrackingState(); if (state === com.google.ar.core.TrackingState.PAUSED) { } else if (state === com.google.ar.core.TrackingState.TRACKING) { if (augmentedImages.indexOf(augmentedImage.getName()) === -1) { var anchor = new com.google.ar.sceneform.AnchorNode(augmentedImage.createAnchor(augmentedImage.getCenterPose())); augmentedImages.push(augmentedImage.getName()); scene.addChild(anchor); var planeNode = new com.google.ar.sceneform.Node(); anchor.addChild(planeNode); planeNode.setLocalRotation(new com.google.ar.sceneform.math.Quaternion(new com.google.ar.sceneform.math.Vector3(-90, 0, 0))); var eventData = { eventName: ar_common_1.AR.trackingImageDetectedEvent, object: _this, size: { width: augmentedImage.getExtentX(), height: augmentedImage.getExtentZ() }, position: { x: augmentedImage.getCenterPose().tx(), y: augmentedImage.getCenterPose().ty(), z: augmentedImage.getCenterPose().tz() }, imageName: augmentedImage.getName(), imageTrackingActions: new ARImageTrackingActionsImpl(augmentedImage, planeNode) }; _this.notify(eventData); } } else if (state === com.google.ar.core.TrackingState.STOPPED) { var i_1 = augmentedImages.indexOf(augmentedImage.getName()); augmentedImages.splice(i_1, 1); } } } })); }).catch(console.log); } else { _fragment = new com.google.ar.sceneform.ux.ArFragment(); } } var onCamPermissionGranted = function () { if (_this.trackingMode === "FACE") { setTimeout(function () { var sceneView = _fragment.getArSceneView(); if (!sceneView) { return; } sceneView.setCameraStreamRenderPriority(com.google.ar.sceneform.rendering.Renderable.RENDER_PRIORITY_FIRST); var scene = sceneView.getScene(); scene.addOnUpdateListener(new com.google.ar.sceneform.Scene.OnUpdateListener({ onUpdate: function (frameTime) { var faceList = sceneView.getSession().getAllTrackables(com.google.ar.core.AugmentedFace.class); for (var i = 0; i < faceList.size(); i++) { var face = faceList.get(i); if (!_this.faceNodeMap.has(face)) { var faceNode = new com.google.ar.sceneform.ux.AugmentedFaceNode(face); _this.faceNodeMap.set(face, faceNode); var eventData = { eventType: "FOUND", eventName: ar_common_1.AR.trackingFaceDetectedEvent, object: _this, faceTrackingActions: new ARFaceTrackingActionsImpl(faceNode) }; _this.notify(eventData); } else { } } _this.faceNodeMap.forEach(function (node, face) { if (face.getTrackingState() === com.google.ar.core.TrackingState.STOPPED) { node.setParent(null); _this.faceNodeMap.delete(node); var eventData = { eventType: "LOST", eventName: ar_common_1.AR.trackingFaceDetectedEvent, object: _this }; _this.notify(eventData); } }); } })); }, 1000); } var supportFragmentManager = (application.android.foregroundActivity || application.android.startActivity).getSupportFragmentManager(); supportFragmentManager.beginTransaction().add(_this.nativeView.getId(), _fragment).commit(); _fragment.setOnTapArPlaneListener(new com.google.ar.sceneform.ux.BaseArFragment.OnTapArPlaneListener({ onTapPlane: function (hitResult, plane, motionEvent) { var eventData = { eventName: ar_common_1.AR.planeTappedEvent, object: _this, position: { x: hitResult.getHitPose().tx(), y: hitResult.getHitPose().ty(), z: hitResult.getHitPose().tz() } }; _this.notify(eventData); } })); _this.fireArLoadedEvent(1000); }; var cameraPermission = android.Manifest.permission.CAMERA; if (this.wasPermissionGranted(cameraPermission)) { setTimeout(function () { return onCamPermissionGranted(); }, 0); } else { this._requestPermission(cameraPermission, function () { return onCamPermissionGranted(); }); } }; AR.prototype.fireArLoadedEvent = function (attemptsLeft) { var _this = this; if (attemptsLeft-- <= 0) { return; } setTimeout(function () { if (_fragment.getArSceneView() && _fragment.getArSceneView().getSession() && _fragment.getArSceneView().getArFrame() && _fragment.getArSceneView().getArFrame().getCamera() && _fragment.getArSceneView().getArFrame().getCamera().getTrackingState() === com.google.ar.core.TrackingState.TRACKING) { var eventData = { eventName: ar_common_1.AR.arLoadedEvent, object: _this, android: _fragment }; _this.notify(eventData); } else { _this.fireArLoadedEvent(attemptsLeft); } }, 300); }; AR.isSupported = function () { return true; }; AR.prototype.getFragment = function () { return _fragment; }; Object.defineProperty(AR.prototype, "android", { get: function () { return this.nativeView; }, enumerable: true, configurable: true }); AR.prototype.togglePlaneVisibility = function (to) { _fragment.getArSceneView().getPlaneRenderer().setVisible(to); }; AR.prototype.setPlaneDetection = function (to) { }; AR.prototype.toggleStatistics = function (on) { console.log("Method not implemented: toggleStatistics"); }; AR.prototype.setDebugLevel = function (to) { console.log("Method not implemented: setDebugLevel"); }; AR.prototype.grabScreenshot = function () { return (new screengrab_android_1.FragmentScreenGrab()).grabScreenshot(_fragment); }; AR.prototype.startRecordingVideo = function () { var _this = this; return new Promise(function (resolve, reject) { if (!_videoRecorder) { _videoRecorder = videorecorder_android_1.VideoRecorder.fromFragment(_fragment); } else if (_videoRecorder.isRecording()) { reject("already recording"); return; } var record = function () { _videoRecorder.setVideoQualityAuto(); _videoRecorder.startRecordingVideo(); }; var permission = android.Manifest.permission.WRITE_EXTERNAL_STORAGE; if (!_this.wasPermissionGranted(permission)) { _this._requestPermission(permission, record, reject); return; } record(); resolve(true); }); }; AR.prototype.stopRecordingVideo = function () { return new Promise(function (resolve, reject) { if (!(_videoRecorder && _videoRecorder.isRecording())) { reject("not recording"); } _videoRecorder.stopRecordingVideo(); resolve(_videoRecorder.getVideoPath()); }); }; AR.prototype.reset = function () { console.log("Method not implemented: reset"); return null; }; AR.prototype.addNode = function (options) { return addNode(options, resolveParentNode(options)); }; AR.prototype.addVideo = function (options) { return addVideo(options, resolveParentNode(options)); }; AR.prototype.addImage = function (options) { return addImage(options, resolveParentNode(options)); }; AR.prototype.addModel = function (options) { return addModel(options, resolveParentNode(options)); }; AR.prototype.addPlane = function (options) { return addPlane(options, resolveParentNode(options)); }; AR.prototype.addBox = function (options) { return addBox(options, resolveParentNode(options)); }; AR.prototype.addSphere = function (options) { return addSphere(options, resolveParentNode(options)); }; AR.prototype.addText = function (options) { return new Promise(function (resolve, reject) { reject("Method not implemented: addText"); }); }; AR.prototype.addTube = function (options) { return addTube(options, resolveParentNode(options)); }; AR.prototype.addUIView = function (options) { return addUIView(options, resolveParentNode(options)); }; AR.prototype.trackImage = function (options) { if (!(_fragment instanceof imagefragment_android_1.TNSArFragmentForImageDetection)) { throw "On Android, this is only supported in trackingMode: IMAGE"; } var name = options.name || options.image.split('/').pop().split('.').slice(0, -1).join('.'); _fragment.addImage(options.image, name, options.width || -1); if (!options.onDetectedImage) { return; } this.on(ar_common_1.AR.trackingImageDetectedEvent, function (args) { if (args.imageName === options.image.split('/').pop().split('.').slice(0, -1).join('.')) { options.onDetectedImage(args); } }); }; AR.prototype.wasPermissionGranted = function (permission) { var hasPermission = android.os.Build.VERSION.SDK_INT < 23; if (!hasPermission) { hasPermission = android.content.pm.PackageManager.PERMISSION_GRANTED === ContentPackageName.ContextCompat.checkSelfPermission(utils.ad.getApplicationContext(), permission); } return hasPermission; }; AR.prototype._requestPermission = function (permission, onPermissionGranted, reject) { var permissionRequestCode = 678; var onPermissionEvent = function (args) { if (args.requestCode === permissionRequestCode) { for (var i = 0; i < args.permissions.length; i++) { if (args.grantResults[i] === android.content.pm.PackageManager.PERMISSION_DENIED) { application.off(application.AndroidApplication.activityRequestPermissionsEvent, onPermissionEvent); reject && reject("Please allow access to external storage and try again."); return; } } application.off(application.AndroidApplication.activityRequestPermissionsEvent, onPermissionEvent); onPermissionGranted(); } }; application.android.on(application.AndroidApplication.activityRequestPermissionsEvent, onPermissionEvent); AppPackageName.ActivityCompat.requestPermissions(application.android.foregroundActivity || application.android.startActivity, [permission], permissionRequestCode); }; return AR; }(ar_common_1.AR)); exports.AR = AR;