Worker version

This commit is contained in:
moxitech 2024-11-18 16:11:36 +07:00
parent 14546dd854
commit af1cefc71c
4 changed files with 164 additions and 165 deletions

View File

@ -29,17 +29,17 @@ http {
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
} }
} }
# server { server {
# listen 80; listen 80;
# server_name ws.localhost; server_name math.localhost;
# # add_header 'Access-Control-Allow-Origin' 'http://socket' always; # add_header 'Access-Control-Allow-Origin' 'http://math' always;
# location / { location / {
# proxy_pass http://socket:9091; proxy_pass http://math:10000;
# proxy_set_header Host $host; proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
# } }
# } }
} }

View File

@ -0,0 +1,22 @@
import { SimDrone } from "../Threejs/Models"
// IPlayerSimulationPart - часть симуляции
// export interface IPlayerSimulationPart {
// Timestamp?: number // Временная метка
// CGS?: [] // базовые станции - DTO
// UAV?: SimDrone[] // беспилотные аппараты - DTO
// }
export interface Drone {
connected_to: string | null;
frequency: number;
name: string;
position: [number, number, number];
rssi: number | null;
}
export interface IPlayerSimulationPart {
[key: string]: {
[droneName: string]: Drone;
};
}

View File

@ -3,6 +3,7 @@ import { Canvas } from '@react-three/fiber';
import { OrbitControls, useGLTF, Line, Text } from '@react-three/drei'; import { OrbitControls, useGLTF, Line, Text } from '@react-three/drei';
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { Drone, BaseStation, SimDrone } from '../Threejs/Models'; import { Drone, BaseStation, SimDrone } from '../Threejs/Models';
import { IPlayerSimulationPart } from './Model';
interface Player { interface Player {
@ -10,7 +11,7 @@ interface Player {
TimeEnd: number; // Время окончания TimeEnd: number; // Время окончания
TimeStep: number; // временной шаг TimeStep: number; // временной шаг
onTimeUpdate?: (currentTime: number) => void; // callback для возврата текущего времени onTimeUpdate?: (currentTime: number) => void; // callback для возврата текущего времени
simulationEndedValues?: object simulationEndedValues?: IPlayerSimulationPart
} }
const InitPlayer: React.FC<Player> = ({ Click, TimeStep, TimeEnd, onTimeUpdate, simulationEndedValues }) => { const InitPlayer: React.FC<Player> = ({ Click, TimeStep, TimeEnd, onTimeUpdate, simulationEndedValues }) => {
@ -20,36 +21,20 @@ const InitPlayer: React.FC<Player> = ({ Click, TimeStep, TimeEnd, onTimeUpdate,
const [isDropdownOpen, setIsDropdownOpen] = useState(false); // состояние выпадающей панели const [isDropdownOpen, setIsDropdownOpen] = useState(false); // состояние выпадающей панели
const [TimestampEnd, setTimestampEnd] = useState<number>(); const [TimestampEnd, setTimestampEnd] = useState<number>();
const [TimestampStep, setTimestampStep] = useState<number>(); const [TimestampStep, setTimestampStep] = useState<number>();
const [Simulations, setSimulations] = useState<IPlayerSimulationPart[]>(); const [Simulations, setSimulations] = useState<IPlayerSimulationPart>();
const ParseSimulationResponse = (simulationResponse: any): IPlayerSimulationPart[] => {
const parsedParts: IPlayerSimulationPart[] = Object.keys(simulationResponse).map((timestamp) => {
const drones = Object.values(simulationResponse[timestamp]).map((drone: any) => ({
connected_to: drone.connected_to,
position: drone.position as [number, number, number],
rssi: drone.rssi,
name: drone.name,
frequency: drone.frequency,
}));
return {
Timestamp: parseInt(timestamp, 10),
UAV: drones,
};
});
return parsedParts;
};
useEffect(() => { useEffect(() => {
let interval: NodeJS.Timeout | null = null; let interval: NodeJS.Timeout | null = null;
if (simulationEndedValues) { if (simulationEndedValues) {
console.log("TODO: parse this pls") setSimulations(simulationEndedValues);
// console.log(simulationEndedValues);
console.log(simulationEndedValues)
setTimestampStep(1)
setTimestampEnd(299)
} else { } else {
fetch("/tests/test_results.json") fetch("/tests/test_results.json")
.then(simulationResponse => simulationResponse.json().then(val => { .then(simulationResponse => simulationResponse.json().then(val => {
let parts = ParseSimulationResponse(val)
setSimulations(parts)
setTimestampStep(1) setTimestampStep(1)
setTimestampEnd(100) setTimestampEnd(100)
})) }))
@ -79,7 +64,7 @@ const InitPlayer: React.FC<Player> = ({ Click, TimeStep, TimeEnd, onTimeUpdate,
clearInterval(interval); clearInterval(interval);
} }
}; };
}, [isPlaying, TimeStep, TimeEnd, playbackSpeed, onTimeUpdate]); }, [isPlaying, TimeStep, TimeEnd, playbackSpeed, onTimeUpdate, simulationEndedValues]);
const handlePlayPause = () => { const handlePlayPause = () => {
setIsPlaying(!isPlaying); setIsPlaying(!isPlaying);
@ -99,7 +84,7 @@ const InitPlayer: React.FC<Player> = ({ Click, TimeStep, TimeEnd, onTimeUpdate,
return ( return (
<div className="bg-slate-600 p-4 rounded-md w-full max-w-5xl mx-auto"> <div className="bg-slate-600 p-4 rounded-md w-full max-w-5xl mx-auto">
<PlayerTsInstance/> <PlayerTsInstance Simulations={Simulations}/>
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<a href='/pages/simulations' <a href='/pages/simulations'
className={`text-white p-2 rounded-md bg-green-600`} className={`text-white p-2 rounded-md bg-green-600`}
@ -128,7 +113,7 @@ const InitPlayer: React.FC<Player> = ({ Click, TimeStep, TimeEnd, onTimeUpdate,
className="w-full" className="w-full"
/> />
<div className="text-white mt-2"> <div className="text-white mt-2">
Текущее время: {currentTime}s / {TimeEnd}s Текущее время: {currentTime}s / 299s
</div> </div>
</div> </div>
<div className="mt-4 relative"> <div className="mt-4 relative">
@ -159,159 +144,131 @@ const InitPlayer: React.FC<Player> = ({ Click, TimeStep, TimeEnd, onTimeUpdate,
); );
}; };
// IPlayerSimulationPart - часть симуляции
interface IPlayerSimulationPart {
Timestamp?: number // Временная метка
CGS?: [] // базовые станции - DTO
UAV?: SimDrone[] // беспилотные аппараты - DTO
}
// IPlayerTsInstance - объект плеера // IPlayerTsInstance - объект плеера
interface IPlayerTsInstance { interface IPlayerTsInstance {
TimestampEnd?: number TimestampEnd?: number
TimestampStep?: number TimestampStep?: number
Simulations?: IPlayerSimulationPart[] Simulations?: IPlayerSimulationPart
//// IPlayerSimulationPart - часть симуляции
// interface Drone {
// connected_to: string | null;
// frequency: number;
// name: string;
// position: [number, number, number];
// rssi: number | null;
// }
// interface IPlayerSimulationPart {
// [key: string]: {
// [droneName: string]: Drone;
// };
// }
} }
const PlayerTsInstance : React.FC<IPlayerTsInstance> = ({ const PlayerTsInstance: React.FC<IPlayerTsInstance> = ({
TimestampEnd, TimestampEnd = 299, // Конечная временная метка
TimestampStep, TimestampStep = 1, // Шаг временной метки
Simulations Simulations,
}) => { }) => {
const [currentTimestamp, setCurrentTimestamp] = useState(0);
const [drones, setDrones] = useState<Drone[]>([]); const [drones, setDrones] = useState<Drone[]>([]);
const [baseStations, setBaseStations] = useState<BaseStation[]>([]); const [baseStations, setBaseStations] = useState<BaseStation[]>([]);
const [selectedObject, setSelectedObject] = useState<{ type: 'drone' | 'baseStation'; id: number } | null>(null); const [isPlaying, setIsPlaying] = useState(false); // Флаг для управления анимацией
const orbitControlsRef = useRef<any>(null); // Reference to OrbitControls
const addDrone = (drone?: Drone) => {
setDrones((prev) => [
...prev,
drone || {
id: prev.length,
name: `Drone ${prev.length + 1}`,
position: [Math.random() * 10, 5, 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
},
]);
};
const addBaseStation = (baseStation?: BaseStation) => { const intervalRef = useRef<NodeJS.Timeout | null>(null);
setBaseStations((prev) => [
...prev,
baseStation || {
id: prev.length,
name: `Base Station ${prev.length + 1}`,
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],
},
]);
};
useEffect(() => {
// Инициализация объектов на начальной метке времени
const handleObjectClick = (type: 'drone' | 'baseStation', id: number) => { if (Simulations) {
setSelectedObject({ type, id }); updateObjects(currentTimestamp);
focusOnObject(type, id); }
}; }, [Simulations, currentTimestamp]);
const focusOnObject = (type: 'drone' | 'baseStation', id: number) => { const updateObjects = (timestamp: number) => {
const object = type === 'drone' ? drones.find((d) => d.id === id) : baseStations.find((b) => b.id === id); if (!Simulations) return;
if (object && orbitControlsRef.current) {
orbitControlsRef.current.target.set(...object.position); const simulationStep = Simulations[timestamp];
if (simulationStep) {
const updatedDrones = Object.values(simulationStep).map((drone) => ({
...drone,
}));
// @ts-ignore
setDrones(updatedDrones);
} }
}; };
const selectNextObject = (direction: 'next' | 'prev') => { const startSimulation = () => {
if (!selectedObject) return; if (!Simulations || isPlaying) return;
const currentList = selectedObject.type === 'drone' ? drones : baseStations; setIsPlaying(true);
const currentIndex = currentList.findIndex((obj) => obj.id === selectedObject.id); intervalRef.current = setInterval(() => {
const newIndex = direction === 'next' setCurrentTimestamp((prev) => {
? (currentIndex + 1) % currentList.length const nextTimestamp = prev + TimestampStep;
: (currentIndex - 1 + currentList.length) % currentList.length; if (nextTimestamp >= TimestampEnd) {
setSelectedObject({ type: selectedObject.type, id: currentList[newIndex].id }); clearInterval(intervalRef.current!);
focusOnObject(selectedObject.type, currentList[newIndex].id); setIsPlaying(false);
return prev; // Остановим на последней метке
}
return nextTimestamp;
});
}, 100); // Интервал обновления в миллисекундах
};
const stopSimulation = () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
setIsPlaying(false);
};
const resetSimulation = () => {
stopSimulation();
setCurrentTimestamp(0);
if (Simulations) updateObjects(0); // Сброс объектов к начальной метке
}; };
return ( return (
<div className='mt-20'> <div className="mt-20">
<div style={{ height: '550px' }} /> <div style={{ height: '550px' }} />
<div className='border border-blue-500 bg-blue-500 flex justify-center items-start'> <div className="border border-blue-500 bg-blue-500 flex justify-center items-start">
<Canvas <Canvas style={{ height: '550px', width: '1100px' }} shadows>
style={{ height: '550px', width: '1100px' }}
shadows
>
<ambientLight intensity={0.5} /> <ambientLight intensity={0.5} />
<directionalLight position={[5, 10, 5]} intensity={1} castShadow /> <directionalLight position={[5, 10, 5]} intensity={1} castShadow />
<pointLight position={[10, 10, 10]} intensity={0.8} /> <pointLight position={[10, 10, 10]} intensity={0.8} />
<spotLight position={[-10, 15, 10]} angle={0.3} intensity={0.7} castShadow /> <spotLight position={[-10, 15, 10]} angle={0.3} intensity={0.7} castShadow />
<OrbitControls ref={orbitControlsRef} /> <OrbitControls />
<MapModel /> <MapModel />
{baseStations.map((baseStation) => ( {baseStations.map((baseStation) => (
<BaseStationModel <BaseStationModel
key={baseStation.id} key={baseStation.id}
onClick={() => handleObjectClick('baseStation', baseStation.id)}
isSelected={selectedObject?.type === 'baseStation' && selectedObject.id === baseStation.id}
position={baseStation.position} position={baseStation.position}
// @ts-ignore
baseStationName={baseStation.name}
/> />
))} ))}
{drones.map((drone) => ( {drones.map((drone) => (
// @ts-ignore
<DroneModel <DroneModel
key={drone.id} key={drone.name}
position={drone.position} position={drone.position}
droneName={drone.name} droneName={drone.name}
onClick={() => 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 (
<Line
key={`link-${drone.id}-${baseStation.id}`}
points={[drone.position, baseStation.position]}
color="yellow"
lineWidth={Math.min(drone.frequency, baseStation.frequency) / 200} // Adjust line width based on frequency
dashed={false}
/>
);
}
return null;
})
))}
{baseStations.map((baseStation) => (
baseStation.signalRadius > 0 && (
<mesh key={`signal-${baseStation.id}`} position={baseStation.position}>
<sphereGeometry args={[baseStation.signalRadius, 32, 32]} />
<meshBasicMaterial color="red" opacity={0.3} transparent />
</mesh>
)
))}
{drones.map((drone) => (
drone.signalRadius > 0 && (
<mesh key={`signal-${drone.id}`} position={drone.position}>
<sphereGeometry args={[drone.signalRadius, 32, 32]} />
<meshBasicMaterial color="green" opacity={0.3} transparent />
</mesh>
)
))}
</Canvas> </Canvas>
</div> </div>
<div className='col-auto row-auto m-auto items-center'> <div className="col-auto row-auto m-auto items-center">
<button onClick={() => selectNextObject('prev')} className="p-2 m-2 bg-yellow-500 text-white rounded transition duration-300 ease-in-out transform hover:scale-105 focus:scale-95">&lt;</button> <button onClick={startSimulation} disabled={isPlaying} className="p-2 m-2 bg-green-500 text-white rounded">
<button onClick={() => selectNextObject('next')} className="p-2 m-2 bg-yellow-500 text-white rounded transition duration-300 ease-in-out transform hover:scale-105 focus:scale-95">&gt;</button> Start
</button>
<button onClick={stopSimulation} className="p-2 m-2 bg-red-500 text-white rounded">
Stop
</button>
<button onClick={resetSimulation} className="p-2 m-2 bg-gray-500 text-white rounded">
Reset
</button>
</div> </div>
</div> </div>
); );
}; };
@ -344,6 +301,10 @@ const DroneModel = ({ position, droneName, onClick, isSelected }: { position: [n
<meshBasicMaterial color="red" wireframe /> <meshBasicMaterial color="red" wireframe />
</mesh> </mesh>
)} )}
<mesh position={position}>
<sphereGeometry args={[1, 16, 16]} />
<meshBasicMaterial color="red" wireframe />
</mesh>
</group> </group>
); );
}; };

View File

@ -1,4 +1,5 @@
"use client"; "use client";
import { IPlayerSimulationPart } from '@/app/components/Player/Model';
import InitPlayer from '@/app/components/Player/Player'; import InitPlayer from '@/app/components/Player/Player';
import { BaseStation, Drone } from '@/app/components/Threejs/Models'; import { BaseStation, Drone } from '@/app/components/Threejs/Models';
import ThreeJsInstance from '@/app/components/Threejs/ThreeJsInstance'; import ThreeJsInstance from '@/app/components/Threejs/ThreeJsInstance';
@ -8,7 +9,7 @@ import React, { useEffect, useState } from 'react';
const Simulations: React.FC = () => { const Simulations: React.FC = () => {
const [activeSimulationWindow, setActiveSimulationWindow] = useState(false); const [activeSimulationWindow, setActiveSimulationWindow] = useState(false);
const [mathServer, setMathServer] = useState(""); const [mathServer, setMathServer] = useState("");
const [simulationDto, setSimulationDto] = useState({}); const [simulationDto, setSimulationDto] = useState<IPlayerSimulationPart>();
const ActiveSimulation = (value: boolean, Drones : Drone[], CGS: BaseStation[]) => { const ActiveSimulation = (value: boolean, Drones : Drone[], CGS: BaseStation[]) => {
// Используя mathServer - отправляем массив данных // Используя mathServer - отправляем массив данных
@ -20,7 +21,7 @@ const Simulations: React.FC = () => {
position: drone.position, position: drone.position,
freq: drone.frequency, freq: drone.frequency,
radius: drone.signalRadius, radius: drone.signalRadius,
endpoints: [[0, 0, 1], [10, 0, 1]], // TODO: статические значения endpoints: [[0, 5, 1], [10, 5, 1]], // TODO: статические значения
speed: 1 // TODO: можно изменить при необходимости speed: 1 // TODO: можно изменить при необходимости
})); }));
@ -43,25 +44,40 @@ const Simulations: React.FC = () => {
sendToMathServer(simulationData); sendToMathServer(simulationData);
// Устанавливает окно симуляции // Устанавливает окно симуляции
setActiveSimulationWindow(value); setActiveSimulationWindow(value);
}; };
// Пример функции для отправки данных // Пример функции для отправки данных
const sendToMathServer = (data: object) => { const sendToMathServer = (data: object) => {
console.log("Sending simulation data:", JSON.stringify(data, null, 2)); console.log("Sending simulation data:", JSON.stringify(data, null, 2));
// Реализовать отправку данных, например, через fetch
fetch(mathServer, {
method: 'POST', const myHeaders = new Headers();
headers: { myHeaders.append("Content-Type", "application/json");
'Content-Type': 'application/json'
}, const requestOptions : RequestInit = {
body: JSON.stringify(data) method: "POST",
}).then( headers: myHeaders,
out => console.log(out) body: JSON.stringify(data),
// TODO: setup to end redirect: "follow"
};
fetch(mathServer, requestOptions).then(
// TODO: setup to end
out => {
if (out.status == 200){
// console.log(out.json())
const val = out.json() as Promise<IPlayerSimulationPart>
val.then(v => {
setSimulationDto(v)
console.log(v)
});
} else {
console.log(out)
}
}
); );
}; };
useEffect(() => { useEffect(() => {
setMathServer("http://localhost:10000/simulation/forceRunCalc/") setMathServer("http://localhost:10000/simulation/forceRunCalc")
}, []) }, [])
return ( return (
@ -74,7 +90,7 @@ const Simulations: React.FC = () => {
Click={() => {}} Click={() => {}}
TimeEnd={100} TimeEnd={100}
TimeStep={1} TimeStep={1}
// simulationEndedValues={null} // TODO: SET AFTER SIMULATION REALY COMPLETE simulationEndedValues={simulationDto} // TODO: SET AFTER SIMULATION REALY COMPLETE
/> />
</div> : <ThreeJsInstance </div> : <ThreeJsInstance
Click={ActiveSimulation} Click={ActiveSimulation}