CHeT Library
Loading...
Searching...
No Matches
CHeTVisualizer.cc
Go to the documentation of this file.
3
4// --- Internal Implementation Details ---
5namespace
6{
7
8// Helper: Clipping algorithm to keep lines inside the detector box.
9// Moved to anonymous namespace to keep the header clean.
10bool ClipLineToBox(double x0, double y0, double z0, double ux, double uy, double uz, double xmin,
11 double xmax, double ymin, double ymax, double zmin, double zmax, double &tmin, double &tmax)
12{
13 // Use bounds provided by caller (e.g. -inf, +inf for line, or 0, L for segment)
14
15 auto clip = [&](double p0, double dp, double pmin, double pmax) -> bool
16 {
17 if(std::abs(dp) < 1e-12)
18 return (p0 >= pmin && p0 <= pmax);
19
20 double t1 = (pmin - p0) / dp;
21 double t2 = (pmax - p0) / dp;
22 if(t1 > t2)
23 std::swap(t1, t2);
24 tmin = std::max(tmin, t1);
25 tmax = std::min(tmax, t2);
26 return tmin <= tmax;
27 };
28
29 if(!clip(x0, ux, xmin, xmax))
30 return false;
31 if(!clip(y0, uy, ymin, ymax))
32 return false;
33 if(!clip(z0, uz, zmin, zmax))
34 return false;
35
36 return true;
37}
38
39} // anonymous namespace
40
41namespace CHeT
42{
43namespace Vis
44{
45
46// --- Overloads for different track types in 2D ---
47
48void RenderTrack2D(const VisLineTrack &tr, TMultiGraph *mg_xy)
49{
50 TGraph *gxy = new TGraph();
51 // Use a large enough range so the line covers the detector view.
52 // The view limits are set by Draw2DCore based on geometry.
53 double range = 2000.0;
54 double pts[2] = { -range, range };
55
56 for(int i = 0; i < 2; i++)
57 {
58 if(std::abs(tr.ux) > 1e-6)
59 {
60 double t = (pts[i] - tr.x0) / tr.ux;
61 gxy->SetPoint(i, pts[i], tr.y0 + tr.uy * t);
62 }
63 else
64 {
65 gxy->SetPoint(0, tr.x0, -range);
66 gxy->SetPoint(1, tr.x0, range);
67 }
68 }
69 gxy->SetLineColor(tr.color);
70 gxy->SetLineWidth(tr.width);
71 gxy->SetLineStyle(tr.style);
72 mg_xy->Add(gxy, "L");
73}
74
75void RenderTrack2D(const VisHelixTrack &tr, TMultiGraph *mg_xy)
76{
77 int n_pts = 100;
78 TGraph *gxy = new TGraph(n_pts);
79 double dt = (tr.t_max - tr.t_min) / (n_pts - 1);
80 for(int i = 0; i < n_pts; ++i)
81 {
82 double t = tr.t_min + i * dt;
83 gxy->SetPoint(i, tr.cx + tr.radius * std::cos(t), tr.cy + tr.radius * std::sin(t));
84 }
85 gxy->SetLineColor(tr.color);
86 gxy->SetLineWidth(tr.width);
87 gxy->SetLineStyle(tr.style);
88 mg_xy->Add(gxy, "L");
89}
90
91void RenderTrack2D(const VisGenericTrack &tr, TMultiGraph *mg_xy)
92{
93 if(tr.points.empty())
94 return;
95 TGraph *gxy = new TGraph(tr.points.size());
96 for(size_t i = 0; i < tr.points.size(); ++i)
97 {
98 gxy->SetPoint(i, tr.points[i].x, tr.points[i].y);
99 }
100 gxy->SetLineColor(tr.color);
101 gxy->SetLineWidth(tr.width);
102 gxy->SetLineStyle(tr.style);
103 mg_xy->Add(gxy, "L");
104}
105
106// --- ZX Projection (X vs Z) ---
107void RenderTrackZX(const VisLineTrack &tr, TMultiGraph *mg_zx)
108{
109 TGraph *g = new TGraph();
110 double range = 2000.0;
111 double pts[2] = { -range, range };
112
113 for(int i = 0; i < 2; i++)
114 {
115 if(std::abs(tr.ux) > 1e-6)
116 {
117 double t = (pts[i] - tr.x0) / tr.ux;
118 g->SetPoint(i, pts[i], tr.z0 + tr.uz * t);
119 }
120 else
121 {
122 g->SetPoint(0, tr.x0, -range);
123 g->SetPoint(1, tr.x0, range);
124 }
125 }
126 g->SetLineColor(tr.color);
127 g->SetLineWidth(tr.width);
128 g->SetLineStyle(tr.style);
129 mg_zx->Add(g, "L");
130}
131
132void RenderTrackZX(const VisHelixTrack &tr, TMultiGraph *mg_zx)
133{
134 int n_pts = 100;
135 TGraph *g = new TGraph(n_pts);
136 double dt = (tr.t_max - tr.t_min) / (n_pts - 1);
137 for(int i = 0; i < n_pts; ++i)
138 {
139 double t = tr.t_min + i * dt;
140 double x = tr.cx + tr.radius * std::cos(t);
141 double z = tr.z0 + tr.dz_dt * t;
142 g->SetPoint(i, x, z);
143 }
144 g->SetLineColor(tr.color);
145 g->SetLineWidth(tr.width);
146 g->SetLineStyle(tr.style);
147 mg_zx->Add(g, "L");
148}
149
150void RenderTrackZX(const VisGenericTrack &tr, TMultiGraph *mg_zx)
151{
152 if(tr.points.empty())
153 return;
154 TGraph *g = new TGraph(tr.points.size());
155 for(size_t i = 0; i < tr.points.size(); ++i)
156 g->SetPoint(i, tr.points[i].x, tr.points[i].z);
157 g->SetLineColor(tr.color);
158 g->SetLineWidth(tr.width);
159 g->SetLineStyle(tr.style);
160 mg_zx->Add(g, "L");
161}
162
163// --- ZY Projection (Z vs Y) ---
164void RenderTrackZY(const VisLineTrack &tr, TMultiGraph *mg_zy)
165{
166 TGraph *g = new TGraph();
167 double range = 2000.0;
168 double pts[2] = { -range, range }; // Z is horizontal
169
170 for(int i = 0; i < 2; i++)
171 {
172 if(std::abs(tr.uz) > 1e-6)
173 {
174 double t = (pts[i] - tr.z0) / tr.uz;
175 g->SetPoint(i, pts[i], tr.y0 + tr.uy * t);
176 }
177 else
178 {
179 g->SetPoint(0, tr.z0, -range);
180 g->SetPoint(1, tr.z0, range);
181 }
182 }
183 g->SetLineColor(tr.color);
184 g->SetLineWidth(tr.width);
185 g->SetLineStyle(tr.style);
186 mg_zy->Add(g, "L");
187}
188
189void RenderTrackZY(const VisHelixTrack &tr, TMultiGraph *mg_zy)
190{
191 int n_pts = 100;
192 TGraph *g = new TGraph(n_pts);
193 double dt = (tr.t_max - tr.t_min) / (n_pts - 1);
194 for(int i = 0; i < n_pts; ++i)
195 {
196 double t = tr.t_min + i * dt;
197 double y = tr.cy + tr.radius * std::sin(t);
198 double z = tr.z0 + tr.dz_dt * t;
199 g->SetPoint(i, z, y);
200 }
201 g->SetLineColor(tr.color);
202 g->SetLineWidth(tr.width);
203 g->SetLineStyle(tr.style);
204 mg_zy->Add(g, "L");
205}
206
207void RenderTrackZY(const VisGenericTrack &tr, TMultiGraph *mg_zy)
208{
209 if(tr.points.empty())
210 return;
211 TGraph *g = new TGraph(tr.points.size());
212 for(size_t i = 0; i < tr.points.size(); ++i)
213 g->SetPoint(i, tr.points[i].z, tr.points[i].y);
214 g->SetLineColor(tr.color);
215 g->SetLineWidth(tr.width);
216 g->SetLineStyle(tr.style);
217 mg_zy->Add(g, "L");
218}
219
220// --- PhiZ Projection (Phi vs Z) ---
221void RenderTrackPhiZ(const VisLineTrack &tr, TMultiGraph *mg_phiz, bool wrap_phi)
222{
223 int n_pts = 200;
224 TGraph *g = new TGraph();
225 double range = 1000.0;
226 int cnt = 0;
227 for(int i = 0; i < n_pts; ++i)
228 {
229 double t = -range + i * (2 * range) / (n_pts - 1);
230 double x = tr.x0 + tr.ux * t;
231 double y = tr.y0 + tr.uy * t;
232 double z = tr.z0 + tr.uz * t;
233
234 if(std::abs(z) > 400)
235 continue;
236
237 double phi = std::atan2(y, x);
238 if(wrap_phi && phi < 0)
239 phi += 2 * M_PI;
240 g->SetPoint(cnt++, phi, z);
241 }
242 g->SetLineColor(tr.color);
243 g->SetLineWidth(tr.width);
244 g->SetLineStyle(tr.style);
245 mg_phiz->Add(g, "L");
246}
247
248void RenderTrackPhiZ(const VisHelixTrack &tr, TMultiGraph *mg_phiz, bool wrap_phi)
249{
250 int n_pts = 100;
251 TGraph *g = new TGraph(n_pts);
252 double dt = (tr.t_max - tr.t_min) / (n_pts - 1);
253 for(int i = 0; i < n_pts; ++i)
254 {
255 double t = tr.t_min + i * dt;
256 double x = tr.cx + tr.radius * std::cos(t);
257 double y = tr.cy + tr.radius * std::sin(t);
258 double z = tr.z0 + tr.dz_dt * t;
259
260 double phi = std::atan2(y, x);
261 if(wrap_phi && phi < 0)
262 phi += 2 * M_PI;
263
264 g->SetPoint(i, phi, z);
265 }
266 g->SetLineColor(tr.color);
267 g->SetLineWidth(tr.width);
268 g->SetLineStyle(tr.style);
269 mg_phiz->Add(g, "L");
270}
271
272void RenderTrackPhiZ(const VisGenericTrack &tr, TMultiGraph *mg_phiz, bool wrap_phi)
273{
274 if(tr.points.empty())
275 return;
276 TGraph *g = new TGraph(tr.points.size());
277 for(size_t i = 0; i < tr.points.size(); ++i)
278 {
279 double phi = std::atan2(tr.points[i].y, tr.points[i].x);
280 if(wrap_phi && phi < 0)
281 phi += 2 * M_PI;
282 g->SetPoint(i, phi, tr.points[i].z);
283 }
284 g->SetLineColor(tr.color);
285 g->SetLineWidth(tr.width);
286 g->SetLineStyle(tr.style);
287 mg_phiz->Add(g, "L");
288}
289
290// --- Overloads for different track types in 3D ---
291
292void RenderTrack3D(const VisLineTrack &tr_in, double bounds[6])
293{
294 VisLineTrack tr = tr_in;
295 if(tr.isLocalFrame)
296 {
299 }
300
301 double tmin = -1e30;
302 double tmax = 1e30;
303 bool ok = ClipLineToBox(tr.x0, tr.y0, tr.z0, tr.ux, tr.uy, tr.uz, bounds[0], bounds[1],
304 bounds[2], bounds[3], bounds[4], bounds[5], tmin, tmax);
305 if(ok)
306 {
307 TPolyLine3D *lt = new TPolyLine3D(2);
308 lt->SetPoint(0, tr.z0 + tr.uz * tmin, tr.x0 + tr.ux * tmin, tr.y0 + tr.uy * tmin);
309 lt->SetPoint(1, tr.z0 + tr.uz * tmax, tr.x0 + tr.ux * tmax, tr.y0 + tr.uy * tmax);
310 lt->SetLineColor(tr.color);
311 lt->SetLineWidth(tr.width);
312 lt->SetLineStyle(tr.style);
313 lt->Draw("same");
314 }
315}
316
317void RenderTrack3D(const VisHelixTrack &tr, double bounds[6])
318{
319 int n_pts = 200; // High resolution for 3D helix
320 TPolyLine3D *lt = new TPolyLine3D(n_pts);
321 double dt = (tr.t_max - tr.t_min) / (n_pts - 1);
322
323 for(int i = 0; i < n_pts; ++i)
324 {
325 double t = tr.t_min + i * dt;
326 double x = tr.cx + tr.radius * std::cos(t);
327 double y = tr.cy + tr.radius * std::sin(t);
328 double z = tr.z0 + tr.dz_dt * t;
329
330 if(tr.isLocalFrame)
331 {
333 }
334 // ROOT Frame: Z_root=Y_phys, etc. (Respecting original code mapping)
335 lt->SetPoint(i, z, x, y);
336 }
337 lt->SetLineColor(tr.color);
338 lt->SetLineWidth(tr.width);
339 lt->SetLineStyle(tr.style);
340 lt->Draw("same");
341}
342
343void RenderTrack3D(const VisGenericTrack &tr, double bounds[6])
344{
345 if(tr.points.empty())
346 return;
347 TPolyLine3D *lt = new TPolyLine3D(tr.points.size());
348
349 for(size_t i = 0; i < tr.points.size(); ++i)
350 {
351 double x = tr.points[i].x;
352 double y = tr.points[i].y;
353 double z = tr.points[i].z;
354
355 if(tr.isLocalFrame)
356 {
358 }
359 lt->SetPoint(i, z, x, y);
360 }
361 lt->SetLineColor(tr.color);
362 lt->SetLineWidth(tr.width);
363 lt->SetLineStyle(tr.style);
364 lt->Draw("same");
365}
366
367// --- Core Functions ---
368
369void Draw2DCore(const std::vector<int> &bundle_ids, const std::vector<VisPoint2D> &extraPoints,
370 const std::function<void(TMultiGraph *, TMultiGraph *, TMultiGraph *, TMultiGraph *)>
371 &trackDrawer,
372 bool wrap_phi)
373{
374 // --- 1. Canvas Phi-Z (Unrolled) ---
375 TCanvas *c_phiz = (TCanvas *)gROOT->FindObject("c_phiz");
376 if(!c_phiz)
377 c_phiz = new TCanvas("c_phiz", "Map Phi-Z", 750, 850);
378 else
379 c_phiz->Clear();
380
381 c_phiz->SetLeftMargin(0.15);
382 c_phiz->SetGrid();
383
384 TMultiGraph *mg_phiz = new TMultiGraph();
385
386 // --- 2. Canvas Lateral Projections ---
387 TCanvas *c_lat = (TCanvas *)gROOT->FindObject("c_lat");
388 if(!c_lat)
389 c_lat = new TCanvas("c_lat", "Projections ZX / ZY", 1200, 750);
390 else
391 c_lat->Clear();
392
393 TPad *pad_zx = new TPad("pad_zx", "ZX", 0.01, 0.01, 0.42, 1);
394 TPad *pad_zy = new TPad("pad_zy", "ZY", 0.4, 0.15, 1, 0.8);
395 pad_zx->SetLeftMargin(0.15);
396 pad_zy->SetBottomMargin(0.15);
397 pad_zx->Draw();
398 pad_zy->Draw();
399
400 TMultiGraph *mg_zx = new TMultiGraph();
401 TMultiGraph *mg_zy = new TMultiGraph();
402
403 // --- 3. Canvas XY View ---
404 TCanvas *c_xy = (TCanvas *)gROOT->FindObject("c_xy");
405 if(!c_xy)
406 c_xy = new TCanvas("c_xy", "Transverse View XY", 700, 700);
407 else
408 c_xy->Clear();
409
410 c_xy->SetGrid();
411 TMultiGraph *mg_xy = new TMultiGraph();
412
413 // --- Draw Bundles ---
414 for(int b_id : bundle_ids)
415 {
417 double d_phi_w = (CHeT::Config::BUNDLE_WIDTH / p.r) / 2.0;
418
419 std::vector<double> vz, vphi, vx, vy;
420 vz.reserve(500);
421 vphi.reserve(500);
422 vx.reserve(500);
423 vy.reserve(500);
424
425 // Generate points along the fiber
426 for(int i = 0; i < 500; ++i)
427 {
428 double z = -CHeT::Config::L_HALF + i * (2.0 * CHeT::Config::L_HALF / 499.0);
429 double alpha = (z + CHeT::Config::L_HALF) / (2.0 * CHeT::Config::L_HALF);
430 double ph = p.phi0 + p.dir * alpha * M_PI;
431 vz.push_back(z);
432 vphi.push_back(ph);
433 vx.push_back(p.r * std::cos(ph));
434 vy.push_back(p.r * std::sin(ph));
435 }
436
437 // Linear Graphs (ZX, ZY, XY)
438 TGraph *l_zx = new TGraph(500, &vx[0], &vz[0]);
439 l_zx->SetLineColor(p.color);
440 l_zx->SetLineWidth(2);
441 mg_zx->Add(l_zx, "L");
442
443 TGraph *l_zy = new TGraph(500, &vz[0], &vy[0]);
444 l_zy->SetLineColor(p.color);
445 l_zy->SetLineWidth(2);
446 mg_zy->Add(l_zy, "L");
447
448 // Phi-Z Graphs (Handle 2pi wrapping)
449 std::vector<double> sz, sf;
450 for(size_t i = 0; i < 500; ++i)
451 {
452 double cf = wrap_phi ? CHeT::Config::wrap0_2pi(vphi[i]) : vphi[i];
453
454 // Check for wrap-around jump
455 if(wrap_phi && i > 0 && std::abs(cf - CHeT::Config::wrap0_2pi(vphi[i - 1])) > M_PI)
456 {
457 // Draw current segment
458 TGraph *h = new TGraph();
459 int nn = sz.size();
460 for(int j = 0; j < nn; ++j)
461 h->SetPoint(j, sf[j] + d_phi_w, sz[j]);
462 for(int j = 0; j < nn; ++j)
463 h->SetPoint(nn + j, sf[nn - 1 - j] - d_phi_w, sz[nn - 1 - j]);
464
465 h->SetFillColorAlpha(p.color, 0.3);
466 h->SetLineWidth(0);
467 mg_phiz->Add(h, "F");
468
469 TGraph *l = new TGraph(nn, &sf[0], &sz[0]);
470 l->SetLineColor(p.color);
471 l->SetLineWidth(2);
472 mg_phiz->Add(l, "L");
473
474 sz.clear();
475 sf.clear();
476 }
477 sz.push_back(vz[i]);
478 sf.push_back(cf);
479 }
480
481 // Draw final segment
482 if(!sz.empty())
483 {
484 TGraph *hf = new TGraph();
485 int nn = sz.size();
486 for(int j = 0; j < nn; ++j)
487 hf->SetPoint(j, sf[j] + d_phi_w, sz[j]);
488 for(int j = 0; j < nn; ++j)
489 hf->SetPoint(nn + j, sf[nn - 1 - j] - d_phi_w, sz[nn - 1 - j]);
490
491 hf->SetFillColorAlpha(p.color, 0.3);
492 hf->SetLineWidth(0);
493 mg_phiz->Add(hf, "F");
494
495 TGraph *lf = new TGraph(nn, &sf[0], &sz[0]);
496 lf->SetLineColor(p.color);
497 lf->SetLineWidth(2);
498 mg_phiz->Add(lf, "L");
499 }
500 }
501
502 // --- Draw Tracks (All Projections) ---
503 if(trackDrawer)
504 trackDrawer(mg_xy, mg_zx, mg_zy, mg_phiz);
505
506 // --- Draw Extra Points (XY) ---
507 for(const auto &pt : extraPoints)
508 {
509 TGraph *gp = new TGraph(1);
510 gp->SetPoint(0, pt.x, pt.y);
511 gp->SetMarkerColor(pt.color);
512 gp->SetMarkerStyle(pt.markerStyle);
513 gp->SetMarkerSize(pt.size);
514 mg_xy->Add(gp, "P");
515 }
516
517 // --- Draw Intersections ---
518 auto inters = Config::FindIntersections(bundle_ids);
519 if(!inters.empty())
520 {
521 // XY
522 TGraph *gi_xy = new TGraph();
523 for(size_t i = 0; i < inters.size(); ++i)
524 gi_xy->SetPoint(i, inters[i].x_loc, inters[i].y_loc);
525 gi_xy->SetMarkerStyle(20);
526 gi_xy->SetMarkerSize(0.8);
527 gi_xy->SetMarkerColor(kBlack);
528 mg_xy->Add(gi_xy, "P");
529
530 // ZX (x vs z)
531 TGraph *gi_zx = new TGraph();
532 for(size_t i = 0; i < inters.size(); ++i)
533 gi_zx->SetPoint(i, inters[i].x_loc, inters[i].z_loc);
534 gi_zx->SetMarkerStyle(20);
535 gi_zx->SetMarkerSize(0.8);
536 gi_zx->SetMarkerColor(kBlack);
537 mg_zx->Add(gi_zx, "P");
538
539 // ZY (z vs y)
540 TGraph *gi_zy = new TGraph();
541 for(size_t i = 0; i < inters.size(); ++i)
542 gi_zy->SetPoint(i, inters[i].z_loc, inters[i].y_loc);
543 gi_zy->SetMarkerStyle(20);
544 gi_zy->SetMarkerSize(0.8);
545 gi_zy->SetMarkerColor(kBlack);
546 mg_zy->Add(gi_zy, "P");
547
548 // PhiZ (phi vs z)
549 TGraph *gi_phiz = new TGraph();
550 for(size_t i = 0; i < inters.size(); ++i)
551 {
552 double phi = std::atan2(inters[i].y_loc, inters[i].x_loc);
553 if(wrap_phi && phi < 0)
554 phi += 2 * M_PI;
555 gi_phiz->SetPoint(i, phi, inters[i].z_loc);
556 }
557 gi_phiz->SetMarkerStyle(20);
558 gi_phiz->SetMarkerSize(0.8);
559 gi_phiz->SetMarkerColor(kBlack);
560 mg_phiz->Add(gi_phiz, "P");
561 }
562
563 // --- Final Rendering ---
564
565 // 1. Phi-Z
566 c_phiz->cd();
567 mg_phiz->Draw("A");
568 mg_phiz->SetTitle("Detector Map #phi-z; #phi [rad]; z [mm]");
569 if(wrap_phi)
570 {
571 mg_phiz->GetXaxis()->SetLimits(0, 2 * M_PI);
572 mg_phiz->GetXaxis()->SetNdivisions(-504);
573
574 // Custom axis labels
575 TAxis *ax = mg_phiz->GetXaxis();
576 ax->ChangeLabel(1, -1, -1, -1, -1, -1, "0");
577 ax->ChangeLabel(2, -1, -1, -1, -1, -1, "#pi/2");
578 ax->ChangeLabel(3, -1, -1, -1, -1, -1, "#pi");
579 ax->ChangeLabel(4, -1, -1, -1, -1, -1, "3#pi/2");
580 ax->ChangeLabel(5, -1, -1, -1, -1, -1, "2#pi");
581 }
582
583 // 2. ZX and ZY
584 auto cyls = CHeT::Config::GetCylinders();
585
586 double max_R = 0;
587 for(const auto &cyl : cyls)
588 {
589 if(cyl.outer.radius > max_R)
590 max_R = cyl.outer.radius;
591 }
592 if(max_R < 30.0)
593 max_R = 30.0;
594
595 double margin = 10.0;
596 double limit = max_R + margin;
597
598 pad_zx->cd();
599 pad_zx->SetGrid();
600 mg_zx->Draw("A");
601 mg_zx->SetTitle("Top View ZX; x [mm]; z [mm]");
602 mg_zx->GetXaxis()->SetLimits(-limit, limit);
603 mg_zx->GetYaxis()->SetRangeUser(-CHeT::Config::L_HALF - 20, CHeT::Config::L_HALF + 20);
604 for(auto &c : cyls)
605 {
606 TBox *b = new TBox(
607 -c.nominalRadius, -CHeT::Config::L_HALF, c.nominalRadius, CHeT::Config::L_HALF);
608 b->SetFillStyle(0);
609 b->SetLineColor(kGray + 1);
610 b->Draw("same");
611 }
612
613 pad_zy->cd();
614 pad_zy->SetGrid();
615 mg_zy->Draw("A");
616 mg_zy->SetTitle("Lateral View ZY; z [mm]; y [mm]");
617 mg_zy->GetXaxis()->SetLimits(-CHeT::Config::L_HALF - 20, CHeT::Config::L_HALF + 20);
618 mg_zy->GetYaxis()->SetRangeUser(-limit, limit);
619 for(auto &c : cyls)
620 {
621 TBox *b = new TBox(
622 -CHeT::Config::L_HALF, -c.nominalRadius, CHeT::Config::L_HALF, c.nominalRadius);
623 b->SetFillStyle(0);
624 b->SetLineColor(kGray + 1);
625 b->Draw("same");
626 }
627
628 // 3. XY
629 c_xy->cd();
630 mg_xy->Draw("A");
631 mg_xy->SetTitle("XY View; x [mm]; y [mm]");
632 mg_xy->GetXaxis()->SetLimits(-limit, limit);
633 mg_xy->GetYaxis()->SetRangeUser(-limit, limit);
634 for(auto &c : cyls)
635 {
636 TEllipse *e = new TEllipse(0, 0, c.nominalRadius);
637 e->SetFillStyle(0);
638 e->Draw();
639 }
640
641 c_phiz->Update();
642 c_lat->Update();
643 c_xy->Update();
644}
645
646void Draw3DCore(const std::vector<int> &hit_ids, const std::vector<VisPoint3D> &points,
647 bool drawSkeleton, const std::function<void(double[6])> &trackDrawer)
648{
649 // gStyle->SetCanvasPreferGL(kTRUE);
650
651 TCanvas *c_3d = (TCanvas *)gROOT->FindObject("c_3d");
652 if(!c_3d)
653 c_3d = new TCanvas("c_3d", "Detector 3D View", 1200, 800);
654 else
655 c_3d->Clear();
656
657 // Calculate dynamic bounding box based on geometry and transformation
658 double min_x_phys = 1e9, max_x_phys = -1e9;
659 double min_y_phys = 1e9, max_y_phys = -1e9;
660 double min_z_phys = 1e9, max_z_phys = -1e9;
661
662 auto cylinders = CHeT::Config::GetCylinders();
663 double max_R = 0;
664 for(const auto &cyl : cylinders)
665 {
666 if(cyl.outer.radius > max_R)
667 max_R = cyl.outer.radius;
668 }
669 if(max_R < 1.0)
670 max_R = 100.0; // Fallback
671
672 double corners[8][3]
673 = { { max_R, max_R, CHeT::Config::L_HALF }, { max_R, -max_R, CHeT::Config::L_HALF },
674 { -max_R, max_R, CHeT::Config::L_HALF }, { -max_R, -max_R, CHeT::Config::L_HALF },
675 { max_R, max_R, -CHeT::Config::L_HALF }, { max_R, -max_R, -CHeT::Config::L_HALF },
676 { -max_R, max_R, -CHeT::Config::L_HALF }, { -max_R, -max_R, -CHeT::Config::L_HALF } };
677
678 for(int i = 0; i < 8; ++i)
679 {
680 double x = corners[i][0];
681 double y = corners[i][1];
682 double z = corners[i][2];
684
685 if(x < min_x_phys)
686 min_x_phys = x;
687 if(x > max_x_phys)
688 max_x_phys = x;
689 if(y < min_y_phys)
690 min_y_phys = y;
691 if(y > max_y_phys)
692 max_y_phys = y;
693 if(z < min_z_phys)
694 min_z_phys = z;
695 if(z > max_z_phys)
696 max_z_phys = z;
697 }
698
699 double margin = 20.0;
700 min_x_phys -= margin;
701 max_x_phys += margin;
702 min_y_phys -= margin;
703 max_y_phys += margin;
704 min_z_phys -= margin;
705 max_z_phys += margin;
706
707 // Force aspect ratio to be isotropic (Cube) only if rotated
708 double rx, ry, rz;
709 CHeT::Config::GetRotation(rx, ry, rz);
710 bool isRotated = (std::abs(rx) > 1e-9 || std::abs(ry) > 1e-9 || std::abs(rz) > 1e-9);
711
712 if(isRotated)
713 {
714 double dx = max_x_phys - min_x_phys;
715 double dy = max_y_phys - min_y_phys;
716 double dz = max_z_phys - min_z_phys;
717 double max_dim = std::max({ dx, dy, dz });
718
719 double cx = (min_x_phys + max_x_phys) / 2.0;
720 double cy = (min_y_phys + max_y_phys) / 2.0;
721 double cz = (min_z_phys + max_z_phys) / 2.0;
722
723 min_x_phys = cx - max_dim / 2.0;
724 max_x_phys = cx + max_dim / 2.0;
725 min_y_phys = cy - max_dim / 2.0;
726 max_y_phys = cy + max_dim / 2.0;
727 min_z_phys = cz - max_dim / 2.0;
728 max_z_phys = cz + max_dim / 2.0;
729 }
730
731 double bounds[6] = { min_x_phys, max_x_phys, min_y_phys, max_y_phys, min_z_phys, max_z_phys };
732
733 // ROOT Frame: X->Z_phys, Y->X_phys, Z->Y_phys
734 TH3F *h_frame = new TH3F("h_frame", "; Z [mm]; X [mm]; Y [mm]", 1, min_z_phys, max_z_phys, 1,
735 min_x_phys, max_x_phys, 1, min_y_phys, max_y_phys);
736 h_frame->SetDirectory(0); // Detach from directory to prevent ROOT auto-deletion issues
737 h_frame->SetStats(0);
738 h_frame->GetXaxis()->SetTitleOffset(1.5);
739 h_frame->GetYaxis()->SetTitleOffset(1.5);
740 h_frame->GetZaxis()->SetTitleOffset(1.);
741 h_frame->Draw();
742
743 // --- Draw Skeleton (Inactive fibers) ---
744 if(drawSkeleton)
745 {
746 auto cylinders = CHeT::Config::GetCylinders();
747 for(const auto &cyl : cylinders)
748 {
749 const CHeT::Config::LayerConfig *layers[2] = { &cyl.inner, &cyl.outer };
750 for(int l = 0; l < 2; ++l)
751 {
752 for(int b = 0; b < layers[l]->nBundles; ++b)
753 {
754 int global_id = CHeT::Config::GetGlobalIdFromGeometry(cyl.id, l, b);
756
757 // Ghost fiber
758 TPolyLine3D *bg_f = new TPolyLine3D(10);
759 for(int i = 0; i < 10; ++i)
760 {
761 double z = -CHeT::Config::L_HALF + i * (2.0 * CHeT::Config::L_HALF / 9.0);
762 double a = (z + CHeT::Config::L_HALF) / (2.0 * CHeT::Config::L_HALF);
763 double ph = p.phi0 + p.dir * a * M_PI;
764
765 double x3 = p.r * std::cos(ph);
766 double y3 = p.r * std::sin(ph);
767 double z3 = z;
769
770 // Map to ROOT: X_root=z, Y_root=x, Z_root=y
771 bg_f->SetPoint(i, z3, x3, y3);
772 }
773 bg_f->SetLineColorAlpha(p.color, 0.1); // Very transparent
774 bg_f->Draw("same");
775 }
776 }
777 }
778 }
779
780 // --- Draw Hits (Active fibers) ---
781 for(int id : hit_ids)
782 {
783 if(id < 0)
784 continue;
786
787 TPolyLine3D *fl = new TPolyLine3D(50); // More detailed for active ones
788 for(int i = 0; i < 50; ++i)
789 {
790 double z = -CHeT::Config::L_HALF + i * (2.0 * CHeT::Config::L_HALF / 49.0);
791 double a = (z + CHeT::Config::L_HALF) / (2.0 * CHeT::Config::L_HALF);
792 double ph = p.phi0 + p.dir * a * M_PI;
793
794 double x3 = p.r * std::cos(ph);
795 double y3 = p.r * std::sin(ph);
796 double z3 = z;
798
799 // Map to ROOT: X_root=z, Y_root=x, Z_root=y
800 fl->SetPoint(i, z3, x3, y3);
801 }
802 fl->SetLineColor(p.color);
803 fl->SetLineWidth(3);
804 fl->Draw("same");
805 }
806
807 // --- Draw Tracks ---
808 if(trackDrawer)
809 trackDrawer(bounds);
810
811 // --- Draw 3D Points ---
812 for(const auto &pt_in : points)
813 {
814 VisPoint3D pt = pt_in;
815 if(pt.isLocalFrame)
816 {
818 }
819
820 TPolyMarker3D *pm = new TPolyMarker3D(1);
821 // Note: Mapping Physics (x,y,z) to ROOT 3D Frame (Z, X, Y)
822 // ROOT X axis = Physics Z
823 // ROOT Y axis = Physics X
824 // ROOT Z axis = Physics Y
825 pm->SetPoint(0, pt.z, pt.x, pt.y);
826
827 pm->SetMarkerColor(pt.color);
828 pm->SetMarkerStyle(pt.markerStyle);
829 pm->SetMarkerSize(pt.size);
830 pm->Draw("same");
831 }
832
833 c_3d->Update();
834}
835
836} // namespace Vis
837} // namespace CHeT
#define M_PI
FiberProp GetFiberProp(int b_id)
Retrieves fiber properties given a global bundle ID.
void ApplyRotation(double &x, double &y, double &z)
Rotates a 3D VECTOR in-place from the Detector Local Frame to the Global Lab Frame....
std::vector< BundlesIntersection > FindIntersections(const std::vector< int > &hit_ids)
Finds 3D intersections between a list of hit bundles.
constexpr double BUNDLE_WIDTH
Physical width of a bundle [mm].
void ApplyTransformation(double &x, double &y, double &z)
Transforms a 3D POINT in-place from the Detector Local Frame to the Global Lab Frame....
double wrap0_2pi(double angle)
Wraps an angle into the [0, 2*PI) range.
const std::vector< CylinderConfig > & GetCylinders()
Retrieves the configuration for all active cylinders.
int GetGlobalIdFromGeometry(int cyl_id, int layer_id, int layer_idx)
Helper: Converts Geometry (Cyl, Layer, Index) to Global ID.
constexpr double L_HALF
Half-length of the detector [mm].
void GetRotation(double &rx, double &ry, double &rz)
Retrieves the current global rotation angles.
void RenderTrack3D(const VisLineTrack &tr, double bounds[6])
void RenderTrack2D(const VisLineTrack &tr, TMultiGraph *mg_xy)
void RenderTrackZX(const VisLineTrack &tr, TMultiGraph *mg_zx)
void Draw3DCore(const std::vector< int > &hit_ids, const std::vector< VisPoint3D > &points, bool drawSkeleton, const std::function< void(double[6])> &trackDrawer)
void RenderTrackPhiZ(const VisLineTrack &tr, TMultiGraph *mg_phiz, bool wrap_phi=true)
void RenderTrackZY(const VisLineTrack &tr, TMultiGraph *mg_zy)
void Draw2DCore(const std::vector< int > &bundle_ids, const std::vector< VisPoint2D > &extraPoints, const std::function< void(TMultiGraph *, TMultiGraph *, TMultiGraph *, TMultiGraph *)> &trackDrawer, bool wrap_phi=true)
Root namespace for the Cylindrical Helix Tracker (CHeT) project.
Properties of a specific reconstructed fiber.
int dir
Winding direction.
int color
ROOT color index.
double phi0
Initial angle [rad].
Configuration for a single fiber layer.
int nBundles
Number of bundles in the layer.
Structure representing a reconstructed 3D generic track for visualization.
int color
ROOT Color index.
bool isLocalFrame
If true, coordinates are in Detector Local Frame.
std::vector< VisPoint3D > points
Sequence of 3D points.
Structure representing a reconstructed 3D helix track for visualization.
double z0
Initial Z position (at t=0)
double t_min
Minimum angular parameter range.
double dz_dt
Pitch: Z advancement per radian.
bool isLocalFrame
If true, coordinates are in Detector Local Frame.
double t_max
Maximum angular parameter range (default: 2*PI)
double cy
Helix center in XY plane.
int color
ROOT Color index.
Structure representing a reconstructed 3D line track for visualization.
double uz
Direction unit vector.
double z0
Origin point.
bool isLocalFrame
If true, coordinates are in Detector Local Frame.
int color
ROOT Color index.
Structure representing a 3D point (e.g., space points, clusters).
double size
Marker size.
int markerStyle
ROOT Marker style.
int color
ROOT Color index.
bool isLocalFrame
If true, coordinates are in Detector Local Frame.
double z
Coordinates.