Geant4 Cross Reference |
1 // 2 // ******************************************************************** 3 // * License and Disclaimer * 4 // * * 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. * 10 // * * 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitation of liability. * 17 // * * 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************************************** 25 // 26 // John Allison 6th October 2020 27 28 #include "G4ToolsSGSceneHandler.hh" 29 30 #include "G4ToolsSGNode.hh" 31 32 #include "G4TransportationManager.hh" 33 #include "G4Polyline.hh" 34 #include "G4Polymarker.hh" 35 #include "G4Circle.hh" 36 #include "G4Square.hh" 37 #include "G4Polyhedron.hh" 38 #include "G4Text.hh" 39 #include "G4Mesh.hh" 40 #include "G4PlotterManager.hh" 41 42 #include <tools/sg/separator> 43 #include <tools/sg/matrix> 44 #include <tools/sg/rgba> 45 #include <tools/sg/draw_style> 46 #include <tools/sg/atb_vertices> 47 #include <tools/sg/markers> 48 #ifdef TOOLS_USE_FREETYPE 49 #include <toolx/sg/text_freetype> 50 #include <tools/sg/strings> 51 #include <tools/font/lato_regular_ttf> 52 #include <tools/font/roboto_bold_ttf> 53 #include <toolx/sg/text_freetype_marker> 54 #else 55 #include <tools/sg/dummy_freetype> 56 #include <tools/sg/text_hershey_marker> 57 #endif 58 59 //for plotting: 60 #include <tools/sg/dummy_freetype> 61 #include <tools/sg/light_off> 62 #include <tools/sg/plots> 63 #include <tools/sg/h2plot_cp> 64 #include <tools/sg/plotter_style> 65 #include <tools/sg/event_dispatcher> 66 #include <tools/sg/path> 67 #include <tools/sg/search> 68 #include <tools/histo/h1d> 69 #include <tools/histo/h2d> 70 #include <tools/sg/plotter_some_styles> 71 72 #include <utility> 73 74 G4int G4ToolsSGSceneHandler::fSceneIdCount = 0; 75 76 G4ToolsSGSceneHandler::G4ToolsSGSceneHandler 77 (G4VGraphicsSystem& system, const G4String& name) 78 :parent(system, fSceneIdCount++, name) 79 ,fFreetypeNode(0) 80 { 81 //::printf("debug : G4ToolsSGSceneHandler : %lu, %s\n",this,name.c_str()); 82 EstablishBaseNodes(); 83 #if defined(TOOLS_USE_FREETYPE) 84 fFreetypeNode = new toolx::sg::text_freetype(); 85 fFreetypeNode->add_embedded_font(tools::sg::font_lato_regular_ttf(),tools::font::lato_regular_ttf); 86 fFreetypeNode->add_embedded_font(tools::sg::font_roboto_bold_ttf(),tools::font::roboto_bold_ttf); 87 #else 88 fFreetypeNode = new tools::sg::dummy_freetype(); 89 #endif 90 Messenger::Create(); 91 } 92 93 G4ToolsSGSceneHandler::~G4ToolsSGSceneHandler() 94 { 95 //::printf("debug : ~G4ToolsSGSceneHandler : %lu\n",this); 96 //WARNING : nodes may refer graphics managers (as tools/sg/[GL_manager,gl2ps_manager,zb_manager] 97 // used by viewers) to handle gstos (for GPU) or textures, then we have to delete them first. 98 // It is assumed that we pass here BEFORE the attached/managed viewers are deleted. 99 fpTransient2DObjects.clear(); 100 fpPersistent2DObjects.clear(); 101 fpTransient3DObjects.clear(); 102 fpPersistent3DObjects.clear(); 103 delete fFreetypeNode; 104 } 105 106 void G4ToolsSGSceneHandler::EstablishBaseNodes() 107 { 108 // Physical volume objects for each world hang from POs 109 G4TransportationManager* transportationManager = G4TransportationManager::GetTransportationManager (); 110 size_t nWorlds = transportationManager->GetNoWorlds(); 111 std::vector<G4VPhysicalVolume*>::iterator iterWorld = transportationManager->GetWorldsIterator(); 112 fpPhysicalVolumeObjects.resize(nWorlds); 113 for (size_t i = 0; i < nWorlds; ++i, ++iterWorld) { 114 G4VPhysicalVolume* _world = (*iterWorld); 115 auto entity = new G4ToolsSGNode; 116 fpPersistent3DObjects.add(entity); 117 entity->SetPVNodeID(G4PhysicalVolumeModel::G4PhysicalVolumeNodeID(_world)); 118 fpPhysicalVolumeObjects[i] = entity; 119 } 120 } 121 122 tools::sg::separator* G4ToolsSGSceneHandler::GetOrCreateNode() 123 { // Retrieve or create a G4ToolsSGNode node suitable for next solid or primitive 124 125 // For time being, avoid errors in MT mode - see G4ToolsSGViewer::SwitchToMasterThread 126 if (!G4Threading::IsMasterThread()) return nullptr; 127 128 if (fReadyForTransients) { // All transients hang from this node 129 tools::sg::separator* sep = new tools::sg::separator; 130 fpTransient3DObjects.add(sep); 131 return sep; 132 } 133 134 auto* pPVModel = dynamic_cast<G4PhysicalVolumeModel*>(fpModel); 135 136 if (!pPVModel) { // Persistent objects (e.g., axes) 137 tools::sg::separator* sep = new tools::sg::separator; 138 fpPersistent3DObjects.add(sep); 139 return sep; 140 } 141 142 // So this is a G4PhysicalVolumeModel 143 typedef G4PhysicalVolumeModel::G4PhysicalVolumeNodeID PVNodeID; 144 typedef std::vector<PVNodeID> PVPath; 145 //const PVPath& drawnPVPath = pPVModel->GetDrawnPVPath(); 146 const PVPath& fullPVPath = pPVModel->GetFullPVPath(); 147 //G4int currentDepth = pPVModel->GetCurrentDepth(); 148 //G4VPhysicalVolume* pCurrentPV = pPVModel->GetCurrentPV(); 149 //G4LogicalVolume* pCurrentLV = pPVModel->GetCurrentLV(); 150 //G4Material* pCurrentMaterial = pPVModel->GetCurrentMaterial(); 151 // Note: pCurrentMaterial may be zero (parallel world). 152 153 // Find appropriate root 154 const size_t nWorlds = fpPhysicalVolumeObjects.size(); 155 size_t iWorld = 0; 156 for (; iWorld < nWorlds; ++iWorld) { 157 if (fullPVPath[0].GetPhysicalVolume() == 158 fpPhysicalVolumeObjects[iWorld]->GetPVNodeID().GetPhysicalVolume()) break; 159 } 160 if (iWorld == nWorlds) { 161 G4Exception("G4ToolsSGSceneHandler::GetOrCreateNode", "ToolsSG-0000", FatalException, 162 "World mis-match - not possible(!?)"); 163 } 164 165 // (Re-)establish pv path of root entity 166 G4ToolsSGNode* _world = fpPhysicalVolumeObjects[iWorld]; 167 _world->SetPVNodeID(fullPVPath[0]); 168 169 // Provide nodes as required - may be a new node or a pre-existing node 170 G4ToolsSGNode* node = _world; // Working variable - default to world 171 const size_t depth = fullPVPath.size(); 172 size_t iDepth = 1; 173 while (iDepth < depth) { 174 const auto& children = node->children(); 175 const G4int nChildren = (G4int)children.size(); 176 G4int iChild = 0; 177 G4ToolsSGNode* child = nullptr; 178 for (; iChild < nChildren; ++iChild) { 179 child = static_cast<G4ToolsSGNode*>(children[iChild]); 180 if (child->GetPVNodeID() == fullPVPath[iDepth]) break; 181 } 182 if (iChild != nChildren) { // Existing node found 183 node = child; // Must be the ancestor of new node (subsequent iteration) 184 } else { 185 // Add a new node as child of node 186 G4ToolsSGNode* newNode = new G4ToolsSGNode; 187 node->add(newNode); 188 newNode->SetPVNodeID(fullPVPath[iDepth]); 189 node = newNode; 190 } 191 ++iDepth; 192 } 193 return node; 194 } 195 196 void G4ToolsSGSceneHandler::ClearStore () 197 { 198 fpTransient2DObjects.clear(); 199 fpPersistent2DObjects.clear(); 200 fpTransient3DObjects.clear(); 201 fpPersistent3DObjects.clear(); 202 EstablishBaseNodes(); 203 } 204 205 void G4ToolsSGSceneHandler::ClearTransientStore () 206 { 207 fpTransient2DObjects.clear(); 208 fpTransient3DObjects.clear(); 209 } 210 211 void G4ToolsSGSceneHandler::AddPrimitive(const G4Polyline& a_polyline) 212 { 213 //G4cout << "debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Polyline&) : \n" << a_polyline << G4endl; 214 if (a_polyline.size() == 0) return; 215 216 tools::sg::separator* parentNode = 0; 217 if(fProcessing2D) { 218 parentNode = new tools::sg::separator; 219 if (fReadyForTransients) { 220 fpTransient2DObjects.add(parentNode); 221 } else { 222 fpPersistent2DObjects.add(parentNode); 223 } 224 225 } else { 226 parentNode = GetOrCreateNode(); 227 if(!parentNode) return; 228 229 tools::sg::matrix* mtx = new tools::sg::matrix; 230 G4Transform3D& elem = fObjectTransformation; 231 mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3), 232 elem(1,0),elem(1,1),elem(1,2),elem(1,3), 233 elem(2,0),elem(2,1),elem(2,2),elem(2,3), 234 0, 0, 0, 1); 235 parentNode->add(mtx); 236 } 237 238 {const auto& colour = GetColour(a_polyline); 239 tools::sg::rgba* mat = new tools::sg::rgba(); 240 mat->color = 241 tools::colorf(float(colour.GetRed()), 242 float(colour.GetGreen()), 243 float(colour.GetBlue()), 244 float(colour.GetAlpha())); 245 parentNode->add(mat);} 246 247 {tools::sg::draw_style* ds = new tools::sg::draw_style; 248 ds->style = tools::sg::draw_lines; 249 ds->line_width = 1; 250 parentNode->add(ds);} 251 252 tools::sg::vertices* vtxs = new tools::sg::vertices; 253 vtxs->mode = tools::gl::line_strip(); //polyline 254 parentNode->add(vtxs); 255 256 {for (size_t i = 0; i < a_polyline.size(); ++i) { 257 vtxs->add(float(a_polyline[i].x()),float(a_polyline[i].y()),float(a_polyline[i].z())); 258 }} 259 260 } 261 262 void G4ToolsSGSceneHandler::AddPrimitive (const G4Polymarker& a_polymarker) 263 { 264 //::printf("debug G4ToolsSGSceneHandler::AddPrimitive(const G4Polymarker&) : %lu, type %d\n", 265 // a_polymarker.size(),a_polymarker.GetMarkerType()); 266 if (a_polymarker.size() == 0) return; 267 auto currentNode = GetOrCreateNode(); 268 if (!currentNode) return; // Node not available 269 270 // Transformation 271 {tools::sg::matrix* mtx = new tools::sg::matrix; 272 G4Transform3D& elem = fObjectTransformation; 273 mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3), 274 elem(1,0),elem(1,1),elem(1,2),elem(1,3), 275 elem(2,0),elem(2,1),elem(2,2),elem(2,3), 276 0, 0, 0, 1); 277 currentNode->add(mtx);} 278 279 {const auto& colour = GetColour(a_polymarker); 280 tools::sg::rgba* mat = new tools::sg::rgba(); 281 mat->color = 282 tools::colorf(float(colour.GetRed()), 283 float(colour.GetGreen()), 284 float(colour.GetBlue()), 285 float(colour.GetAlpha())); 286 currentNode->add(mat);} 287 288 MarkerSizeType markerSizeType; 289 G4double markerSize = GetMarkerSize(a_polymarker, markerSizeType); 290 291 switch (a_polymarker.GetMarkerType()) { 292 default: 293 case G4Polymarker::dots:{ 294 //::printf("debug : GB : Add Markers : +++++++++++++++++++++++++++++++++++++++++++ : dots\n"); 295 tools::sg::draw_style* ds = new tools::sg::draw_style; 296 ds->style = tools::sg::draw_points; 297 ds->point_size = 1; 298 currentNode->add(ds); 299 tools::sg::vertices* vtxs = new tools::sg::vertices; 300 vtxs->mode = tools::gl::points(); 301 {for (size_t i = 0; i < a_polymarker.size(); ++i) { 302 vtxs->add(float(a_polymarker[i].x()),float(a_polymarker[i].y()),float(a_polymarker[i].z())); 303 }} 304 currentNode->add(vtxs); 305 }break; 306 case G4Polymarker::circles:{ 307 //::printf("debug : GB : Add Markers : +++++++++++++++++++++++++++++++++++++++++++ : circles\n"); 308 {tools::sg::markers* markers = new tools::sg::markers; 309 G4double diameter = markerSize; // OK for "screen-size" (the usual case) 310 if (markerSizeType == G4VSceneHandler::world ) { 311 const G4double scale = 200.; // Roughly pixels per scene 312 diameter *= fpScene->GetExtent().GetExtentRadius()/scale; 313 } 314 markers->size = diameter; 315 markers->style = tools::sg::marker_circle_line; 316 for (size_t i = 0; i < a_polymarker.size(); ++i) { 317 markers->add(float(a_polymarker[i].x()),float(a_polymarker[i].y()),float(a_polymarker[i].z())); 318 } 319 currentNode->add(markers);} 320 }break; 321 case G4Polymarker::squares:{ 322 //::printf("debug : GB : Add Markers : +++++++++++++++++++++++++++++++++++++++++++ : square\n"); 323 {tools::sg::markers* markers = new tools::sg::markers; 324 G4double side = markerSize; // OK for "screen-size" (the usual case) 325 if (markerSizeType == G4VSceneHandler::world ) { 326 const G4double scale = 200.; // Roughly pixels per scene 327 side *= fpScene->GetExtent().GetExtentRadius()/scale; 328 } 329 markers->size = side; 330 markers->style = tools::sg::marker_square_line; 331 for (size_t i = 0; i < a_polymarker.size(); ++i) { 332 markers->add(float(a_polymarker[i].x()),float(a_polymarker[i].y()),float(a_polymarker[i].z())); 333 } 334 currentNode->add(markers);} 335 }break; 336 } 337 } 338 339 void G4ToolsSGSceneHandler::AddPrimitive(const G4Text& a_text) 340 { 341 //::printf("debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Text&) : 000 : \"%s\"\n",a_text.GetText().c_str()); 342 //::printf("debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Text&) : 2D ? %d\n",fProcessing2D); 343 auto pos = a_text.GetPosition(); 344 //::printf("debug : Add Text : pos %g %g %g\n",pos.x(),pos.y(),pos.z()); 345 346 tools::sg::separator* parentNode = 0; 347 if(fProcessing2D) { 348 parentNode = new tools::sg::separator; 349 if (fReadyForTransients) { 350 fpTransient2DObjects.add(parentNode); 351 } else { 352 fpPersistent2DObjects.add(parentNode); 353 } 354 355 tools::sg::matrix* mtx = new tools::sg::matrix; 356 mtx->set_translate(pos.x(),pos.y(),pos.z()); 357 parentNode->add(mtx); 358 359 } else { 360 parentNode = GetOrCreateNode(); 361 if (!parentNode) return; 362 363 tools::sg::matrix* mtx = new tools::sg::matrix; 364 auto elem = fObjectTransformation*G4Translate3D(pos); 365 mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3), 366 elem(1,0),elem(1,1),elem(1,2),elem(1,3), 367 elem(2,0),elem(2,1),elem(2,2),elem(2,3), 368 0, 0, 0, 1); 369 parentNode->add(mtx); 370 } 371 372 MarkerSizeType sizeType; 373 G4double size = GetMarkerSize(a_text, sizeType); 374 375 {const auto& colour = GetTextColour(a_text); 376 tools::sg::rgba* mat = new tools::sg::rgba(); 377 mat->color = 378 tools::colorf(float(colour.GetRed()), 379 float(colour.GetGreen()), 380 float(colour.GetBlue()), 381 float(colour.GetAlpha())); 382 parentNode->add(mat);} 383 384 #ifdef TOOLS_USE_FREETYPE 385 toolx::sg::text_freetype_marker* text = new toolx::sg::text_freetype_marker; 386 text->add_embedded_font(tools::sg::font_lato_regular_ttf(),tools::font::lato_regular_ttf); 387 text->font = tools::sg::font_lato_regular_ttf(); 388 text->front_face = tools::sg::winding_cw; 389 //text->modeling = tools::sg::font_pixmap; //problem with Qt/GL. It slows rendering! 390 #else 391 tools::sg::text_hershey_marker* text = new tools::sg::text_hershey_marker; 392 //text->encoding.value(a_encoding); 393 #endif 394 text->height = float(size); //pixels 395 text->strings.add(a_text.GetText()); 396 {switch (a_text.GetLayout()) { 397 default: 398 case G4Text::left: 399 text->hjust = tools::sg::left; 400 break; 401 case G4Text::centre: 402 text->hjust = tools::sg::center; 403 break; 404 case G4Text::right: 405 text->hjust = tools::sg::right; 406 break; 407 }} 408 //text->vjust.value(a_vjust); 409 parentNode->add(text); 410 411 } 412 413 void G4ToolsSGSceneHandler::AddPrimitive(const G4Circle& a_circle) 414 { 415 G4Polymarker oneCircle(a_circle); 416 oneCircle.push_back(a_circle.GetPosition()); 417 oneCircle.SetMarkerType(G4Polymarker::circles); 418 // Call this AddPrimitive to avoid re-doing sub-class code. 419 G4ToolsSGSceneHandler::AddPrimitive(oneCircle); 420 } 421 422 void G4ToolsSGSceneHandler::AddPrimitive(const G4Square& a_square) 423 { 424 G4Polymarker oneSquare(a_square); 425 oneSquare.push_back(a_square.GetPosition()); 426 oneSquare.SetMarkerType(G4Polymarker::squares); 427 // Call this AddPrimitive to avoid re-doing sub-class code. 428 G4ToolsSGSceneHandler::AddPrimitive(oneSquare); 429 } 430 431 void G4ToolsSGSceneHandler::AddPrimitive(const G4Polyhedron& a_polyhedron) 432 { 433 if (a_polyhedron.GetNoFacets() == 0) return; 434 435 //::printf("debug : G4ToolsSGSceneHandler::AddPrimitive(const G4Polyhedron&) : %d\n",a_polyhedron.GetNoFacets()); 436 437 fpVisAttribs = fpViewer->GetApplicableVisAttributes(a_polyhedron.GetVisAttributes()); 438 439 // Roll out vertices and normals for the faces. Note that this means vertices 440 // are duplicated. For example a box has 8 vertices, but to define 6 faces 441 // you need 12 triangles and 36 vertices. If it was just a matter of vertices 442 // we could restrict the number to 8 and use the indices to define the 443 // triangles, but we also have to consider the normals. A vertex can be have 444 // more than one normal, depending on which face it is being used to define. 445 // So we roll out all the vertices and normals for each triangle. 446 std::vector<G4Point3D> vertices; 447 std::vector<G4Normal3D> normals; 448 449 // Also roll out edges (as lines) for wireframe. Avoid duplicate lines, 450 // including those that differ only in the order of vertices. 451 typedef std::pair<G4Point3D,G4Point3D> Line; 452 std::vector<Line> lines; 453 auto insertIfNew = [&lines](const Line& newLine) { 454 // for (const auto& line: lines) { 455 // if ((newLine.first==line.first && newLine.second==line.second) || 456 // (newLine.first==line.second && newLine.second==line.first)) 457 // return; 458 // } 459 lines.push_back(newLine); 460 }; 461 462 G4bool isAuxilaryEdgeVisible = fpViewer->GetViewParameters().IsAuxEdgeVisible(); 463 G4bool notLastFace; 464 do { 465 G4int nEdges; 466 G4Point3D vertex [4]; 467 G4int edgeFlag[4]; 468 G4Normal3D normal [4]; 469 notLastFace = a_polyhedron.GetNextFacet(nEdges, vertex, edgeFlag, normal); 470 vertices.push_back(vertex[0]); 471 vertices.push_back(vertex[1]); 472 vertices.push_back(vertex[2]); 473 normals.push_back(normal[0]); 474 normals.push_back(normal[1]); 475 normals.push_back(normal[2]); 476 if(isAuxilaryEdgeVisible||edgeFlag[0]>0)insertIfNew(Line(vertex[0],vertex[1])); 477 if(isAuxilaryEdgeVisible||edgeFlag[1]>0)insertIfNew(Line(vertex[1],vertex[2])); 478 if (nEdges == 3) { 479 // Face is a triangle 480 // One more line for wireframe, triangles for surfaces are complete 481 if(isAuxilaryEdgeVisible||edgeFlag[2]>0)insertIfNew(Line(vertex[2],vertex[0])); 482 } else if (nEdges == 4) { 483 // Face is a quadrilateral 484 // Create another triangle for surfaces, add two more lines for wireframe 485 vertices.push_back(vertex[2]); 486 vertices.push_back(vertex[3]); 487 vertices.push_back(vertex[0]); 488 normals.push_back(normal[2]); 489 normals.push_back(normal[3]); 490 normals.push_back(normal[0]); 491 if(isAuxilaryEdgeVisible||edgeFlag[2]>0)insertIfNew(Line(vertex[2],vertex[3])); 492 if(isAuxilaryEdgeVisible||edgeFlag[3]>0)insertIfNew(Line(vertex[3],vertex[0])); 493 } else { 494 G4cerr 495 << "ERROR: polyhedron face with unexpected number of edges (" << nEdges << ')' 496 << "\n Tag: " << fpModel->GetCurrentTag() 497 << G4endl; 498 return; 499 } 500 } while (notLastFace); 501 502 G4ViewParameters::DrawingStyle drawing_style = GetDrawingStyle (fpVisAttribs); 503 switch (drawing_style) { 504 case G4ViewParameters::wireframe: 505 //vertices.clear(); 506 break; 507 case G4ViewParameters::hlr: 508 break; 509 case G4ViewParameters::hsr: 510 //lines.clear(); 511 break; 512 case G4ViewParameters::hlhsr: 513 break; 514 case G4ViewParameters::cloud: 515 // Shouldn't happen in this function (it's a polyhedron!) - ignore 516 return; 517 } 518 519 auto currentNode = GetOrCreateNode(); 520 if (!currentNode) return; // Node not available 521 522 tools::sg::separator* sep = new tools::sg::separator; 523 currentNode->add(sep); 524 525 // Transformation 526 {tools::sg::matrix* mtx = new tools::sg::matrix; 527 G4Transform3D& elem = fObjectTransformation; 528 mtx->mtx.value().set_matrix(elem(0,0),elem(0,1),elem(0,2),elem(0,3), 529 elem(1,0),elem(1,1),elem(1,2),elem(1,3), 530 elem(2,0),elem(2,1),elem(2,2),elem(2,3), 531 0, 0, 0, 1); 532 sep->add(mtx);} 533 534 {const auto& colour = GetColour(a_polyhedron); 535 tools::sg::rgba* mat = new tools::sg::rgba(); 536 mat->color = 537 tools::colorf(float(colour.GetRed()), 538 float(colour.GetGreen()), 539 float(colour.GetBlue()), 540 float(colour.GetAlpha())); 541 sep->add(mat);} 542 543 if (drawing_style == G4ViewParameters::hlr || 544 drawing_style == G4ViewParameters::hsr || 545 drawing_style == G4ViewParameters::hlhsr) { 546 547 {tools::sg::draw_style* ds = new tools::sg::draw_style; 548 ds->style = tools::sg::draw_filled; 549 //ds->cull_face = true; 550 sep->add(ds);} 551 552 tools::sg::atb_vertices* vtxs = new tools::sg::atb_vertices; 553 vtxs->mode = tools::gl::triangles(); 554 sep->add(vtxs); 555 556 const auto nVerts = vertices.size(); 557 for (size_t i = 0; i < nVerts; i++) { 558 vtxs->add(float(vertices[i].x()),float(vertices[i].y()),float(vertices[i].z())); 559 vtxs->add_normal(float(normals[i].x()),float(normals[i].y()),float(normals[i].z())); 560 } 561 } 562 563 if (drawing_style == G4ViewParameters::wireframe || 564 drawing_style == G4ViewParameters::hlr || 565 drawing_style == G4ViewParameters::hlhsr) { 566 567 {tools::sg::draw_style* ds = new tools::sg::draw_style; 568 ds->style = tools::sg::draw_lines; 569 ds->line_width = 1; 570 sep->add(ds);} 571 572 tools::sg::vertices* vtxs = new tools::sg::vertices; 573 vtxs->mode = tools::gl::lines(); //segments 574 sep->add(vtxs); 575 576 for (const auto& line: lines) { 577 vtxs->add(float(line.first.x()),float(line.first.y()),float(line.first.z())); 578 vtxs->add(float(line.second.x()),float(line.second.y()),float(line.second.z())); 579 } 580 581 } 582 } 583 584 void G4ToolsSGSceneHandler::AddCompound(const G4Mesh& mesh) 585 { 586 StandardSpecialMeshRendering(mesh); 587 } 588 589 //plotting: 590 inline void SetRegionStyles(tools::xml::styles& a_styles, 591 tools::sg::plots& a_plots, 592 tools::sg::plotter& a_plotter, 593 const G4String& a_style) { 594 if(a_style=="reset") { 595 a_plotter.reset_style(true); 596 a_plots.touch(); //to apply indirectly plots::set_plotter_layout() on _plotter. 597 } else if( (a_style=="inlib_default")|| (a_style=="default")) { 598 tools::sg::set_inlib_default_style(G4cout,a_styles.cmaps(),a_plotter,tools::sg::font_hershey()); 599 } else if(a_style=="ROOT_default") { 600 tools::sg::set_ROOT_default_style(G4cout,a_styles.cmaps(),a_plotter,tools::sg::font_roboto_bold_ttf()); 601 } else if(a_style=="hippodraw") { 602 tools::sg::set_hippodraw_style(G4cout,a_styles.cmaps(),a_plotter,tools::sg::font_lato_regular_ttf()); 603 } else { 604 tools::sg::style_from_res(a_styles,a_style,a_plotter,false); 605 } 606 } 607 608 inline tools::xml::styles::style_t* find_style(tools::xml::styles& a_styles,const std::string& a_name) { 609 tools_vforit(tools::xml::styles::named_style_t,a_styles.named_styles(),it){ 610 if((*it).first==a_name) return &((*it).second); 611 } 612 return 0; 613 } 614 615 inline void SetPlotterStyles(tools::sg::plots& a_plots, 616 const std::vector<G4String>& a_plotter_styles, 617 const std::vector<G4Plotter::RegionStyle>& a_region_styles) { 618 619 G4PlotterManager::Styles& _styles = G4PlotterManager::GetInstance().GetStyles(); 620 621 tools::xml::styles _tools_styles(G4cout); 622 _tools_styles.add_colormap("default",tools::sg::style_default_colormap()); 623 _tools_styles.add_colormap("ROOT",tools::sg::style_ROOT_colormap()); 624 625 {tools_vforcit(G4PlotterManager::NamedStyle,_styles,it) { 626 tools::xml::styles::style_t _tools_style; 627 tools_vforcit(G4PlotterManager::StyleItem,(*it).second,its) { 628 const G4String& param = (*its).first; 629 if(param.find('.')==std::string::npos) { 630 const G4String& value = (*its).second; 631 _tools_style.push_back(tools::xml::styles::style_item_t(param,value)); 632 } 633 } 634 _tools_styles.add_style((*it).first,_tools_style); 635 }} 636 637 // sub styles: 638 {tools_vforcit(G4PlotterManager::NamedStyle,_styles,it) { 639 tools_vforcit(G4PlotterManager::StyleItem,(*it).second,its) { 640 const G4String& param = (*its).first; 641 std::string::size_type pos = param.rfind('.'); 642 if(pos!=std::string::npos) { 643 std::string sub_style = (*it).first+"."+param.substr(0,pos); 644 G4String parameter = param.substr(pos+1,param.size()-pos); 645 const G4String& value = (*its).second; 646 tools::xml::styles::style_t* _tools_style = find_style(_tools_styles,sub_style); 647 if(_tools_style) { 648 _tools_style->push_back(tools::xml::styles::style_item_t(parameter,value)); 649 } else { 650 tools::xml::styles::style_t _tools_style_2; 651 _tools_style_2.push_back(tools::xml::styles::style_item_t(parameter,value)); 652 _tools_styles.add_style(sub_style,_tools_style_2); 653 } 654 } 655 } 656 }} 657 658 {unsigned int number = a_plots.number(); 659 for(unsigned int index=0;index<number;index++) { 660 tools::sg::plotter* _plotter = a_plots.find_plotter(index); 661 if(_plotter) { 662 tools_vforcit(G4String,a_plotter_styles,it) { 663 SetRegionStyles(_tools_styles,a_plots,*_plotter,*it); 664 } 665 } 666 }} 667 {tools_vforcit(G4Plotter::RegionStyle,a_region_styles,it) { 668 tools::sg::plotter* _plotter = a_plots.find_plotter((*it).first); 669 if(_plotter) { 670 SetRegionStyles(_tools_styles,a_plots,*_plotter,(*it).second); 671 } 672 }} 673 } 674 675 inline void SetPlotterParameters(tools::sg::cmaps_t& a_cmaps,tools::sg::plots& a_plots, 676 const std::vector<G4Plotter::RegionParameter>& a_region_parameters) { 677 // parameter/field examples : 678 // title_automated 679 // title 680 // bins_style.0.color 681 // x_axis.divisions 682 // x_axis.line_style.color 683 // background_style.back_color 684 tools_vforcit(G4Plotter::RegionParameter,a_region_parameters,it) { 685 tools::sg::plotter* _plotter = a_plots.find_plotter((*it).first); 686 if(_plotter) { 687 const G4String& parameter = (*it).second.first; 688 const G4String& value = (*it).second.second; 689 tools::sg::field* fd = _plotter->find_field_by_name(parameter); 690 if(!fd) fd = _plotter->find_field_by_name(_plotter->s_cls()+"."+parameter); 691 if(fd) {if(fd->s2value(value)) continue;} 692 // look for sf_enum for which value is given with a string, or 693 // for sf<bool> for which value given with true/false, or 694 // for a style, for example: bins_style.0.color: 695 if(!_plotter->set_from_string(G4cout,a_cmaps,parameter,value)) { 696 G4cout << "G4ToolsSGSceneHandler::SetPlotterParameters: plotter.set_from_string() failed for field " 697 << tools::sout(parameter) << ", and value " << tools::sout(value) << "." 698 << std::endl; 699 } 700 } 701 } 702 } 703 704 #include "G4UImanager.hh" 705 706 void G4ToolsSGSceneHandler::SetPlotterHistograms(tools::sg::plots& a_plots) { 707 a_plots.clear(); 708 G4UImanager* UI = G4UImanager::GetUIpointer(); 709 if(UI==NULL) return; 710 {tools_vforcit(Region_h1,fRegionH1s,it) { 711 tools::sg::plotter* _plotter = a_plots.find_plotter((*it).first); 712 if(_plotter) { 713 int hid = (*it).second; 714 std::ostringstream os; 715 os << hid; 716 std::string cmd("/analysis/h1/get "); 717 cmd += std::string(os.str()); 718 auto keepControlVerbose = UI->GetVerboseLevel(); 719 UI->SetVerboseLevel(0); 720 G4int status = UI->ApplyCommand(cmd.c_str()); 721 UI->SetVerboseLevel(keepControlVerbose); 722 if(status==G4UIcommandStatus::fCommandSucceeded) { 723 G4String hexString = UI->GetCurrentValues("/analysis/h1/get"); 724 if(hexString.size()) { 725 void* ptr; 726 std::istringstream is(hexString); 727 is >> ptr; 728 tools::histo::h1d* _h = (tools::histo::h1d*)ptr; 729 tools::sg::plottable* p = new tools::sg::h1d2plot_cp(*_h); 730 _plotter->add_plottable(p); //give ownership of p to sg::plotter. 731 } 732 } else { 733 G4cerr << 734 "G4ToolsSGSceneHandler::SetPlotterHistograms: cannot get histogram - maybe doesn't exist?" 735 "\n Maybe this app does not do analysis at all?" 736 << G4endl; 737 } 738 } 739 }} 740 {tools_vforcit(Region_h2,fRegionH2s,it) { 741 tools::sg::plotter* _plotter = a_plots.find_plotter((*it).first); 742 if(_plotter) { 743 int hid = (*it).second; 744 std::ostringstream os; 745 os << hid; 746 std::string cmd("/analysis/h2/get "); 747 cmd += std::string(os.str()); 748 auto keepControlVerbose = UI->GetVerboseLevel(); 749 UI->SetVerboseLevel(0); 750 G4int status = UI->ApplyCommand(cmd.c_str()); 751 UI->SetVerboseLevel(keepControlVerbose); 752 if(status==G4UIcommandStatus::fCommandSucceeded) { 753 G4String hexString = UI->GetCurrentValues("/analysis/h2/get"); 754 if(hexString.size()) { 755 void* ptr; 756 std::istringstream is(hexString); 757 is >> ptr; 758 tools::histo::h2d* _h = (tools::histo::h2d*)ptr; 759 tools::sg::plottable* p = new tools::sg::h2d2plot_cp(*_h); 760 _plotter->add_plottable(p); //give ownership of p to sg::plotter. 761 } 762 } else { 763 G4cerr << 764 "G4ToolsSGSceneHandler::SetPlotterHistograms: cannot get histogram - maybe doesn't exist?" 765 "\n Maybe this app does not do analysis at all?" 766 << G4endl; 767 } 768 } 769 }} 770 } 771 772 class plots_cbk : public tools::sg::ecbk { 773 TOOLS_CBK(plots_cbk,plots_cbk,tools::sg::ecbk) 774 public: 775 virtual tools::sg::return_action action() { 776 if(const tools::sg::size_event* sz_evt = tools::sg::event_cast<tools::sg::event,tools::sg::size_event>(*m_event)){ 777 m_plots.adjust_size(sz_evt->width(),sz_evt->height()); 778 m_event_action->set_done(true); 779 return tools::sg::return_to_render; 780 } 781 return tools::sg::return_none; 782 } 783 public: 784 plots_cbk(tools::sg::plots& a_plots) 785 :parent() 786 ,m_plots(a_plots) 787 {} 788 virtual ~plots_cbk(){} 789 public: 790 plots_cbk(const plots_cbk& a_from) 791 :parent(a_from) 792 ,m_plots(a_from.m_plots) 793 {} 794 plots_cbk& operator=(const plots_cbk& a_from){ 795 parent::operator=(a_from); 796 return *this; 797 } 798 protected: 799 tools::sg::plots& m_plots; 800 }; 801 802 void G4ToolsSGSceneHandler::TouchPlotters(tools::sg::node& a_sg) { 803 tools::sg::search_action sa(G4cout); 804 const tools::sg::search_action::paths_t& paths = tools::sg::find_paths<tools::sg::plots>(sa,a_sg); 805 tools_vforcit(tools::sg::path_t,paths,it) { 806 tools::sg::plots* _plots = tools::sg::tail<tools::sg::plots>(*it); 807 if(_plots) { 808 SetPlotterHistograms(*_plots); 809 } 810 } 811 } 812 813 void G4ToolsSGSceneHandler::AddPrimitive(const G4Plotter& a_plotter) 814 { 815 //G4cout << "debug : G4ToolsSGSceneHandler::AddPrimitive : 004" << std::endl; 816 if(!fpViewer) return; 817 818 auto currentNode = GetOrCreateNode(); 819 if (!currentNode) return; // Node not available 820 821 currentNode->add(new tools::sg::light_off()); 822 823 tools::sg::plots* _plots = new tools::sg::plots(*fFreetypeNode); 824 currentNode->add(_plots); 825 826 _plots->view_border = false; 827 _plots->set_regions(a_plotter.GetColumns(),a_plotter.GetRows()); 828 829 {tools::sg::event_dispatcher* dpt = new tools::sg::event_dispatcher; 830 dpt->add_callback(new plots_cbk(*_plots)); 831 currentNode->add(dpt);} 832 833 SetPlotterStyles(*_plots,a_plotter.GetStyles(),a_plotter.GetRegionStyles()); 834 835 tools::sg::cmaps_t _cmaps; 836 _cmaps["default"] = tools::sg::style_default_colormap(); 837 _cmaps["ROOT"] = tools::sg::style_ROOT_colormap(); 838 839 SetPlotterParameters(_cmaps,*_plots,a_plotter.GetRegionParameters()); 840 841 fRegionH1s = a_plotter.GetRegionH1s(); 842 fRegionH2s = a_plotter.GetRegionH2s(); 843 844 SetPlotterHistograms(*_plots); 845 } 846 847 void G4ToolsSGSceneHandler::Messenger::SetNewValue(G4UIcommand* a_cmd,G4String) { 848 G4VSceneHandler* pSceneHandler = GetVisManager()->GetCurrentSceneHandler(); 849 if (!pSceneHandler) { 850 G4cout << "G4ToolsSGSceneHandler::Messenger::SetNewValue: no current sceneHandler. Please create one." << G4endl; 851 return; 852 } 853 auto* tsg_scene_handler = dynamic_cast<G4ToolsSGSceneHandler*>(pSceneHandler); 854 if(!tsg_scene_handler) { 855 G4cout << "G4ToolsSGSceneHandler::Messenger::SetNewValue: current sceneHandler not a G4ToolsSGSceneHandler." << G4endl; 856 return; 857 } 858 if(a_cmd==print_plotter_params) { 859 tools::sg::dummy_freetype _ttf; 860 tools::sg::plotter _plotter(_ttf); 861 _plotter.print_available_customization(G4cout); 862 } 863 } 864