add multiplier for simulation time in editor and main window
This commit is contained in:
parent
1094f63b4c
commit
19547f8764
@ -40,24 +40,31 @@
|
||||
"trajectory": [
|
||||
{
|
||||
"maneuver_type": "Fly to Point",
|
||||
"duration_s": 10.0,
|
||||
"duration_s": 1.0,
|
||||
"target_altitude_ft": 10000.0,
|
||||
"target_range_nm": 20.0,
|
||||
"target_range_nm": 10.0,
|
||||
"target_azimuth_deg": 0.0
|
||||
},
|
||||
{
|
||||
"maneuver_type": "Fly for Duration",
|
||||
"target_velocity_fps": 506.343,
|
||||
"target_velocity_fps": 1687.81,
|
||||
"target_heading_deg": 10.0,
|
||||
"duration_s": 10.0,
|
||||
"duration_s": 30.0,
|
||||
"target_altitude_ft": 10000.0
|
||||
},
|
||||
{
|
||||
"maneuver_type": "Fly for Duration",
|
||||
"target_velocity_fps": 506.343,
|
||||
"target_heading_deg": 90.0,
|
||||
"duration_s": 10.0,
|
||||
"target_heading_deg": -90.0,
|
||||
"duration_s": 30.0,
|
||||
"target_altitude_ft": 10000.0
|
||||
},
|
||||
{
|
||||
"maneuver_type": "Fly to Point",
|
||||
"duration_s": 30.0,
|
||||
"target_altitude_ft": 10000.0,
|
||||
"target_range_nm": 40.0,
|
||||
"target_azimuth_deg": 0.0
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@ class SimulationEngine(threading.Thread):
|
||||
|
||||
self.communicator = communicator
|
||||
self.update_queue = update_queue
|
||||
self.time_multiplier = 1.0
|
||||
|
||||
self.scenario: Optional[Scenario] = None
|
||||
self._stop_event = threading.Event()
|
||||
@ -43,6 +44,11 @@ class SimulationEngine(threading.Thread):
|
||||
self.scenario = scenario
|
||||
self.scenario.reset_simulation()
|
||||
|
||||
def set_time_multiplier(self, multiplier: float):
|
||||
"""Sets the simulation time speed multiplier."""
|
||||
self.logger.info(f"Setting simulation time multiplier to {multiplier}x")
|
||||
self.time_multiplier = multiplier
|
||||
|
||||
def run(self):
|
||||
"""The main loop of the simulation thread."""
|
||||
self.logger.info("Simulation engine thread started.")
|
||||
@ -58,9 +64,10 @@ class SimulationEngine(threading.Thread):
|
||||
current_time = time.monotonic()
|
||||
delta_time = current_time - self._last_tick_time
|
||||
self._last_tick_time = current_time
|
||||
simulated_delta_time = delta_time * self.time_multiplier
|
||||
|
||||
# --- Simulation Step (always runs) ---
|
||||
self.scenario.update_state(delta_time)
|
||||
self.scenario.update_state(simulated_delta_time)
|
||||
|
||||
updated_targets = self.scenario.get_all_targets()
|
||||
|
||||
|
||||
@ -51,6 +51,7 @@ class MainView(tk.Tk):
|
||||
self.simulation_engine: Optional[SimulationEngine] = None
|
||||
self.gui_update_queue = Queue()
|
||||
self.is_simulation_running = tk.BooleanVar(value=False)
|
||||
self.time_multiplier = 1.0
|
||||
|
||||
# --- Window and UI Setup ---
|
||||
self.title("Radar Target Simulator")
|
||||
@ -140,6 +141,12 @@ class MainView(tk.Tk):
|
||||
self.reset_button = ttk.Button(engine_frame, text="Reset State", command=self._on_reset_simulation)
|
||||
self.reset_button.pack(side=tk.RIGHT, padx=5, pady=5)
|
||||
|
||||
ttk.Label(engine_frame, text="Speed:").pack(side=tk.LEFT, padx=(10, 2), pady=5)
|
||||
self.time_multiplier_var = tk.StringVar(value="1x")
|
||||
self.multiplier_combo = ttk.Combobox(engine_frame, textvariable=self.time_multiplier_var, values=["1x", "2x", "4x", "10x"], state="readonly", width=4)
|
||||
self.multiplier_combo.pack(side=tk.LEFT, padx=(0, 5), pady=5)
|
||||
self.multiplier_combo.bind("<<ComboboxSelected>>", self._on_time_multiplier_changed)
|
||||
|
||||
# --- TAB 3: LRU SIMULATION ---
|
||||
lru_tab = ttk.Frame(left_notebook)
|
||||
left_notebook.add(lru_tab, text="LRU Simulation")
|
||||
@ -276,6 +283,7 @@ class MainView(tk.Tk):
|
||||
|
||||
self.scenario.reset_simulation()
|
||||
self.simulation_engine = SimulationEngine(self.target_communicator, self.gui_update_queue)
|
||||
self.simulation_engine.set_time_multiplier(self.time_multiplier)
|
||||
self.simulation_engine.load_scenario(self.scenario)
|
||||
self.simulation_engine.start()
|
||||
|
||||
@ -314,6 +322,7 @@ class MainView(tk.Tk):
|
||||
|
||||
self.start_button.config(state=tk.DISABLED if is_running else tk.NORMAL)
|
||||
self.stop_button.config(state=tk.NORMAL if is_running else tk.DISABLED)
|
||||
self.multiplier_combo.config(state="readonly" if not is_running else tk.DISABLED)
|
||||
|
||||
self.scenario_controls.new_button.config(state=state)
|
||||
self.scenario_controls.save_button.config(state=state)
|
||||
@ -326,6 +335,17 @@ class MainView(tk.Tk):
|
||||
self.target_list.edit_button.config(state=state)
|
||||
self.target_list.tree.config(selectmode="browse" if not is_running else "none")
|
||||
|
||||
def _on_time_multiplier_changed(self, event=None):
|
||||
"""Handles changes to the time multiplier selection."""
|
||||
try:
|
||||
multiplier_str = self.time_multiplier_var.get().replace('x', '')
|
||||
self.time_multiplier = float(multiplier_str)
|
||||
if self.simulation_engine and self.simulation_engine.is_running():
|
||||
self.simulation_engine.set_time_multiplier(self.time_multiplier)
|
||||
except ValueError:
|
||||
self.logger.error(f"Invalid time multiplier value: {self.time_multiplier_var.get()}")
|
||||
self.time_multiplier = 1.0
|
||||
|
||||
def _on_targets_changed(self, targets: List[Target]):
|
||||
"""Callback executed when the target list is modified by the user."""
|
||||
# 1. Update the internal scenario object
|
||||
|
||||
@ -31,6 +31,7 @@ class TrajectoryEditorWindow(tk.Toplevel):
|
||||
self.existing_ids = existing_ids
|
||||
self.result_target: Optional[Target] = None
|
||||
self.initial_max_range = max_range_nm
|
||||
self.time_multiplier = 1.0
|
||||
|
||||
self.waypoints: List[Waypoint] = []
|
||||
is_editing = target_to_edit is not None
|
||||
@ -89,6 +90,12 @@ class TrajectoryEditorWindow(tk.Toplevel):
|
||||
self.reset_button = ttk.Button(preview_controls, text="⟲ Reset", command=self._on_preview_reset)
|
||||
self.reset_button.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
ttk.Label(preview_controls, text="Speed:").pack(side=tk.LEFT, padx=(10, 2), pady=5)
|
||||
self.time_multiplier_var = tk.StringVar(value="1x")
|
||||
self.multiplier_combo = ttk.Combobox(preview_controls, textvariable=self.time_multiplier_var, values=["1x", "2x", "4x", "10x"], state="readonly", width=4)
|
||||
self.multiplier_combo.pack(side=tk.LEFT, padx=(0, 5), pady=5)
|
||||
self.multiplier_combo.bind("<<ComboboxSelected>>", self._on_time_multiplier_changed)
|
||||
|
||||
button_frame = ttk.Frame(self)
|
||||
button_frame.pack(fill=tk.X, padx=10, pady=(0, 10), side=tk.BOTTOM)
|
||||
ttk.Button(button_frame, text="Cancel", command=self._on_cancel).pack(side=tk.RIGHT)
|
||||
@ -181,6 +188,16 @@ class TrajectoryEditorWindow(tk.Toplevel):
|
||||
# Passa l'intera lista di waypoint, il PPI ora sa come gestirla
|
||||
self.ppi_preview.draw_trajectory_preview(self.waypoints)
|
||||
|
||||
def _on_time_multiplier_changed(self, event=None):
|
||||
"""Handles changes to the time multiplier selection."""
|
||||
try:
|
||||
multiplier_str = self.time_multiplier_var.get().replace('x', '')
|
||||
self.time_multiplier = float(multiplier_str)
|
||||
if self.preview_engine and self.preview_engine.is_running():
|
||||
self.preview_engine.set_time_multiplier(self.time_multiplier)
|
||||
except ValueError:
|
||||
self.time_multiplier = 1.0
|
||||
|
||||
def _on_preview_play(self):
|
||||
if self.is_preview_running.get(): return
|
||||
if not self.waypoints or self.waypoints[0].maneuver_type != ManeuverType.FLY_TO_POINT:
|
||||
@ -194,6 +211,7 @@ class TrajectoryEditorWindow(tk.Toplevel):
|
||||
preview_scenario = Scenario(); preview_scenario.add_target(preview_target)
|
||||
|
||||
self.preview_engine = SimulationEngine(communicator=None, update_queue=self.gui_update_queue)
|
||||
self.preview_engine.set_time_multiplier(self.time_multiplier)
|
||||
self.preview_engine.load_scenario(preview_scenario)
|
||||
self.preview_engine.start()
|
||||
|
||||
@ -226,6 +244,7 @@ class TrajectoryEditorWindow(tk.Toplevel):
|
||||
|
||||
self.play_button.config(state=tk.DISABLED if is_running else tk.NORMAL)
|
||||
self.stop_button.config(state=tk.NORMAL if is_running else tk.DISABLED)
|
||||
self.multiplier_combo.config(state="readonly" if not is_running else tk.DISABLED)
|
||||
self.wp_tree.config(selectmode="browse" if not is_running else "none")
|
||||
|
||||
def _on_ok(self):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user