* feat: add boilerplate
* feat: add working paths
* feat: improve building selection controls and add week schedule
Signed-off-by: doprz <52579214+doprz@users.noreply.github.com>
* fix: sort week schedule
Signed-off-by: doprz <52579214+doprz@users.noreply.github.com>
* feat(testing): improve pathfinding
* Revert "feat(testing): improve pathfinding"
This reverts commit 87998cedbf.
* feat: add pathfinding with building selection controls
Signed-off-by: doprz <52579214+doprz@users.noreply.github.com>
* feat: improve path finding algorithm thresholds
* feat: add DaySelector, PathStats, and WeekSchedule components
* feat: add working stats and daily schedule
* chore: refactor everything
* feat: add linear walkway node generation
* feat: add bezier curve walkway node generation
* feat: add circular walkway node generation
* docs: add docs
* feat: add individual path selection and bump version
* fix: tsdoc and updated components/utils
* chore(deps): update deps
* feat: add UTRP Map and Debug Page to Settings > Developer Mode
* chore: fix pr review comments
* chore: add showDebugNodes
* chore: add all buildings around the UT tower
* chore: add stadium POIs
* chore: add east mall buildings
* chore: update DaySelector to use proper button styling
* chore: add university ave walkway
* feat: add zoom, pan, and dev controls functionality
- Fix SVG Overlay Alignment
- Use SVG for map
- Add Dev Controls
- Fix day selector position
- Update the SVG's `preserveAspectRatio` attribute to `xMidYMid` meet to
ensure proper scaling
- Use `useCallback` for event handlers to prevent unnecessary re-renders
- Remove old PNG map
* feat: add dynamic rendering"
* feat: add dynamicRendering dev toggle and fullscreen support
* chore: update deps
* chore: disable viewport svg overlay culling if dynamic rendering is off
* chore: update pnpm-lock.yaml
* chore: add north mall buildings
* chore: add buildings next to JES
* refactor: map components into individual files
* fix: missing import
---------
Signed-off-by: doprz <52579214+doprz@users.noreply.github.com>
112 lines
4.2 KiB
TypeScript
112 lines
4.2 KiB
TypeScript
import { graphNodes } from './graphNodes';
|
|
import type { Graph, MapNode, NodeCoordinates, NodeId } from './types';
|
|
import { isValidNode, NEIGHBOR_DISTANCE_THRESHOLD } from './types';
|
|
|
|
/**
|
|
* Calculates the Euclidean distance between two points.
|
|
*
|
|
* @param point1 - The coordinates of the first point.
|
|
* @param point2 - The coordinates of the second point.
|
|
* @returns The distance between the two points.
|
|
*/
|
|
export const calculateDistance = (point1: NodeCoordinates, point2: NodeCoordinates): number =>
|
|
Math.sqrt((point2.x - point1.x) ** 2 + (point2.y - point1.y) ** 2);
|
|
|
|
/**
|
|
* Finds the nearest nodes to a given node in a graph.
|
|
*
|
|
* @param nodeId - The ID of the node for which to find the nearest nodes.
|
|
* @param graph - The graph containing all nodes.
|
|
* @returns An array of node IDs representing the nearest nodes.
|
|
*
|
|
* The function first checks if the current node is valid. If not, it returns an empty array.
|
|
* It then calculates the distances to all other valid nodes in the graph.
|
|
* The nodes are sorted by distance, and the function first attempts to connect to the nearest intersections.
|
|
* If no intersections are found, it connects to the nearest buildings.
|
|
*/
|
|
const findNearestNodes = (nodeId: NodeId, graph: Graph): NodeId[] => {
|
|
const currentNode = graph[nodeId];
|
|
if (!isValidNode(currentNode)) return [];
|
|
|
|
// Calculate distances to all other nodes
|
|
const distances = Object.entries(graph)
|
|
.filter((entry): entry is [string, MapNode] => {
|
|
const [id, node] = entry;
|
|
return id !== nodeId && isValidNode(node);
|
|
})
|
|
.map(([id, node]) => ({
|
|
id,
|
|
distance: calculateDistance(currentNode, node),
|
|
isIntersection: node.type === 'intersection',
|
|
}))
|
|
.sort((a, b) => a.distance - b.distance);
|
|
|
|
// First try to connect to nearest intersections
|
|
const nearestIntersections = distances
|
|
.filter(node => node.isIntersection)
|
|
.slice(0, 2)
|
|
.map(node => node.id);
|
|
|
|
if (nearestIntersections.length > 0) {
|
|
return nearestIntersections;
|
|
}
|
|
|
|
// If no intersections found, connect to nearest buildings
|
|
return distances.slice(0, 2).map(node => node.id);
|
|
};
|
|
|
|
/**
|
|
* Retrieves the neighboring nodes of a given node within a graph.
|
|
*
|
|
* @param nodeId - The ID of the node for which neighbors are to be found.
|
|
* @param graph - The graph containing all nodes and their connections.
|
|
* @returns An array of node IDs representing the neighbors of the given node.
|
|
*
|
|
* This function first checks if the current node is valid. If not, it returns an empty array.
|
|
* It then filters the graph to find all valid neighboring nodes within a specified distance threshold.
|
|
* If no direct neighbors are found, it attempts to connect to the nearest intersection or building.
|
|
*/
|
|
export const getNeighbors = (nodeId: NodeId, graph: Graph): NodeId[] => {
|
|
const currentNode = graph[nodeId];
|
|
if (!isValidNode(currentNode)) return [];
|
|
|
|
// Get all possible neighbors within the increased threshold
|
|
const neighbors = Object.entries(graph)
|
|
.filter((entry): entry is [string, MapNode] => {
|
|
const [id, node] = entry;
|
|
if (!isValidNode(node) || id === nodeId) return false;
|
|
const distance = calculateDistance(currentNode, node);
|
|
return distance < NEIGHBOR_DISTANCE_THRESHOLD;
|
|
})
|
|
.map(([id]) => id);
|
|
|
|
// If no direct neighbors found, connect to the nearest intersection or building
|
|
if (neighbors.length === 0) {
|
|
const nearestNodes = findNearestNodes(nodeId, graph);
|
|
return nearestNodes;
|
|
}
|
|
|
|
return neighbors;
|
|
};
|
|
|
|
/**
|
|
* Calculates the midpoint between two nodes identified by their IDs.
|
|
*
|
|
* @param startId - The ID of the starting node.
|
|
* @param endId - The ID of the ending node.
|
|
* @returns An object containing the x and y coordinates of the midpoint, or null if either node is invalid.
|
|
*/
|
|
export const getMidpoint = (startId: string, endId: string) => {
|
|
const startNode = graphNodes[startId];
|
|
const endNode = graphNodes[endId];
|
|
|
|
if (!isValidNode(startNode) || !isValidNode(endNode)) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
x: (startNode.x + endNode.x) / 2,
|
|
y: (startNode.y + endNode.y) / 2,
|
|
};
|
|
};
|