Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TGeoColorScheme.cxx
Go to the documentation of this file.
1//==============================================================================
2// TGeoColorScheme.cxx
3//==============================================================================
4
5/**
6 * @class TGeoColorScheme
7 * @ingroup Geometry_classes
8 * @brief Strategy class for assigning colors/transparency to geometry volumes.
9 *
10 * @details
11 * Helper "strategy" class used by TGeoManager::DefaultColors() to assign
12 * visualization attributes (line color and optional transparency) to imported
13 * geometries (e.g. GDML), where the source format does not encode colors.
14 *
15 * @par Design goals
16 * @li Backward compatibility: calling TGeoManager::DefaultColors() with no
17 * arguments behaves like today (default "natural" scheme).
18 * @li Reasonable defaults for detector geometries: first try name-based material
19 * classification (e.g. copper, aluminium, steel, FR4/G10, kapton/polyimide,
20 * gases), then fall back to a Z-binned lookup.
21 * @li User extensibility without requiring subclassing: users can provide hooks
22 * (std::function) that override the default decisions partially or fully.
23 * Hooks are runtime-only (not persistified).
24 *
25 * @par How TGeoManager::DefaultColors() uses a scheme
26 * For each volume:
27 * @li scheme->Color(vol) is queried:
28 * @li return >= 0 : use returned ROOT color index (TColor index)
29 * @li return < 0 : caller may ignore or use its own fallback
30 * @li scheme->Transparency(vol) is queried:
31 * @li return in [0..100] : set volume transparency
32 * @li return < 0 : do not change transparency
33 *
34 * @par Default behavior
35 * @li Color(vol):
36 * @li If a user color hook is installed, it is called first. If it returns
37 * >= 0, that color is used.
38 * @li Otherwise, try name-based overrides (tokens like "copper", "steel",
39 * "fr4", "g10", "kapton", "argon", "c6f14", ...).
40 * @li If still unresolved, fall back to ColorForZ(effectiveZ). Users can
41 * override the Z fallback via SetZFallbackHook() or by subclassing and
42 * overriding ColorForZ().
43 * @li Transparency(vol):
44 * @li If a user transparency hook is installed and returns >= 0, use it.
45 * @li Otherwise, the default makes very low-density materials (gases)
46 * semi-transparent (60), preserving historical behavior.
47 *
48 * @par User extensibility examples
49 * Example A: Tweak just copper-like materials (leave everything else default)
50 * @code{.cpp}
51 * TGeoColorScheme cs(EGeoColorSet::kNatural);
52 * cs.SetColorHook([](const TGeoVolume* v) -> Int_t {
53 * const TGeoMaterial* m = TGeoColorScheme::GetMaterial(v);
54 * if (!m || !m->GetName()) return -1;
55 * std::string n = m->GetName();
56 * std::transform(n.begin(), n.end(), n.begin(), ::tolower);
57 * if (n.find("copper") != std::string::npos || n.find("_cu") != std::string::npos)
58 * return TColor::GetColor(0.90f, 0.55f, 0.30f); // custom copper tint
59 * return -1; // let defaults handle the rest
60 * });
61 * gGeoManager->DefaultColors(&cs);
62 * @endcode
63 *
64 * Example B: Override Z-fallback mapping (keep name overrides)
65 * @code{.cpp}
66 * TGeoColorScheme cs(EGeoColorSet::kNatural);
67 * cs.SetZFallbackHook([](Int_t Z, EGeoColorSet) -> Int_t {
68 * float t = std::min(1.f, std::max(0.f, Z / 100.f));
69 * return TColor::GetColor(t, t, t); // grayscale by Z
70 * });
71 * gGeoManager->DefaultColors(&cs);
72 * @endcode
73 *
74 * Example C: Full custom policy via subclassing (optional)
75 * @code{.cpp}
76 * class MyScheme : public TGeoColorScheme {
77 * public:
78 * using TGeoColorScheme::TGeoColorScheme;
79 * Int_t ColorForZ(Int_t Z, EGeoColorSet set) const override { ... }
80 * Int_t Color(const TGeoVolume* vol) const override { ... }
81 * };
82 * MyScheme cs(EGeoColorSet::kFlashy);
83 * gGeoManager->DefaultColors(&cs);
84 * @endcode
85 *
86 * @par Notes
87 * @li This class is intended for runtime use; it is not persistified because
88 * hooks are user-provided callables which are not I/O friendly.
89 * @li The default name token rules are heuristic and aimed at typical HEP
90 * detector material naming conventions; users can refine them locally via
91 * hooks or subclassing.
92 *
93 * @see TGeoManager::DefaultColors
94 */
95
96#include <string>
97#include <algorithm>
98
99#include "TGeoColorScheme.h"
100#include "TColor.h"
101#include "TGeoVolume.h"
102#include "TGeoMedium.h"
103#include "TGeoMaterial.h"
104
105//---- local helpers -----------------------------------------------------------
106
107namespace {
108
109inline Int_t RGB(int r, int g, int b)
110{
111 return TColor::GetColor(r / 255.f, g / 255.f, b / 255.f);
112}
113
114inline Int_t ClampTransp(Int_t t)
115{
116 if (t < 0)
117 return -1;
118 if (t > 100)
119 return 100;
120 return t;
121}
122
123inline std::string Norm(std::string s)
124{
125 std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) {
126 if (c == '-' || c == ' ' || c == '.' || c == '/' || c == '\\' || c == ',')
127 return '_';
128 return (char)std::tolower(c);
129 });
130 return s;
131}
132
133inline bool Has(const std::string &s, const char *token)
134{
135 return s.find(token) != std::string::npos;
136}
137
138enum class EMatClass {
139 kGas,
140 kAir,
141 kVacuum,
142 kCopper,
143 kAluminium,
144 kTungsten,
145 kSteel,
146 kIron,
147 kFR4_G10,
148 kCarbonFiber,
149 kEpoxy,
150 kPE,
151 kBoratedPE,
152 kPVC,
153 kPolyurethane,
154 kPolyimide,
155 kNomex,
156 kTyvek,
157 kFoam,
158 kRohacell,
159 kSiO2,
160 kAlN,
161 kCeramic,
162 kCables,
163 kThermalScreen,
165};
166
167EMatClass ClassFromName(const TGeoMaterial *mat)
168{
169 if (!mat || !mat->GetName())
170 return EMatClass::kUnknown;
171 const std::string n = Norm(mat->GetName());
172
173 // gases/fluids
174 if (Has(n, "vacuum"))
175 return EMatClass::kVacuum;
176 if (Has(n, "air"))
177 return EMatClass::kAir;
178 if (Has(n, "c6f14") || Has(n, "cf4") || Has(n, "co2") || Has(n, "argon") || Has(n, "gas") || Has(n, "dead_"))
179 return EMatClass::kGas;
180
181 // metals
182 if (Has(n, "hmp_w") || Has(n, "tungsten") || Has(n, "_w_") || Has(n, "_w"))
183 return EMatClass::kTungsten;
184 if (Has(n, "hmp_cu") || Has(n, "copper") || Has(n, "_cu"))
185 return EMatClass::kCopper;
186 if (Has(n, "hmp_al") || Has(n, "aluminium") || Has(n, "aluminum") || Has(n, "2219") || Has(n, "_al"))
187 return EMatClass::kAluminium;
188
189 if (Has(n, "steel") || Has(n, "stainless"))
190 return EMatClass::kSteel;
191 if (Has(n, "cast_iron") || (Has(n, "iron") && !Has(n, "iridium")))
192 return EMatClass::kIron;
193
194 // PCB / laminates
195 if (Has(n, "g10") || Has(n, "fr4") || Has(n, "textolit"))
196 return EMatClass::kFR4_G10;
197
198 // composites / organics
199 if (Has(n, "carbon_fibre") || Has(n, "carbon_fiber"))
200 return EMatClass::kCarbonFiber;
201 if (Has(n, "epoxy"))
202 return EMatClass::kEpoxy;
203
204 if (Has(n, "borated") && (Has(n, "polyethyl") || Has(n, "polyethylene") || Has(n, "pe")))
205 return EMatClass::kBoratedPE;
206
207 if (Has(n, "polyimide") || Has(n, "kapton"))
208 return EMatClass::kPolyimide;
209 if (Has(n, "polyurethane"))
210 return EMatClass::kPolyurethane;
211 if (Has(n, "pvc"))
212 return EMatClass::kPVC;
213 if (Has(n, "polyethyl") || Has(n, "polyethylene"))
214 return EMatClass::kPE;
215 if (Has(n, "nomex"))
216 return EMatClass::kNomex;
217 if (Has(n, "tyvek"))
218 return EMatClass::kTyvek;
219 if (Has(n, "foam"))
220 return EMatClass::kFoam;
221 if (Has(n, "roha") || Has(n, "rohacell"))
222 return EMatClass::kRohacell;
223
224 // ceramics / oxides / nitrides
225 if (Has(n, "sio2") || Has(n, "quartz") || Has(n, "silica"))
226 return EMatClass::kSiO2;
227 if (Has(n, "aluminium_nitride") || Has(n, "aln"))
228 return EMatClass::kAlN;
229 if (Has(n, "ceramic"))
230 return EMatClass::kCeramic;
231
232 // non-dominant services
233 if (Has(n, "cables") || Has(n, "cable"))
234 return EMatClass::kCables;
235 if (Has(n, "thermalscreen") || Has(n, "thermal_screen") || Has(n, "thermal"))
236 return EMatClass::kThermalScreen;
237
238 return EMatClass::kUnknown;
239}
240
241Int_t ClassColor(EMatClass c, EGeoColorSet set)
242{
243 switch (set) {
245 switch (c) {
246 case EMatClass::kGas: return RGB(190, 230, 240);
247 case EMatClass::kAir: return RGB(210, 210, 210);
248 case EMatClass::kVacuum: return RGB(230, 230, 230);
249
250 case EMatClass::kCopper: return RGB(184, 115, 51);
251 case EMatClass::kAluminium: return RGB(190, 190, 195);
252 case EMatClass::kTungsten: return RGB(45, 45, 50);
253 case EMatClass::kSteel: return RGB(120, 125, 135);
254 case EMatClass::kIron: return RGB(90, 95, 105);
255
256 case EMatClass::kFR4_G10: return RGB(35, 115, 55);
257 case EMatClass::kCarbonFiber: return RGB(35, 35, 38);
258 case EMatClass::kEpoxy: return RGB(140, 95, 55);
259
260 case EMatClass::kPE: return RGB(220, 215, 205);
261 case EMatClass::kBoratedPE: return RGB(215, 205, 185);
262 case EMatClass::kPVC: return RGB(200, 200, 205);
263 case EMatClass::kPolyurethane: return RGB(230, 225, 185);
264 case EMatClass::kPolyimide: return RGB(185, 140, 50);
265 case EMatClass::kNomex: return RGB(220, 185, 90);
266 case EMatClass::kTyvek: return RGB(235, 240, 245);
267 case EMatClass::kFoam: return RGB(245, 245, 240);
268 case EMatClass::kRohacell: return RGB(245, 240, 235);
269
270 case EMatClass::kSiO2: return RGB(230, 235, 240);
271 case EMatClass::kAlN: return RGB(235, 235, 225);
272 case EMatClass::kCeramic: return RGB(225, 225, 220);
273
274 case EMatClass::kCables: return RGB(55, 55, 60);
275 case EMatClass::kThermalScreen: return RGB(195, 205, 215);
276
277 default: return -1;
278 }
279
281 switch (c) {
282 case EMatClass::kGas: return RGB(120, 220, 255);
283 case EMatClass::kAir: return RGB(170, 240, 255);
284 case EMatClass::kVacuum: return RGB(245, 245, 245);
285
286 case EMatClass::kCopper: return RGB(255, 140, 60);
287 case EMatClass::kAluminium: return RGB(210, 210, 220);
288 case EMatClass::kTungsten: return RGB(80, 80, 90);
289 case EMatClass::kSteel: return RGB(160, 160, 175);
290 case EMatClass::kIron: return RGB(130, 135, 150);
291
292 case EMatClass::kFR4_G10: return RGB(0, 200, 70);
293 case EMatClass::kCarbonFiber: return RGB(120, 120, 130);
294 case EMatClass::kEpoxy: return RGB(255, 180, 80);
295
296 case EMatClass::kBoratedPE: return RGB(255, 240, 160);
297 case EMatClass::kPolyimide: return RGB(255, 200, 40);
298 case EMatClass::kTyvek: return RGB(230, 250, 255);
299 case EMatClass::kFoam: return RGB(255, 230, 230);
300 case EMatClass::kRohacell: return RGB(230, 255, 230);
301
302 case EMatClass::kSiO2: return RGB(210, 235, 255);
303 case EMatClass::kAlN: return RGB(255, 255, 210);
304
305 case EMatClass::kCables: return RGB(255, 80, 80);
306 case EMatClass::kThermalScreen: return RGB(180, 220, 255);
307
308 default: return -1;
309 }
310
312 switch (c) {
313 case EMatClass::kGas: return RGB(20, 90, 110);
314 case EMatClass::kAir: return RGB(70, 70, 75);
315 case EMatClass::kVacuum: return RGB(110, 110, 115);
316
317 case EMatClass::kCopper: return RGB(110, 45, 10);
318 case EMatClass::kAluminium: return RGB(90, 95, 105);
319 case EMatClass::kTungsten: return RGB(30, 30, 35);
320 case EMatClass::kSteel: return RGB(60, 65, 75);
321 case EMatClass::kIron: return RGB(50, 55, 65);
322
323 case EMatClass::kFR4_G10: return RGB(10, 80, 30);
324 case EMatClass::kCarbonFiber: return RGB(25, 25, 28);
325 case EMatClass::kEpoxy: return RGB(85, 55, 25);
326
327 case EMatClass::kBoratedPE: return RGB(110, 95, 55);
328 case EMatClass::kPolyimide: return RGB(100, 70, 10);
329 case EMatClass::kTyvek: return RGB(80, 95, 110);
330 case EMatClass::kFoam: return RGB(100, 80, 80);
331 case EMatClass::kRohacell: return RGB(85, 105, 85);
332
333 case EMatClass::kSiO2: return RGB(70, 85, 100);
334 case EMatClass::kAlN: return RGB(90, 90, 70);
335
336 case EMatClass::kCables: return RGB(80, 20, 20);
337 case EMatClass::kThermalScreen: return RGB(70, 85, 100);
338
339 default: return -1;
340 }
341 }
342
343 return -1;
344}
345
347{
348 const auto cls = ClassFromName(mat);
349 return ClassColor(cls, set);
350}
351
352} // namespace
353
354//==============================================================================
355// TGeoColorScheme implementation
356//==============================================================================
357
359
361
363{
364 if (!vol)
365 return nullptr;
366 const TGeoMedium *med = vol->GetMedium();
367 if (!med)
368 return nullptr;
369 return med->GetMaterial();
370}
371
373{
374 if (!vol)
375 return -1;
376
377 // User override hook first
378 if (fColorHook) {
379 const Int_t c = fColorHook(vol);
380 if (c >= 0)
381 return c;
382 }
383
384 const TGeoMaterial *mat = GetMaterial(vol);
385 if (!mat)
386 return -1;
387
388 // Built-in name token override
390 if (cName >= 0)
391 return cName;
392
393 // Built-in Z fallback
394 const Int_t Z = (Int_t)mat->GetZ();
395 return ColorForZ(Z, fSet);
396}
397
399{
400 if (!vol)
401 return -1;
402
403 if (fTranspHook) {
404 const Int_t t = fTranspHook(vol);
405 if (t >= 0)
406 return ClampTransp(t);
407 }
408
409 const TGeoMaterial *mat = GetMaterial(vol);
410 if (!mat)
411 return -1;
412
413 // Historical default: gases transparent by density.
414 if (mat->GetDensity() < 0.1)
415 return 60;
416
417 return -1;
418}
419
421{
422 if (fZFallbackHook) {
423 const Int_t c = fZFallbackHook(Z, set);
424 if (c >= 0)
425 return c;
426 }
427
428 if (Z <= 0)
429 return kGray + 1;
430 if (Z > 109)
431 Z = 109;
432
433 switch (set) {
435 if (Z <= 2)
436 return kGray + 2;
437 if (Z <= 6)
438 return RGB(60, 60, 60);
439 if (Z <= 8)
440 return RGB(90, 110, 130);
441 if (Z <= 10)
442 return RGB(120, 140, 155);
443 if (Z <= 14)
444 return RGB(40, 85, 170);
445 if (Z <= 16)
446 return RGB(140, 160, 120);
447 if (Z <= 20)
448 return RGB(175, 175, 175);
449 if (Z <= 26)
450 return RGB(110, 120, 130);
451 if (Z <= 28)
452 return RGB(95, 105, 115);
453 if (Z == 29)
454 return RGB(184, 115, 51);
455 if (Z <= 30)
456 return RGB(150, 150, 155);
457 if (Z <= 35)
458 return RGB(160, 130, 70);
459 if (Z <= 40)
460 return RGB(140, 145, 150);
461 if (Z <= 50)
462 return RGB(120, 125, 130);
463 if (Z <= 56)
464 return RGB(105, 110, 120);
465 if (Z <= 74)
466 return RGB(45, 45, 50);
467 if (Z <= 79)
468 return RGB(130, 110, 30);
469 if (Z <= 82)
470 return RGB(90, 80, 95);
471 return RGB(80, 85, 90);
472
474 if (Z <= 2)
475 return RGB(120, 220, 255);
476 if (Z <= 6)
477 return RGB(255, 120, 220);
478 if (Z <= 10)
479 return RGB(80, 140, 255);
480 if (Z <= 14)
481 return RGB(80, 200, 255);
482 if (Z <= 20)
483 return RGB(80, 240, 140);
484 if (Z <= 26)
485 return RGB(255, 240, 100);
486 if (Z <= 30)
487 return RGB(255, 170, 60);
488 if (Z <= 40)
489 return RGB(255, 90, 90);
490 if (Z <= 56)
491 return RGB(140, 255, 200);
492 if (Z <= 74)
493 return RGB(200, 140, 255);
494 return RGB(255, 160, 220);
495
497 if (Z <= 2)
498 return RGB(30, 30, 30);
499 if (Z <= 6)
500 return RGB(70, 20, 20);
501 if (Z <= 10)
502 return RGB(15, 45, 90);
503 if (Z <= 14)
504 return RGB(10, 65, 120);
505 if (Z <= 20)
506 return RGB(25, 80, 35);
507 if (Z <= 26)
508 return RGB(90, 70, 15);
509 if (Z <= 30)
510 return RGB(110, 45, 10);
511 if (Z <= 40)
512 return RGB(110, 15, 35);
513 if (Z <= 56)
514 return RGB(55, 20, 85);
515 if (Z <= 74)
516 return RGB(35, 35, 45);
517 return RGB(60, 50, 70);
518 }
519
520 return kGray;
521}
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
#define g(i)
Definition RSha256.hxx:105
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
@ kGray
Definition Rtypes.h:66
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
@ kCopper
Definition TColor.h:138
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
EGeoColorSet
Enumeration of predefined geometry color schemes.
@ kNatural
Natural, material-inspired colors (default)
@ kFlashy
Bright, high-contrast colors for presentations.
@ kHighContrast
Dark, saturated colors for light backgrounds.
@ kUnknown
Definition TStructNode.h:19
static Int_t GetColor(const char *hexcolor)
Static method returning color number for color specified by hex color string of form: "#rrggbb",...
Definition TColor.cxx:1926
virtual Int_t Transparency(const TGeoVolume *vol) const
Compute the transparency for a given volume.
TGeoColorScheme(EGeoColorSet set=EGeoColorSet::kNatural)
Constructor.
virtual Int_t ColorForZ(Int_t Z, EGeoColorSet set) const
Compute fallback color based on material effective Z.
virtual Int_t Color(const TGeoVolume *vol) const
Compute the color for a given volume.
EGeoColorSet fSet
Active color set selection.
TranspHook_t fTranspHook
Optional user hook for transparency.
static const TGeoMaterial * GetMaterial(const TGeoVolume *vol)
Retrieve the material associated with a geometry volume.
ZFallbackHook_t fZFallbackHook
Optional user hook for Z fallback.
virtual ~TGeoColorScheme()
Virtual destructor.
ColorHook_t fColorHook
Optional user hook for color assignment.
Base class describing materials.
Media are used to store properties related to tracking and which are useful only when using geometry ...
Definition TGeoMedium.h:23
TGeoVolume, TGeoVolumeMulti, TGeoVolumeAssembly are the volume classes.
Definition TGeoVolume.h:43
TGeoMedium * GetMedium() const
Definition TGeoVolume.h:176
const Int_t n
Definition legend1.C:16