Revision 8ec6cc78313b28e5df61efda1417440cdeb6b3d3 authored by Axel Naumann on 23 August 2019, 20:51:28 UTC, committed by Axel Naumann on 23 August 2019, 20:51:28 UTC
1 parent b147571
Raw File
collection_proxies.C
/// \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 <ROOT/REveGeoShape.hxx>
#include <ROOT/REveJetCone.hxx>
#include <ROOT/REvePointSet.hxx>
#include <ROOT/REveProjectionBases.hxx>
#include <ROOT/REveProjectionManager.hxx>
#include <ROOT/REveScene.hxx>
#include <ROOT/REveTableProxyBuilder.hxx>
#include <ROOT/REveTableInfo.hxx>
#include <ROOT/REveTrack.hxx>
#include <ROOT/REveTrackPropagator.hxx>
#include <ROOT/REveViewer.hxx>
#include <ROOT/REveViewContext.hxx>

#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 =====================================
//==============================================================================


// 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<TList*> m_data;

   void Clear() {
      for (auto &l : m_data)
         delete l;
      m_data.clear();
   }

   void Create() {
      Clear();
      MakeJets(4);
      MakeParticles(10);
      eventId++;
   }
};

//==============================================================================
//============ PROXY BUILDERS  ================================================
//==============================================================================
class XYJetProxyBuilder: public REX::REveDataSimpleProxyBuilderTemplate<XYJet>
{
   virtual bool HaveSingleProduct() const { return false; }

   using REveDataSimpleProxyBuilderTemplate<XYJet>::BuildViewType;
   virtual void BuildViewType(const XYJet& dj, REX::REveElement* iItemHolder, std::string viewType, const REX::REveViewContext* context)
   {
      auto jet = new REX::REveJetCone();
      jet->SetCylinder(context->GetMaxR(), context->GetMaxZ());
      jet->AddEllipticCone(dj.Eta(), dj.Phi(), dj.GetEtaSize(), dj.GetPhiSize());
      SetupAddElement(jet, iItemHolder, true);

      REX::REveVector p1;
      REX::REveVector p2;

      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 = 3;
            r = r_ecal/sin(theta);
         }

         p1.Set( 0., (phi<TMath::Pi() ? r*fabs(sin(theta)) : -r*fabs(sin(theta))), r*cos(theta));
         p2.Set( 0., (phi<TMath::Pi() ? (r+size)*fabs(sin(theta)) : -(r+size)*fabs(sin(theta))), (r+size)*cos(theta) );


         auto marker = new REX::REveScalableStraightLineSet("jetline");
         marker->SetScaleCenter(p1.fX, p1.fY, p1.fZ);
         marker->AddLine(p1, p2);

         marker->SetLineWidth(4);
         if (debug)
             marker->AddMarker(0, 0.9);

         SetupAddElement(marker, iItemHolder, true);
      }

      jet->SetName(Form("element %s", iItemHolder->GetName().c_str()));
   }
};

class TrackProxyBuilder : public REX::REveDataSimpleProxyBuilderTemplate<TParticle>
{
   using REveDataSimpleProxyBuilderTemplate<TParticle>::Build;
   virtual void Build(const TParticle& p, REX::REveElement* iItemHolder, const REX::REveViewContext* context)
   {
      const TParticle *x = &p;
      // printf("==============  BUILD track %s (pt=%f, eta=%f) \n", iItemHolder->GetCName(), p.Pt(), p.Eta());
      auto track = new REX::REveTrack((TParticle*)(x), 1, context->GetPropagator());
      track->MakeTrack();
      SetupAddElement(track, iItemHolder, true);
      // iItemHolder->AddElement(track);
      track->SetName(Form("element %s id=%d", iItemHolder->GetCName(), track->GetElementId()));
   }
};


//==============================================================================
//==============================================================================
// ================= XY MANGER  ================================================
//==============================================================================
//==============================================================================
class XYManager
{
private:
   Event *m_event{nullptr};

   std::vector<REX::REveScene *> m_scenes;
   REX::REveViewContext *m_viewContext{nullptr};
   REX::REveProjectionManager *m_mngRhoZ{nullptr};

   std::vector<REX::REveDataProxyBuilderBase *> m_builders;
   REX::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 REX::REveTrackPropagator();
      prop->SetMagFieldObj(new REX::REveMagFieldDuo(350, -3.5, 2.0));
      prop->SetMaxR(r);
      prop->SetMaxZ(z);
      prop->SetMaxOrbs(6);
      prop->IncRefCount();

