17bool Invert(std::array<std::array<double, 3>, 3>& a) {
20 const double c11 = a[1][1] * a[2][2] - a[1][2] * a[2][1];
21 const double c12 = a[1][2] * a[2][0] - a[1][0] * a[2][2];
22 const double c13 = a[1][0] * a[2][1] - a[1][1] * a[2][0];
23 const double c21 = a[2][1] * a[0][2] - a[2][2] * a[0][1];
24 const double c22 = a[2][2] * a[0][0] - a[2][0] * a[0][2];
25 const double c23 = a[2][0] * a[0][1] - a[2][1] * a[0][0];
26 const double c31 = a[0][1] * a[1][2] - a[0][2] * a[1][1];
27 const double c32 = a[0][2] * a[1][0] - a[0][0] * a[1][2];
28 const double c33 = a[0][0] * a[1][1] - a[0][1] * a[1][0];
29 const double t1 =
fabs(a[0][0]);
30 const double t2 =
fabs(a[1][0]);
31 const double t3 =
fabs(a[2][0]);
34 if (t2 < t1 && t3 < t1) {
36 det = c22 * c33 - c23 * c32;
37 }
else if (t1 < t2 && t3 < t2) {
39 det = c13 * c32 - c12 * c33;
42 det = c23 * c12 - c22 * c13;
44 if (det == 0.)
return false;
45 const double s = pivot / det;
58std::string Fmt(
const double x) {
60 sprintf(buf,
"%g", x);
61 return std::string(buf);
77 if (!m_canvas) m_canvas.reset(
new TCanvas(name.c_str(),
""));
78 m_pad = m_canvas.get();
85 if (pad->GetListOfPrimitives()->GetSize() == 0 &&
86 pad->GetX1() == 0 && pad->GetX2() == 1 &&
87 pad->GetY1() == 0 && pad->GetY2() == 1) {
94 const double x1,
const double y1) {
96 const double bm = pad->GetBottomMargin();
97 const double lm = pad->GetLeftMargin();
98 const double rm = pad->GetRightMargin();
99 const double tm = pad->GetTopMargin();
100 const double dx = x1 - x0;
101 const double dy = y1 - y0;
102 pad->Range(x0 - dx * (lm / (1. - rm - lm)),
103 y0 - dy * (bm / (1. - tm - lm)),
104 x1 + dx * (rm / (1. - rm - lm)),
105 y1 + dy * (tm / (1. - tm - lm)));
110 const double xmax,
const double ymax) {
112 if (xmin == xmax || ymin == ymax) {
113 std::cerr <<
m_className <<
"::SetArea: Null area is not permitted.\n"
114 <<
" " << xmin <<
" < x < " << xmax <<
"\n"
115 <<
" " << ymin <<
" < y < " << ymax <<
"\n";
126 const double xmax,
const double ymax,
129 if (xmin == xmax || ymin == ymax || zmin == zmax) {
130 std::cerr <<
m_className <<
"::SetArea: Null area range not permitted.\n";
143 const double x0,
const double y0,
const double z0) {
145 const double fnorm = sqrt(fx * fx + fy * fy + fz * fz);
146 if (fnorm > 0 && fx * fx + fz * fz > 0) {
147 const double fxz = sqrt(fx * fx + fz * fz);
151 m_proj[1][0] = -fx * fy / (fxz * fnorm);
152 m_proj[1][1] = (fx * fx + fz * fz) / (fxz * fnorm);
153 m_proj[1][2] = -fy * fz / (fxz * fnorm);
157 }
else if (fnorm > 0 && fy * fy + fz * fz > 0) {
158 const double fyz = sqrt(fy * fy + fz * fz);
159 m_proj[0][0] = (fy * fy + fz * fz) / (fyz * fnorm);
160 m_proj[0][1] = -fx * fz / (fyz * fnorm);
161 m_proj[0][2] = -fy * fz / (fyz * fnorm);
170 <<
" Normal vector has zero norm. No new projection set.\n";
177 m_plane[3] = fx * x0 + fy * y0 + fz * z0;
183 const double x0,
const double y0,
const double z0,
184 const double hx,
const double hy,
const double hz) {
186 const double fnorm = sqrt(fx * fx + fy * fy + fz * fz);
189 <<
" Normal vector has zero norm. No new projection set.\n";
193 const double wx = fx / fnorm;
194 const double wy = fy / fnorm;
195 const double wz = fz / fnorm;
200 m_plane[3] = wx * x0 + wy * y0 + wz * z0;
202 double d = hx * wx + hy * wy + hz * wz;
203 double ux = hx - d * wx;
204 double uy = hy - d * wy;
205 double uz = hz - d * wz;
206 double unorm = std::sqrt(ux * ux + uy * uy + uz * uz);
207 if (unorm < 1.e-10) {
209 if (fy * fy + fz * fz > 0) {
220 d = ux * wx + uy * wy + uz * wz;
224 unorm = std::sqrt(ux * ux + uy * uy + uz * uz);
234 m_prmat[0][1] = wy * uz - wz * uy;
235 m_prmat[1][1] = wz * ux - wx * uz;
236 m_prmat[2][1] = wx * uy - wy * ux;
241 for (
unsigned int i = 0; i < 3; ++i) {
250 <<
" Inversion failed; reset to default.\n";
257 double auxu[3], auxv[3];
258 const double ctheta = cos(theta);
259 const double stheta = sin(theta);
260 for (
int i = 0; i < 3; ++i) {
261 auxu[i] = ctheta *
m_proj[0][i] - stheta *
m_proj[1][i];
262 auxv[i] = stheta *
m_proj[0][i] + ctheta *
m_proj[1][i];
264 for (
int i = 0; i < 3; ++i) {
273 m_proj = {{{1, 0, 0}, {0, 1, 0}, {0, 0, 0}}};
275 m_prmat = {{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}};
279 m_proj = {{{1, 0, 0}, {0, 0, 1}, {0, 0, 0}}};
285 m_proj = {{{0, 1, 0}, {0, 0, 1}, {0, 0, 0}}};
292 std::string fname = s +
"_0";
293 while (gROOT->GetListOfFunctions()->FindObject(fname.c_str())) {
295 fname = s +
"_" + std::to_string(idx);
302 std::string hname = s +
"_0";
303 while (gDirectory->GetList()->FindObject(hname.c_str())) {
305 hname = s +
"_" + std::to_string(idx);
312 std::string hname = s +
"_0";
313 while (gROOT->GetListOfCanvases()->FindObject(hname.c_str())) {
315 hname = s +
"_" + std::to_string(idx);
332 std::cerr <<
m_className <<
"::UpdateProjectionMatrix:\n"
333 <<
" Zero norm vector; reset to default.\n";
341 std::cerr <<
m_className <<
"::UpdateProjectionMatrix:\n"
342 <<
" Inversion failed; reset to default.\n";
348 const std::array<float, 3>& x1,
349 std::array<float, 3>& xc)
const {
352 const bool in0 =
InBox(x0);
353 const bool in1 =
InBox(x1);
354 if (in0 == in1)
return;
356 const std::array<float, 3> dx = {x1[0] - x0[0], x1[1] - x0[1],
360 for (
size_t i = 0; i < 3; ++i) {
361 if (dx[i] == 0. || (xc[i] >= bmin[i] && xc[i] <= bmax[i]))
continue;
362 const double b = xc[i] < bmin[i] ? bmin[i] : bmax[i];
363 const double s = (b - xc[i]) / dx[i];
365 for (
size_t j = 0; j < 3; ++j) {
366 if (j != i) xc[j] += dx[j] * s;
372 const short col,
const short lw) {
374 const size_t nP = xl.size();
378 gr.SetLineColor(col);
381 std::vector<float> xgr;
382 std::vector<float> ygr;
384 bool in0 =
InBox(x0);
386 float xp = 0., yp = 0.;
387 ToPlane(x0[0], x0[1], x0[2], xp, yp);
391 for (
unsigned int j = 1; j < nP; ++j) {
393 bool in1 =
InBox(x1);
395 float xp = 0., yp = 0.;
396 std::array<float, 3> xc;
398 ToPlane(xc[0], xc[1], xc[2], xp, yp);
403 float xp = 0., yp = 0.;
404 ToPlane(x1[0], x1[1], x1[2], xp, yp);
407 }
else if (!xgr.empty()) {
408 gr.DrawGraph(xgr.size(), xgr.data(), ygr.data(),
"Lsame");
416 gr.DrawGraph(xgr.size(), xgr.data(), ygr.data(),
"Lsame");
422 std::string xLabel =
"";
423 constexpr double tol = 1.e-4;
425 if (fabs(
m_proj[0][0] - 1) < tol) {
427 }
else if (fabs(
m_proj[0][0] + 1) < tol) {
428 xLabel =
"#minus#it{x}";
429 }
else if (fabs(
m_proj[0][0]) > tol) {
430 xLabel = Fmt(
m_proj[0][0]) +
" #it{x}";
434 if (!xLabel.empty()) {
435 if (
m_proj[0][1] < -tol) {
436 xLabel +=
" #minus ";
437 }
else if (
m_proj[0][1] > tol) {
440 if (fabs(
m_proj[0][1] - 1) < tol || fabs(
m_proj[0][1] + 1) < tol) {
442 }
else if (fabs(
m_proj[0][1]) > tol) {
443 xLabel += Fmt(fabs(
m_proj[0][1])) +
" #it{y}";
446 if (fabs(
m_proj[0][1] - 1) < tol) {
448 }
else if (fabs(
m_proj[0][1] + 1) < tol) {
449 xLabel =
"#minus#it{y}";
450 }
else if (fabs(
m_proj[0][1]) > tol) {
451 xLabel = Fmt(
m_proj[0][1]) +
" #it{y}";
456 if (!xLabel.empty()) {
457 if (
m_proj[0][2] < -tol) {
458 xLabel +=
" #minus ";
459 }
else if (
m_proj[0][2] > tol) {
462 if (fabs(
m_proj[0][2] - 1) < tol || fabs(
m_proj[0][2] + 1) < tol) {
464 }
else if (fabs(
m_proj[0][2]) > tol) {
465 xLabel += Fmt(fabs(
m_proj[0][2])) +
" #it{z}";
468 if (fabs(
m_proj[0][2] - 1) < tol) {
470 }
else if (fabs(
m_proj[0][2] + 1) < tol) {
471 xLabel =
"#minus#it{z}";
472 }
else if (fabs(
m_proj[0][2]) > tol) {
473 xLabel = Fmt(
m_proj[0][2]) +
" #it{z}";
485 std::string yLabel =
"";
486 constexpr double tol = 1.e-4;
488 if (fabs(
m_proj[1][0] - 1) < tol) {
490 }
else if (fabs(
m_proj[1][0] + 1) < tol) {
491 yLabel =
"#minus#it{x}";
492 }
else if (fabs(
m_proj[1][0]) > tol) {
493 yLabel = Fmt(
m_proj[1][0]) +
" #it{x}";
497 if (!yLabel.empty()) {
498 if (
m_proj[1][1] < -tol) {
499 yLabel +=
" #minus ";
500 }
else if (
m_proj[1][1] > tol) {
503 if (fabs(
m_proj[1][1] - 1) < tol || fabs(
m_proj[1][1] + 1) < tol) {
505 }
else if (fabs(
m_proj[1][1]) > tol) {
506 yLabel += Fmt(fabs(
m_proj[1][1])) +
" #it{y}";
509 if (fabs(
m_proj[1][1] - 1) < tol) {
511 }
else if (fabs(
m_proj[1][1] + 1) < tol) {
512 yLabel =
"#minus#it{y}";
513 }
else if (fabs(
m_proj[1][1]) > tol) {
514 yLabel = Fmt(
m_proj[1][1]) +
" #it{y}";
519 if (!yLabel.empty()) {
520 if (
m_proj[1][2] < -tol) {
521 yLabel +=
" #minus ";
522 }
else if (
m_proj[1][2] > tol) {
525 if (fabs(
m_proj[1][2] - 1) < tol || fabs(
m_proj[1][2] + 1) < tol) {
527 }
else if (fabs(
m_proj[1][2]) > tol) {
528 yLabel += Fmt(fabs(
m_proj[1][2])) +
" #it{z}";
531 if (fabs(
m_proj[1][2] - 1) < tol) {
533 }
else if (fabs(
m_proj[1][2] + 1) < tol) {
534 yLabel =
"#minus#it{z}";
535 }
else if (fabs(
m_proj[1][2]) > tol) {
536 yLabel = Fmt(
m_proj[1][2]) +
" #it{z}";
547 std::string description;
549 constexpr double tol = 1.e-4;
551 if (fabs(
m_plane[0] - 1) < tol) {
553 }
else if (fabs(
m_plane[0] + 1) < tol) {
555 }
else if (fabs(
m_plane[0]) > tol) {
556 description = Fmt(
m_plane[0]) +
" x";
560 if (!description.empty()) {
562 description +=
" - ";
564 description +=
" + ";
568 }
else if (fabs(
m_plane[1]) > tol) {
569 description += Fmt(fabs(
m_plane[1])) +
" y";
572 if (fabs(
m_plane[1] - 1) < tol) {
574 }
else if (fabs(
m_plane[1] + 1) < tol) {
576 }
else if (fabs(
m_plane[1]) > tol) {
577 description = Fmt(
m_plane[1]) +
" y";
582 if (!description.empty()) {
584 description +=
" - ";
586 description +=
" + ";
590 }
else if (fabs(
m_plane[2]) > tol) {
591 description += Fmt(fabs(
m_plane[2])) +
" z";
594 if (fabs(
m_plane[2] - 1) < tol) {
596 }
else if (fabs(
m_plane[2] + 1) < tol) {
598 }
else if (fabs(
m_plane[2]) > tol) {
599 description = Fmt(
m_plane[2]) +
" z";
604 description +=
" = " + Fmt(
m_plane[3]);
609 double& xmin,
double& ymin,
610 double& xmax,
double& ymax)
const {
612 if (!sensor)
return false;
614 std::array<double, 3> bbmin;
615 std::array<double, 3> bbmax;
616 if (!sensor->
GetArea(bbmin[0], bbmin[1], bbmin[2],
617 bbmax[0], bbmax[1], bbmax[2])) {
619 <<
" Sensor area is not defined.\n"
620 <<
" Please set the plot limits explicitly (SetArea).\n";
623 return PlotLimits(bbmin, bbmax, xmin, ymin, xmax, ymax);
627 double& xmin,
double& ymin,
628 double& xmax,
double& ymax)
const {
630 if (!cmp)
return false;
632 std::array<double, 3> bbmin;
633 std::array<double, 3> bbmax;
635 bbmax[0], bbmax[1], bbmax[2])) {
637 <<
" Bounding box of the component is not defined.\n"
638 <<
" Please set the plot limits explicitly (SetArea).\n";
641 if (std::isinf(bbmin[0]) || std::isinf(bbmax[0]) ||
642 std::isinf(bbmin[1]) || std::isinf(bbmax[1]) ||
643 std::isinf(bbmin[2]) || std::isinf(bbmax[2])) {
644 std::array<double, 3> cellmin = {0., 0., 0.};
645 std::array<double, 3> cellmax = {0., 0., 0.};
647 cellmax[0], cellmax[1], cellmax[2])) {
649 <<
" Cell boundaries are not defined.\n"
650 <<
" Please set the plot limits explicitly (SetArea).\n";
653 for (
size_t i = 0; i < 3; ++i) {
654 if (std::isinf(bbmin[i]) || std::isinf(bbmax[i])) {
655 bbmin[i] = cellmin[i];
656 bbmax[i] = cellmax[i];
660 return PlotLimits(bbmin, bbmax, xmin, ymin, xmax, ymax);
664 double& xmax,
double& ymax)
const {
668 return PlotLimits(bbmin, bbmax, xmin, ymin, xmax, ymax);
672 std::array<double, 3>& bbmax,
673 double& xmin,
double& ymin,
674 double& xmax,
double& ymax)
const {
675 constexpr double tol = 1.e-4;
676 double umin[2] = {-std::numeric_limits<double>::max(),
677 -std::numeric_limits<double>::max()};
678 double umax[2] = {std::numeric_limits<double>::max(),
679 std::numeric_limits<double>::max()};
680 for (
unsigned int i = 0; i < 3; ++i) {
683 for (
unsigned int j = 0; j < 2; ++j) {
684 if (fabs(
m_proj[j][i]) < tol)
continue;
685 const double t1 = bbmin[i] /
m_proj[j][i];
686 const double t2 = bbmax[i] /
m_proj[j][i];
687 const double tmin = std::min(t1, t2);
688 const double tmax = std::max(t1, t2);
689 if (tmin > umin[j] && tmin < umax[j]) umin[j] = tmin;
690 if (tmax < umax[j] && tmax > umin[j]) umax[j] = tmax;
Abstract base class for components.
virtual bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Get the bounding box coordinates.
virtual bool GetElementaryCell(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Get the coordinates of the elementary cell.
void SetDefaultStyle()
Apply the default Garfield ROOT style.
bool GetArea(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Return the current user area.
std::array< double, 4 > m_plane
std::array< std::array< double, 3 >, 3 > m_prmat
void Clip(const std::array< float, 3 > &x0, const std::array< float, 3 > &x1, std::array< float, 3 > &xc) const
bool InBox(const std::array< T, 3 > &x) const
void DrawLine(const std::vector< std::array< float, 3 > > &xl, const short col, const short lw)
static std::string FindUnusedHistogramName(const std::string &s)
Find an unused histogram name.
void SetPlaneYZ()
Set the viewing plane to y-z.
static std::string FindUnusedCanvasName(const std::string &s)
Find an unused canvas name.
std::array< std::array< double, 3 >, 3 > m_proj
TPad * GetCanvas()
Retrieve the canvas.
void SetRange(TPad *pad, const double x0, const double y0, const double x1, const double y1)
void SetPlaneXZ()
Set the viewing plane to x-z.
bool PlotLimits(Sensor *sensor, double &xmin, double &ymin, double &xmax, double &ymax) const
void SetPlaneXY()
Set the viewing plane to x-y.
void ToPlane(const T x, const T y, const T z, T &xp, T &yp) const
std::string PlaneDescription()
bool PlotLimitsFromUserBox(double &xmin, double &ymin, double &xmax, double &ymax) const
static std::string FindUnusedFunctionName(const std::string &s)
Find an unused function name.
void Rotate(const double angle)
Rotate the viewing plane (angle in radian).
ViewBase()=delete
Default constructor.
void UpdateProjectionMatrix()
virtual void SetPlane(const double fx, const double fy, const double fz, const double x0, const double y0, const double z0)
PlottingEngine plottingEngine
DoubleAc fabs(const DoubleAc &f)