From 2d7f8ea75d9d74355a975c05ba89e8a7330a63ef Mon Sep 17 00:00:00 2001 From: VALLONGOL Date: Mon, 17 Nov 2025 13:33:50 +0100 Subject: [PATCH] sistemata x gialla su target a fine simulazione --- target_simulator/gui/main_view.py | 3 ++- target_simulator/gui/ppi_adapter.py | 10 ++++++++++ target_simulator/gui/ppi_display.py | 22 +++++++++++++++++++++- target_simulator/utils/logger.py | 9 ++------- todo.md | 4 ++-- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/target_simulator/gui/main_view.py b/target_simulator/gui/main_view.py index 1958456..b9cbce3 100644 --- a/target_simulator/gui/main_view.py +++ b/target_simulator/gui/main_view.py @@ -314,7 +314,7 @@ class MainView(tk.Tk): self.analysis_tree.column("datetime", width=150) self.analysis_tree.column("scenario", width=200) self.analysis_tree.column("duration", width=80, anchor=tk.E) - + # Bind double-click to open analysis self.analysis_tree.bind("", lambda e: self._on_analyze_run()) @@ -501,6 +501,7 @@ class MainView(tk.Tk): self.simulation_hub.reset() self.ppi_widget.clear_trails() + self.ppi_widget.clear_finished_trajectory_markers() self.scenario.reset_simulation() self._update_all_views() self.show_status_message("Scenario reset to initial state.", timeout_ms=3000) diff --git a/target_simulator/gui/ppi_adapter.py b/target_simulator/gui/ppi_adapter.py index 9fb3ecc..c2f8b09 100644 --- a/target_simulator/gui/ppi_adapter.py +++ b/target_simulator/gui/ppi_adapter.py @@ -117,10 +117,20 @@ def build_display_data( pass sim_target.active = True + # Try to get active status from engine first, then fall back to scenario if engine and getattr(engine, "scenario", None): t_engine = engine.scenario.get_target(tid) if t_engine is not None: sim_target.active = bool(getattr(t_engine, "active", True)) + elif scenario: + # If engine is None (e.g., after simulation finishes), use the main scenario + t_scenario = scenario.get_target(tid) + if t_scenario is not None: + sim_target.active = bool(getattr(t_scenario, "active", True)) + if logger and not sim_target.active: + logger.debug( + f"PPI Adapter: Target {tid} is INACTIVE (from scenario fallback)" + ) simulated_targets_for_ppi.append(sim_target) diff --git a/target_simulator/gui/ppi_display.py b/target_simulator/gui/ppi_display.py index f32e886..3800347 100644 --- a/target_simulator/gui/ppi_display.py +++ b/target_simulator/gui/ppi_display.py @@ -55,6 +55,8 @@ class PPIDisplay(ttk.Frame): self.real_trail_artists: List[mpl.artist.Artist] = [] self.sim_label_artists: List[mpl.artist.Artist] = [] self.real_label_artists: List[mpl.artist.Artist] = [] + # Persistent markers for finished trajectories (yellow X) - not cleared on simulation end + self.finished_trajectory_markers: List[mpl.artist.Artist] = [] self.trail_length = trail_length or self.TRAIL_LENGTH self._trails = { "simulated": collections.defaultdict( @@ -345,7 +347,7 @@ class PPIDisplay(ttk.Frame): self.canvas.draw_idle() def clear_all_targets(self): - """Clears all target artists from the display.""" + """Clears all target artists from the display (except finished trajectory markers).""" all_artists = ( self.sim_target_artists + self.real_target_artists @@ -362,6 +364,7 @@ class PPIDisplay(ttk.Frame): self.real_trail_artists.clear() self.sim_label_artists.clear() self.real_label_artists.clear() + # NOTE: finished_trajectory_markers are NOT cleared here - they persist until new simulation def update_simulated_targets(self, targets: List[Target]): """Updates and redraws only the simulated targets.""" @@ -486,6 +489,8 @@ class PPIDisplay(ttk.Frame): zorder=6, ) label_artist_list.append(x_mark) + # Add to persistent list so it survives simulation end + self.finished_trajectory_markers.append(x_mark) except Exception: pass @@ -558,10 +563,25 @@ class PPIDisplay(ttk.Frame): ) artist_list.append(line) + def clear_finished_trajectory_markers(self): + """Clears the persistent yellow X markers for finished trajectories. + Called when starting a new simulation or changing scenario. + """ + for artist in self.finished_trajectory_markers: + try: + artist.remove() + except (ValueError, AttributeError): + # Artist may have already been removed or is invalid + pass + self.finished_trajectory_markers.clear() + if self.canvas: + self.canvas.draw() + def clear_trails(self): self._trails["simulated"].clear() self._trails["real"].clear() self.clear_all_targets() + self.clear_finished_trajectory_markers() if self.canvas: self.canvas.draw() diff --git a/target_simulator/utils/logger.py b/target_simulator/utils/logger.py index 1663597..496c9be 100644 --- a/target_simulator/utils/logger.py +++ b/target_simulator/utils/logger.py @@ -262,13 +262,8 @@ def setup_basic_logging( _actual_console_handler = logging.StreamHandler() _actual_console_handler.setFormatter(_base_formatter) _actual_console_handler.setLevel(logging.DEBUG) - try: - # Also attach console handler directly to the root logger so - # console output appears immediately (helps during development - # and when the Tk polling loop hasn't started yet). - root_logger.addHandler(_actual_console_handler) - except Exception: - pass + # DO NOT attach console handler directly to root logger - it will be + # processed through the queue system to avoid duplicate output queue_putter = QueuePuttingHandler(handler_queue=_global_log_queue) queue_putter.setLevel(logging.DEBUG) diff --git a/todo.md b/todo.md index 15edc12..0d30201 100644 --- a/todo.md +++ b/todo.md @@ -12,7 +12,7 @@ - [ ] vedere anche la simulazione in 3d usando le mappe dem e le mappe operstreetmap. - [ ] Scrivere test unitari - [ ] creare repository su git aziendale, usando codice PJ40906 come progetto -- [ ] aprire l'analisi direttamente cliccando sulla riga della tabella +- [x] aprire l'analisi direttamente cliccando sulla riga della tabella - [ ] creare una procedura di allineamento tra server e client usando il comando di ping da implementare anche sul server - [ ] funzione di sincronizzazione: è stato aggiunto al server la possibilità di gestire dei messaggi che sono di tipo SY (tag) che sono fatti per gestire il sincronismo tra client e server. In questa nuova tipologia di messaggi io invio un mio timetag che poi il server mi restituirà subito appena lo riceve, facendo così sappiamo in quanto tempo il messaggio che spedisco è arrivato al server, viene letto, e viene risposto il mio numero con anche il timetag del server. Facendo così misurando i delta posso scroprire esattamente il tempo che intercorre tra inviare un messaggio al server e ricevere una risposta. Per come è fatto il server il tempo di applicazione dei nuovi valori per i target sarà al massimo di 1 batch, che può essere variabile, ma a quel punto lo potremmo calibrare in altro modo. Con l'analisi sui sync possiamo sapere come allineare gli orologi. @@ -34,7 +34,7 @@ - [X] sistemare l'animazione della antenna che adesso non si muove più - [X] rivedere la visualizzazione della combobox per scegliere lo scenario da usare. - [X] quando è finita la simulazione i target nella tabella si devono fermare all'ultima posizione scambiata. -- [ ] quando la traiettoria si ferma deve comparire la x gialla e non deve sparire a fine simulazione +- [x] quando la traiettoria si ferma deve comparire la x gialla e non deve sparire a fine simulazione - [X] IMPORTANTE: verificare la rotazione dei target quando durante la simulazione ruota l'aereo, in questo caso se ruota l'aereo ed i target sono parttiti con un certo angolo rispetto allo 0, poi la traiettoria dei target deve essere aggiornata rispetto al momento iniziale e non calcolata ad ogni step di rotazione. Al momento dello start, devo memorizzare l'angolo di rotazione dell'aereo e quindi quello è l'angolo con cui dovranno essere aggiornate sempre le traiettorie dei target e non quella corrente dell'aereo che potrà girare dove vuole ma a quel punto le tracce sono partite e quindi seguiranno la loro strada. - [x] salvare i dati di perfomance della simulazione in altro file per evitare di appesantire file di salvataggio simulazione - [x] caricare solo i dati dei file ce ci interessano quando passo all'analisi