      m_viewContext = new REX::REveViewContext();
      m_viewContext->SetBarrel(r, z);
      m_viewContext->SetTrackPropagator(prop);

      // table specs
      auto tableInfo = new REX::REveTableViewInfo();
      tableInfo->table("XYTracks").
         column("pt", 1, "Pt").
         column("eta", 3, "Eta").
         column("phi", 3, "Phi");

      tableInfo->table("XYJets").
         column("eta", 1, "Eta").
         column("phi", 1, "Phi").
         column("etasize", 2, "GetEtaSize").
         column("phisize", 2, "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 REX::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 REX::REveProjectionManager(REX::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
   REX::REveDataProxyBuilderBase*  makeGLBuilderForType(TClass* c)
   {
      std::string cn = c->GetName();
      // printf("proxy builder for type %s\n", c->GetName());
      if (cn == "XYJet") {
         return new XYJetProxyBuilder();
      }
      else
      {
         return new TrackProxyBuilder();
      }
   }

   void LoadCurrentEvent(REX::REveDataCollection* collection)
   {
      //  printf("load current event \n");
      for (auto &l : m_event->m_data) {
         TIter next(l);
         if (collection->GetName() == std::string(l->GetName()))
         {
            // printf("collection for list %s %s\n", collection->GetCName(), l->GetName());
            collection->ClearItems();
            collection->DestroyElements();

            for (int i = 0; i <= l->GetLast(); ++i)
            {
               TString pname; pname.Form("item %2d", i);
               collection->AddItem(l->At(i), pname.Data(), "");
            }
         }
         //collections->RefChildren())
       }
   }

   void NextEvent()
   {
      m_inEventLoading = true;
      for (auto &el: m_collections->RefChildren())
      {
         auto c = dynamic_cast<REX::REveDataCollection *>(el);
         LoadCurrentEvent(c);
         c->ApplyFilter();
      }

      for (auto proxy : m_builders) {
         proxy->Build();
      }
      m_inEventLoading = false;
   }

   void addCollection(REX::REveDataCollection* collection, bool makeTable)
   {
      // load data
      LoadCurrentEvent(collection);

      // GL view types
      auto glBuilder = makeGLBuilderForType(collection->GetItemClass());
      glBuilder->SetCollection(collection);
      glBuilder->SetHaveAWindow(true);
      for (auto scene : m_scenes) {
         REX::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();

      if (makeTable) {
         // Table view types      {
         auto tableBuilder = new REX::REveTableProxyBuilder();
         tableBuilder->SetHaveAWindow(true);
         tableBuilder->SetCollection(collection);
         REX::REveElement* tablep = tableBuilder->CreateProduct("table-type", m_viewContext);

         auto tableMng =  m_viewContext->GetTableViewInfo();
         tableMng->SetDisplayedCollection(collection->GetElementId());
         tableMng->AddDelegate([=](REX::ElementId_t elId) { tableBuilder->DisplayedCollectionChanged(elId); });

         for (REX::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);
      }

      m_collections->AddElement(collection);
      collection->SetHandlerFunc([&] (REX::REveDataCollection* collection) { this->CollectionChanged( collection ); });
      collection->SetHandlerFuncIds([&] (REX::REveDataCollection* collection, const REX::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(REX::REveDataCollection* collection) {
      printf("collection changes not implemented %s!\n", collection->GetCName());
   }

   void ModelChanged(REX::REveDataCollection* collection, const REX::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);
         }
      }
   }
};


//==============================================================================

class EventManager : public REX::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();
   }
};

//______________________________________________________________________________


void collection_proxies(bool proj=true)
{
   eveMng = REX::REveManager::Create();

   auto event = new Event();
   event->Create();
   event->N_tracks = 10;
   event->N_jets = 4;

   gRhoZView = true;

   // debug settings
   auto xyManager = new XYManager(event);

   if (1) {
      REX::REveDataCollection* trackCollection = new REX::REveDataCollection("XYTracks");
      trackCollection->SetItemClass(TParticle::Class());
      trackCollection->SetMainColor(kGreen);
      //trackCollection->SetFilterExpr("i.Pt() > 0.1 && std::abs(i.Eta()) < 1");
      xyManager->addCollection(trackCollection, true);
   }

   if (1) {
      REX::REveDataCollection* jetCollection = new REX::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();
}
back to top