#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const int NCH = 64; // Conversione big-endian -> little-endian uint16_t swap16(uint16_t val) { return (val << 8) | (val >> 8); } // Posizione di un pixel struct PixelPos { int col; int row; }; // Mappa pixel [col][row] -> canale (righe dal basso verso l'alto) int pixelPos[8][8] = { {31,27,20,16,12,8,7,4}, // Col A=0 {28,24,23,19,15,3,11,0}, // Col B=1 {30,26,22,17,13,9,5,1}, // Col C=2 {29,25,21,18,14,10,6,2}, // Col D=3 {63,59,55,50,46,42,38,34},// Col E=4 {60,56,53,49,45,41,37,33},// Col F=5 {62,61,57,48,44,40,36,32},// Col G=6 {58,54,52,51,47,43,39,35} // Col H=7 }; PixelPos channelToPixel[NCH]; void buildChannelMap(){ for(int col=0; col<8; ++col){ for(int row=0; row<8; ++row){ int ch = pixelPos[col][row]; channelToPixel[ch] = {col,row}; } } } // Variabili globali per la navigazione std::vector> gEventsHG; std::vector> gEventsLG; int gCurrentEvent = 0; TCanvas *gCanvas = nullptr; TH2F *gHistHG = nullptr; TH2F *gHistLG = nullptr; bool gIsPlaying = false; // ============================================== // DICHIARAZIONI DELLE FUNZIONI (prima di main) // ============================================== void ShowCurrentEvent(); void NextEvent(); void PrevEvent(); void FirstEvent(); void LastEvent(); void GotoEvent(); void PlayMovie(); void StopMovie(); void SaveCurrentEvent(); bool LoadAllEvents(const char* filename); // ============================================== // DEFINIZIONI DELLE FUNZIONI // ============================================== void ShowCurrentEvent() { if(gEventsHG.empty() || gCurrentEvent < 0 || gCurrentEvent >= (int)gEventsHG.size()) { std::cout << "Nessun evento da visualizzare!" << std::endl; return; } // Pulisci gli istogrammi gHistHG->Reset(); gHistLG->Reset(); // Riempie gli istogrammi const auto& hg = gEventsHG[gCurrentEvent]; const auto& lg = gEventsLG[gCurrentEvent]; for(int ch=0; chSetBinContent(x+1, y+1, hg[ch]); gHistLG->SetBinContent(x+1, y+1, lg[ch]); } // Disegna gCanvas->cd(1); gHistHG->SetTitle(Form("High Gain - Event %d/%lu", gCurrentEvent, gEventsHG.size()-1)); gHistHG->Draw("COLZ TEXT"); gCanvas->cd(2); gHistLG->SetTitle(Form("Low Gain - Event %d/%lu", gCurrentEvent, gEventsLG.size()-1)); gHistLG->Draw("COLZ TEXT"); gCanvas->Update(); std::cout << "Evento: " << gCurrentEvent << "/" << gEventsHG.size()-1 << std::endl; } void NextEvent() { if(gEventsHG.empty()) return; if(gCurrentEvent < (int)gEventsHG.size()-1) { gCurrentEvent++; ShowCurrentEvent(); } else { std::cout << "Sei all'ultimo evento!" << std::endl; } } void PrevEvent() { if(gEventsHG.empty()) return; if(gCurrentEvent > 0) { gCurrentEvent--; ShowCurrentEvent(); } else { std::cout << "Sei al primo evento!" << std::endl; } } void FirstEvent() { if(gEventsHG.empty()) return; gCurrentEvent = 0; ShowCurrentEvent(); } void LastEvent() { if(gEventsHG.empty()) return; gCurrentEvent = gEventsHG.size()-1; ShowCurrentEvent(); } void GotoEvent() { if(gEventsHG.empty()) return; int evt; std::cout << "\n=== VAI A EVENTO SPECIFICO ===" << std::endl; std::cout << "Inserisci numero evento (0-" << gEventsHG.size()-1 << "): "; std::cin >> evt; if(evt >= 0 && evt < (int)gEventsHG.size()) { gCurrentEvent = evt; ShowCurrentEvent(); } else { std::cout << "Numero evento non valido!" << std::endl; } } void PlayMovie() { if(gEventsHG.empty()) return; std::cout << "\n=== PLAY MOVIE ===" << std::endl; std::cout << "Film degli eventi in riproduzione..." << std::endl; std::cout << "Premi Ctrl+C per fermare" << std::endl; gIsPlaying = true; int delayMs = 100; // 100ms tra eventi for(int i = gCurrentEvent; i < (int)gEventsHG.size() && gIsPlaying; i++) { gCurrentEvent = i; ShowCurrentEvent(); // Pausa senza threading (versione portabile) clock_t startTime = clock(); while((clock() - startTime) < delayMs * CLOCKS_PER_SEC / 1000) { // Loop di attesa gSystem->ProcessEvents(); } } gIsPlaying = false; std::cout << "Film terminato!" << std::endl; } void StopMovie() { gIsPlaying = false; std::cout << "Film fermato!" << std::endl; } void SaveCurrentEvent() { if(gEventsHG.empty()) return; std::cout << "\n=== SALVA EVENTO CORRENTE ===" << std::endl; std::cout << "Salvataggio evento " << gCurrentEvent << "..." << std::endl; // Crea file ROOT per l'evento corrente TFile* fout = new TFile(Form("event_%d.root", gCurrentEvent), "RECREATE"); TTree* tree = new TTree("event", "Single event data"); std::vector hg = gEventsHG[gCurrentEvent]; std::vector lg = gEventsLG[gCurrentEvent]; tree->Branch("HG", &hg); tree->Branch("LG", &lg); tree->Branch("event", &gCurrentEvent, "event/I"); tree->Fill(); tree->Write(); fout->Close(); std::cout << "Evento salvato in: event_" << gCurrentEvent << ".root" << std::endl; } bool LoadAllEvents(const char* filename) { std::ifstream fin(filename, std::ios::binary); if(!fin.is_open()) { std::cerr << "Errore apertura file: " << filename << std::endl; return false; } gEventsHG.clear(); gEventsLG.clear(); std::vector hg(NCH), lg(NCH); int eventCount = 0; std::cout << "Caricamento eventi in corso..." << std::endl; while(true) { bool success = true; for(int ch=0; ch(&tmp), sizeof(uint16_t)); if(!fin.good()) { success = false; break; } hg[ch] = swap16(tmp); // Low Gain fin.read(reinterpret_cast(&tmp), sizeof(uint16_t)); if(!fin.good()) { success = false; break; } lg[ch] = swap16(tmp); } if(!success) break; gEventsHG.push_back(hg); gEventsLG.push_back(lg); eventCount++; if(eventCount % 100 == 0) { std::cout << "Caricato evento " << eventCount << std::endl; } } fin.close(); if(gEventsHG.empty()) { std::cerr << "Nessun evento caricato!" << std::endl; return false; } std::cout << "\n========================================" << std::endl; std::cout << "TOTALE EVENTI CARICATI: " << gEventsHG.size() << std::endl; std::cout << "========================================\n" << std::endl; return true; } // ============================================== // FUNZIONE MAIN // ============================================== int main(int argc, char** argv) { // Inizializza ROOT TApplication app("app", &argc, argv); // ============================================== // FUNZIONI PER ROOT (necessarie per TControlBar) // ============================================== // gInterpreter->LoadText("void ShowCurrentEvent();"); gInterpreter->LoadText("void NextEvent();"); gInterpreter->LoadText("void PrevEvent();"); gInterpreter->LoadText("void FirstEvent();"); gInterpreter->LoadText("void LastEvent();"); gInterpreter->LoadText("void GotoEvent();"); gInterpreter->LoadText("void PlayMovie();"); gInterpreter->LoadText("void StopMovie();"); gInterpreter->LoadText("void SaveCurrentEvent();"); // Costruisci mappa canali buildChannelMap(); // File di input const char* inputFile = "raw_acq_rad0-500mV-22122025_122614.dat"; std::cout << "========================================" << std::endl; std::cout << "S13361 EVENT MOVIE PLAYER" << std::endl; std::cout << "========================================" << std::endl; // Carica tutti gli eventi in memoria if(!LoadAllEvents(inputFile)) { std::cerr << "Errore nel caricamento degli eventi!" << std::endl; return 1; } // Crea canvas gCanvas = new TCanvas("c_event", "S13361 Event Movie Display", 1000, 500); gCanvas->Divide(2,1); // Crea istogrammi gHistHG = new TH2F("hHG_movie", "High Gain", 8, 0, 8, 8, 0, 8); gHistLG = new TH2F("hLG_movie", "Low Gain", 8, 0, 8, 8, 0, 8); // Crea control bar con bottoni - USA LE FUNZIONI "_C" TControlBar *bar = new TControlBar("vertical", "Event Controls"); // Bottoni di navigazione bar->AddButton("<< First", "FirstEvent()", "Vai al primo evento"); bar->AddButton("< Previous", "PrevEvent()", "Evento precedente"); bar->AddButton("Next >", "NextEvent()", "Prossimo evento"); bar->AddButton("Last >>", "LastEvent()", "Vai all'ultimo evento"); bar->AddButton("---", "", ""); // Separatore // Controlli film bar->AddButton("PLAY Movie", "PlayMovie()", "Riproduci tutti gli eventi come film"); bar->AddButton("STOP Movie", "StopMovie()", "Ferma la riproduzione"); bar->AddButton("---", "", ""); // Separatore // Altri comandi bar->AddButton("Goto Event", "GotoEvent()", "Vai a evento specifico"); bar->AddButton("Save Event", "SaveCurrentEvent()", "Salva evento corrente in file ROOT"); bar->AddButton("---", "", ""); // Separatore bar->AddButton("QUIT", ".q", "Esci dall'applicazione"); // Mostra la barra di controllo bar->Show(); // Mostra il primo evento FirstEvent(); // Informazioni per l'utente std::cout << "\n=== CONTROLLI DISPONIBILI ===" << std::endl; std::cout << "1. Usa i bottoni nella finestra 'Event Controls'" << std::endl; std::cout << "2. 'PLAY Movie': visualizza tutti gli eventi in sequenza" << std::endl; std::cout << "3. Premi Ctrl+C nel terminale per fermare il film" << std::endl; std::cout << "========================================\n" << std::endl; // Esegui l'applicazione app.Run(); // Pulizia if(gHistHG) delete gHistHG; if(gHistLG) delete gHistLG; if(gCanvas) delete gCanvas; return 0; }