Проверка адреса с помощью карты полигонов React Native и Leaflet

Мне нужна помощь с проверкой адреса. Я построил многоугольник на карте с помощью 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":{}}

Если бы кто-нибудь мог помочь мне написать код, чтобы нажатие кнопки для его проверки генерировало вывод консоли. Меня устраивает, указано ли в журнале, что оно находится внутри полигона или нет; Я просто не могу этого сделать. Я получаю сообщение об ошибке, говорящее, что данных нет, но они есть; кнопка «Журнал данных» записывает ранее извлеченные данные. Фото карты:

Пример полигона карты

Фото меню проверки адреса:

Панель проверки адреса

Кнопка «Журнал данных» регистрирует полученные данные и отображает их на консоли. Кнопка «Подтвердить» должна проверить текст внутри «Входного адреса» и убедиться, что он находится внутри многоугольника.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
109
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Решение:

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, а также преобразовал предоставленный адрес в широту и долготу, чтобы позже проверить, находится ли он внутри полигона.

В результате, независимо от того, сколько точек у многоугольника, он всегда будет давать правильный ответ.

Другие вопросы по теме