Under http://inexlib.lal.in2p3.fr/download/exp/geant4 can be found the g4inex.zip distribution. It contains modified geant4 examples (for example the A01 one) to demonstrate how to use the inlib/exlib histogramming and graphics to work with Geant4. The way to "exlib instrument a Geant4 example" is sufficiently simple to be used also on your own Geant4 application. The look and feel of an instrumented Geant4 example is similar to the ioda application. In particular the menu system is done with the same tools (exlib/sg) than the ioda one (and then done on OpenGL-ES). The "straight C++ way of doing" applies here : it is sufficient to include one file (exlib/geant4/session), instanciate one class, change the Geant4 example GNUmakefile (or your own Geant4 application build system) to have the "-I" toward inlib/exlib, some "-L -l" toward some standard libraries and then build and run. Here too, it is quite simple and straightforward.
To build and run the modifed A01 :
UNIX> <get g4inex.zip> UNIX> <unzip g4inex.zip> UNIX> cd g4inex/A01 UNIX> <modify setup.csh to say where is Geant4> UNIX> tcsh csh> source setup.csh csh> make csh> ${G4BIN}/${G4SYSTEM}/A01app
At startup you should see :
click on init and then geom :
As for ioda, you can play with the key controls (or the camera panel) to move around. Then go back to the main menu by clicking in the bottom "meta zone" and then click on "beam on" :
Select a number of event and then "Ok". You should see events flashing :
By default the g4inexa/A01 has histogramming code done with inlib. You can see plots by clicking "plot" and then "beam on", you should see the filling of the histograms and clouds :
It is clear that with the inlib/exlib we have all the material at hand to handle interactivity for a Geant4 application on an Android or an iDevice. But for that you shall need CLHEP and Geant4 ported on this kind of platform...
On Darwin it is expected to have jpeg installed with MacPort and then found under :
/opt/local/include and /opt/local/lib
If not (for example because installed with Fink under /sw), you have to change in inexlib.gmk the line CPPFLAGS and LDLIBS about jpeg :
ifeq ($(G4SYSTEM),Darwin-g++) # freetype 2 : CPPFLAGS += -I/usr/X11/include/freetype2 LDLIBS += -L/usr/X11R6/lib -lGLU -lfreetype # jpeg : CPPFLAGS += -I/opt/local/include LDLIBS += -L/opt/local/lib -ljpeg endif
// NOTE : in A01EventAction.hh, have the AIDA objects (IHistogram1D, etc...) // fields made public : // public: // IHistogram1D* dc1Hits; // ... #include "G4RunManager.hh" #include "G4UImanager.hh" #include "A01DetectorConstruction.hh" #include "A01PhysicsList.hh" #include "A01PrimaryGeneratorAction.hh" #include "A01EventAction.hh" #define WALL_DATA_CLIENT #include <exlib/geant4/session> #ifdef G4ANALYSIS_USE #include <exlib/AIDA/h2plot> #include <exlib/AIDA/cloud2plot> #endif #ifdef G4ANALYSIS_INEX #include <inlib/sg/h2plot> #include <inlib/sg/cloud2plot> #endif namespace A01 { class session : public exlib::geant4::session { protected: virtual exlib::sg::list* create_home_menu() { exlib::sg::list* list = exlib::geant4::session::create_home_menu(); #if defined(G4ANALYSIS_USE) || defined(G4ANALYSIS_INEX) list->add_before("params","rebook",new book_cbk(*this)); list->add_before("params","plot",new plot_cbk(*this)); #endif return list; } virtual void event_end() { if(m_eva.m_build_rep){ plot_cbk cbk(*this); cbk.action(); } } public: // pass the A01EventAction to get the histos. session(A01EventAction& a_eva,int a_argc = 0,char** a_argv = NULL) : exlib::geant4::session(a_argc,a_argv) ,m_eva(a_eva) //to get histos. { push_home(); //to enforce the upper create_home_menu(). } private: session(const session& a_from) : exlib::geant4::session(a_from) ,m_eva(a_from.m_eva) {} session& operator=(const session&){return *this;} private: class book_cbk : public inlib::sg::cbk { public: virtual return_action action() { m_sess.plots().clear(); m_sess.m_eva.m_cloud_auto_cnv_limit = m_sess.m_cloud_auto_cnv_limit; m_sess.m_eva.Book(); return return_to_render; } virtual inlib::sg::cbk* copy() const {return new book_cbk(*this);} public: book_cbk(session& a_gv): inlib::sg::cbk(),m_sess(a_gv){} virtual ~book_cbk(){} private: book_cbk(const book_cbk& a_from) :inlib::sg::cbk(a_from),m_sess(a_from.m_sess){} book_cbk& operator=(const book_cbk& a_from){ inlib::sg::cbk::operator=(a_from); return *this; } private: session& m_sess; }; class plot_cbk : public inlib::sg::cbk { public: virtual return_action action() { #ifdef G4ANALYSIS_USE #ifdef WALL_DATA_CLIENT m_sess.create_plotter(1,1); {m_sess.plots().set_current_plotter(0); AIDA::IHistogram1D* dc1Hits = m_sess.m_eva.dc1Hits; exlib::sg::plotter& plotter = m_sess.plots().current_plotter(); plotter.background_style().visible = true; if(dc1Hits) { plotter.add_plottable(new exlib::AIDA::h1d2plot(*dc1Hits)); //ui.style_from_res("A01",*plotter); }} #else m_sess.create_plotter(2,2); {m_sess.plots().set_current_plotter(0); AIDA::IHistogram1D* dc1Hits = m_sess.m_eva.dc1Hits; exlib::sg::plotter& plotter = m_sess.plots().current_plotter(); if(dc1Hits) { plotter.add_plottable(new exlib::AIDA::h1d2plot(*dc1Hits)); }} {m_sess.plots().next(); AIDA::ICloud2D* dc1XY = m_sess.m_eva.dc1XY; exlib::sg::plotter& plotter = m_sess.plots().current_plotter(); if(dc1XY) { plotter.add_plottable(new exlib::AIDA::cloud2D_2plot(*dc1XY)); }} {m_sess.plots().next(); AIDA::ICloud2D* dc2XY = m_sess.m_eva.dc2XY; exlib::sg::plotter& plotter = m_sess.plots().current_plotter(); if(dc2XY) { plotter.add_plottable(new exlib::AIDA::cloud2D_2plot(*dc2XY)); }} {m_sess.plots().next(); AIDA::ICloud2D* evstof = m_sess.m_eva.evstof; exlib::sg::plotter& plotter = m_sess.plots().current_plotter(); if(evstof) { plotter.add_plottable(new exlib::AIDA::cloud2D_2plot(*evstof)); }} #endif #endif #ifdef G4ANALYSIS_INEX m_sess.create_plotter(2,2); {m_sess.plots().set_current_plotter(0); inlib::histo::h1d* dc1Hits = m_sess.m_eva.dc1Hits; exlib::sg::plotter& plotter = m_sess.plots().current_plotter(); plotter.background_style().visible = true; if(dc1Hits) { plotter.add_plottable(new inlib::sg::h1d2plot(*dc1Hits)); }} {m_sess.plots().next(); inlib::histo::c2d* dc1XY = m_sess.m_eva.dc1XY; exlib::sg::plotter& plotter = m_sess.plots().current_plotter(); plotter.background_style().visible = true; if(dc1XY) { //NOTE : we should find a way to automatically switch the rep // when the c2d is auto converted to an histogram. if(dc1XY->is_converted()) { plotter.add_plottable(new inlib::sg::h2d2plot(dc1XY->histogram())); } else { plotter.add_plottable(new inlib::sg::c2d2plot(*dc1XY)); } }} {m_sess.plots().next(); inlib::histo::c2d* dc2XY = m_sess.m_eva.dc2XY; exlib::sg::plotter& plotter = m_sess.plots().current_plotter(); plotter.background_style().visible = true; if(dc2XY) { if(dc2XY->is_converted()) { plotter.add_plottable(new inlib::sg::h2d2plot(dc2XY->histogram())); } else { plotter.add_plottable(new inlib::sg::c2d2plot(*dc2XY)); } }} {m_sess.plots().next(); inlib::histo::c2d* evstof = m_sess.m_eva.evstof; exlib::sg::plotter& plotter = m_sess.plots().current_plotter(); plotter.background_style().visible = true; if(evstof) { if(evstof->is_converted()) { plotter.add_plottable(new inlib::sg::h2d2plot(evstof->histogram())); } else { plotter.add_plottable(new inlib::sg::c2d2plot(*evstof)); } }} #endif return return_to_render; } virtual inlib::sg::cbk* copy() const {return new plot_cbk(*this);} public: plot_cbk(session& a_gv): inlib::sg::cbk(),m_sess(a_gv){} virtual ~plot_cbk(){} private: plot_cbk(const plot_cbk& a_from) :inlib::sg::cbk(a_from),m_sess(a_from.m_sess){} plot_cbk& operator=(const plot_cbk& a_from){ inlib::sg::cbk::operator=(a_from); return *this; } private: session& m_sess; }; private: A01EventAction& m_eva; }; } int main(int argc,char** argv) { // RunManager construction G4RunManager* runManager = new G4RunManager; // mandatory user initialization classes runManager->SetUserInitialization(new A01DetectorConstruction); runManager->SetUserInitialization(new A01PhysicsList); // initialize Geant4 kernel runManager->Initialize(); // mandatory user action class runManager->SetUserAction(new A01PrimaryGeneratorAction); // optional user action classes A01EventAction* eventAction = new A01EventAction(); runManager->SetUserAction(eventAction); #ifdef WALL_DATA_CLIENT eventAction->m_cloud_auto_cnv_limit = 1000; #endif {//exlib gui and graphics : A01::session ui(*eventAction,argc,argv); ui.set_background(inlib::colorf::white()); ui.set_cloud_auto_cnv_limit(eventAction->m_cloud_auto_cnv_limit); exlib::sg::ortho* camera = new exlib::sg::ortho(); camera->height = 10.0*m; float z = 10.*m; camera->znear = 0.01f*z; camera->zfar = 100*z; camera->position = inlib::vec3f(0,0,z); camera->dx = z*0.003f; camera->da = camera->da.value()/2; ui.replace_camera(camera); //it takes ownership of camera. ui.steer();} delete runManager; std::cout << "main : exit..." << std::endl; return 0; }