Fixed and made changes to the Haversine distance formula calculation. We now point it to the user's location as intended

This commit is contained in:
Keannu Bernasol 2023-09-11 19:02:11 +08:00
parent 7b9d05f84b
commit 00928ac947
2 changed files with 106 additions and 53 deletions

View file

@ -9,59 +9,82 @@ import {
} from "../../interfaces/Interfaces"; } from "../../interfaces/Interfaces";
import { Double, Float } from "react-native/Libraries/Types/CodegenTypes"; import { Double, Float } from "react-native/Libraries/Types/CodegenTypes";
export default function ParseStudyGroupList(data: any) { export default function ParseStudyGroupList(
let result: any[] = []; data: any,
user_location: LocationType
) {
// Circle generation for students in a study group // Circle generation for students in a study group
let result: any[] = [];
// We first remove any instances that do not have a study group associated with it
let data_filtered = data.filter(
(item: StudentStatusFilterType) => item.study_group !== ""
);
// console.log("Filtered Data:", data_filtered);
// Then we flatten the data so that all attributes are in the first layer
// We first flatten the data to remove nested entries // We first flatten the data to remove nested entries
console.log("Initial Data:", data); let data_flattened = data_filtered.map((item: StudentStatusFilterType) => ({
let flattened_data = data active: item.active,
.filter((item: StudentStatusFilterType) => item.study_group !== "") distance: item.distance,
.map((item: StudentStatusFilterType) => ({ landmark: item.landmark,
active: item.active, latitude: item.location.latitude,
distance: item.distance, longitude: item.location.longitude,
landmark: item.landmark, study_group: item.study_group,
latitude: item.location.latitude, subject: item.subject,
longitude: item.location.longitude, user: item.user,
study_group: item.study_group, weight: 1,
subject: item.subject, }));
user: item.user, // console.log("Flattened Data:", data_flattened);
weight: 1,
}));
console.log("Filtered Data:", flattened_data);
// We get each unique subject // We take from the array all unique subject names
let unique_subjects = [ let unique_subjects = [
...new Set( ...new Set(
flattened_data.map((item: StudentStatusFilterType) => item.subject) data_flattened.map((item: StudentStatusFilterType) => item.subject)
), ),
]; ];
// Then append all entries belonging to that subject to its own array // Then we create arrays unique to each subject
unique_subjects.forEach((subject, index: number) => { unique_subjects.forEach((subject, index: number) => {
index++; // We build another array for each subject, including only those instances that are the same subject name
let filteredData = flattened_data.filter( let unique_subject_list = data_flattened
.filter(
(item: StudentStatusFilterTypeFlattened) => item.subject === subject
)
.map((item: StudentStatusFilterTypeFlattened) => ({
active: item.active,
distance: item.distance,
landmark: item.landmark,
latitude: item.latitude,
longitude: item.longitude,
study_group: item.study_group,
subject: item.subject,
user: item.user,
weight: 1,
}));
/*
let unique_subject_object = data_flattened.filter(
(item: StudentStatusFilterTypeFlattened) => item.subject === subject (item: StudentStatusFilterTypeFlattened) => item.subject === subject
); );
console.log("Subject #", index, "-", filteredData[0].subject, filteredData); */
// We get the circle's center by averaging all the points // We get the circle's center by averaging all the points
// Calculate the average latitude and longitude // Calculate the average latitude and longitude
const totalLat = filteredData.reduce( const totalLat = unique_subject_list.reduce(
(sum: Double, point: LocationType) => sum + point.latitude, (sum: Double, point: LocationType) => sum + point.latitude,
0 0
); );
const totalLng = filteredData.reduce( const totalLng = unique_subject_list.reduce(
(sum: Double, point: LocationType) => sum + point.longitude, (sum: Double, point: LocationType) => sum + point.longitude,
0 0
); );
const avgLat = totalLat / filteredData.length; let avgLat = totalLat / unique_subject_list.length;
const avgLng = totalLng / filteredData.length; let avgLng = totalLng / unique_subject_list.length;
console.log("Center Latitude:", avgLat); // console.log("Center Latitude:", avgLat);
console.log("Center Longitude:", avgLng); // console.log("Center Longitude:", avgLng);
// We now calculate the radius of the circle using the Haversine Distance Formula
// Haversine Distance Function
function haversineDistance( function haversineDistance(
lat1: number, lat1: number,
lon1: number, lon1: number,
@ -72,31 +95,56 @@ export default function ParseStudyGroupList(data: any) {
return (x * Math.PI) / 180; return (x * Math.PI) / 180;
} }
var R = 6371; // km lat1 = toRad(lat1);
var x1 = lat2 - lat1; lon1 = toRad(lon1);
var dLat = toRad(x1); lat2 = toRad(lat2);
var x2 = lon2 - lon1; lon2 = toRad(lon2);
var dLon = toRad(x2);
var a = let dLat = lat2 - lat1;
let dLon = lon2 - lon1;
let a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRad(lat1)) * Math.cos(lat1) *
Math.cos(toRad(lat2)) * Math.cos(lat2) *
Math.sin(dLon / 2) * Math.sin(dLon / 2) *
Math.sin(dLon / 2); Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d; // Multiply by Earth's radius (in kilometers) to obtain distance
let distance = 6371 * c;
// Convert to meters
return distance * 1000;
} }
let circle_radius = // We now calculate the radius of the circle using the Haversine Distance Formula
Math.max( // For each entry, we calculate the Haversine Distance from the user's location.
...filteredData.map((item: StudentStatusFilterTypeFlattened) => // The largest value is used as the circle radius
haversineDistance(avgLat, avgLng, item.latitude, item.longitude)
)
) * 1000;
console.log("Radius:", circle_radius);
// We now build the object let circle_radius = Math.max(
...unique_subject_list.map(
(item: StudentStatusFilterTypeFlattened, index: number) => {
let distance = haversineDistance(
item.latitude,
item.longitude,
user_location.latitude,
user_location.longitude
);
console.log(
"Haversine Distance for entry #",
index + 1,
":",
distance
);
return distance;
}
)
);
// console.log("Radius:", circle_radius);
// We now build the object that we will return
const subjectUserMap: subjectUserMapType = { const subjectUserMap: subjectUserMapType = {
subject: "", subject: "",
users: [], users: [],
@ -104,7 +152,7 @@ export default function ParseStudyGroupList(data: any) {
longitude: 0, longitude: 0,
radius: 0, radius: 0,
}; };
filteredData.forEach((item: StudentStatusFilterType) => { unique_subject_list.forEach((item: StudentStatusFilterType) => {
if (!subjectUserMap["users"]) { if (!subjectUserMap["users"]) {
subjectUserMap["users"] = []; subjectUserMap["users"] = [];
} }

View file

@ -193,8 +193,13 @@ export default function Home() {
return data; return data;
}, },
onSuccess: (data: StudentStatusListReturnType) => { onSuccess: (data: StudentStatusListReturnType) => {
if (data[1]) { if (data[1] && location) {
setStudyGroups(ParseStudentStatusList(data[1])); setStudyGroups(
ParseStudentStatusList(data[1], {
latitude: location.coords.latitude,
longitude: location.coords.longitude,
})
);
} }
}, },
onError: (error: Error) => { onError: (error: Error) => {