10#include <QSignalBlocker>
20#include "G4VisAttributes.hh"
21#include "G4Material.hh"
24#include "G4SystemOfUnits.hh"
32 std::string lname = lvolume->GetName();
34 auto mlvolume = pvolume->GetMotherLogical();
35 mother = mlvolume->GetName();
36 material = lvolume->GetMaterial()->GetName();
40 material =
"G4_Galactic";
44 auto visAttributes = lvolume->GetVisAttributes();
45 auto gcolor = visAttributes->GetColour();
47 double red = gcolor.GetRed();
48 double green = gcolor.GetGreen();
49 double blue = gcolor.GetBlue();
50 auto alpha = gcolor.GetAlpha();
52 color = QColor::fromRgbF(red, green, blue);
56 is_visible = visAttributes->IsVisible();
59 mass = lvolume->GetMass(
false,
true) / (CLHEP::g);
60 volume = svolume->GetCubicVolume() / CLHEP::cm3;
61 density = (mass / volume);
68 return v4name.substr(v4name.find_last_of(
'/') + 1);
74 return v4name.substr(0, v4name.find_last_of(
'/'));
80 std::unordered_map<std::string, G4Volume*> g4volumes_map,
85 build_tree(g4volumes_map);
88 treeWidget =
new QTreeWidget(
this);
89 treeWidget->setColumnCount(3);
91 headers <<
"Visibility" <<
"Color" <<
"Name";
92 treeWidget->setHeaderLabels(headers);
93 treeWidget->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
94 treeWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
95 treeWidget->header()->setSectionResizeMode(2, QHeaderView::Stretch);
96 treeWidget->setRootIsDecorated(
true);
97 treeWidget->setAlternatingRowColors(
true);
99 auto* mainLayout =
new QHBoxLayout(
this);
100 mainLayout->addWidget(treeWidget, 3);
103 rightPanel = right_widget();
104 mainLayout->addWidget(rightPanel, 3);
106 setLayout(mainLayout);
112 connect(treeWidget, &QTreeWidget::itemChanged,
113 this, >ree::onItemChanged);
117 connect(treeWidget, &QTreeWidget::itemClicked,
118 this, >ree::onTreeItemClicked);
120 connect(treeWidget, &QTreeWidget::currentItemChanged,
121 this, >ree::onCurrentItemChanged);
125 SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem*)),
126 this, SLOT(changeStyle()));
130 connect(opacitySlider, &QSlider::valueChanged,
131 this, >ree::onOpacitySliderChanged);
137void GTree::populateTree() {
139 for (
auto& [systemName, volMap] : g4_systems_tree) {
141 auto* systemItem =
new QTreeWidgetItem(treeWidget);
142 systemItem->setText(2, QString::fromStdString(systemName));
143 systemItem->setFlags(systemItem->flags() | Qt::ItemIsUserCheckable);
144 systemItem->setCheckState(0, Qt::Checked);
147 std::map<std::string, QTreeWidgetItem*> itemLookup;
152 for (
auto& [volName, vptr] : volMap) {
155 auto* item =
new QTreeWidgetItem;
157 item->setData(2, Qt::UserRole, QString::fromStdString(volName));
160 item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
161 item->setCheckState(0, vitem->
get_visibility() ? Qt::Checked : Qt::Unchecked);
163 itemLookup[volName] = item;
169 for (
auto& [volName, vptr] : volMap) {
172 auto* thisItem = itemLookup[volName];
174 QTreeWidgetItem* parentItem = systemItem;
177 if (!mother.empty() && mother !=
"root") {
178 auto itM = itemLookup.find(mother);
179 if (itM != itemLookup.end()) {
180 parentItem = itM->second;
184 parentItem->addChild(thisItem);
190 for (
auto& [volName, vptr] : volMap) {
192 QTreeWidgetItem* item = itemLookup[volName];
194 auto* colorBtn =
new QPushButton(treeWidget);
196 colorBtn->setFixedSize(20, 20);
197 colorBtn->setFlat(
true);
198 colorBtn->setText(QString());
200 colorBtn->setStyleSheet(
201 QString(
"QPushButton { background-color: %1; border: 1px solid black; }")
206 colorBtn->setProperty(
"volumeName", QString::fromStdString(volName));
207 connect(colorBtn, &QPushButton::clicked,
this, >ree::onColorButtonClicked);
209 treeWidget->setItemWidget(item, 1, colorBtn);
213 treeWidget->expandAll();
218void GTree::build_tree(std::unordered_map<std::string, G4Volume*> g4volumes_map) {
220 for (
auto [name, g4volume] : g4volumes_map) {
232 auto& system_tree = g4_systems_tree[system_name];
233 system_tree[name] = std::make_unique<G4Ttree_item>(g4volume);
235 log->
info(2,
"Adding ", name,
" to tree, system_name is ", system_name,
236 ", density: ", system_tree[name]->get_density(),
237 "g/cm3, mass: ", system_tree[name]->get_mass(),
238 "g, volume: ", system_tree[name]->get_volume(),
"cm3");
243void GTree::onItemChanged(QTreeWidgetItem* item,
int column) {
244 if (column != 0)
return;
247 QVariant v = item->data(2, Qt::UserRole);
253 bool visible = (item->checkState(0) == Qt::Checked);
255 QSignalBlocker blocker(treeWidget);
257 const int nChildren = item->childCount();
258 for (
int i = 0; i < nChildren; ++i) {
259 QTreeWidgetItem* child = item->child(i);
260 QVariant cv = child->data(2, Qt::UserRole);
264 const QString fullName = cv.toString();
267 child->setCheckState(0, visible ? Qt::Checked : Qt::Unchecked);
270 set_visibility(fullName.toStdString(), visible);
279 const QString fullName = v.toString();
280 bool visible = (item->checkState(0) == Qt::Checked);
282 QSignalBlocker blocker(treeWidget);
285 set_visibility(fullName.toStdString(), visible);
288 const int nChildren = item->childCount();
289 for (
int i = 0; i < nChildren; ++i) {
290 QTreeWidgetItem* child = item->child(i);
291 QVariant cv = child->data(2, Qt::UserRole);
295 const QString childName = cv.toString();
298 child->setCheckState(0, visible ? Qt::Checked : Qt::Unchecked);
301 set_visibility(childName.toStdString(), visible);
307void GTree::onColorButtonClicked() {
308 auto* btn = qobject_cast<QPushButton*>(sender());
312 const QString volName = btn->property(
"volumeName").toString();
313 if (volName.isEmpty())
316 QColor initial = Qt::white;
318 QColor c = QColorDialog::getColor(initial,
this, tr(
"Select color"));
324 QString(
"QPushButton { background-color: %1; border: 1px solid black; }")
329 set_color(volName.toStdString(), c);
334void GTree::set_visibility(
const std::string& volumeName,
bool visible) {
335 std::string vis_int = visible ?
"1" :
"0";
337 std::string command =
"/vis/geometry/set/visibility " + volumeName +
" -1 " + vis_int;
340 if (volumeName == ROOTWORLDGVOLUMENAME) {
341 command =
"/vis/geometry/set/visibility " + volumeName +
" 0 " + vis_int;
348void GTree::set_color(
const std::string& volumeName,
const QColor& c) {
350 c.getRgb(&r, &g, &b);
352 std::string command =
"/vis/geometry/set/colour " + volumeName +
" 0 "
353 + std::to_string(r / 255.0) +
" "
354 + std::to_string(g / 255.0) +
" "
355 + std::to_string(b / 255.0);
361int GTree::get_ndaughters(QTreeWidgetItem* item)
const {
363 return item->childCount();
367G4Ttree_item* GTree::findTreeItem(
const std::string& fullName) {
368 for (
const auto& [systemName, volMap] : g4_systems_tree) {
369 auto it = volMap.find(fullName);
370 if (it != volMap.end()) {
371 return it->second.get();
379void GTree::onTreeItemClicked(QTreeWidgetItem* item,
int ) {
384 bottomPanel->setVisible(
false);
385 current_volume_name.clear();
389 bottomPanel->setVisible(
true);
392 QVariant v = item->data(2, Qt::UserRole);
393 bool isVolume = v.isValid();
397 typeLabel->setText(QStringLiteral(
"<b>G4 Volume</b>"));
398 current_volume_name = v.toString().toStdString();
401 typeLabel->setText(QStringLiteral(
"<b>System</b>"));
402 current_volume_name.clear();
406 int nd = get_ndaughters(item);
407 daughtersLabel->setText(tr(
"Daughters: %1").arg(nd));
410 QString itemName = item->text(2);
411 nameLabel->setText(tr(
"Name: %1").arg(itemName));
415 styleButtons->setVisible(
true);
417 const std::string fullName = v.toString().toStdString();
421 materialLabel->setText(
422 tr(
"Material: %1").arg(QString::fromStdString(titem->
get_material()))
426 massLabel->setText(tr(
"Total Mass: %1 g").arg(mass));
429 massLabel->setText(tr(
"Total Mass: %1 kg").arg(mass / 1000));
432 if (volume < 1000000) {
433 volumeLabel->setText(tr(
"Volume: %1 cm3").arg(volume));
436 volumeLabel->setText(tr(
"Volume: %1 m3").arg(volume / 1000000));
439 densityLabel->setText(
440 tr(
"Average Density: %1 g / cm3").arg(titem->
get_density())
445 int sliderVal =
static_cast<int>(op * 100.0 + 0.5);
447 QSignalBlocker blocker(opacitySlider);
448 opacitySlider->setValue(sliderVal);
450 opacityLabel->setText(QString::number(op,
'f', 2));
451 opacitySlider->setVisible(
true);
455 styleButtons->setVisible(
false);
456 opacitySlider->setVisible(
false);
458 materialLabel->setText(tr(
""));
459 massLabel->setText(tr(
""));
460 volumeLabel->setText(tr(
""));
461 densityLabel->setText(tr(
""));
466void GTree::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous) {
475 onTreeItemClicked(current, 0);
479void GTree::changeStyle() {
482 if (current_volume_name.empty())
489 if (button_index == 0) {
490 command =
"/vis/geometry/set/forceWireframe " + current_volume_name +
" 0 1 ";
492 else if (button_index == 1) {
493 command =
"/vis/geometry/set/forceSolid " + current_volume_name +
" 0 1 ";
495 else if (button_index == 2) {
496 command =
"/vis/geometry/set/forceCloud " + current_volume_name +
" 0 1 ";
508void GTree::onOpacitySliderChanged(
int value) {
509 if (current_volume_name.empty())
512 double opacity = value / 100.0;
515 opacityLabel->setText(QString::number(opacity,
'f', 2));
518 set_opacity(current_volume_name, opacity);
522void GTree::set_opacity(
const std::string& volumeName,
double opacity) {
530 double g = c.greenF();
531 double b = c.blueF();
534 std::string command =
"/vis/geometry/set/colour " + volumeName +
" 0 "
535 + std::to_string(r) +
" "
536 + std::to_string(g) +
" "
537 + std::to_string(b) +
" "
538 + std::to_string(opacity);
Lightweight per-volume record used by GTree to populate the UI.
static std::string vname_from_v4name(std::string v4name)
Extract the "leaf" volume name from a full volume name.
double get_opacity() const
Return the cached opacity (alpha) in [0,1].
G4Ttree_item(G4Volume *g4volume)
Construct a cached record for a single geometry volume.
double get_density() const
Return the cached density.
void set_opacity(double opacity)
Update the cached opacity.
double get_volume() const
Return the cached volume.
bool get_visibility() const
Return the cached visibility state.
double get_mass() const
Return the cached mass.
QColor get_color() const
Return the cached RGB color.
void set_color(QColor &c)
Update the cached color.
static std::string system_from_v4name(std::string v4name)
Extract the system name from a full volume name.
std::string get_material() const
Return the cached material name.
std::string get_mother() const
Return the cached mother name.
G4VSolid * getSolid() const noexcept
G4VPhysicalVolume * getPhysical() const noexcept
G4LogicalVolume * getLogical() const noexcept
std::shared_ptr< GLogger > log
void debug(debug_type type, Args &&... args) const
void info(int level, Args &&... args) const
GTree(const std::shared_ptr< GOptions > &gopt, std::unordered_map< std::string, G4Volume * > g4volumes_map, QWidget *parent=nullptr)
Construct the geometry tree widget.
#define ROOTWORLDGVOLUMENAME
Option-set definition entry point for the GTree module.
constexpr const char * GTREE_LOGGER
void apply_uimanager_commands(const std::string &commands)