diff --git a/frontend/src/pages/scenario.jsx b/frontend/src/pages/scenario.jsx index 7c83359..8f95126 100644 --- a/frontend/src/pages/scenario.jsx +++ b/frontend/src/pages/scenario.jsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, useRef } from 'react'; import { Stage, Layer, Circle, Text, Line } from 'react-konva'; -import { Slider } from '@mui/material'; +import { Slider, Button } from '@mui/material'; import axios from 'axios'; const API_KEY = 'LF7i77oqghRiq54HEFJh991WgjHcKsETP9D5ofsg'; @@ -23,11 +23,12 @@ function Scenario() { size: 1, speed: 0.05, mass: 1, - angle: Math.PI / 4, + angle: Math.PI / 9, x: 100, y: CANVAS_HEIGHT / 2 - 100, }); const [trajectoryPoints, setTrajectoryPoints] = useState([]); + const [forecastPoints, setForecastPoints] = useState([]); const animationRef = useRef(); const asteroidsData = useRef([]); const [isSimulating, setIsSimulating] = useState(false); @@ -59,16 +60,18 @@ function Scenario() { console.log('Asteroid Data:', asteroidData); const size = asteroidData.estimated_diameter.kilometers.estimated_diameter_max; const mass = estimateMass(size); + const speed = asteroidData.close_approach_data[0].relative_velocity.kilometers_per_second / 1000; setAsteroid({ name: asteroidData.name, size: size, - speed: asteroidData.close_approach_data[0].relative_velocity.kilometers_per_second / 1000, + speed: speed, mass: mass, - angle: Math.PI / 8, + angle: Math.PI / 9, x: 100, y: CANVAS_HEIGHT / 2 - 100, }); setTrajectoryPoints([]); + calculateForecastPath(size, speed, Math.PI / 9, mass); // Calculate the forecast path once }; const handleAsteroidSelect = (event) => { @@ -86,6 +89,52 @@ function Scenario() { return { vx, vy }; }; + const calculateForecastPath = (size, speed, angle, mass) => { + let x = 100; + let y = CANVAS_HEIGHT / 2 - 100; + let vx = speed * Math.cos(angle); + let vy = speed * Math.sin(angle); + const points = []; + let iterationCount = 0; + const maxIterations = 2000; // Extended limit to allow for longer forecast + + while (true) { + const dx = EARTH_X - x; + const dy = EARTH_Y - y; + const distance = Math.sqrt(dx * dx + dy * dy); + + // Check if the asteroid hits Earth + if (distance <= EARTH_RADIUS_KM * EARTH_DISPLAY_SCALE + size * ASTEROID_DISPLAY_SCALE) { + break; + } + + // Apply gravitational force + const force = (G * EARTH_MASS * mass) / (distance * distance); + const ax = force * (dx / distance) / mass; + const ay = force * (dy / distance) / mass; + + vx += ax * timeStep; + vy += ay * timeStep; + + x += vx * timeStep; + y += vy * timeStep; + + points.push(x, y); + + iterationCount++; + if (iterationCount >= maxIterations) { + break; + } + + // Stop the loop if the asteroid goes off screen + if (y > CANVAS_HEIGHT * SIMULATION_AREA_MULTIPLIER || x > CANVAS_WIDTH * SIMULATION_AREA_MULTIPLIER || y < -CANVAS_HEIGHT * SIMULATION_AREA_MULTIPLIER || x < -CANVAS_WIDTH * SIMULATION_AREA_MULTIPLIER) { + break; + } + } + + setForecastPoints(points); + }; + const simulate = () => { let { x, y, speed, angle, mass } = asteroid; @@ -143,6 +192,11 @@ function Scenario() { setTimeStep(newValue); }; + const handleAngleChange = (event, newValue) => { + setAsteroid(prev => ({ ...prev, angle: newValue })); + calculateForecastPath(asteroid.size, asteroid.speed, newValue, asteroid.mass); + }; + return ( <>