diff --git a/src/usn-frontend/src/app/components/Modal/Modal.tsx b/src/usn-frontend/src/app/components/Modal/Modal.tsx index 704c7af..0a9a16c 100644 --- a/src/usn-frontend/src/app/components/Modal/Modal.tsx +++ b/src/usn-frontend/src/app/components/Modal/Modal.tsx @@ -36,11 +36,11 @@ const Modal: React.FC = ({ children, isOpen, onClose }) => { onClick={onClose} >
e.stopPropagation()} // Prevent closing when clicking inside the modal > +
+
+ {/* Полоска плеера симуляции */} + +
+ Текущее время: {currentTime}s / {TimeEnd}s +
+
+
+ {/* Панель изменения скорости воспроизведения */} + + {isDropdownOpen && ( +
+
    + {[0.5, 1, 1.5, 2].map((speed) => ( +
  • handleSpeedChange(speed)} + className="px-4 py-2 hover:bg-gray-600 cursor-pointer" + > + {speed}x +
  • + ))} +
+
+ )} +
+ + ); +}; + +export default InitPlayer; + diff --git a/src/usn-frontend/src/app/components/Sidebar/Sidebar.tsx b/src/usn-frontend/src/app/components/Sidebar/Sidebar.tsx index 040330d..28bd648 100644 --- a/src/usn-frontend/src/app/components/Sidebar/Sidebar.tsx +++ b/src/usn-frontend/src/app/components/Sidebar/Sidebar.tsx @@ -96,7 +96,7 @@ export default function NavBar() {
  • {item.icon} {item.name} diff --git a/src/usn-frontend/src/app/components/SimulationWindow/SimulationWindow.tsx b/src/usn-frontend/src/app/components/SimulationWindow/SimulationWindow.tsx new file mode 100644 index 0000000..fdc3fef --- /dev/null +++ b/src/usn-frontend/src/app/components/SimulationWindow/SimulationWindow.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import InitPlayer from "../Player/Player" + + + +interface ISimulation { + TimeEnd: number; + TimeStep: number; + ResultSourceOrUrl?: string; + OnLoading?: () => void; +} + +// SimulationWindow -Основное окно с симуляцией +// на вход подается словарь время:Массив объектов +// массив объектов рендериться согласно времени и параметрам объектов +const SimulationWindow: React.FC = ({TimeEnd, TimeStep, ResultSourceOrUrl, OnLoading}) => { + return ( + {console.log("STOP")}} TimeEnd={1000} TimeStep={1} onTimeUpdate={(e) => {console.log(e)}}> + + + ) +} \ No newline at end of file diff --git a/src/usn-frontend/src/app/components/Threejs/ThreeJsInstance.tsx b/src/usn-frontend/src/app/components/Threejs/ThreeJsInstance.tsx index e3faa9f..0ad2426 100644 --- a/src/usn-frontend/src/app/components/Threejs/ThreeJsInstance.tsx +++ b/src/usn-frontend/src/app/components/Threejs/ThreeJsInstance.tsx @@ -1,8 +1,9 @@ "use client"; import { Canvas } from '@react-three/fiber'; -import { OrbitControls, useGLTF, Line } from '@react-three/drei'; +import { OrbitControls, useGLTF, Line, Text } from '@react-three/drei'; import { useState, useEffect, useRef } from 'react'; import { Drone, BaseStation } from './Models'; +import { PlayCircleIcon } from '@heroicons/react/24/outline'; import FormComponent from '../ObjectProps/FormComponent'; import Modal from '../Modal/Modal'; @@ -12,7 +13,24 @@ const ThreeJsInstance = () => { const [selectedObject, setSelectedObject] = useState<{ type: 'drone' | 'baseStation'; id: number } | null>(null); const [isModalOpen, setIsModalOpen] = useState(false); const orbitControlsRef = useRef(null); // Reference to OrbitControls + const handleJsonUpload = (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (!file) return; + const reader = new FileReader(); + reader.onload = (e) => { + try { + const content = e.target?.result; + if (typeof content === "string") { + const jsonData = JSON.parse(content); + console.log(jsonData); + } + } catch (error) { + console.error("Ошибка при чтении файла:", error); + } + }; + reader.readAsText(file); + }; const addDrone = (drone?: Drone) => { setDrones((prev) => [ ...prev, @@ -32,7 +50,7 @@ const ThreeJsInstance = () => { baseStation || { id: prev.length, name: `Base Station ${prev.length + 1}`, - position: [Math.random() * 10, 20, Math.random() * 10], + position: [Math.random() * 10, -1, Math.random() * 10], frequency: Math.random() * 100 + 400, // Example frequency range between 400-500 signalRadius: Math.random() * 5 + 5, // Example signal radius between 5-10 antennaDirection: [0, 1, 0], @@ -84,94 +102,151 @@ const ThreeJsInstance = () => { }; return ( - <> - - - - - - - - {baseStations.map((baseStation) => ( - handleObjectClick('baseStation', baseStation.id)} - isSelected={selectedObject?.type === 'baseStation' && selectedObject.id === baseStation.id} - position={baseStation.position} - /> - ))} - {drones.map((drone) => ( - handleObjectClick('drone', drone.id)} - isSelected={selectedObject?.type === 'drone' && selectedObject.id === drone.id} - /> - ))} - {drones.flatMap((drone) => ( - baseStations.map((baseStation) => { - const distance = Math.sqrt( - Math.pow(drone.position[0] - baseStation.position[0], 2) + - Math.pow(drone.position[1] - baseStation.position[1], 2) + - Math.pow(drone.position[2] - baseStation.position[2], 2) - ); - - if (distance <= drone.signalRadius && distance <= baseStation.signalRadius) { - return ( - +
    +
    +
    + + + + + + + + {baseStations.map((baseStation) => ( + handleObjectClick('baseStation', baseStation.id)} + isSelected={selectedObject?.type === 'baseStation' && selectedObject.id === baseStation.id} + position={baseStation.position} + /> + ))} + {drones.map((drone) => ( + handleObjectClick('drone', drone.id)} + isSelected={selectedObject?.type === 'drone' && selectedObject.id === drone.id} + /> + ))} + {drones.flatMap((drone) => ( + baseStations.map((baseStation) => { + const distance = Math.sqrt( + Math.pow(drone.position[0] - baseStation.position[0], 2) + + Math.pow(drone.position[1] - baseStation.position[1], 2) + + Math.pow(drone.position[2] - baseStation.position[2], 2) ); - } - return null; - }) - ))} - - - - - - - {selectedObject && ( - setIsModalOpen(false)}> -
    - {selectedObject.type === 'drone' && ( - d.id === selectedObject.id)!} - onUpdate={handleUpdate} - /> - )} - {selectedObject.type === 'baseStation' && ( - b.id === selectedObject.id)!} - onUpdate={handleUpdate} - /> - )} -
    -
    - )} - + if (distance <= drone.signalRadius && distance <= baseStation.signalRadius) { + return ( + + ); + } + return null; + }) + ))} + {baseStations.map((baseStation) => ( + baseStation.signalRadius > 0 && ( + + + + + ) + ))} + {drones.map((drone) => ( + drone.signalRadius > 0 && ( + + + + + ) + ))} + +
    + + <> + + + + + + + + + {selectedObject && ( + setIsModalOpen(false)}> +
    + {selectedObject.type === 'drone' && ( + d.id === selectedObject.id)!} + onUpdate={handleUpdate} + /> + )} + {selectedObject.type === 'baseStation' && ( + b.id === selectedObject.id)!} + onUpdate={handleUpdate} + /> + )} +
    +
    + )} + + + +
    + {/* TODO: EXTERNAL COMPONENT */} +
    + Тестовая симуляция 1 +
    + +
    +
    ); }; const MapModel = () => { const { scene } = useGLTF('/map/map.glb'); - return ; + return ; }; -const DroneModel = ({ position, onClick, isSelected }: { position: [number, number, number]; onClick: () => void; isSelected: boolean }) => { +const DroneModel = ({ position, droneName, onClick, isSelected }: { position: [number, number, number]; droneName?: string; onClick: () => void; isSelected: boolean }) => { const { scene } = useGLTF('/objects/drone.glb'); return ( - + + {/* Добавляем текстовую подпись над дроном */} + + {droneName} + {isSelected && ( - + )} diff --git a/src/usn-frontend/src/app/pages/simulations/page.tsx b/src/usn-frontend/src/app/pages/simulations/page.tsx index 04fc13c..25bd73b 100644 --- a/src/usn-frontend/src/app/pages/simulations/page.tsx +++ b/src/usn-frontend/src/app/pages/simulations/page.tsx @@ -1,13 +1,17 @@ +"use client"; import ThreeJsInstance from '@/app/components/Threejs/ThreeJsInstance'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; const Simulations: React.FC = () => { + const [activeSimalationWindow, setActiveSimalationWindow] = useState(false); + return (
    - + {activeSimalationWindow ?
    +
    : }