Мне нужна помощь с проверкой адреса. Я построил многоугольник на карте с помощью Leaflet на другом конце, и этот многоугольник записывается в базу данных, которую я импортирую в мобильное приложение (имейте в виду, что многоугольник может измениться). Вот код компонента проверки адреса:
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Dimensions,
Button,
TextInput,
Alert,
} from "react-native";
import React, { useEffect, useState } from "react";
import { Entypo } from "@expo/vector-icons";
import allVariables from "../utils/allVariables";
import GeoFencing from "react-native-geo-fencing";
const screenWidth = Dimensions.get("window").width;
const screenHeight = Dimensions.get("window").height;
const CurrentLocationPanel = ({ closeCL }) => {
const [data, setData] = useState(null);
const [address, setAddress] = useState("");
const [isAddressInsidePolygon, setIsAddressInsidePolygon] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(
`${allVariables.strapiBaseURL}/api/mapvalidations/1`,
{
headers: {
Authorization: `Bearer ${allVariables.strapiApiUpdateMapBearer}`,
},
}
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const jsonData = await response.json();
setData(jsonData);
} catch (error) {
console.error("Fetch error:", error);
}
};
fetchData();
}, []);
const handleValidate = () => {
if (!data || !data[0] || !data[0].latlngs) {
Alert.alert("Polygon data not available");
return;
}
const polygon = data[0].latlngs.map((point) => [point.lat, point.lng]);
if (!address) {
Alert.alert("Please enter an address");
return;
}
GeoFencing.containsLocation(
address,
polygon,
(result) => {
if (result) {
Alert.alert("Address is inside the polygon");
} else {
Alert.alert("Address is not inside the polygon");
}
},
(error) => {
console.error(error);
Alert.alert("Error checking polygon:", error);
}
);
};
return (
<>
<TouchableOpacity
style = {styles.mainViewNoBG}
onPress = {closeCL}
activeOpacity = {0}
></TouchableOpacity>
<View style = {styles.blockView}>
<TouchableOpacity
style = {styles.closeBtn}
activeOpacity = {0.5}
onFocus = {closeCL}
>
<Entypo
name = "circle-with-cross"
size = {24}
color = {allVariables.headerColor}
/>
</TouchableOpacity>
<Text>CurrentLocationPanel</Text>
<TextInput
style = {styles.input}
placeholder = "Enter Address"
value = {address}
onChangeText = {setAddress}
/>
<Button title = "Validate" onPress = {handleValidate} />
<Text>
{isAddressInsidePolygon === null
? ""
: isAddressInsidePolygon
? "Address is inside the polygon"
: "Address is not inside the polygon"}
</Text>
<Button
title = "Log Data"
onPress = {() => console.info(JSON.stringify(data))}
/>
</View>
</>
);
};
Полученные данные выглядят примерно так: (пример данных)
{"data":{"id":1,"attributes":{"polygon":[{"id":505,"latlngs":[{"lat":50.06077558832056,"lng":19.938096776604656},{"lat":50.06226329572605,"lng":19.940414205193523},{"lat":50.06427438239518,"lng":19.93745304644108},{"lat":50.06328262416413,"lng":19.935436025261883},{"lat":50.06176739838387,"lng":19.934878125786785}]}],"createdAt":"2023-03-31T08:20:58.283Z","updatedAt":"2023-04-01T11:44:21.428Z","publishedAt":"2023-03-31T08:21:02.535Z"}},"meta":{}}
Если бы кто-нибудь мог помочь мне написать код, чтобы нажатие кнопки для его проверки генерировало вывод консоли. Меня устраивает, указано ли в журнале, что оно находится внутри полигона или нет; Я просто не могу этого сделать. Я получаю сообщение об ошибке, говорящее, что данных нет, но они есть; кнопка «Журнал данных» записывает ранее извлеченные данные. Фото карты:
Фото меню проверки адреса:
Кнопка «Журнал данных» регистрирует полученные данные и отображает их на консоли. Кнопка «Подтвердить» должна проверить текст внутри «Входного адреса» и убедиться, что он находится внутри многоугольника.
Решение:
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Dimensions,
Button,
TextInput,
Alert,
} from "react-native";
import React, { useEffect, useState } from "react";
import { Entypo } from "@expo/vector-icons";
import allVariables from "../utils/allVariables";
const screenWidth = Dimensions.get("window").width;
function rayCasting(point, polygon) {
const n = polygon.length;
let isIn = false;
const x = point[0];
const y = point[1];
let x1, x2, y1, y2;
x1 = polygon[n - 1][0];
y1 = polygon[n - 1][1];
for (let i = 0; i < n; ++i) {
x2 = polygon[i][0];
y2 = polygon[i][1];
if (y < y1 !== y < y2 && x < ((x2 - x1) * (y - y1)) / (y2 - y1) + x1) {
isIn = !isIn;
}
x1 = x2;
y1 = y2;
}
return isIn;
}
const CurrentLocationPanel = ({ closeCL }) => {
const [data, setData] = useState(null);
const [address, setAddress] = useState("");
const [point, setPoint] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(
`${allVariables.strapiBaseURL}/api/mapvalidations/1`,
{
headers: {
Authorization: `Bearer ${allVariables.strapiApiUpdateMapBearer}`,
},
}
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const jsonData = await response.json();
setData(jsonData);
} catch (error) {
console.error("Fetch error:", error);
}
};
fetchData();
}, []);
const polygon = data?.data?.attributes?.polygon?.[0]?.latlngs?.map(
(latlng) => [latlng.lng, latlng.lat]
);
const handleValidate = async () => {
if (!address) {
Alert.alert("Please enter an address.");
return;
}
try {
const response = await fetch(
`https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(
address
)}&format=json&limit=1`
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const jsonData = await response.json();
if (!jsonData.length) {
Alert.alert("Address not found.");
return;
}
const { lat, lon } = jsonData[0];
const point = [parseFloat(lon), parseFloat(lat)];
const isInsidePolygon = rayCasting(point, polygon);
Alert.alert(
"Validation Result",
isInsidePolygon
? "The entered address is inside the polygon."
: "The entered address is outside the polygon.",
[{ text: "OK" }]
);
} catch (error) {
console.error("Fetch error:", error);
Alert.alert("Something went wrong. Please try again later.");
}
};
return (
<>
<TouchableOpacity
style = {styles.mainViewNoBG}
onPress = {closeCL}
activeOpacity = {0}
></TouchableOpacity>
<View style = {styles.blockView}>
<TouchableOpacity
style = {styles.closeBtn}
activeOpacity = {0.5}
onPress = {closeCL}
>
<Entypo
name = "circle-with-cross"
size = {24}
color = {allVariables.headerColor}
/>
</TouchableOpacity>
<Text>CurrentLocationPanel</Text>
<TextInput
style = {styles.input}
placeholder = "Enter Address"
value = {address}
onChangeText = {setAddress}
/>
<Button title = "Validate" onPress = {handleValidate} />
<Button
title = "Log Data"
onPress = {() => console.info(JSON.stringify(data))}
/>
<Button title = "Log Polygon Data" onPress = {() => console.info(polygon)} />
</View>
</>
);
};
const styles = StyleSheet.create({
mainViewNoBG: {
width: "100%",
height: "100%",
backgroundColor: "transparent",
position: "absolute",
},
blockView: {
backgroundColor: "white",
borderRadius: 10,
top: screenWidth >= 768 ? 75 : 60,
alignSelf: "center",
alignItems: "center",
justifyContent: "center",
position: "absolute",
width: screenWidth >= 768 ? "50%" : "75%",
height: "auto",
padding: 10,
borderWidth: 1,
borderColor: "black",
},
closeBtn: {
position: "absolute",
zIndex: 9999,
right: 10,
top: 10, // use top 20 if device is iOS, otherwise use top 10
},
});
export default CurrentLocationPanel;
Я использовал функцию RayCasting, а также преобразовал предоставленный адрес в широту и долготу, чтобы позже проверить, находится ли он внутри полигона.
В результате, независимо от того, сколько точек у многоугольника, он всегда будет давать правильный ответ.