Improve surface detection and position of item

This commit is contained in:
John Lyon-Smith
2018-04-14 04:53:37 -07:00
parent 43d86d9f61
commit 9acc48f096
5 changed files with 171 additions and 65 deletions

View File

@@ -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() {

View File

@@ -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 (
<ViroARScene>
<ViroARScene ref={(ref) => (this.arScene = ref)}>
<ViroAmbientLight color="#ffffff" intensity={200} />
<ViroARPlane>
<ViroNode
visible={true}
position={this.state.position}
scale={this.state.scale}
key="hardhat">
<ViroSpotLight
innerAngle={5}
outerAngle={20}
direction={[0, -1, 0]}
position={[0, 4, 0]}
color="#ffffff"
castsShadow={true}
shadowNearZ={0.1}
shadowFarZ={6}
shadowOpacity={0.9}
/>
<Viro3DObject
position={[0, 0, 0]}
source={shapes["hardhat"].shape}
resources={shapes["hardhat"].materials}
type="OBJ"
/>
<ViroSurface
rotation={[-90, 0, 0]}
position={[0, -0.001, 0]}
width={2.5}
height={2.5}
arShadowReceiver={true}
ignoreEventHandling={true}
/>
</ViroNode>
</ViroARPlane>
<ViroNode
ref={(ref) => (this.arNode = ref)}
transformBehaviors={shouldBillboard ? "billboardY" : []}
position={position}
scale={scale}
rotation={rotation}>
<ViroSpotLight
innerAngle={5}
outerAngle={20}
direction={[0, -1, 0]}
position={[0, 15, 0]}
color="#ffffff"
castsShadow={true}
shadowNearZ={0.1}
shadowFarZ={6}
shadowOpacity={0.9}
/>
<Viro3DObject
position={[0, 0, -1]}
source={shapes["hardhat"].shape}
resources={shapes["hardhat"].materials}
type="OBJ"
onLoadEnd={this.handleLoadEnd}
/>
<ViroSurface
rotation={[-90, 0, 0]}
position={[0, -0.001, 0]}
width={2.5}
height={2.5}
arShadowReceiver={true}
ignoreEventHandling={true}
/>
</ViroNode>
</ViroARScene>
)
}

View File

@@ -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,
}

View File

@@ -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",
"<ViroSurface>",
]
export default class App extends React.Component {
render() {
return (
<NativeRouter>
<View style={{ width: '100%', height: '100%' }}>
<View style={{ width: "100%", height: "100%" }}>
<Switch>
<Route exact path='/login' component={Login}/>
<Route exact path='/logout' component={Logout}/>
<ProtectedRoute exact path='/home' component={Home}/>
<ProtectedRoute exact path='/arviewer' component={ARViewer}/>
<ProtectedRoute exact path='/activity' component={Activity}/>
<ProtectedRoute exact admin path='/workitem' component={WorkItem}/>
<ProtectedRoute exact admin path='/workitemlist' component={WorkItemList}/>
<Route exact path="/login" component={Login} />
<Route exact path="/logout" component={Logout} />
<ProtectedRoute exact path="/home" component={Home} />
<ProtectedRoute exact path="/arviewer" component={ARViewer} />
<ProtectedRoute exact path="/activity" component={Activity} />
<ProtectedRoute exact admin path="/workitem" component={WorkItem} />
<ProtectedRoute
exact
admin
path="/workitemlist"
component={WorkItemList}
/>
<DefaultRoute />
</Switch>
</View>
@@ -39,7 +48,7 @@ export default class App extends React.Component {
const styles = StyleSheet.create({
container: {
width: '100%',
height: '100%',
width: "100%",
height: "100%",
},
})

View File

@@ -0,0 +1,2 @@
export const localIPAddr = "192.168.1.175"
export const defaultUser = "john@lyon-smith.org"