Skip to content

Commit

Permalink
updated bbox creation
Browse files Browse the repository at this point in the history
  • Loading branch information
ahardy42 committed Mar 25, 2020
1 parent 2c0c5e1 commit 19d346f
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 23 deletions.
38 changes: 38 additions & 0 deletions components/PolyBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { Polygon, MapEvent, LatLng, Point, Polyline, Circle, } from 'react-native-maps';

// hook to emit polygon / editing state
export const usePolygonCreator: () => [LatLng[], (e: any, isEditing: boolean) => void] = () => {

const [coords, setCoords] = React.useState<LatLng[]>([]);

const addToPolygon: (e: any, isEditing: boolean) => void = (e, isEditing) => {
e.persist();
if (!isEditing) return;
setCoords(prevState => [...prevState, e.nativeEvent.coordinate])
// console.log(e.nativeEvent)
}

return [coords, addToPolygon]
}

// PolyBoundary Component
type PolyProps = {
coords: LatLng[],
}

export function PolyBoundary({ coords }: PolyProps) {

return (
<>
{coords.length < 2 && <Circle center={coords[0]} radius={5} strokeWidth={5} strokeColor='green'/>}
{coords.length < 3 && <Polyline coordinates={coords} strokeWidth={5} strokeColor='green'/>}
<Polygon
coordinates={coords}
strokeColor='green'
strokeWidth={5}
/>
</>
);
}
35 changes: 35 additions & 0 deletions components/PolyButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

type ButtonProps = {
coordsLen: number,
setIsEditing: React.Dispatch<React.SetStateAction<boolean>>
}

export default function PolyButton({ coordsLen, setIsEditing }) {

const handlePress: () => void = () => {
if (coordsLen < 3) return;
setIsEditing(false);
}
return (
<TouchableOpacity onPress={() => setIsEditing(false)} style={styles.button}>
<Text style={styles.text}>Set Boundary</Text>
</TouchableOpacity>
);
}

const styles = StyleSheet.create({
button: {
position: 'absolute',
bottom: 50,
left: '50%',
marginLeft: -50,
width: 100,
zIndex: 500
},
text: {
fontSize: 15,
textAlign: 'center'
}
})
51 changes: 37 additions & 14 deletions screens/MapScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import { StackNavigationProp } from '@react-navigation/stack';
import { filterMarkersByProximity, initMarkerList, initSnappedMarkerList } from '../utils/markers';
import { useFormContext } from '../context/FormContext';
import { Feature, Point } from '@turf/turf';
// components
import MarkerList from '../components/MarkerList';
import StartModal from '../components/StartModal';
import PointsTally from '../components/PointsTally';
import { usePolygonCreator, PolyBoundary } from '../components/PolyBoundary';
import PolyButton from '../components/PolyButton';

