From 9acc48f09600b80808b40ff106f4c181a20f3c15 Mon Sep 17 00:00:00 2001 From: John Lyon-Smith Date: Sat, 14 Apr 2018 04:53:37 -0700 Subject: [PATCH] Improve surface detection and position of item --- mobile/src/API.js | 4 +- mobile/src/ARViewer/ARViewer.js | 172 ++++++++++++++++++++++++-------- mobile/src/Auth/Login.js | 3 +- mobile/src/app.js | 55 +++++----- mobile/src/development.js | 2 + 5 files changed, 171 insertions(+), 65 deletions(-) create mode 100644 mobile/src/development.js diff --git a/mobile/src/API.js b/mobile/src/API.js index 34a32f7..666afc0 100644 --- a/mobile/src/API.js +++ b/mobile/src/API.js @@ -2,7 +2,7 @@ import EventEmitter from "eventemitter3" import io from "socket.io-client" import { AsyncStorage } from "react-native" import autobind from "autobind-decorator" -import { local } from "./local" +import { localIPAddr } from "./development" const authTokenKeyName = "AuthToken" const backendKeyName = "Backend" @@ -37,7 +37,7 @@ class API extends EventEmitter { static urls = { normal: "https://dar.kss.us.com/api", test: "https://dar-test.kss.us.com/api", - local: `http://${local.ipAddr}:3001`, + local: `http://${localIPAddr || "localhost"}:3001`, } constructor() { diff --git a/mobile/src/ARViewer/ARViewer.js b/mobile/src/ARViewer/ARViewer.js index 634b028..8429c89 100644 --- a/mobile/src/ARViewer/ARViewer.js +++ b/mobile/src/ARViewer/ARViewer.js @@ -4,11 +4,12 @@ import { ViroARSceneNavigator, ViroARScene, ViroARPlane, - ViroBox, - ViroNode, ViroAmbientLight, - ViroSpotLight, + ViroDirectionalLight, + ViroMaterials, Viro3DObject, + ViroSpotLight, + ViroNode, ViroSurface, } from "react-viro" import autobind from "autobind-decorator" @@ -35,53 +36,146 @@ const shapes = { materials: [require("./models/clipboard.mtl")], }, } +const distance = (vectorA, vectorB) => { + return Math.sqrt( + (vectorB[0] - vectorA[0]) * (vectorB[0] - vectorA[0]) + + (vectorB[1] - vectorA[1]) * (vectorB[1] - vectorA[1]) + + (vectorB[2] - vectorA[2]) * (vectorB[2] - vectorA[2]) + ) +} class WorkItemSceneAR extends React.Component { constructor(props) { super(props) + this.state = { - position: [0, 0.2, 0], - scale: [0.2, 0.2, 0.2], + position: [0, 0, 0], + rotation: [0, 0, 0], + scale: [0.15, 0.15, 0.15], + shouldBillboard: true, } } + @autobind + handleLoadEnd() { + this.arScene.getCameraOrientationAsync().then((orientation) => { + return this.arScene + .performARHitTestWithRay(orientation.forward) + .then((results) => { + // Default position is just 1.5 meters in front of the user. + const forward = orientation.forward + const defaultPosition = [ + forward[0] * 1.5, + forward[1] * 1.5, + forward[2] * 1.5, + ] + let hitResultPosition = null + + // Filter the hit test results based on the position. + if (results.length > 0) { + for (var i = 0; i < results.length; i++) { + let result = results[i] + + if (result.type == "ExistingPlaneUsingExtent") { + let distance = Math.sqrt( + (result.transform.position[0] - position[0]) * + (result.transform.position[0] - position[0]) + + (result.transform.position[1] - position[1]) * + (result.transform.position[1] - position[1]) + + (result.transform.position[2] - position[2]) * + (result.transform.position[2] - position[2]) + ) + if (distance > 0.2 && distance < 10) { + // If we found a plane greater than .2 and less than 10 meters away then choose it! + hitResultPosition = result.transform.position + break + } + } else if (result.type == "FeaturePoint" && !hitResultPosition) { + // If we haven't found a plane and this feature point is within range, + // then we'll use it as the initial display point + let distance = this._distance( + position, + result.transform.position + ) + + if (distance > 0.2 && distance < 10) { + hitResultPosition = result.transform.position + } + } + } + } + + this.setState({ + position: hitResultPosition || defaultPosition, + }) + + setTimeout(() => { + this.updateInitialRotation() + }, 200) + }) + }) + } + + @autobind + updateInitialRotation() { + this.arNode.getTransformAsync().then((retDict) => { + let rotation = retDict.rotation + let absX = Math.abs(rotation[0]) + let absZ = Math.abs(rotation[2]) + + let yRotation = rotation[1] + + // If the X and Z aren't 0, then adjust the y rotation. + if (absX > 1 && absZ > 1) { + yRotation = 180 - yRotation + } + + this.setState({ + rotation: [0, yRotation, 0], + shouldBillboard: false, + }) + }) + } + render() { + const { position, scale, rotation, shouldBillboard } = this.state + return ( - + (this.arScene = ref)}> - - - - - - - + (this.arNode = ref)} + transformBehaviors={shouldBillboard ? "billboardY" : []} + position={position} + scale={scale} + rotation={rotation}> + + + + ) } diff --git a/mobile/src/Auth/Login.js b/mobile/src/Auth/Login.js index f05f89e..a4388ee 100644 --- a/mobile/src/Auth/Login.js +++ b/mobile/src/Auth/Login.js @@ -19,6 +19,7 @@ import KeyboardSpacer from "react-native-keyboard-spacer" import { versionInfo } from "../version" import autobind from "autobind-decorator" import { isIphoneX } from "react-native-iphone-x-helper" +import { defaultUser } from "../development" export class Login extends React.Component { static bindings = { @@ -75,7 +76,7 @@ export class Login extends React.Component { constructor(props) { super(props) this.state = { - binder: new FormBinder({ email: "john@lyon-smith.org" }, Login.bindings), + binder: new FormBinder({ email: defaultUser }, Login.bindings), messageModal: null, apiModal: null, } diff --git a/mobile/src/app.js b/mobile/src/app.js index 3e658d1..9edfa83 100644 --- a/mobile/src/app.js +++ b/mobile/src/app.js @@ -1,34 +1,43 @@ -import React from 'react' -import { View, StyleSheet } from 'react-native' +import React from "react" +import { View, StyleSheet } from "react-native" import { - ViroARSceneNavigator, ViroARScene, ViroARPlane, ViroBox -} from 'react-viro' -import { NativeRouter, Route, Link, Switch } from 'react-router-native' -import MapView from 'react-native-maps' -import { WorkItem, WorkItemList } from './WorkItem' -import { Activity } from './Activity' -import { Home } from './Home' -import { ARViewer } from './ARViewer' -import { Login, Logout, ProtectedRoute, DefaultRoute } from './Auth' + ViroARSceneNavigator, + ViroARScene, + ViroARPlane, + ViroBox, +} from "react-viro" +import { NativeRouter, Route, Link, Switch } from "react-router-native" +import MapView from "react-native-maps" +import { WorkItem, WorkItemList } from "./WorkItem" +import { Activity } from "./Activity" +import { Home } from "./Home" +import { ARViewer } from "./ARViewer" +import { Login, Logout, ProtectedRoute, DefaultRoute } from "./Auth" -// See https://github.com/facebook/react-native/issues/12981 console.ignoredYellowBox = [ - 'Setting a timer' + // See https://github.com/facebook/react-native/issues/12981 + "Setting a timer", + "", ] export default class App extends React.Component { render() { return ( - + - - - - - - - + + + + + + + @@ -39,7 +48,7 @@ export default class App extends React.Component { const styles = StyleSheet.create({ container: { - width: '100%', - height: '100%', + width: "100%", + height: "100%", }, }) diff --git a/mobile/src/development.js b/mobile/src/development.js new file mode 100644 index 0000000..5dd7622 --- /dev/null +++ b/mobile/src/development.js @@ -0,0 +1,2 @@ +export const localIPAddr = "192.168.1.175" +export const defaultUser = "john@lyon-smith.org"