From 19d346f5753e370e4f82dc7bf3ac7110f8880c1c Mon Sep 17 00:00:00 2001 From: Andy Hardy Date: Wed, 25 Mar 2020 08:12:40 -0600 Subject: [PATCH] updated bbox creation --- components/PolyBoundary.tsx | 38 +++++++++++++++++++++++++++ components/PolyButton.tsx | 35 +++++++++++++++++++++++++ screens/MapScreen.tsx | 51 +++++++++++++++++++++++++++---------- utils/markers.ts | 24 ++++++++++------- 4 files changed, 125 insertions(+), 23 deletions(-) create mode 100644 components/PolyBoundary.tsx create mode 100644 components/PolyButton.tsx diff --git a/components/PolyBoundary.tsx b/components/PolyBoundary.tsx new file mode 100644 index 0000000..5761f4b --- /dev/null +++ b/components/PolyBoundary.tsx @@ -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([]); + + 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 && } + {coords.length < 3 && } + + + ); +} \ No newline at end of file diff --git a/components/PolyButton.tsx b/components/PolyButton.tsx new file mode 100644 index 0000000..1ad6ee2 --- /dev/null +++ b/components/PolyButton.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'; + +type ButtonProps = { + coordsLen: number, + setIsEditing: React.Dispatch> +} + +export default function PolyButton({ coordsLen, setIsEditing }) { + + const handlePress: () => void = () => { + if (coordsLen < 3) return; + setIsEditing(false); + } + return ( + setIsEditing(false)} style={styles.button}> + Set Boundary + + ); +} + +const styles = StyleSheet.create({ + button: { + position: 'absolute', + bottom: 50, + left: '50%', + marginLeft: -50, + width: 100, + zIndex: 500 + }, + text: { + fontSize: 15, + textAlign: 'center' + } +}) \ No newline at end of file diff --git a/screens/MapScreen.tsx b/screens/MapScreen.tsx index 3d24553..da7930a 100644 --- a/screens/MapScreen.tsx +++ b/screens/MapScreen.tsx @@ -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, @@ -35,6 +38,10 @@ export default function MapScreen({ navigation }: HomeScreenProps) { const [location, setLocation] = React.useState(null); const removeRef = React.useRef(null); const [markerList, setList] = React.useState[]>([]); + // setting the polygon boundary to use in game + const [isEditing, setEditing] = React.useState(true); + const [boundary, setBoundary] = React.useState([]); + const [coords, addToPolygon] = usePolygonCreator(); const [timer, setTimer] = React.useState(5); const timerRef = React.useRef(null); const [formState] = useFormContext(); @@ -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, @@ -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) { @@ -116,6 +114,29 @@ 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 ( @@ -123,12 +144,14 @@ export default function MapScreen({ navigation }: HomeScreenProps) { addToPolygon(e, isEditing)} followsUserLocation={timer > 0} showsUserLocation={timer > 0 || formState.difficulty === 'easy'} > + {isEditing && } - + {isEditing && } ); } diff --git a/utils/markers.ts b/utils/markers.ts index 678d189..d473eab 100644 --- a/utils/markers.ts +++ b/utils/markers.ts @@ -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, 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[] = (location, len) => { - let markerArray = randomPoint(len, { bbox: generateBbox(location, 1000) }).features; +export const initMarkerList: (boundary: LatLng[], len: number) => Feature[] = (boundary, len) => { + let markerArray = randomPoint(len, { bbox: generateBbox(boundary) }).features; return markerArray; } -export const initSnappedMarkerList: (location: LocationData, len: number) => Promise[]> = async (location, len) => { - let markerArray = randomPoint(len, { bbox: generateBbox(location, 1000) }).features; +export const initSnappedMarkerList: (boundary: LatLng[], len: number) => Promise[]> = async (boundary, len) => { + let markerArray = randomPoint(len, { bbox: generateBbox(boundary) }).features; let updatedArray = await snapArray(markerArray); return updatedArray; }