FERS 0.1.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
AntennaInspector.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 Alert,
6 Box,
7 FormControl,
8 InputLabel,
9 MenuItem,
10 Select,
11} from '@mui/material';
12import { Antenna, useScenarioStore } from '@/stores/scenarioStore';
13import { BufferedTextField, FileInput, NumberField } from './InspectorControls';
14
15interface AntennaInspectorProps {
16 item: Antenna;
17}
18
19export function AntennaInspector({ item }: AntennaInspectorProps) {
20 const previewError = useScenarioStore(
21 (state) => state.antennaPreviewErrors[item.id]
22 );
23 const { updateItem, setAntennaPattern } = useScenarioStore.getState();
24 const handleChange = (path: string, value: unknown) =>
25 updateItem(item.id, path, value);
26
27 return (
28 <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
29 <BufferedTextField
30 label="Name"
31 variant="outlined"
32 size="small"
33 fullWidth
34 value={item.name}
35 allowEmpty={false}
36 onChange={(v) => handleChange('name', v)}
37 />
38 <FormControl fullWidth size="small">
39 <InputLabel>Pattern</InputLabel>
40 <Select
41 label="Pattern"
42 value={item.pattern}
43 onChange={(e) =>
44 setAntennaPattern(
45 item.id,
46 e.target.value as Antenna['pattern']
47 )
48 }
49 >
50 <MenuItem value="isotropic">Isotropic</MenuItem>
51 <MenuItem value="sinc">Sinc</MenuItem>
52 <MenuItem value="gaussian">Gaussian</MenuItem>
53 <MenuItem value="squarehorn">Square Horn</MenuItem>
54 <MenuItem value="parabolic">Parabolic</MenuItem>
55 <MenuItem value="xml">XML</MenuItem>
56 <MenuItem value="file">File (H5)</MenuItem>
57 </Select>
58 </FormControl>
59 <NumberField
60 label="Efficiency"
61 value={item.efficiency}
62 emptyBehavior="revert"
63 onChange={(v) => handleChange('efficiency', v)}
64 />
65 <NumberField
66 label="Mesh Scale Multiplier"
67 value={item.meshScale ?? null}
68 emptyBehavior="null"
69 onChange={(v) => handleChange('meshScale', v)}
70 />
71 {previewError && <Alert severity="error">{previewError}</Alert>}
72
73 {item.pattern === 'sinc' && (
74 <>
75 <NumberField
76 label="Alpha"
77 value={item.alpha ?? null}
78 emptyBehavior="revert"
79 onChange={(v) => handleChange('alpha', v)}
80 />
81 <NumberField
82 label="Beta"
83 value={item.beta ?? null}
84 emptyBehavior="revert"
85 onChange={(v) => handleChange('beta', v)}
86 />
87 <NumberField
88 label="Gamma"
89 value={item.gamma ?? null}
90 emptyBehavior="revert"
91 onChange={(v) => handleChange('gamma', v)}
92 />
93 </>
94 )}
95 {item.pattern === 'gaussian' && (
96 <>
97 <NumberField
98 label="Azimuth Scale"
99 value={item.azscale ?? null}
100 emptyBehavior="revert"
101 onChange={(v) => handleChange('azscale', v)}
102 />
103 <NumberField
104 label="Elevation Scale"
105 value={item.elscale ?? null}
106 emptyBehavior="revert"
107 onChange={(v) => handleChange('elscale', v)}
108 />
109 </>
110 )}
111 {(item.pattern === 'squarehorn' ||
112 item.pattern === 'parabolic') && (
113 <>
114 <NumberField
115 label="Diameter (m)"
116 value={item.diameter ?? null}
117 emptyBehavior="revert"
118 onChange={(v) => handleChange('diameter', v)}
119 />
120 <NumberField
121 label="Design Frequency (Hz)"
122 value={item.design_frequency ?? null}
123 emptyBehavior="null"
124 onChange={(v) => handleChange('design_frequency', v)}
125 />
126 </>
127 )}
128
129 {(item.pattern === 'xml' || item.pattern === 'file') && (
130 <>
131 {/* TODO: Support authoring antenna XML in-app. That requires a real editor flow plus UI/store/schema
132 changes for antenna asset contents, rather than treating XML antennas as opaque filename-only assets. */}
133 <FileInput
134 label="Pattern File"
135 value={item.filename}
136 onChange={(v) => handleChange('filename', v)}
137 filters={[
138 {
139 name: 'Antenna Pattern',
140 extensions:
141 item.pattern === 'xml' ? ['xml'] : ['h5'],
142 },
143 { name: 'All Files', extensions: ['*'] },
144 ]}
145 />
146 </>
147 )}
148 </Box>
149 );
150}