// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // John Allison 6th October 2020 #include "G4ToolsSGSceneHandler.hh" #include "G4ToolsSGNode.hh" #include "G4TransportationManager.hh" #include "G4Polyline.hh" #include "G4Polymarker.hh" #include "G4Circle.hh" #include "G4Square.hh" #include "G4Polyhedron.hh" #include "G4Text.hh" #include "G4Mesh.hh" #include "G4PlotterManager.hh" #include #include #include #include #include #include #ifdef TOOLS_USE_FREETYPE #include #include #include #include #include #else #include #include #endif //for plotting: #include #include #include #include #include #include #include #include #include #include #include #include G4int G4ToolsSGSceneHandler::fSceneIdCount = 0; G4ToolsSGSceneHandler::G4ToolsSGSceneHandler (G4VGraphicsSystem& system, const G4String& name) :parent(system, fSceneIdCount++, name) ,fFreetypeNode(0) ,fMarkerScale(1) { //::printf("debug : G4ToolsSGSceneHandler : %lu, %s\n",this,name.c_str()); EstablishBaseNodes(); #if defined(TOOLS_USE_FREETYPE) fFreetypeNode = new toolx::sg::text_freetype(); fFreetypeNode->add_embedded_font(tools::sg::font_lato_regular_ttf(),tools::font::lato_regular_ttf); fFreetypeNode->add_embedded_font(tools::sg::font_roboto_bold_ttf(),tools::font::roboto_bold_ttf); #else fFreetypeNode = new tools::sg::dummy_freetype(); #endif Messenger::Create(); } G4ToolsSGSceneHandler::~G4ToolsSGSceneHandler() { //::printf("debug : ~G4ToolsSGSceneHandler : %lu\n",this); //WARNING : nodes may refer graphics managers (as tools/sg/[GL_manager,gl2ps_manager,zb_manager] // used by viewers) to handle gstos (for GPU) or textures, then we have to delete them first. // It is assumed that we pass here BEFORE the attached/managed viewers are deleted. fpTransient2DObjects.clear(); fpPersistent2DObjects.clear(); fpTransient3DObjects.clear(); fpPersistent3DObjects.clear(); delete fFreetypeNode; } void G4ToolsSGSceneHandler::EstablishBaseNodes() { // Physical volume objects for each world hang from POs G4TransportationManager* transportationManager = G4TransportationManager::GetTransportationManager (); size_t nWorlds = transportationManager->GetNoWorlds(); std::vector::iterator iterWorld = transportationManager->GetWorldsIterator(); fpPhysicalVolumeObjects.resize(nWorlds); for (size_t i = 0; i < nWorlds; ++i, ++iterWorld) { G4VPhysicalVolume* _world = (*iterWorld); auto entity = new G4ToolsSGNode; fpPersistent3DObjects.add(entity); entity->SetPVNodeID(G4PhysicalVolumeModel::G4PhysicalVolumeNodeID(_world)); fpPhysicalVolumeObjects[i] = entity; } } tools::sg::separator* G4ToolsSGSceneHandler::GetOrCreateNode() { // Retrieve or create a G4ToolsSGNode node suitable for next solid or primitive if (fReadyForTransients) { // All transients hang from this node tools::sg::separator* sep = new tools::sg::separator; fpTransient3DObjects.add(sep); return sep; } auto* pPVModel = dynamic_cast(fpModel); if (!pPVModel) { // Persistent objects (e.g., axes) tools::sg::separator* sep = new tools::sg::separator; fpPersistent3DObjects.add(sep); return sep; } // So this is a G4PhysicalVolumeModel typedef G4PhysicalVolumeModel::G4PhysicalVolumeNodeID PVNodeID; typedef std::vector PVPath; //const PVPath& drawnPVPath = pPVModel->GetDrawnPVPath(); const PVPath& fullPVPath = pPVModel->GetFullPVPath(); //G4int currentDepth = pPVModel->GetCurrentDepth(); //G4VPhysicalVolume* pCurrentPV = pPVModel->GetCurrentPV(); //G4LogicalVolume* pCurrentLV = pPVModel->GetCurrentLV(); //G4Material* pCurrentMaterial = pPVModel->GetCurrentMaterial(); // Note: pCurrentMaterial may be zero (parallel world). // Find appropriate root const size_t nWorlds = fpPhysicalVolumeObjects.size(); size_t iWorld = 0; for (; iWorld < nWorlds; ++iWorld) { if (fullPVPath[0].GetPhysicalVolume() == fpPhysicalVolumeObjects[iWorld]->GetPVNodeID().GetPhysicalVolume()) break; } if (iWorld == nWorlds) { G4Exception("G4ToolsSGSceneHandler::GetOrCreateNode", "ToolsSG-0000", FatalException, "World mis-match - not possible(!?)"); } // (Re-)establish pv path of root entity G4ToolsSGNode* _world = fpPhysicalVolumeObjects[iWorld]; _world->SetPVNodeID(fullPVPath[0]); // Provide nodes as required - may be a new node or a pre-existing node G4ToolsSGNode* node = _world; // Working variable - default to world const size_t depth = fullPVPath.size(); size_t iDepth = 1; while (iDepth < depth) { const auto& children = node->children(); const G4int nChildren = (G4int)children.size(); G4int iChild = 0; G4ToolsSGNode* child = nullptr; for (; iChild < nChildren; ++iChild) { child = static_cast(children[iChild]); if (child->GetPVNodeID() == fullPVPath[iDepth]) break; } if (iChild != nChildren) { // Existing node found node = child; // Must be the ancestor of new node (subsequent iteration) } else { // Add a new node as child of node G4ToolsSGNode* newNode = new G4ToolsSGNode; node->add(newNode); newNode->SetPVNodeID(fullPVPath[iDepth]); node = newNode; } ++iDepth; } return node; } void G4ToolsSGSceneHandler::ClearStore () { fpTransient2DObjects.clear(); fpPersistent2DObjects.clear(); fpTransient3DObjects.clear(); fpPersistent3DObjects.clear(); EstablishBaseNodes(); } #include "G4ToolsSGViewer.hh" void G4ToolsSGSceneHandler::ClearTransientStore () { fpTransient2DObjects.clear(); fpTransient3DObjects.clear(); if(fpViewer) { G4ToolsSG_viewer* tsg_viewer = dynamic_cast(fpViewer); if(tsg_viewer) tsg_viewer->EmitWindowRender(); } } void G4ToolsSGSceneHandler::AddPrimitive(const G4Polyline& a_polyline) { //G4cout << "debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Polyline&) : \n" << a_polyline << G4endl; if (a_polyline.size() == 0) return; tools::sg::separator* parentNode = 0; if(fProcessing2D) { parentNode = new tools::sg::separator; if (fReadyForTransients) { fpTransient2DObjects.add(parentNode); } else { fpPersistent2DObjects.add(parentNode); } } else { parentNode = GetOrCreateNode(); if(!parentNode) return; tools::sg::matrix* mtx = new tools::sg::matrix; G4Transform3D& elem = fObjectTransformation; mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3), elem(1,0),elem(1,1),elem(1,2),elem(1,3), elem(2,0),elem(2,1),elem(2,2),elem(2,3), 0, 0, 0, 1); parentNode->add(mtx); } {const auto& colour = GetColour(a_polyline); tools::sg::rgba* mat = new tools::sg::rgba(); mat->color = tools::colorf(float(colour.GetRed()), float(colour.GetGreen()), float(colour.GetBlue()), float(colour.GetAlpha())); parentNode->add(mat);} {tools::sg::draw_style* ds = new tools::sg::draw_style; ds->style = tools::sg::draw_lines; auto visAtts = GetCurrentViewer()->GetApplicableVisAttributes(a_polyline.GetVisAttributes()); ds->line_width = GetLineWidth(visAtts); // Multiplies by GetGlobalLineWidthScale parentNode->add(ds);} tools::sg::vertices* vtxs = new tools::sg::vertices; vtxs->mode = tools::gl::line_strip(); //polyline parentNode->add(vtxs); {for (const auto& i : a_polyline) { vtxs->add(float(i.x()),float(i.y()),float(i.z())); }} } void G4ToolsSGSceneHandler::AddPrimitive (const G4Polymarker& a_polymarker) { //::printf("debug G4ToolsSGSceneHandler::AddPrimitive(const G4Polymarker&) : %lu, type %d\n", // a_polymarker.size(),a_polymarker.GetMarkerType()); if (a_polymarker.size() == 0) return; auto currentNode = GetOrCreateNode(); if (!currentNode) return; // Node not available // Transformation {tools::sg::matrix* mtx = new tools::sg::matrix; G4Transform3D& elem = fObjectTransformation; mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3), elem(1,0),elem(1,1),elem(1,2),elem(1,3), elem(2,0),elem(2,1),elem(2,2),elem(2,3), 0, 0, 0, 1); currentNode->add(mtx);} {const auto& colour = GetColour(a_polymarker); tools::sg::rgba* mat = new tools::sg::rgba(); mat->color = tools::colorf(float(colour.GetRed()), float(colour.GetGreen()), float(colour.GetBlue()), float(colour.GetAlpha())); currentNode->add(mat);} MarkerSizeType markerSizeType; G4double markerSize = GetMarkerSize(a_polymarker, markerSizeType); switch (a_polymarker.GetMarkerType()) { default: case G4Polymarker::dots:{ tools::sg::draw_style* ds = new tools::sg::draw_style; ds->style = tools::sg::draw_points; ds->point_size = markerSize; ds->point_smooth = fpViewer->GetViewParameters().IsDotsSmooth()?true:false; currentNode->add(ds); tools::sg::vertices* vtxs = new tools::sg::vertices; vtxs->mode = tools::gl::points(); {for (const auto& i : a_polymarker) { vtxs->add(float(i.x()),float(i.y()),float(i.z())); }} currentNode->add(vtxs); }break; case G4Polymarker::circles:{ {tools::sg::markers* markers = new tools::sg::markers; G4double diameter = markerSize; // OK for "screen-size" (the usual case) if (markerSizeType == G4VSceneHandler::world ) { const G4double scale = 200.; // Roughly pixels per scene diameter *= fpScene->GetExtent().GetExtentRadius()/scale; } markers->size = diameter; markers->style = tools::sg::marker_circle_filled; for (const auto& i : a_polymarker) { markers->add(float(i.x()),float(i.y()),float(i.z())); } currentNode->add(markers);} }break; case G4Polymarker::squares:{ {tools::sg::markers* markers = new tools::sg::markers; G4double side = markerSize; // OK for "screen-size" (the usual case) if (markerSizeType == G4VSceneHandler::world ) { const G4double scale = 200.; // Roughly pixels per scene side *= fpScene->GetExtent().GetExtentRadius()/scale; } markers->size = side; markers->style = tools::sg::marker_square_filled; for (const auto& i : a_polymarker) { markers->add(float(i.x()),float(i.y()),float(i.z())); } currentNode->add(markers);} }break; } } void G4ToolsSGSceneHandler::SetMarkerScale(double a_scale) {fMarkerScale = a_scale;} void G4ToolsSGSceneHandler::AddPrimitive(const G4Text& a_text) { //::printf("debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Text&) : 000 : \"%s\"\n",a_text.GetText().c_str()); //::printf("debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Text&) : 2D ? %d\n",fProcessing2D); auto pos = a_text.GetPosition(); //::printf("debug : Add Text : pos %g %g %g\n",pos.x(),pos.y(),pos.z()); tools::sg::separator* parentNode = 0; if(fProcessing2D) { parentNode = new tools::sg::separator; if (fReadyForTransients) { fpTransient2DObjects.add(parentNode); } else { fpPersistent2DObjects.add(parentNode); } tools::sg::matrix* mtx = new tools::sg::matrix; mtx->set_translate(pos.x(),pos.y(),pos.z()); parentNode->add(mtx); } else { parentNode = GetOrCreateNode(); if (!parentNode) return; tools::sg::matrix* mtx = new tools::sg::matrix; auto elem = fObjectTransformation*G4Translate3D(pos); mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3), elem(1,0),elem(1,1),elem(1,2),elem(1,3), elem(2,0),elem(2,1),elem(2,2),elem(2,3), 0, 0, 0, 1); parentNode->add(mtx); } MarkerSizeType sizeType; G4double size = GetMarkerSize(a_text, sizeType); size *= fMarkerScale; {const auto& colour = GetTextColour(a_text); tools::sg::rgba* mat = new tools::sg::rgba(); mat->color = tools::colorf(float(colour.GetRed()), float(colour.GetGreen()), float(colour.GetBlue()), float(colour.GetAlpha())); parentNode->add(mat);} #ifdef TOOLS_USE_FREETYPE toolx::sg::text_freetype_marker* text = new toolx::sg::text_freetype_marker; text->add_embedded_font(tools::sg::font_lato_regular_ttf(),tools::font::lato_regular_ttf); text->font = tools::sg::font_lato_regular_ttf(); text->front_face = tools::sg::winding_cw; //text->modeling = tools::sg::font_pixmap; //problem with Qt/GL. It slows rendering! #else tools::sg::text_hershey_marker* text = new tools::sg::text_hershey_marker; //text->encoding.value(a_encoding); #endif text->height = float(size); //pixels text->strings.add(a_text.GetText()); {switch (a_text.GetLayout()) { default: case G4Text::left: text->hjust = tools::sg::left; break; case G4Text::centre: text->hjust = tools::sg::center; break; case G4Text::right: text->hjust = tools::sg::right; break; }} //text->vjust.value(a_vjust); parentNode->add(text); } void G4ToolsSGSceneHandler::AddPrimitive(const G4Circle& a_circle) { G4Polymarker oneCircle(a_circle); oneCircle.push_back(a_circle.GetPosition()); oneCircle.SetMarkerType(G4Polymarker::circles); // Call this AddPrimitive to avoid re-doing sub-class code. G4ToolsSGSceneHandler::AddPrimitive(oneCircle); } void G4ToolsSGSceneHandler::AddPrimitive(const G4Square& a_square) { G4Polymarker oneSquare(a_square); oneSquare.push_back(a_square.GetPosition()); oneSquare.SetMarkerType(G4Polymarker::squares); // Call this AddPrimitive to avoid re-doing sub-class code. G4ToolsSGSceneHandler::AddPrimitive(oneSquare); } void G4ToolsSGSceneHandler::AddPrimitive(const G4Polyhedron& a_polyhedron) { if (a_polyhedron.GetNoFacets() == 0) return; //::printf("debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Polyhedron&) : %d\n",a_polyhedron.GetNoFacets()); fpVisAttribs = fpViewer->GetApplicableVisAttributes(a_polyhedron.GetVisAttributes()); // Roll out vertices and normals for the faces. Note that this means vertices // are duplicated. For example a box has 8 vertices, but to define 6 faces // you need 12 triangles and 36 vertices. If it was just a matter of vertices // we could restrict the number to 8 and use the indices to define the // triangles, but we also have to consider the normals. A vertex can be have // more than one normal, depending on which face it is being used to define. // So we roll out all the vertices and normals for each triangle. std::vector vertices; std::vector normals; // Also roll out edges (as lines) for wireframe. Avoid duplicate lines, // including those that differ only in the order of vertices. typedef std::pair Line; std::vector lines; auto insertIfNew = [&lines](const Line& newLine) { // for (const auto& line: lines) { // if ((newLine.first==line.first && newLine.second==line.second) || // (newLine.first==line.second && newLine.second==line.first)) // return; // } lines.push_back(newLine); }; G4bool isAuxilaryEdgeVisible = fpViewer->GetViewParameters().IsAuxEdgeVisible(); G4bool notLastFace; do { G4int nEdges; G4Point3D vertex [4]; G4int edgeFlag[4]; G4Normal3D normal [4]; notLastFace = a_polyhedron.GetNextFacet(nEdges, vertex, edgeFlag, normal); vertices.push_back(vertex[0]); vertices.push_back(vertex[1]); vertices.push_back(vertex[2]); normals.push_back(normal[0]); normals.push_back(normal[1]); normals.push_back(normal[2]); if(isAuxilaryEdgeVisible||edgeFlag[0]>0)insertIfNew(Line(vertex[0],vertex[1])); if(isAuxilaryEdgeVisible||edgeFlag[1]>0)insertIfNew(Line(vertex[1],vertex[2])); if (nEdges == 3) { // Face is a triangle // One more line for wireframe, triangles for surfaces are complete if(isAuxilaryEdgeVisible||edgeFlag[2]>0)insertIfNew(Line(vertex[2],vertex[0])); } else if (nEdges == 4) { // Face is a quadrilateral // Create another triangle for surfaces, add two more lines for wireframe vertices.push_back(vertex[2]); vertices.push_back(vertex[3]); vertices.push_back(vertex[0]); normals.push_back(normal[2]); normals.push_back(normal[3]); normals.push_back(normal[0]); if(isAuxilaryEdgeVisible||edgeFlag[2]>0)insertIfNew(Line(vertex[2],vertex[3])); if(isAuxilaryEdgeVisible||edgeFlag[3]>0)insertIfNew(Line(vertex[3],vertex[0])); } else { G4cerr << "G4ToolsSGSceneHandler::AddPrimitive(G4Polyhedron): WARNING:" << "\n G4Polyhedron facet with unexpected number of edges (" << nEdges << ")." << G4endl; return; } } while (notLastFace); G4ViewParameters::DrawingStyle drawing_style = GetDrawingStyle (fpVisAttribs); switch (drawing_style) { case G4ViewParameters::wireframe: //vertices.clear(); break; case G4ViewParameters::hlr: break; case G4ViewParameters::hsr: //lines.clear(); break; case G4ViewParameters::hlhsr: break; case G4ViewParameters::cloud: // Shouldn't happen in this function (it's a polyhedron!) - ignore return; } auto currentNode = GetOrCreateNode(); if (!currentNode) return; // Node not available tools::sg::separator* sep = new tools::sg::separator; currentNode->add(sep); // Transformation {tools::sg::matrix* mtx = new tools::sg::matrix; G4Transform3D& elem = fObjectTransformation; mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3), elem(1,0),elem(1,1),elem(1,2),elem(1,3), elem(2,0),elem(2,1),elem(2,2),elem(2,3), 0, 0, 0, 1); sep->add(mtx);} {const auto& colour = GetColour(a_polyhedron); tools::sg::rgba* mat = new tools::sg::rgba(); mat->color = tools::colorf(float(colour.GetRed()), float(colour.GetGreen()), float(colour.GetBlue()), float(colour.GetAlpha())); sep->add(mat);} if (drawing_style == G4ViewParameters::hlr || drawing_style == G4ViewParameters::hsr || drawing_style == G4ViewParameters::hlhsr) { {tools::sg::draw_style* ds = new tools::sg::draw_style; ds->style = tools::sg::draw_filled; //ds->cull_face = true; sep->add(ds);} tools::sg::atb_vertices* vtxs = new tools::sg::atb_vertices; vtxs->mode = tools::gl::triangles(); sep->add(vtxs); const auto nVerts = vertices.size(); for (size_t i = 0; i < nVerts; i++) { vtxs->add(float(vertices[i].x()),float(vertices[i].y()),float(vertices[i].z())); vtxs->add_normal(float(normals[i].x()),float(normals[i].y()),float(normals[i].z())); } } if (drawing_style == G4ViewParameters::wireframe || drawing_style == G4ViewParameters::hlr || drawing_style == G4ViewParameters::hlhsr) { {tools::sg::draw_style* ds = new tools::sg::draw_style; ds->style = tools::sg::draw_lines; auto visAtts = GetCurrentViewer()->GetApplicableVisAttributes(a_polyhedron.GetVisAttributes()); ds->line_width = GetLineWidth(visAtts); // Multiplies by GetGlobalLineWidthScale sep->add(ds);} tools::sg::vertices* vtxs = new tools::sg::vertices; vtxs->mode = tools::gl::lines(); //segments sep->add(vtxs); for (const auto& line: lines) { vtxs->add(float(line.first.x()),float(line.first.y()),float(line.first.z())); vtxs->add(float(line.second.x()),float(line.second.y()),float(line.second.z())); } } } void G4ToolsSGSceneHandler::AddCompound(const G4Mesh& mesh) { StandardSpecialMeshRendering(mesh); } //plotting: inline void SetRegionStyles(tools::xml::styles& a_styles, tools::sg::plots& a_plots, tools::sg::plotter& a_plotter, const G4String& a_style) { if(a_style=="reset") { a_plotter.reset_style(true); a_plots.touch(); //to apply indirectly plots::set_plotter_layout() on _plotter. } else if( (a_style=="inlib_default")|| (a_style=="default")) { tools::sg::set_inlib_default_style(G4cout,a_styles.cmaps(),a_plotter,tools::sg::font_hershey()); } else if(a_style=="ROOT_default") { tools::sg::set_ROOT_default_style(G4cout,a_styles.cmaps(),a_plotter,tools::sg::font_roboto_bold_ttf()); } else if(a_style=="hippodraw") { tools::sg::set_hippodraw_style(G4cout,a_styles.cmaps(),a_plotter,tools::sg::font_lato_regular_ttf()); } else { tools::sg::style_from_res(a_styles,a_style,a_plotter,false); } } inline tools::xml::styles::style_t* find_style(tools::xml::styles& a_styles,const std::string& a_name) { for(auto& style : a_styles.named_styles()) { if(style.first==a_name) return &(style.second); } return nullptr; } inline void SetPlotterStyles(tools::sg::plots& a_plots, const std::vector& a_plotter_styles, const std::vector& a_region_styles) { G4PlotterManager::Styles& _styles = G4PlotterManager::GetInstance().GetStyles(); tools::xml::styles _tools_styles(G4cout); _tools_styles.add_colormap("default",tools::sg::style_default_colormap()); _tools_styles.add_colormap("ROOT",tools::sg::style_ROOT_colormap()); for(const auto& [name, style_items] : _styles) { tools::xml::styles::style_t _tools_style; for(const auto& [param, value] : style_items) { if(param.find('.')==std::string::npos) { _tools_style.push_back(tools::xml::styles::style_item_t(param,value)); } } _tools_styles.add_style(name, _tools_style); } // sub styles: for(const auto& [name, style_items] : _styles) { for(const auto& [param, value] : style_items) { std::string::size_type pos = param.rfind('.'); if(pos!=std::string::npos) { std::string sub_style = name + "." + param.substr(0,pos); G4String parameter = param.substr(pos+1,param.size()-pos); tools::xml::styles::style_t* _tools_style = find_style(_tools_styles,sub_style); if(_tools_style) { _tools_style->push_back(tools::xml::styles::style_item_t(parameter,value)); } else { tools::xml::styles::style_t _tools_style_2; _tools_style_2.push_back(tools::xml::styles::style_item_t(parameter,value)); _tools_styles.add_style(sub_style,_tools_style_2); } } } } unsigned int number = a_plots.number(); for(unsigned int index=0;index& a_region_parameters) { // parameter/field examples : // title_automated // title // bins_style.0.color // x_axis.divisions // x_axis.line_style.color // background_style.back_color for(const auto& [region,param] : a_region_parameters) { tools::sg::plotter* _plotter = a_plots.find_plotter(region); if(_plotter) { const G4String& parameter = param.first; const G4String& value = param.second; tools::sg::field* fd = _plotter->find_field_by_name(parameter); if(!fd) fd = _plotter->find_field_by_name(_plotter->s_cls()+"."+parameter); if(fd) {if(fd->s2value(value)) continue;} // look for sf_enum for which value is given with a string, or // for sf for which value given with true/false, or // for a style, for example: bins_style.0.color: if(!_plotter->set_from_string(G4cout,a_cmaps,parameter,value)) { G4cout << "G4ToolsSGSceneHandler::SetPlotterParameters: plotter.set_from_string() failed for field " << tools::sout(parameter) << ", and value " << tools::sout(value) << "." << std::endl; } } } } #include "G4UImanager.hh" void G4ToolsSGSceneHandler::SetPlotterHistograms(tools::sg::plots& a_plots) { a_plots.clear(); G4UImanager* UI = G4UImanager::GetUIpointer(); if(UI==NULL) return; for(const auto& [region, hid] : fRegionH1s) { tools::sg::plotter* _plotter = a_plots.find_plotter(region); if(_plotter) { std::ostringstream os; os << hid; std::string cmd("/analysis/h1/get "); cmd += std::string(os.str()); auto keepControlVerbose = UI->GetVerboseLevel(); UI->SetVerboseLevel(0); G4int status = UI->ApplyCommand(cmd.c_str()); UI->SetVerboseLevel(keepControlVerbose); if(status==G4UIcommandStatus::fCommandSucceeded) { G4String hexString = UI->GetCurrentValues("/analysis/h1/get"); if(hexString.size()) { void* ptr; std::istringstream is(hexString); is >> ptr; tools::histo::h1d* _h = (tools::histo::h1d*)ptr; tools::sg::plottable* p = new tools::sg::h1d2plot_cp(*_h); _plotter->add_plottable(p); //give ownership of p to sg::plotter. } } else { G4cerr << "G4ToolsSGSceneHandler::SetPlotterHistograms: cannot get histogram - maybe doesn't exist?" "\n Maybe this app does not do analysis at all?" << G4endl; } } } for(const auto& [region, hid] : fRegionH2s) { tools::sg::plotter* _plotter = a_plots.find_plotter(region); if(_plotter) { std::ostringstream os; os << hid; std::string cmd("/analysis/h2/get "); cmd += std::string(os.str()); auto keepControlVerbose = UI->GetVerboseLevel(); UI->SetVerboseLevel(0); G4int status = UI->ApplyCommand(cmd.c_str()); UI->SetVerboseLevel(keepControlVerbose); if(status==G4UIcommandStatus::fCommandSucceeded) { G4String hexString = UI->GetCurrentValues("/analysis/h2/get"); if(hexString.size()) { void* ptr; std::istringstream is(hexString); is >> ptr; tools::histo::h2d* _h = (tools::histo::h2d*)ptr; tools::sg::plottable* p = new tools::sg::h2d2plot_cp(*_h); _plotter->add_plottable(p); //give ownership of p to sg::plotter. } } else { G4cerr << "G4ToolsSGSceneHandler::SetPlotterHistograms: cannot get histogram - maybe doesn't exist?" "\n Maybe this app does not do analysis at all?" << G4endl; } } } } class plots_cbk : public tools::sg::ecbk { TOOLS_CBK(plots_cbk,plots_cbk,tools::sg::ecbk) public: virtual tools::sg::return_action action() { if(!m_event) return tools::sg::return_none; if(const tools::sg::size_event* sz_evt = tools::sg::event_cast(*m_event)){ m_plots.adjust_size(sz_evt->width(),sz_evt->height()); m_event_action->set_done(true); return tools::sg::return_to_render; } return tools::sg::return_none; } public: plots_cbk(tools::sg::plots& a_plots) :parent() ,m_plots(a_plots) {} virtual ~plots_cbk(){} public: plots_cbk(const plots_cbk& a_from) :parent(a_from) ,m_plots(a_from.m_plots) {} plots_cbk& operator=(const plots_cbk& a_from){ parent::operator=(a_from); return *this; } protected: tools::sg::plots& m_plots; }; void G4ToolsSGSceneHandler::TouchPlotters(tools::sg::node& a_sg) { tools::sg::search_action sa(G4cout); const tools::sg::search_action::paths_t& paths = tools::sg::find_paths(sa,a_sg); for(const auto& path : paths) { tools::sg::plots* _plots = tools::sg::tail(path); if(_plots) { SetPlotterHistograms(*_plots); } } } void G4ToolsSGSceneHandler::AddPrimitive(const G4Plotter& a_plotter) { //G4cout << "debug : G4ToolsSGSceneHandler::AddPrimitive : 004" << std::endl; if(!fpViewer) return; auto currentNode = GetOrCreateNode(); if (!currentNode) return; // Node not available currentNode->add(new tools::sg::light_off()); tools::sg::plots* _plots = new tools::sg::plots(*fFreetypeNode); currentNode->add(_plots); _plots->view_border = false; _plots->set_regions(a_plotter.GetColumns(),a_plotter.GetRows()); {tools::sg::event_dispatcher* dpt = new tools::sg::event_dispatcher; dpt->add_callback(new plots_cbk(*_plots)); currentNode->add(dpt);} SetPlotterStyles(*_plots,a_plotter.GetStyles(),a_plotter.GetRegionStyles()); tools::sg::cmaps_t _cmaps; _cmaps["default"] = tools::sg::style_default_colormap(); _cmaps["ROOT"] = tools::sg::style_ROOT_colormap(); SetPlotterParameters(_cmaps,*_plots,a_plotter.GetRegionParameters()); fRegionH1s = a_plotter.GetRegionH1s(); fRegionH2s = a_plotter.GetRegionH2s(); SetPlotterHistograms(*_plots); } void G4ToolsSGSceneHandler::Messenger::SetNewValue(G4UIcommand* a_cmd,G4String) { G4VSceneHandler* pSceneHandler = GetVisManager()->GetCurrentSceneHandler(); if (!pSceneHandler) { G4cout << "G4ToolsSGSceneHandler::Messenger::SetNewValue: no current sceneHandler. Please create one." << G4endl; return; } auto* tsg_scene_handler = dynamic_cast(pSceneHandler); if(!tsg_scene_handler) { G4cout << "G4ToolsSGSceneHandler::Messenger::SetNewValue: current sceneHandler not a G4ToolsSGSceneHandler." << G4endl; return; } if(a_cmd==print_plotter_params) { tools::sg::dummy_freetype _ttf; tools::sg::plotter _plotter(_ttf); _plotter.print_available_customization(G4cout); } }