/// \file /// \ingroup tutorial_eve7 /// This example display collection of ??? in web browser /// /// \macro_code /// #include "ROOT/REveDataClasses.hxx" //#include "ROOT/REveDataProxyBuilderBase.hxx" //#include "ROOT/REveDataSimpleProxyBuilder.hxx" #include "ROOT/REveDataSimpleProxyBuilderTemplate.hxx" #include "ROOT/REveManager.hxx" #include "ROOT/REveScalableStraightLineSet.hxx" #include "ROOT/REveViewContext.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include "TGeoTube.h" #include "TList.h" #include "TParticle.h" #include "TRandom.h" #include "TApplication.h" namespace REX = ROOT::Experimental; bool gRhoZView = false; REX::REveManager *eveMng = nullptr; //============================================================================== //============== EMULATE FRAMEWORK CLASSES ===================================== //============================================================================== using namespace ROOT::Experimental; // a demo class, can be provided from experiment framework class XYJet : public TParticle { private: float m_etaSize{0}; float m_phiSize{0}; public: float GetEtaSize() const { return m_etaSize; } float GetPhiSize() const { return m_phiSize; } void SetEtaSize(float iEtaSize) { m_etaSize = iEtaSize; } void SetPhiSize(float iPhiSize) { m_phiSize = iPhiSize; } XYJet(Int_t pdg, Int_t status, Int_t mother1, Int_t mother2, Int_t daughter1, Int_t daughter2, Double_t px, Double_t py, Double_t pz, Double_t etot) : TParticle(pdg, status, mother1, mother2, daughter1, daughter2, px, py, pz, etot, 0, 0, 0, 0) {} ClassDef(XYJet, 1); }; class Event { public: int eventId{0}; int N_tracks{0}; int N_jets{0}; Event() = default; void MakeJets(int N) { TRandom &r = *gRandom; r.SetSeed(0); TList* list = new TList(); list->SetName("XYJets"); for (int i = 1; i <= N; ++i) { double pt = r.Uniform(0.5, 10); double eta = r.Uniform(-2.55, 2.55); double phi = r.Uniform(-TMath::Pi(), TMath::Pi()); double px = pt * std::cos(phi); double py = pt * std::sin(phi); double pz = pt * (1. / (std::tan(2*std::atan(std::exp(-eta))))); auto jet = new XYJet(0, 0, 0, 0, 0, 0, px, py, pz, std::sqrt(px*px + py*py + pz*pz + 80*80)); jet->SetEtaSize(r.Uniform(0.02, 0.2)); jet->SetPhiSize(r.Uniform(0.01, 0.3)); list->Add(jet); } m_data.push_back(list); } void MakeParticles(int N) { TRandom &r = *gRandom; r.SetSeed(0); TList* list = new TList(); list->SetName("XYTracks"); for (int i = 1; i <= N; ++i) { double pt = r.Uniform(0.5, 10); double eta = r.Uniform(-2.55, 2.55); double phi = r.Uniform(0, TMath::TwoPi()); double px = pt * std::cos(phi); double py = pt * std::sin(phi); double pz = pt * (1. / (std::tan(2*std::atan(std::exp(-eta))))); // printf("Event::MakeParticles %2d: pt=%.2f, eta=%.2f, phi=%.2f\n", i, pt, eta, phi); auto particle = new TParticle(0, 0, 0, 0, 0, 0, px, py, pz, std::sqrt(px*px + py*py + pz*pz + 80*80), 0, 0, 0, 0 ); int pdg = 11 * (r.Integer(2) > 0 ? 1 : -1); particle->SetPdgCode(pdg); list->Add(particle); } m_data.push_back(list); } std::vector m_data; void Clear() { for (auto &l : m_data) delete l; m_data.clear(); } void Create() { Clear(); MakeJets(4); MakeParticles(100); eventId++; } }; //============================================================================== //== PROXY BUILDERS ============================================================ //============================================================================== class XYJetProxyBuilder: public REveDataSimpleProxyBuilderTemplate { bool HaveSingleProduct() const override { return false; } using REveDataSimpleProxyBuilderTemplate::BuildViewType; void BuildViewType(const XYJet& dj, int idx, REveElement* iItemHolder, std::string viewType, const REveViewContext* context) override { auto jet = new REveJetCone(); jet->SetCylinder(context->GetMaxR(), context->GetMaxZ()); jet->AddEllipticCone(dj.Eta(), dj.Phi(), dj.GetEtaSize(), dj.GetPhiSize()); SetupAddElement(jet, iItemHolder, true); jet->SetLineColor(jet->GetMainColor()); float size = 50.f * dj.Pt(); // values are saved in scale double theta = dj.Theta(); // printf("%s jet theta = %f, phi = %f \n", iItemHolder->GetCName(), theta, dj.Phi()); double phi = dj.Phi(); if (viewType == "Projected" ) { static const float_t offr = 6; float r_ecal = context->GetMaxR() + offr; float z_ecal = context->GetMaxZ() + offr; float transAngle = abs(atan(r_ecal/z_ecal)); double r = 0; bool debug = false; if (theta < transAngle || 3.14-theta < transAngle) { z_ecal = context->GetMaxZ() + offr/transAngle; r = z_ecal/fabs(cos(theta)); } else { debug = true; r = r_ecal/sin(theta); } REveVector p1(0, (phiSetScaleCenter(p1.fX, p1.fY, p1.fZ); marker->AddLine(p1, p2); marker->SetLineWidth(4); if (debug) marker->AddMarker(0, 0.9); SetupAddElement(marker, iItemHolder, true); marker->SetName(Form("line %s %d", Collection()->GetCName(), idx)); } } using REveDataProxyBuilderBase::LocalModelChanges; void LocalModelChanges(int idx, REveElement* el, const REveViewContext* ctx) override { printf("LocalModelChanges jet %s ( %s )\n", el->GetCName(), el->FirstChild()->GetCName()); REveJetCone* cone = dynamic_cast(el->FirstChild()); cone->SetLineColor(cone->GetMainColor()); } }; class TrackProxyBuilder : public REveDataSimpleProxyBuilderTemplate { using REveDataSimpleProxyBuilderTemplate::Build; void Build(const TParticle& p, int idx, REveElement* iItemHolder, const REveViewContext* context) override { const TParticle *x = &p; auto track = new REveTrack((TParticle*)(x), 1, context->GetPropagator()); track->MakeTrack(); SetupAddElement(track, iItemHolder, true); } }; //============================================================================== //== XY MANGER ================================================================ //============================================================================== class XYManager { private: Event *m_event{nullptr}; std::vector m_scenes; REveViewContext *m_viewContext {nullptr}; REveProjectionManager *m_mngRhoZ {nullptr}; std::vector m_builders; REveScene *m_collections {nullptr}; bool m_inEventLoading {false}; public: XYManager(Event* event) : m_event(event) { //view context float r = 300; float z = 300; auto prop = new REveTrackPropagator(); prop->SetMagFieldObj(new REveMagFieldDuo(350, 3.5, -2.0)); prop->SetMaxR(r); prop->SetMaxZ(z); prop->SetMaxOrbs(6); prop->IncRefCount(); m_viewContext = new REveViewContext(); m_viewContext->SetBarrel(r, z); m_viewContext->SetTrackPropagator(prop); // table specs auto tableInfo = new REveTableViewInfo(); tableInfo->table("TParticle"). column("pt", 1, "i.Pt()"). column("eta", 3, "i.Eta()"). column("phi", 3, "i.Phi()"); tableInfo->table("XYJet"). column("eta", 1, "i.Eta()"). column("phi", 1, "i.Phi()"). column("etasize", 2, "i.GetEtaSize()"). column("phisize", 2, "i.GetPhiSize()"); m_viewContext->SetTableViewInfo(tableInfo); createScenesAndViews(); } void createScenesAndViews() { // collections m_collections = eveMng->SpawnNewScene("Collections", "Collections"); // 3D m_scenes.push_back(eveMng->GetEventScene()); // Geometry auto b1 = new REveGeoShape("Barrel 1"); float dr = 3; b1->SetShape(new TGeoTube(m_viewContext->GetMaxR() , m_viewContext->GetMaxR() + dr, m_viewContext->GetMaxZ())); b1->SetMainColor(kCyan); eveMng->GetGlobalScene()->AddElement(b1); // RhoZ if (gRhoZView) { auto rhoZEventScene = eveMng->SpawnNewScene("RhoZ Scene","Projected"); m_mngRhoZ = new REveProjectionManager(REveProjection::kPT_RhoZ); m_mngRhoZ->SetImportEmpty(true); auto rhoZView = eveMng->SpawnNewViewer("RhoZ View", ""); rhoZView->AddScene(rhoZEventScene); m_scenes.push_back(rhoZEventScene); auto pgeoScene = eveMng->SpawnNewScene("Projection Geometry","xxx"); m_mngRhoZ->ImportElements(b1,pgeoScene ); rhoZView->AddScene(pgeoScene); } // Table if (1) { auto tableScene = eveMng->SpawnNewScene ("Tables", "Tables"); auto tableView = eveMng->SpawnNewViewer("Table", "Table View"); tableView->AddScene(tableScene); tableScene->AddElement(m_viewContext->GetTableViewInfo()); m_scenes.push_back(tableScene); } } // this should be handeled with framefor plugins REveDataProxyBuilderBase* makeGLBuilderForType(TClass* c) { std::string cn = c->GetName(); if (cn == "XYJet") { return new XYJetProxyBuilder(); } else { return new TrackProxyBuilder(); } } void LoadCurrentEvent(REveDataCollection* collection) { for (auto &l : m_event->m_data) { TIter next(l); if (collection->GetName() == std::string(l->GetName())) { collection->ClearItems(); collection->DestroyElements(); for (int i = 0; i <= l->GetLast(); ++i) { std::string cname = collection->GetName(); auto len = cname.size(); char end = cname[len-1]; if (end == 's') { cname = cname.substr(0, len-1); } TString pname(Form("%s %2d", cname.c_str(), i)); collection->AddItem(l->At(i), pname.Data(), ""); } } collection->ApplyFilter(); } } void NextEvent() { m_inEventLoading = true; for (auto &el: m_collections->RefChildren()) { auto c = dynamic_cast(el); LoadCurrentEvent(c); } for (auto proxy : m_builders) { proxy->Build(); } m_inEventLoading = false; } void addCollection(REveDataCollection* collection, bool showInTable) { m_collections->AddElement(collection); // load data LoadCurrentEvent(collection); // GL view types auto glBuilder = makeGLBuilderForType(collection->GetItemClass()); glBuilder->SetCollection(collection); glBuilder->SetHaveAWindow(true); for (auto scene : m_scenes) { REveElement *product = glBuilder->CreateProduct(scene->GetTitle(), m_viewContext); if (strncmp(scene->GetCTitle(), "Table", 5) == 0) continue; if (!strncmp(scene->GetCTitle(), "Projected", 8)) { m_mngRhoZ->ImportElements(product, scene); } else { scene->AddElement(product); } } m_builders.push_back(glBuilder); glBuilder->Build(); // Table view types auto tableBuilder = new REveTableProxyBuilder(); tableBuilder->SetHaveAWindow(true); tableBuilder->SetCollection(collection); REveElement* tablep = tableBuilder->CreateProduct("table-type", m_viewContext); auto tableMng = m_viewContext->GetTableViewInfo(); if (showInTable) { tableMng->SetDisplayedCollection(collection->GetElementId()); } tableMng->AddDelegate([=]() { tableBuilder->ConfigChanged(); }); for (REveScene* scene : m_scenes) { if (strncmp(scene->GetCTitle(), "Table", 5) == 0) { scene->AddElement(tablep); tableBuilder->Build(collection, tablep, m_viewContext ); } } m_builders.push_back(tableBuilder); collection->SetHandlerFunc([&] (REveDataCollection* collection) { this->CollectionChanged( collection ); }); collection->SetHandlerFuncIds([&] (REveDataCollection* collection, const REveDataCollection::Ids_t& ids) { this->ModelChanged( collection, ids ); }); } void finishViewCreate() { auto mngTable = m_viewContext->GetTableViewInfo(); if (mngTable) { for (auto &el : m_collections->RefChildren()) { if (el->GetName() == "XYTracks") mngTable->SetDisplayedCollection(el->GetElementId()); } } } void CollectionChanged(REveDataCollection* collection) { printf("collection changes not implemented %s!\n", collection->GetCName()); } void ModelChanged(REveDataCollection* collection, const REveDataCollection::Ids_t& ids) { if (m_inEventLoading) return; for (auto proxy : m_builders) { if (proxy->Collection() == collection) { // printf("Model changes check proxy %s: \n", proxy->Type().c_str()); proxy->ModelChanges(ids); } } } }; //============================================================================== //== Event Manager ============================================================= //============================================================================== class EventManager : public REveElement { private: Event* m_event; XYManager* m_xymng; public: EventManager(Event* e, XYManager* m): m_event(e), m_xymng(m) {} virtual ~EventManager() {} virtual void NextEvent() { m_event->Create(); m_xymng->NextEvent(); } virtual void QuitRoot() { printf("Quit ROOT\n"); if (gApplication) gApplication->Terminate(); } }; //============================================================================== //== main() ==================================================================== //============================================================================== void collection_proxies(bool proj=true) { eveMng = REveManager::Create(); auto event = new Event(); event->Create(); gRhoZView = true; // debug settings auto xyManager = new XYManager(event); if (1) { REveDataCollection* trackCollection = new REveDataCollection("XYTracks"); trackCollection->SetItemClass(TParticle::Class()); trackCollection->SetMainColor(kGreen); trackCollection->SetFilterExpr("i.Pt() > 4.1 && std::abs(i.Eta()) < 1"); xyManager->addCollection(trackCollection, true); } if (1) { REveDataCollection* jetCollection = new REveDataCollection("XYJets"); jetCollection->SetItemClass(XYJet::Class()); jetCollection->SetMainColor(kRed); xyManager->addCollection(jetCollection, false); } auto eventMng = new EventManager(event, xyManager); eventMng->SetName("EventManager"); eveMng->GetWorld()->AddElement(eventMng); eveMng->GetWorld()->AddCommand("QuitRoot", "sap-icon://log", eventMng, "QuitRoot()"); eveMng->GetWorld()->AddCommand("NextEvent", "sap-icon://step", eventMng, "NextEvent()"); eveMng->Show(); }