FERS 1.0.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
GlobalParametersInspector.tsx
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (c) 2025-present FERS Contributors (see AUTHORS.md).
3
4import {
5 Box,
6 Button,
7 Dialog,
8 DialogActions,
9 DialogContent,
10 DialogContentText,
11 DialogTitle,
12 FormControl,
13 InputLabel,
14 MenuItem,
15 Select,
16 TextField,
17} from '@mui/material';
18import { useState } from 'react';
19import { GlobalParameters, useScenarioStore } from '@/stores/scenarioStore';
20import { NumberField, Section } from './InspectorControls';
21
22interface GlobalParametersInspectorProps {
23 item: GlobalParameters;
24}
25
26export function GlobalParametersInspector({
27 item,
28}: GlobalParametersInspectorProps) {
29 const updateItem = useScenarioStore((s) => s.updateItem);
30 const setRotationAngleUnit = useScenarioStore(
31 (s) => s.setRotationAngleUnit
32 );
33 const platforms = useScenarioStore((s) => s.platforms);
34 const handleChange = (path: string, value: unknown) =>
35 updateItem(item.id, path, value);
36 const [pendingRotationUnit, setPendingRotationUnit] = useState<
37 GlobalParameters['rotationAngleUnit'] | null
38 >(null);
39
40 const hasExistingRotationValues = platforms.some((platform) => {
41 if (platform.rotation.type === 'fixed') {
42 return [
43 platform.rotation.startAzimuth,
44 platform.rotation.startElevation,
45 platform.rotation.azimuthRate,
46 platform.rotation.elevationRate,
47 ].some((value) => value !== 0);
48 }
49 return platform.rotation.waypoints.some(
50 (waypoint) => waypoint.azimuth !== 0 || waypoint.elevation !== 0
51 );
52 });
53
54 const handleRotationUnitChange = (
55 nextUnit: GlobalParameters['rotationAngleUnit']
56 ) => {
57 if (nextUnit === item.rotationAngleUnit) {
58 return;
59 }
60 if (hasExistingRotationValues) {
61 setPendingRotationUnit(nextUnit);
62 return;
63 }
64 setRotationAngleUnit(nextUnit, false);
65 };
66
67 return (
68 <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
69 <FormControl fullWidth size="small">
70 <InputLabel>Rotation Angle Unit</InputLabel>
71 <Select
72 label="Rotation Angle Unit"
73 value={item.rotationAngleUnit}
74 onChange={(e) =>
75 handleRotationUnitChange(
76 e.target
77 .value as GlobalParameters['rotationAngleUnit']
78 )
79 }
80 >
81 <MenuItem value="deg">Degrees</MenuItem>
82 <MenuItem value="rad">Radians</MenuItem>
83 </Select>
84 </FormControl>
85 <TextField
86 label="Simulation Name"
87 variant="outlined"
88 size="small"
89 fullWidth
90 value={item.simulation_name}
91 onChange={(e) =>
92 handleChange('simulation_name', e.target.value)
93 }
94 />
95 <NumberField
96 label="Start Time (s)"
97 value={item.start}
98 onChange={(v) => handleChange('start', v)}
99 />
100 <NumberField
101 label="End Time (s)"
102 value={item.end}
103 onChange={(v) => handleChange('end', v)}
104 />
105 <NumberField
106 label="Output Sampling Rate (Hz)"
107 value={item.rate}
108 onChange={(v) => handleChange('rate', v)}
109 />
110 <NumberField
111 label="Internal Sim Sampling Rate (Hz)"
112 value={item.simSamplingRate}
113 onChange={(v) => handleChange('simSamplingRate', v)}
114 />
115 <NumberField
116 label="Speed of Light (m/s)"
117 value={item.c}
118 onChange={(v) => handleChange('c', v)}
119 />
120 <NumberField
121 label="Random Seed"
122 value={item.random_seed}
123 onChange={(v) => handleChange('random_seed', v)}
124 />
125 <NumberField
126 label="ADC Bits"
127 value={item.adc_bits}
128 onChange={(v) => handleChange('adc_bits', v)}
129 />
130 <NumberField
131 label="Oversample Ratio"
132 value={item.oversample_ratio}
133 onChange={(v) => handleChange('oversample_ratio', v)}
134 />
135
136 <Section title="Georeference">
137 <NumberField
138 label="Origin Latitude (deg)"
139 value={item.origin.latitude}
140 onChange={(v) => handleChange('origin.latitude', v)}
141 />
142 <NumberField
143 label="Origin Longitude (deg)"
144 value={item.origin.longitude}
145 onChange={(v) => handleChange('origin.longitude', v)}
146 />
147 <NumberField
148 label="Origin Altitude (m)"
149 value={item.origin.altitude}
150 onChange={(v) => handleChange('origin.altitude', v)}
151 />
152 <FormControl fullWidth size="small">
153 <InputLabel>Coordinate System</InputLabel>
154 <Select
155 label="Coordinate System"
156 value={item.coordinateSystem.frame}
157 onChange={(e) =>
158 handleChange(
159 'coordinateSystem.frame',
160 e.target.value
161 )
162 }
163 >
164 <MenuItem value="ENU">ENU (East-North-Up)</MenuItem>
165 <MenuItem value="UTM">UTM</MenuItem>
166 <MenuItem value="ECEF">ECEF</MenuItem>
167 </Select>
168 </FormControl>
169 {item.coordinateSystem.frame === 'UTM' && (
170 <>
171 <NumberField
172 label="UTM Zone"
173 value={item.coordinateSystem.zone ?? null}
174 onChange={(v) =>
175 handleChange('coordinateSystem.zone', v)
176 }
177 />
178 <FormControl fullWidth size="small">
179 <InputLabel>UTM Hemisphere</InputLabel>
180 <Select
181 label="UTM Hemisphere"
182 value={item.coordinateSystem.hemisphere ?? 'N'}
183 onChange={(e) =>
184 handleChange(
185 'coordinateSystem.hemisphere',
186 e.target.value
187 )
188 }
189 >
190 <MenuItem value="N">North</MenuItem>
191 <MenuItem value="S">South</MenuItem>
192 </Select>
193 </FormControl>
194 </>
195 )}
196 </Section>
197 <Dialog
198 open={pendingRotationUnit !== null}
199 onClose={() => setPendingRotationUnit(null)}
200 >
201 <DialogTitle>Change Rotation Angle Unit</DialogTitle>
202 <DialogContent>
203 <DialogContentText>
204 Existing rotation values are present. Convert them to
205 keep the same physical orientation and rates, or keep
206 the numeric values as they are.
207 </DialogContentText>
208 </DialogContent>
209 <DialogActions>
210 <Button onClick={() => setPendingRotationUnit(null)}>
211 Cancel
212 </Button>
213 <Button
214 onClick={() => {
215 if (pendingRotationUnit) {
216 setRotationAngleUnit(
217 pendingRotationUnit,
218 false
219 );
220 }
221 setPendingRotationUnit(null);
222 }}
223 >
224 Keep Numeric Values
225 </Button>
226 <Button
227 variant="contained"
228 onClick={() => {
229 if (pendingRotationUnit) {
230 setRotationAngleUnit(pendingRotationUnit, true);
231 }
232 setPendingRotationUnit(null);
233 }}
234 >
235 Convert Existing Values
236 </Button>
237 </DialogActions>
238 </Dialog>
239 </Box>
240 );
241}