mirror of
https://github.com/its-michaelroy/Deep-Impact.git
synced 2026-06-04 02:20:41 +00:00
841
frontend/package-lock.json
generated
841
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,8 +10,15 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.11.4",
|
||||||
|
"@emotion/styled": "^11.11.5",
|
||||||
|
"@mui/material": "^5.15.18",
|
||||||
|
"axios": "^1.6.8",
|
||||||
|
"konva": "^9.3.8",
|
||||||
|
"nvm": "^0.0.4",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"react-konva": "^18.2.10",
|
||||||
"react-router-dom": "^6.23.1"
|
"react-router-dom": "^6.23.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -25,6 +32,6 @@
|
|||||||
"eslint-plugin-react-refresh": "^0.4.6",
|
"eslint-plugin-react-refresh": "^0.4.6",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.3",
|
||||||
"vite": "^5.2.0"
|
"vite": "^5.2.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,279 @@
|
|||||||
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
import { Stage, Layer, Circle, Text, Line } from 'react-konva';
|
||||||
|
import { Slider, Button } from '@mui/material';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const API_KEY = 'LF7i77oqghRiq54HEFJh991WgjHcKsETP9D5ofsg';
|
||||||
|
const EARTH_RADIUS_KM = 6371; // Earth's radius in kilometers
|
||||||
|
const EARTH_DISPLAY_SCALE = 0.01; // Display scale for Earth
|
||||||
|
const ASTEROID_DISPLAY_SCALE = 0.3; // Display scale for asteroids
|
||||||
|
const G = 1e-8; // Gravitational constant for simulation
|
||||||
|
const EARTH_MASS = 5.972e6; // Scaled down mass of Earth for simulation
|
||||||
|
const ASTEROID_DENSITY = 2000; // Density in kg/m^3
|
||||||
|
|
||||||
|
const CANVAS_WIDTH = window.innerWidth;
|
||||||
|
const CANVAS_HEIGHT = window.innerHeight;
|
||||||
|
const EARTH_X = CANVAS_WIDTH - 100;
|
||||||
|
const EARTH_Y = CANVAS_HEIGHT / 2;
|
||||||
|
const SIMULATION_AREA_MULTIPLIER = 2; // Extend the simulation area
|
||||||
|
|
||||||
function Scenario() {
|
function Scenario() {
|
||||||
|
const [asteroid, setAsteroid] = useState({
|
||||||
|
name: '',
|
||||||
|
size: 1,
|
||||||
|
speed: 0.05,
|
||||||
|
mass: 1,
|
||||||
|
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);
|
||||||
|
const [simulationResult, setSimulationResult] = useState('');
|
||||||
|
const [strategy, setStrategy] = useState(''); // State for selected strategy
|
||||||
|
const [timeStep, setTimeStep] = useState(100); // State for time step
|
||||||
|
|
||||||
return (
|
useEffect(() => {
|
||||||
<>
|
const fetchAsteroids = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`https://api.nasa.gov/neo/rest/v1/neo/browse?api_key=${API_KEY}`);
|
||||||
|
asteroidsData.current = response.data.near_earth_objects;
|
||||||
|
setAsteroidData(0); // Set initial asteroid
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching asteroid data:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchAsteroids();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const estimateMass = (diameter) => {
|
||||||
|
const radius = diameter / 2;
|
||||||
|
const volume = (4 / 3) * Math.PI * Math.pow(radius, 3);
|
||||||
|
return volume * ASTEROID_DENSITY;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setAsteroidData = (index) => {
|
||||||
|
const asteroidData = asteroidsData.current[index];
|
||||||
|
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: speed,
|
||||||
|
mass: mass,
|
||||||
|
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) => {
|
||||||
|
setAsteroidData(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const applyDeflectionStrategy = (vx, vy) => {
|
||||||
|
if (strategy === 'Nuclear Detonation') {
|
||||||
|
vx += 0.5; // Example effect
|
||||||
|
} else if (strategy === 'Kinetic Impact') {
|
||||||
|
vx += 0.25; // Example effect
|
||||||
|
} else if (strategy === 'Gravity Tractor') {
|
||||||
|
vy -= 0.1; // Example effect
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
let vx = speed * Math.cos(angle);
|
||||||
|
let vy = speed * Math.sin(angle);
|
||||||
|
|
||||||
|
const updateFrame = () => {
|
||||||
|
console.log(`Asteroid position: (${x}, ${y}), velocity: (${vx}, ${vy})`);
|
||||||
|
|
||||||
|
const dx = EARTH_X - x;
|
||||||
|
const dy = EARTH_Y - y;
|
||||||
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (distance <= EARTH_RADIUS_KM * EARTH_DISPLAY_SCALE + asteroid.size * ASTEROID_DISPLAY_SCALE) {
|
||||||
|
setSimulationResult('Asteroid collided with Earth!');
|
||||||
|
setIsSimulating(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
({ vx, vy } = applyDeflectionStrategy(vx, vy));
|
||||||
|
|
||||||
|
x += vx * timeStep;
|
||||||
|
y += vy * timeStep;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
setSimulationResult('Asteroid missed Earth!');
|
||||||
|
setIsSimulating(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAsteroid(prev => ({ ...prev, x, y }));
|
||||||
|
setTrajectoryPoints(prev => [...prev, x, y]);
|
||||||
|
animationRef.current = window.requestAnimationFrame(updateFrame);
|
||||||
|
};
|
||||||
|
|
||||||
|
setIsSimulating(true);
|
||||||
|
setSimulationResult('');
|
||||||
|
animationRef.current = window.requestAnimationFrame(updateFrame);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSimulate = () => {
|
||||||
|
if (isSimulating) return;
|
||||||
|
simulate();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTimeStepChange = (event, newValue) => {
|
||||||
|
setTimeStep(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAngleChange = (event, newValue) => {
|
||||||
|
setAsteroid(prev => ({ ...prev, angle: newValue }));
|
||||||
|
calculateForecastPath(asteroid.size, asteroid.speed, newValue, asteroid.mass);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<h1>Asteroid Collision Scenario</h1>
|
||||||
|
<select onChange={handleAsteroidSelect}>
|
||||||
|
{asteroidsData.current.map((ast, index) => (
|
||||||
|
<option key={index} value={index}>{ast.name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<select onChange={(e) => setStrategy(e.target.value)}>
|
||||||
|
<option value="">Select Deflection Strategy</option>
|
||||||
|
<option value="Nuclear Detonation">Nuclear Detonation</option>
|
||||||
|
<option value="Kinetic Impact">Kinetic Impact</option>
|
||||||
|
<option value="Gravity Tractor">Gravity Tractor</option>
|
||||||
|
</select>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={handleSimulate}
|
||||||
|
disabled={isSimulating}
|
||||||
|
style={{ marginTop: '10px' }}
|
||||||
|
>
|
||||||
|
Simulate
|
||||||
|
</Button>
|
||||||
|
{simulationResult && (
|
||||||
|
<div>
|
||||||
|
<h2>Simulation Result</h2>
|
||||||
|
<p>{simulationResult}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{asteroid.name && (
|
||||||
|
<div>
|
||||||
|
<h3>Asteroid Information</h3>
|
||||||
|
<p><strong>Name:</strong> {asteroid.name}</p>
|
||||||
|
<p><strong>Size:</strong> {asteroid.size.toFixed(3)} kilometers</p>
|
||||||
|
<p><strong>Speed:</strong> {(asteroid.speed * 1000).toFixed(3)} km/s</p>
|
||||||
|
<p><strong>Mass:</strong> {asteroid.mass.toExponential(3)} kg</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div>
|
<div>
|
||||||
<p>Scenario</p>
|
<h3>Time Step: {timeStep}</h3>
|
||||||
|
<Slider
|
||||||
|
value={timeStep}
|
||||||
|
min={10}
|
||||||
|
max={500}
|
||||||
|
step={10}
|
||||||
|
onChange={handleTimeStepChange}
|
||||||
|
aria-labelledby="time-step-slider"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
<div>
|
||||||
)
|
<h3>Initial Angle: {(asteroid.angle * 180 / Math.PI).toFixed(2)}°</h3>
|
||||||
}
|
<Slider
|
||||||
|
value={asteroid.angle}
|
||||||
export default Scenario
|
min={0}
|
||||||
|
max={Math.PI / 2}
|
||||||
|
step={Math.PI / 180}
|
||||||
|
onChange={handleAngleChange}
|
||||||
|
aria-labelledby="angle-slider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Stage width={CANVAS_WIDTH} height={CANVAS_HEIGHT}>
|
||||||
|
<Layer>
|
||||||
|
<Text text="Earth" fontSize={20} x={EARTH_X - EARTH_RADIUS_KM * EARTH_DISPLAY_SCALE} y={EARTH_Y - 10} />
|
||||||
|
<Circle x={EARTH_X} y={EARTH_Y} radius={EARTH_RADIUS_KM * EARTH_DISPLAY_SCALE} fill="blue" />
|
||||||
|
<Circle x={asteroid.x} y={asteroid.y} radius={asteroid.size * ASTEROID_DISPLAY_SCALE} fill="gray" stroke="black" strokeWidth={1} />
|
||||||
|
{trajectoryPoints.length > 0 && (
|
||||||
|
<Line points={trajectoryPoints.flat()} stroke="red" strokeWidth={2} />
|
||||||
|
)}
|
||||||
|
{forecastPoints.length > 0 && (
|
||||||
|
<Line points={forecastPoints} stroke="gray" strokeWidth={2} dash={[10, 10]} />
|
||||||
|
)}
|
||||||
|
</Layer>
|
||||||
|
</Stage>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Scenario;
|
||||||
|
|||||||
Reference in New Issue
Block a user