type ProfileScreenNavigationProp = StackNavigationProp<
RootStackParamList,
Expand All @@ -35,6 +38,10 @@ export default function MapScreen({ navigation }: HomeScreenProps) {
const [location, setLocation] = React.useState<LocationData>(null);
const removeRef = React.useRef(null);
const [markerList, setList] = React.useState<Feature<Point>[]>([]);
// setting the polygon boundary to use in game
const [isEditing, setEditing] = React.useState<boolean>(true);
const [boundary, setBoundary] = React.useState<LatLng[]>([]);
const [coords, addToPolygon] = usePolygonCreator();
const [timer, setTimer] = React.useState<number>(5);
const timerRef = React.useRef<number>(null);
const [formState] = useFormContext();
Expand Down Expand Up @@ -72,13 +79,6 @@ export default function MapScreen({ navigation }: HomeScreenProps) {
}

let location = await Location.getCurrentPositionAsync({});
// init markers
if (formState.activity === 'on-road') {
let list = await initSnappedMarkerList(location, 10);
setList(list);
} else {
setList(initMarkerList(location, 10))
}
// set the region
setRegion({
latitude: location.coords.latitude,
Expand All @@ -98,12 +98,10 @@ export default function MapScreen({ navigation }: HomeScreenProps) {

// start countdown
React.useEffect(() => {
if (markerList.length) {
timerRef.current = window.setInterval(() => {
setTimer(time => time - 1)
}, 1000);
}
}, [markerList])
timerRef.current = window.setInterval(() => {
setTimer(time => time - 1)
}, 1000);
}, [])

React.useEffect(() => {
if (timer < -5) {
Expand All @@ -116,19 +114,44 @@ export default function MapScreen({ navigation }: HomeScreenProps) {
setList(prevState => filterMarkersByProximity(location, prevState))
}, [location])

React.useEffect(() => {
if (!isEditing && coords.length) {
setBoundary(coords);
}
}, [isEditing, coords])

React.useEffect(() => {
if (boundary.length) {
// init markers
if (formState.activity === 'on-road') {
initSnappedMarkerList(boundary, 10)
.then(list => {
setList(list);
})
.catch(e => {
console.log(e);
})
} else {
setList(initMarkerList(boundary, 10))
}
}
}, [boundary])

return (
<View style={styles.container}>
<PointsTally initialLen={10} markerListLen={markerList.length} />
<StartModal timer={timer}/>
<MapView
style={styles.mapStyle}
initialRegion={initialRegion}
onPress={e => addToPolygon(e, isEditing)}
followsUserLocation={timer > 0}
showsUserLocation={timer > 0 || formState.difficulty === 'easy'}
>
<MarkerList markerList={markerList}/>
{isEditing && <PolyBoundary coords={coords} />}
</MapView>

{isEditing && <PolyButton coordsLen={coords.length} setIsEditing={setEditing}/>}
</View>
);
}
Expand Down
24 changes: 15 additions & 9 deletions utils/markers.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import { LocationData } from "expo-location";
import { circle, point, randomPoint, bbox, BBox, Feature, Point, distance } from '@turf/turf';
import { LatLng } from 'react-native-maps';
import { circle, point, randomPoint, bbox, BBox, Feature, Point, distance, lineString } from '@turf/turf';
import { snapArray } from './api';

const generateBbox: (location: LocationData, radius: number) => BBox = (location, radius) => {
// generate a bbox from location and a radius
let circleAroundPosition = circle(point([location.coords.longitude, location.coords.latitude]), radius, { units: 'meters' })
return bbox(circleAroundPosition);
const generateBbox: (boundary: LatLng[]) => BBox = (boundary) => {
// generate a bbox from a boundary array drawn on a map. this is used to create random marker locations
try {
let poly = lineString(boundary.map(el => [el.longitude, el.latitude]))
console.log(poly);
return bbox(poly);
} catch (error) {
console.log(error)
}
}

const filterFunc: (feature: Feature<Point>, location: LocationData) => boolean = (feature, location) => {
return distance([location.coords.longitude, location.coords.latitude], feature.geometry.coordinates, { units: 'meters' }) > 5
}

export const initMarkerList: (location: LocationData, len: number) => Feature<Point>[] = (location, len) => {
let markerArray = randomPoint(len, { bbox: generateBbox(location, 1000) }).features;
export const initMarkerList: (boundary: LatLng[], len: number) => Feature<Point>[] = (boundary, len) => {
let markerArray = randomPoint(len, { bbox: generateBbox(boundary) }).features;
return markerArray;
}

export const initSnappedMarkerList: (location: LocationData, len: number) => Promise<Feature<Point>[]> = async (location, len) => {
let markerArray = randomPoint(len, { bbox: generateBbox(location, 1000) }).features;
export const initSnappedMarkerList: (boundary: LatLng[], len: number) => Promise<Feature<Point>[]> = async (boundary, len) => {
let markerArray = randomPoint(len, { bbox: generateBbox(boundary) }).features;
let updatedArray = await snapArray(markerArray);
return updatedArray;
}
Expand Down

0 comments on commit 19d346f

Please sign in to comment.