g4display
Loading...
Searching...
No Matches
g4displayview.cc
Go to the documentation of this file.
1#include "g4displayview.h"
2#include "g4display_options.h"
3#include "gutilities.h"
4
5using namespace g4display;
6
7// c++
8#include <iostream>
9#include <string>
10using namespace std;
11using namespace gutilities;
12
13// geant4
14#include "G4UImanager.hh" // Geant4 UI manager access
15
16
28G4DisplayView::G4DisplayView(const std::shared_ptr<GOptions>& gopts, std::shared_ptr<GLogger> logger,
29 QWidget* parent) : QWidget(parent), log(logger) {
30 log->debug(CONSTRUCTOR, "G4DisplayView");
31
32 // LCD font
33 QFont flcd;
34 flcd.setFamilies({"Helvetica"}); // Qt6: prefer setFamilies over family string ctor
35 flcd.setPointSize(32);
36 flcd.setBold(true);
37
38 G4Camera jcamera = getG4Camera(gopts);
39
40 double thetaValue = getG4Number(jcamera.theta);
41 double phiValue = getG4Number(jcamera.phi);
42
43 vector<string> toggle_button_titles;
44 toggle_button_titles.emplace_back("Hidden\nLines");
45 toggle_button_titles.emplace_back("Anti\nAliasing");
46 toggle_button_titles.emplace_back("Auxiliary\nEdges");
47 toggle_button_titles.emplace_back("Field\nLines");
48 toggle_button_titles.emplace_back("Axes");
49 toggle_button_titles.emplace_back("Scale");
50
51
52 buttons_set1 = new GQTToggleButtonWidget(80, 80, 20, toggle_button_titles, false, this);
53 connect(buttons_set1, &GQTToggleButtonWidget::buttonPressedIndexChanged, this, &G4DisplayView::apply_buttons_set1);
54
55
56 QStringList theta_angle_Set;
57 for (int t = 0; t <= 180; t += 30) { theta_angle_Set << QString::number(t); }
58 QStringList phi_angle_Set;
59 for (int t = 0; t <= 360; t += 30) { phi_angle_Set << QString::number(t); }
60
61 // Camera sliders
62 cameraTheta = new QSlider(Qt::Horizontal);
63 cameraTheta->setRange(0, 180);
64 cameraTheta->setSingleStep(1);
65 cameraTheta->setValue(thetaValue);
66 cameraTheta->setTracking(true); // updates while dragging
67
68 auto cameraThetaLabel = new QLabel(tr("θ"));
69
70 QLCDNumber* theta_LCD = new QLCDNumber(this);
71 theta_LCD->setFont(flcd);
72 theta_LCD->setMaximumSize(QSize(45, 45));
73 theta_LCD->setSegmentStyle(QLCDNumber::Flat);
74
75 thetaDropdown = new QComboBox(this);
76 thetaDropdown->addItems(theta_angle_Set);
77 thetaDropdown->setMaximumSize(QSize(100, 45));
78
79 auto cameraThetaLayout = new QHBoxLayout;
80 cameraThetaLayout->addWidget(cameraThetaLabel);
81 cameraThetaLayout->addWidget(cameraTheta);
82 cameraThetaLayout->addWidget(theta_LCD);
83 cameraThetaLayout->addWidget(thetaDropdown);
84
85 cameraPhi = new QSlider(Qt::Horizontal);
86 cameraPhi->setRange(0, 360);
87 cameraPhi->setSingleStep(1);
88 cameraPhi->setValue(phiValue);
89 cameraPhi->setTracking(true); // updates while dragging
90 auto cameraPhiLabel = new QLabel(tr("ɸ"));
91
92 QLCDNumber* phi_LCD = new QLCDNumber(this);
93 phi_LCD->setFont(flcd);
94 phi_LCD->setMaximumSize(QSize(45, 45));
95 phi_LCD->setSegmentStyle(QLCDNumber::Flat);
96
97 phiDropdown = new QComboBox(this);
98 phiDropdown->addItems(phi_angle_Set);
99 phiDropdown->setMaximumSize(QSize(100, 45));
100
101 auto cameraPhiLayout = new QHBoxLayout;
102 cameraPhiLayout->addWidget(cameraPhiLabel);
103 cameraPhiLayout->addWidget(cameraPhi);
104 cameraPhiLayout->addWidget(phi_LCD);
105 cameraPhiLayout->addWidget(phiDropdown);
106
107
108 QVBoxLayout* cameraDirectionLayout = new QVBoxLayout;
109 cameraDirectionLayout->addLayout(cameraThetaLayout);
110 cameraDirectionLayout->addSpacing(12);
111 cameraDirectionLayout->addLayout(cameraPhiLayout);
112
113
114 QGroupBox* cameraAnglesGroup = new QGroupBox(tr("Camera Direction"));
115 cameraAnglesGroup->setLayout(cameraDirectionLayout);
116
117 connect(cameraTheta, &QSlider::valueChanged, this, &G4DisplayView::changeCameraDirection);
118 connect(cameraTheta, &QSlider::valueChanged, theta_LCD, qOverload<int>(&QLCDNumber::display));
119 connect(thetaDropdown, &QComboBox::currentTextChanged,
120 this, [this](const QString&) {
121 setCameraDirection(0); // 0 = theta changed
122 });
123
124 connect(cameraPhi, &QSlider::valueChanged, this, &G4DisplayView::changeCameraDirection);
125 connect(cameraPhi, &QSlider::valueChanged, phi_LCD, qOverload<int>(&QLCDNumber::display));
126 connect(phiDropdown, &QComboBox::currentTextChanged,
127 this, [this](const QString&) {
128 setCameraDirection(1); // 1 = phi changed
129 });
130
131
132 // projection: Orthogonal / Perspective
133 QLabel* projLabel = new QLabel(tr("Projection:"));
134 perspectiveDropdown = new QComboBox;
135 perspectiveDropdown->addItem(tr("Orthogonal"));
136 perspectiveDropdown->addItem(tr("Perspective 30"));
137 perspectiveDropdown->addItem(tr("Perspective 45"));
138 perspectiveDropdown->addItem(tr("Perspective 60"));
139
140 QLabel* sides_per_circlesLabel = new QLabel(tr("Sides per circle:"));
141 precisionDropdown = new QComboBox;
142 precisionDropdown->addItem(tr("50"));
143 precisionDropdown->addItem(tr("100"));
144 precisionDropdown->addItem(tr("200"));
145 precisionDropdown->addItem(tr("300"));
146 precisionDropdown->setCurrentIndex(0);
147
148 connect(perspectiveDropdown, &QComboBox::currentTextChanged, this, &G4DisplayView::set_projection);
149 connect(precisionDropdown, &QComboBox::currentTextChanged, this, &G4DisplayView::set_precision);
150
151
152 QVBoxLayout* resolutionAndPerspectiveLayout = new QVBoxLayout;
153 resolutionAndPerspectiveLayout->addWidget(projLabel);
154 resolutionAndPerspectiveLayout->addWidget(perspectiveDropdown);
155 resolutionAndPerspectiveLayout->addSpacing(12);
156 resolutionAndPerspectiveLayout->addWidget(sides_per_circlesLabel);
157 resolutionAndPerspectiveLayout->addWidget(precisionDropdown);
158
159 QGroupBox* propertyGroup = new QGroupBox(tr("View Properties"));
160 propertyGroup->setLayout(resolutionAndPerspectiveLayout);
161
162 QHBoxLayout* cameraAndPerspective = new QHBoxLayout;
163 cameraAndPerspective->addWidget(cameraAnglesGroup);
164 cameraAndPerspective->addSpacing(12);
165 cameraAndPerspective->addWidget(propertyGroup);
166
167
168 // Light Direction
169 lightTheta = new QSlider(Qt::Horizontal);
170 lightTheta->setRange(0, 180);
171 lightTheta->setSingleStep(1);
172 lightTheta->setValue(thetaValue);
173 lightTheta->setTracking(true); // updates while dragging
174 auto lightThetaLabel = new QLabel(tr("θ"));
175
176 QLCDNumber* ltheta_LCD = new QLCDNumber(this);
177 ltheta_LCD->setFont(flcd);
178 ltheta_LCD->setMaximumSize(QSize(45, 45));
179 ltheta_LCD->setSegmentStyle(QLCDNumber::Flat);
180
181 lthetaDropdown = new QComboBox(this);
182 lthetaDropdown->addItems(theta_angle_Set);
183 lthetaDropdown->setMaximumSize(QSize(100, 45));
184
185 auto lightThetaLayout = new QHBoxLayout;
186 lightThetaLayout->addWidget(lightThetaLabel);
187 lightThetaLayout->addWidget(lightTheta);
188 lightThetaLayout->addWidget(ltheta_LCD);
189 lightThetaLayout->addWidget(lthetaDropdown);
190
191 lightPhi = new QSlider(Qt::Horizontal);
192 lightPhi->setRange(0, 360);
193 lightPhi->setSingleStep(1);
194 lightPhi->setValue(phiValue);
195 lightPhi->setTracking(true); // updates while dragging
196 auto lightPhiLabel = new QLabel(tr("ɸ"));
197
198 QLCDNumber* lphi_LCD = new QLCDNumber(this);
199 lphi_LCD->setFont(flcd);
200 lphi_LCD->setMaximumSize(QSize(45, 45));
201 lphi_LCD->setSegmentStyle(QLCDNumber::Flat);
202
203 lphiDropdown = new QComboBox(this);
204 lphiDropdown->addItems(phi_angle_Set);
205 lphiDropdown->setMaximumSize(QSize(100, 45));
206
207 auto lightPhiLayout = new QHBoxLayout;
208 lightPhiLayout->addWidget(lightPhiLabel);
209 lightPhiLayout->addWidget(lightPhi);
210 lightPhiLayout->addWidget(lphi_LCD);
211 lightPhiLayout->addWidget(lphiDropdown);
212
213 auto lightDirectionLayout = new QVBoxLayout;
214 lightDirectionLayout->addLayout(lightThetaLayout);
215 lightDirectionLayout->addSpacing(12);
216 lightDirectionLayout->addLayout(lightPhiLayout);
217
218 QGroupBox* lightAnglesGroup = new QGroupBox(tr("Light Direction"));
219 lightAnglesGroup->setLayout(lightDirectionLayout);
220
221 connect(lightTheta, &QSlider::valueChanged, this, &G4DisplayView::changeLightDirection);
222 connect(lightTheta, &QSlider::valueChanged, ltheta_LCD, qOverload<int>(&QLCDNumber::display));
223 connect(lthetaDropdown, &QComboBox::currentTextChanged,
224 this, [this](const QString&) {
225 setLightDirection(0); // 0 = theta changed
226 });
227
228 connect(lightPhi, &QSlider::valueChanged, this, &G4DisplayView::changeLightDirection);
229 connect(lightPhi, &QSlider::valueChanged, lphi_LCD, qOverload<int>(&QLCDNumber::display));
230 connect(lphiDropdown, &QComboBox::currentTextChanged,
231 this, [this](const QString&) {
232 setLightDirection(1); // 0 = phi changed
233 });
234
235
236 // projection: Orthogonal / Perspective
237 QLabel* cullingLabel = new QLabel(tr("Culling:"));
238 cullingDropdown = new QComboBox;
239 cullingDropdown->addItem(tr("Reset"));
240 cullingDropdown->addItem(tr("Covered Daughters"));
241 cullingDropdown->addItem(tr("Density: 1 mg/cm3"));
242 cullingDropdown->addItem(tr("Density: 10 mg/cm3"));
243 cullingDropdown->addItem(tr("Density: 100 mg/cm3"));
244 cullingDropdown->addItem(tr("Density: 1 g/cm3"));
245 cullingDropdown->addItem(tr("Density: 10 g/cm3"));
246
247
248 QLabel* backgroundColorLabel = new QLabel(tr("Background Color:"));
249 backgroundColorDropdown = new QComboBox;
250 backgroundColorDropdown->addItem(tr("lightslategray"));
251 backgroundColorDropdown->addItem(tr("ghostwhite"));
252 backgroundColorDropdown->addItem(tr("black"));
253 backgroundColorDropdown->addItem(tr("navy"));
254 backgroundColorDropdown->addItem(tr("whitesmoke"));
255 backgroundColorDropdown->addItem(tr("lightskyblue"));
256 backgroundColorDropdown->addItem(tr("deepskyblue"));
257 backgroundColorDropdown->addItem(tr("lightsteelblue"));
258 backgroundColorDropdown->addItem(tr("blueviolet"));
259 backgroundColorDropdown->addItem(tr("turquoise"));
260 backgroundColorDropdown->addItem(tr("mediumaquamarine"));
261 backgroundColorDropdown->addItem(tr("springgreen"));
262 backgroundColorDropdown->addItem(tr("lawngreen"));
263 backgroundColorDropdown->addItem(tr("yellowgreen"));
264 backgroundColorDropdown->addItem(tr("lemonchiffon"));
265 backgroundColorDropdown->addItem(tr("antiquewhite"));
266 backgroundColorDropdown->addItem(tr("wheat"));
267 backgroundColorDropdown->addItem(tr("sienna"));
268 backgroundColorDropdown->addItem(tr("snow"));
269 backgroundColorDropdown->addItem(tr("floralwhite"));
270 backgroundColorDropdown->addItem(tr("lightsalmon"));
271 backgroundColorDropdown->addItem(tr("orchid"));
272 backgroundColorDropdown->addItem(tr("plum"));
273 backgroundColorDropdown->setCurrentIndex(0);
274
275
276 connect(cullingDropdown, &QComboBox::currentTextChanged, this, &G4DisplayView::set_culling);
277 connect(backgroundColorDropdown, &QComboBox::currentTextChanged, this, &G4DisplayView::set_background);
278
279 QVBoxLayout* sceneLayout = new QVBoxLayout;
280 sceneLayout->addWidget(cullingLabel);
281 sceneLayout->addWidget(cullingDropdown);
282 sceneLayout->addSpacing(12);
283 sceneLayout->addWidget(backgroundColorLabel);
284 sceneLayout->addWidget(backgroundColorDropdown);
285
286 QGroupBox* spropertyGroup = new QGroupBox(tr("Scene Properties"));
287 spropertyGroup->setLayout(sceneLayout);
288
289 QHBoxLayout* lightAndProperties = new QHBoxLayout;
290 lightAndProperties->addWidget(lightAnglesGroup);
291 lightAndProperties->addSpacing(12);
292 lightAndProperties->addWidget(spropertyGroup);
293
294
295 // x slice
296 sliceXEdit = new QLineEdit(tr("0"));
297 sliceXEdit->setMaximumWidth(100);
298 sliceXActi = new QCheckBox(tr("&On"));
299 sliceXActi->setChecked(false);
300 sliceXInve = new QCheckBox(tr("&Flip"));
301 sliceXInve->setChecked(false);
302 auto sliceXLayout = new QHBoxLayout;
303 sliceXLayout->addWidget(new QLabel(tr("X: ")));
304 sliceXLayout->addWidget(sliceXEdit);
305 sliceXLayout->addStretch(1);
306 sliceXLayout->addWidget(sliceXActi);
307 sliceXLayout->addWidget(sliceXInve);
308 sliceXLayout->addStretch(1);
309
310 // y slice
311 sliceYEdit = new QLineEdit(tr("0"));
312 sliceYEdit->setMaximumWidth(100);
313 sliceYActi = new QCheckBox(tr("&On"));
314 sliceYActi->setChecked(false);
315 sliceYInve = new QCheckBox(tr("&Flip"));
316 sliceYInve->setChecked(false);
317 auto sliceYLayout = new QHBoxLayout;
318 sliceYLayout->addWidget(new QLabel(tr("Y: ")));
319 sliceYLayout->addWidget(sliceYEdit);
320 sliceYLayout->addStretch(1);
321 sliceYLayout->addWidget(sliceYActi);
322 sliceYLayout->addWidget(sliceYInve);
323 sliceYLayout->addStretch(1);
324
325 // z slice
326 sliceZEdit = new QLineEdit(tr("0"));
327 sliceZEdit->setMaximumWidth(100);
328 sliceZActi = new QCheckBox(tr("&On"));
329 sliceZActi->setChecked(false);
330 sliceZInve = new QCheckBox(tr("&Flip"));
331 sliceZInve->setChecked(false);
332 auto sliceZLayout = new QHBoxLayout;
333 sliceZLayout->addWidget(new QLabel(tr("Z: ")));
334 sliceZLayout->addWidget(sliceZEdit);
335 sliceZLayout->addStretch(1);
336 sliceZLayout->addWidget(sliceZActi);
337 sliceZLayout->addWidget(sliceZInve);
338 sliceZLayout->addStretch(1);
339
340 // clear sice button
341 QPushButton* clearSliceButton = new QPushButton(tr("Clear Slices"));
342 clearSliceButton->setToolTip("Clear Slice Planes");
343 clearSliceButton->setIcon(QIcon::fromTheme("edit-clear"));
344 clearSliceButton->setIconSize(QSize(16, 16)); // Adjust as necessary
345
346 connect(clearSliceButton, &QPushButton::clicked, this, &G4DisplayView::clearSlices);
347
348 // slice style: Intersection or Union
349 QGroupBox* sliceChoiceBox = new QGroupBox(tr("Slices Style"));
350 sliceSectn = new QRadioButton(tr("&Intersection"), sliceChoiceBox);
351 sliceUnion = new QRadioButton(tr("&Union"), sliceChoiceBox);
352 sliceSectn->setChecked(true);
353
354 connect(sliceSectn, &QRadioButton::toggled, this, &G4DisplayView::slice);
355 connect(sliceUnion, &QRadioButton::toggled, this, &G4DisplayView::slice);
356
357 auto sliceChoiceLayout = new QHBoxLayout;
358 sliceChoiceLayout->addWidget(sliceSectn);
359 sliceChoiceLayout->addWidget(sliceUnion);
360 sliceChoiceBox->setLayout(sliceChoiceLayout);
361
362
363 // slices layout
364 auto sliceLayout = new QVBoxLayout;
365 sliceLayout->addLayout(sliceXLayout);
366 sliceLayout->addLayout(sliceYLayout);
367 sliceLayout->addLayout(sliceZLayout);
368 sliceLayout->addWidget(sliceChoiceBox);
369 sliceLayout->addWidget(clearSliceButton);
370
371
372 // connecting widgets to slice
373 connect(sliceXEdit, &QLineEdit::returnPressed, this, &G4DisplayView::slice);
374 connect(sliceYEdit, &QLineEdit::returnPressed, this, &G4DisplayView::slice);
375 connect(sliceZEdit, &QLineEdit::returnPressed, this, &G4DisplayView::slice);
376
377
378#if QT_VERSION < QT_VERSION_CHECK(6, 7, 0) // Qt ≤6.6
379 connect(sliceXActi, &QCheckBox::stateChanged, this, &G4DisplayView::slice);
380 connect(sliceYActi, &QCheckBox::stateChanged, this, &G4DisplayView::slice);
381 connect(sliceZActi, &QCheckBox::stateChanged, this, &G4DisplayView::slice);
382 connect(sliceXInve, &QCheckBox::stateChanged, this, &G4DisplayView::slice);
383 connect(sliceYInve, &QCheckBox::stateChanged, this, &G4DisplayView::slice);
384 connect(sliceZInve, &QCheckBox::stateChanged, this, &G4DisplayView::slice);
385#else // Qt≥6.7
386 connect(sliceXActi, &QCheckBox::checkStateChanged, this, &G4DisplayView::slice);
387 connect(sliceYActi, &QCheckBox::checkStateChanged, this, &G4DisplayView::slice);
388 connect(sliceZActi, &QCheckBox::checkStateChanged, this, &G4DisplayView::slice);
389 connect(sliceXInve, &QCheckBox::checkStateChanged, this, &G4DisplayView::slice);
390 connect(sliceYInve, &QCheckBox::checkStateChanged, this, &G4DisplayView::slice);
391 connect(sliceZInve, &QCheckBox::checkStateChanged, this, &G4DisplayView::slice);
392#endif
393
394
395 QGroupBox* fieldPrecisionBox = new QGroupBox(tr("Number of Field Points"));
396 field_npoints = new QLineEdit(QString::number(field_NPOINTS), this);
397 field_npoints->setMaximumWidth(40);
398
399 QFont font = field_npoints->font();
400 font.setPointSize(24);
401 field_npoints->setFont(font);
402 connect(field_npoints, &QLineEdit::returnPressed, this, &G4DisplayView::field_precision_changed);
403
404 // buttons + field line number
405 auto fieldPointsHBox = new QHBoxLayout;
406 fieldPointsHBox->addWidget(field_npoints);
407 fieldPrecisionBox->setLayout(fieldPointsHBox);
408
409 auto buttons_field_HBox = new QHBoxLayout;
410 buttons_field_HBox->addWidget(buttons_set1);
411 buttons_field_HBox->addWidget(fieldPrecisionBox);
412 fieldPrecisionBox->setMaximumHeight(3 * buttons_set1->height());
413 fieldPrecisionBox->setMaximumWidth(140);
414
415
416 // All layouts together
417 auto mainLayout = new QVBoxLayout;
418 mainLayout->addLayout(buttons_field_HBox);
419 mainLayout->addLayout(cameraAndPerspective);
420 mainLayout->addLayout(lightAndProperties);
421 mainLayout->addLayout(sliceLayout);
422 setLayout(mainLayout);
423}
424
431void G4DisplayView::changeCameraDirection() {
432 // Construct the command using the current slider values and send to the Geant4 UImanager.
433 string command = "/vis/viewer/set/viewpointThetaPhi " +
434 to_string(cameraTheta->value()) + " " +
435 to_string(cameraPhi->value());
436 G4UImanager::GetUIpointer()->ApplyCommand(command);
437}
438
439void G4DisplayView::setCameraDirection(int which) {
440 string thetaValue = thetaDropdown->currentText().toStdString();
441 string phiValue = phiDropdown->currentText().toStdString();
442
443 // Construct the command using the current slider values and send to the Geant4 UImanager.
444 string command = "/vis/viewer/set/viewpointThetaPhi " + thetaValue + " " + phiValue;
445 G4UImanager::GetUIpointer()->ApplyCommand(command);
446
447 int thetaDeg = thetaDropdown->currentText().toInt();
448 int phiDeg = phiDropdown->currentText().toInt();
449
450 if (cameraTheta && which == 0)
451 cameraTheta->setValue(thetaDeg);
452 if (cameraPhi && which == 1)
453 cameraPhi->setValue(phiDeg);
454}
455
456void G4DisplayView::set_projection() {
457 string value = perspectiveDropdown->currentText().toStdString();
458
459 string g4perspective = "o";
460 string g4perpvalue = "0";
461 if (value.find("Perspective") != string::npos) {
462 g4perspective = "p";
463 // g4perpvalue is the second item of value separate by space
464 g4perpvalue = value.substr(value.find(" ") + 1);
465 }
466
467
468 // Construct the command using the current dropdown values and send to the Geant4 UImanager.
469 string command = "/vis/viewer/set/projection " + g4perspective + " " + g4perpvalue;
470 G4UImanager::GetUIpointer()->ApplyCommand(command);
471}
472
473void G4DisplayView::set_precision() {
474 string value = precisionDropdown->currentText().toStdString();
475
476 // Construct the command using the current dropdown values and send to the Geant4 UImanager.
477 string command = "/vis/viewer/set/lineSegmentsPerCircle " + value;
478 G4UImanager::GetUIpointer()->ApplyCommand(command);
479 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/flush");
480}
481
482void G4DisplayView::set_culling() {
483 string value = cullingDropdown->currentText().toStdString();
484 int index = cullingDropdown->currentIndex() - 2;
485
486 if (value.find("Reset") != string::npos) {
487 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/culling global true");
488 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/culling density false");
489 }
490 else if (value.find("Daughters") != string::npos) {
491 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/culling coveredDaughters true");
492 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/culling density false");
493 }
494 else {
495 vector<double> density = {0.001, 0.01, 0.1, 1.0, 10.0, 100.0, 1000.0};
496 string command = "/vis/viewer/set/culling density true " + to_string(density[index]);
497 G4UImanager::GetUIpointer()->ApplyCommand(command);
498 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/flush");
499 log->info(0, command);
500 }
501}
502
503void G4DisplayView::set_background() {
504 string value = backgroundColorDropdown->currentText().toStdString();
505
506 string g4value = "0 0 0";
507 if (value.find("black") != string::npos) {
508 // CSS “black” = #000000
509 g4value = "0.0 0.0 0.0";
510 }
511 else if (value.find("navy") != string::npos) {
512 // CSS “navy” = #000080 → normalized (0,0,128/255 ≈0.50196)
513 g4value = "0.0 0.0 0.50196";
514 }
515 else if (value.find("lightslategray") != string::npos) {
516 // #778899 → (119/255,136/255,153/255) ≈ (0.46667,0.53333,0.6)
517 g4value = "0.46667 0.53333 0.60000";
518 }
519 else if (value.find("whitesmoke") != string::npos) {
520 // #F5F5F5 → (~0.96078,0.96078,0.96078)
521 g4value = "0.96078 0.96078 0.96078";
522 }
523 else if (value.find("ghostwhite") != string::npos) {
524 // #F8F8FF → (0.97255,0.97255,1.0)
525 g4value = "0.97255 0.97255 1.00000";
526 }
527 else if (value.find("lightskyblue") != string::npos) {
528 // #87CEFA → (135/255,206/255,250/255) ≈ (0.52941,0.80784,0.98039)
529 g4value = "0.52941 0.80784 0.98039";
530 }
531 else if (value.find("deepskyblue") != string::npos) {
532 // #00BFFF → (0,191/255,255/255) ≈ (0.0,0.74902,1.0)
533 g4value = "0.00000 0.74902 1.00000";
534 }
535 else if (value.find("lightsteelblue") != string::npos) {
536 // #B0C4DE → (176/255,196/255,222/255) ≈ (0.69020,0.76863,0.87059)
537 g4value = "0.69020 0.76863 0.87059";
538 }
539 else if (value.find("blueviolet") != string::npos) {
540 // #8A2BE2 → (138/255,43/255,226/255) ≈ (0.54118,0.16863,0.88627)
541 g4value = "0.54118 0.16863 0.88627";
542 }
543 else if (value.find("turquoise") != string::npos) {
544 // #40E0D0 → (64/255,224/255,208/255) ≈ (0.25098,0.87843,0.81569)
545 g4value = "0.25098 0.87843 0.81569";
546 }
547 else if (value.find("mediumaquamarine") != string::npos) {
548 // #66CDAA → (102/255,205/255,170/255) ≈ (0.40000,0.80392,0.66667)
549 g4value = "0.40000 0.80392 0.66667";
550 }
551 else if (value.find("springgreen") != string::npos) {
552 // #00FF7F → (0,255/255,127/255) ≈ (0.0,1.0,0.49804)
553 g4value = "0.00000 1.00000 0.49804";
554 }
555 else if (value.find("lawngreen") != string::npos) {
556 // #7CFC00 → (124/255,252/255,0) ≈ (0.48627,0.98824,0.0)
557 g4value = "0.48627 0.98824 0.00000";
558 }
559 else if (value.find("yellowgreen") != string::npos) {
560 // #9ACD32 → (154/255,205/255,50/255) ≈ (0.60392,0.80392,0.19608)
561 g4value = "0.60392 0.80392 0.19608";
562 }
563 else if (value.find("lemonchiffon") != string::npos) {
564 // #FFFACD → (255/255,250/255,205/255) ≈ (1.0,0.98039,0.80392)
565 g4value = "1.00000 0.98039 0.80392";
566 }
567 else if (value.find("antiquewhite") != string::npos) {
568 // #FAEBD7 → (250/255,235/255,215/255) ≈ (0.98039,0.92157,0.84314)
569 g4value = "0.98039 0.92157 0.84314";
570 }
571 else if (value.find("wheat") != string::npos) {
572 // #F5DEB3 → (245/255,222/255,179/255) ≈ (0.96078,0.87059,0.70196)
573 g4value = "0.96078 0.87059 0.70196";
574 }
575 else if (value.find("sienna") != string::npos) {
576 // #A0522D → (160/255,82/255,45/255) ≈ (0.62745,0.32157,0.17647)
577 g4value = "0.62745 0.32157 0.17647";
578 }
579 else if (value.find("snow") != string::npos) {
580 // #FFFAFA → (255/255,250/255,250/255) ≈ (1.0,0.98039,0.98039)
581 g4value = "1.00000 0.98039 0.98039";
582 }
583 else if (value.find("floralwhite") != string::npos) {
584 // #FFFAF0 → (255/255,250/255,240/255) ≈ (1.0,0.98039,0.94118)
585 g4value = "1.00000 0.98039 0.94118";
586 }
587 else if (value.find("lightsalmon") != string::npos) {
588 // #FFA07A → (255/255,160/255,122/255) ≈ (1.0,0.62745,0.47843)
589 g4value = "1.00000 0.62745 0.47843";
590 }
591 else if (value.find("orchid") != string::npos) {
592 // #DA70D6 → (218/255,112/255,214/255) ≈ (0.85490,0.43922,0.83922)
593 g4value = "0.85490 0.43922 0.83922";
594 }
595 else if (value.find("plum") != string::npos) {
596 // #DDA0DD → (221/255,160/255,221/255) ≈ (0.86667,0.62745,0.86667)
597 g4value = "0.86667 0.62745 0.86667";
598 }
599 else {
600 // fallback: white
601 g4value = "1.0 1.0 1.0";
602 }
603
604 string command = "/vis/viewer/set/background " + g4value;
605 G4UImanager::GetUIpointer()->ApplyCommand(command);
606}
607
608
615void G4DisplayView::changeLightDirection() {
616 string command = "/vis/viewer/set/lightsThetaPhi " +
617 to_string(lightTheta->value()) + " " +
618 to_string(lightPhi->value());
619 G4UImanager::GetUIpointer()->ApplyCommand(command);
620}
621
622
623void G4DisplayView::setLightDirection(int which) {
624 string thetaValue = lthetaDropdown->currentText().toStdString();
625 string phiValue = lphiDropdown->currentText().toStdString();
626
627 string command = "/vis/viewer/set/lightsThetaPhi " + thetaValue + " " + phiValue;
628
629 G4UImanager::GetUIpointer()->ApplyCommand(command);
630
631 int thetaDeg = lthetaDropdown->currentText().toInt();
632 int phiDeg = lphiDropdown->currentText().toInt();
633
634 if (lightTheta && which == 0)
635 lightTheta->setValue(thetaDeg);
636 if (lightPhi && which == 1)
637 lightPhi->setValue(phiDeg);
638}
639
640
648void G4DisplayView::slice() {
649 G4UImanager* g4uim = G4UImanager::GetUIpointer();
650 if (g4uim == nullptr) { return; }
651
652 // can't have a mix of wireframe / solid when doing a slice.
653 // forcing all to be solid. Actually this seems not to be true anymore
654 // g4uim->ApplyCommand("/vis/geometry/set/forceSolid all -1 1");
655
656
657 g4uim->ApplyCommand("/vis/viewer/clearCutawayPlanes");
658
659 if (sliceSectn->isChecked()) { g4uim->ApplyCommand("/vis/viewer/set/cutawayMode intersection"); }
660 else if (sliceUnion->isChecked()) { g4uim->ApplyCommand("/vis/viewer/set/cutawayMode union"); }
661
662 g4uim->ApplyCommand("/vis/viewer/clearCutawayPlanes");
663
664 if (sliceXActi->isChecked()) {
665 string command = "/vis/viewer/addCutawayPlane " + sliceXEdit->text().toStdString() + " 0 0 mm " +
666 to_string(sliceXInve->isChecked() ? -1 : 1) + " 0 0 ";
667 cout << "X " << command << endl;
668 g4uim->ApplyCommand(command);
669 }
670
671 if (sliceYActi->isChecked()) {
672 string command = "/vis/viewer/addCutawayPlane 0 " + sliceYEdit->text().toStdString() + " 0 mm 0 " +
673 to_string(sliceYInve->isChecked() ? -1 : 1) + " 0 ";
674 cout << "Y " << command << endl;
675 g4uim->ApplyCommand(command);
676 }
677
678 if (sliceZActi->isChecked()) {
679 string command = "/vis/viewer/addCutawayPlane 0 0 " + sliceZEdit->text().toStdString() + " mm 0 0 " +
680 to_string(sliceZInve->isChecked() ? -1 : 1);
681 cout << "Z " << command << endl;
682 g4uim->ApplyCommand(command);
683 }
684
685 //solidVis = true;
686}
687
688
694void G4DisplayView::clearSlices() {
695 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/clearCutawayPlanes");
696 sliceXActi->setChecked(false);
697}
698
708void G4DisplayView::apply_buttons_set1(int index) {
709 G4UImanager* g4uim = G4UImanager::GetUIpointer();
710 if (g4uim == nullptr) { return; }
711
712 bool button_state = buttons_set1->lastButtonState();
713
714 if (index == 0) {
715 string command = string("/vis/viewer/set/hiddenEdge") + (button_state ? " 1" : " 0");
716 g4uim->ApplyCommand(command);
717 g4uim->ApplyCommand("/vis/viewer/flush");
718 }
719 else if (index == 1) {
720 if (button_state == 0) {
721 glDisable(GL_LINE_SMOOTH);
722 glDisable(GL_POLYGON_SMOOTH);
723 }
724 else {
725 glEnable(GL_LINE_SMOOTH);
726 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
727 glEnable(GL_POLYGON_SMOOTH);
728 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
729 }
730 }
731 else if (index == 2) {
732 string command = string("/vis/viewer/set/auxiliaryEdge") + (button_state ? " 1" : " 0");
733 g4uim->ApplyCommand(command);
734 command = string("/vis/viewer/set/hiddenEdge") + (button_state ? " 1" : " 0");
735 g4uim->ApplyCommand(command);
736 if (buttons_set1->buttonStatus(0) != button_state) { buttons_set1->toggleButton(0); }
737 }
738 else if (index == 3) {
739 if (button_state == 0) {
740 string command = string("/vis/scene/activateModel Field 0");
741 g4uim->ApplyCommand(command);
742 g4uim->ApplyCommand("/vis/scene/removeModel Field");
743 }
744 else {
745 string npoints = to_string(field_NPOINTS);
746 string command = string("/vis/scene/add/magneticField ") + npoints;
747 g4uim->ApplyCommand(command);
748 }
749 }
750 else if (index == 4) {
751 if (button_state == 1) {
752 string command = string("/vis/scene/add/axes");
753 g4uim->ApplyCommand(command);
754 }
755 }
756 else if (index == 5) {
757 if (button_state == 1) {
758 string command = string("/vis/scene/add/scale");
759 g4uim->ApplyCommand(command);
760 }
761 }
762}
763
770void G4DisplayView::field_precision_changed() {
771 G4UImanager* g4uim = G4UImanager::GetUIpointer();
772 if (g4uim == nullptr) { return; }
773 field_NPOINTS = field_npoints->text().toInt();
774 if (buttons_set1->buttonStatus(3) == 1) {
775 string command = string("vis/scene/activateModel Field 0");
776 g4uim->ApplyCommand(command);
777 g4uim->ApplyCommand("/vis/scene/removeModel Field");
778
779 string npoints = to_string(field_NPOINTS);
780 command = string("/vis/scene/add/magneticField ") + npoints;
781 G4UImanager::GetUIpointer()->ApplyCommand(command);
782 }
783}
G4DisplayView(const std::shared_ptr< GOptions > &gopts, std::shared_ptr< GLogger > logger, QWidget *parent=nullptr)
Constructs the G4DisplayView widget.
G4Camera getG4Camera(const std::shared_ptr< GOptions > &gopts)