Improve surface detection and position of item
This commit is contained in:
@@ -2,7 +2,7 @@ import EventEmitter from "eventemitter3"
|
|||||||
import io from "socket.io-client"
|
import io from "socket.io-client"
|
||||||
import { AsyncStorage } from "react-native"
|
import { AsyncStorage } from "react-native"
|
||||||
import autobind from "autobind-decorator"
|
import autobind from "autobind-decorator"
|
||||||
import { local } from "./local"
|
import { localIPAddr } from "./development"
|
||||||
|
|
||||||
const authTokenKeyName = "AuthToken"
|
const authTokenKeyName = "AuthToken"
|
||||||
const backendKeyName = "Backend"
|
const backendKeyName = "Backend"
|
||||||
@@ -37,7 +37,7 @@ class API extends EventEmitter {
|
|||||||
static urls = {
|
static urls = {
|
||||||
normal: "https://dar.kss.us.com/api",
|
normal: "https://dar.kss.us.com/api",
|
||||||
test: "https://dar-test.kss.us.com/api",
|
test: "https://dar-test.kss.us.com/api",
|
||||||
local: `http://${local.ipAddr}:3001`,
|
local: `http://${localIPAddr || "localhost"}:3001`,
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import {
|
|||||||
ViroARSceneNavigator,
|
ViroARSceneNavigator,
|
||||||
ViroARScene,
|
ViroARScene,
|
||||||
ViroARPlane,
|
ViroARPlane,
|
||||||
ViroBox,
|
|
||||||
ViroNode,
|
|
||||||
ViroAmbientLight,
|
ViroAmbientLight,
|
||||||
ViroSpotLight,
|
ViroDirectionalLight,
|
||||||
|
ViroMaterials,
|
||||||
Viro3DObject,
|
Viro3DObject,
|
||||||
|
ViroSpotLight,
|
||||||
|
ViroNode,
|
||||||
ViroSurface,
|
ViroSurface,
|
||||||
} from "react-viro"
|
} from "react-viro"
|
||||||
import autobind from "autobind-decorator"
|
import autobind from "autobind-decorator"
|
||||||
@@ -35,31 +36,124 @@ const shapes = {
|
|||||||
materials: [require("./models/clipboard.mtl")],
|
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 {
|
class WorkItemSceneAR extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
position: [0, 0.2, 0],
|
position: [0, 0, 0],
|
||||||
scale: [0.2, 0.2, 0.2],
|
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() {
|
render() {
|
||||||
|
const { position, scale, rotation, shouldBillboard } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ViroARScene>
|
<ViroARScene ref={(ref) => (this.arScene = ref)}>
|
||||||
<ViroAmbientLight color="#ffffff" intensity={200} />
|
<ViroAmbientLight color="#ffffff" intensity={200} />
|
||||||
<ViroARPlane>
|
|
||||||
<ViroNode
|
<ViroNode
|
||||||
visible={true}
|
ref={(ref) => (this.arNode = ref)}
|
||||||
position={this.state.position}
|
transformBehaviors={shouldBillboard ? "billboardY" : []}
|
||||||
scale={this.state.scale}
|
position={position}
|
||||||
key="hardhat">
|
scale={scale}
|
||||||
|
rotation={rotation}>
|
||||||
<ViroSpotLight
|
<ViroSpotLight
|
||||||
innerAngle={5}
|
innerAngle={5}
|
||||||
outerAngle={20}
|
outerAngle={20}
|
||||||
direction={[0, -1, 0]}
|
direction={[0, -1, 0]}
|
||||||
position={[0, 4, 0]}
|
position={[0, 15, 0]}
|
||||||
color="#ffffff"
|
color="#ffffff"
|
||||||
castsShadow={true}
|
castsShadow={true}
|
||||||
shadowNearZ={0.1}
|
shadowNearZ={0.1}
|
||||||
@@ -67,10 +161,11 @@ class WorkItemSceneAR extends React.Component {
|
|||||||
shadowOpacity={0.9}
|
shadowOpacity={0.9}
|
||||||
/>
|
/>
|
||||||
<Viro3DObject
|
<Viro3DObject
|
||||||
position={[0, 0, 0]}
|
position={[0, 0, -1]}
|
||||||
source={shapes["hardhat"].shape}
|
source={shapes["hardhat"].shape}
|
||||||
resources={shapes["hardhat"].materials}
|
resources={shapes["hardhat"].materials}
|
||||||
type="OBJ"
|
type="OBJ"
|
||||||
|
onLoadEnd={this.handleLoadEnd}
|
||||||
/>
|
/>
|
||||||
<ViroSurface
|
<ViroSurface
|
||||||
rotation={[-90, 0, 0]}
|
rotation={[-90, 0, 0]}
|
||||||
@@ -81,7 +176,6 @@ class WorkItemSceneAR extends React.Component {
|
|||||||
ignoreEventHandling={true}
|
ignoreEventHandling={true}
|
||||||
/>
|
/>
|
||||||
</ViroNode>
|
</ViroNode>
|
||||||
</ViroARPlane>
|
|
||||||
</ViroARScene>
|
</ViroARScene>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import KeyboardSpacer from "react-native-keyboard-spacer"
|
|||||||
import { versionInfo } from "../version"
|
import { versionInfo } from "../version"
|
||||||
import autobind from "autobind-decorator"
|
import autobind from "autobind-decorator"
|
||||||
import { isIphoneX } from "react-native-iphone-x-helper"
|
import { isIphoneX } from "react-native-iphone-x-helper"
|
||||||
|
import { defaultUser } from "../development"
|
||||||
|
|
||||||
export class Login extends React.Component {
|
export class Login extends React.Component {
|
||||||
static bindings = {
|
static bindings = {
|
||||||
@@ -75,7 +76,7 @@ export class Login extends React.Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
binder: new FormBinder({ email: "john@lyon-smith.org" }, Login.bindings),
|
binder: new FormBinder({ email: defaultUser }, Login.bindings),
|
||||||
messageModal: null,
|
messageModal: null,
|
||||||
apiModal: null,
|
apiModal: null,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,43 @@
|
|||||||
import React from 'react'
|
import React from "react"
|
||||||
import { View, StyleSheet } from 'react-native'
|
import { View, StyleSheet } from "react-native"
|
||||||
import {
|
import {
|
||||||
ViroARSceneNavigator, ViroARScene, ViroARPlane, ViroBox
|
ViroARSceneNavigator,
|
||||||
} from 'react-viro'
|
ViroARScene,
|
||||||
import { NativeRouter, Route, Link, Switch } from 'react-router-native'
|
ViroARPlane,
|
||||||
import MapView from 'react-native-maps'
|
ViroBox,
|
||||||
import { WorkItem, WorkItemList } from './WorkItem'
|
} from "react-viro"
|
||||||
import { Activity } from './Activity'
|
import { NativeRouter, Route, Link, Switch } from "react-router-native"
|
||||||
import { Home } from './Home'
|
import MapView from "react-native-maps"
|
||||||
import { ARViewer } from './ARViewer'
|
import { WorkItem, WorkItemList } from "./WorkItem"
|
||||||
import { Login, Logout, ProtectedRoute, DefaultRoute } from './Auth'
|
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 = [
|
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 {
|
export default class App extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<NativeRouter>
|
<NativeRouter>
|
||||||
<View style={{ width: '100%', height: '100%' }}>
|
<View style={{ width: "100%", height: "100%" }}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path='/login' component={Login}/>
|
<Route exact path="/login" component={Login} />
|
||||||
<Route exact path='/logout' component={Logout}/>
|
<Route exact path="/logout" component={Logout} />
|
||||||
<ProtectedRoute exact path='/home' component={Home}/>
|
<ProtectedRoute exact path="/home" component={Home} />
|
||||||
<ProtectedRoute exact path='/arviewer' component={ARViewer}/>
|
<ProtectedRoute exact path="/arviewer" component={ARViewer} />
|
||||||
<ProtectedRoute exact path='/activity' component={Activity}/>
|
<ProtectedRoute exact path="/activity" component={Activity} />
|
||||||
<ProtectedRoute exact admin path='/workitem' component={WorkItem}/>
|
<ProtectedRoute exact admin path="/workitem" component={WorkItem} />
|
||||||
<ProtectedRoute exact admin path='/workitemlist' component={WorkItemList}/>
|
<ProtectedRoute
|
||||||
|
exact
|
||||||
|
admin
|
||||||
|
path="/workitemlist"
|
||||||
|
component={WorkItemList}
|
||||||
|
/>
|
||||||
<DefaultRoute />
|
<DefaultRoute />
|
||||||
</Switch>
|
</Switch>
|
||||||
</View>
|
</View>
|
||||||
@@ -39,7 +48,7 @@ export default class App extends React.Component {
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
width: '100%',
|
width: "100%",
|
||||||
height: '100%',
|
height: "100%",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
2
mobile/src/development.js
Normal file
2
mobile/src/development.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export const localIPAddr = "192.168.1.175"
|
||||||
|
export const defaultUser = "john@lyon-smith.org"
|
||||||
Reference in New Issue
Block a user