35 #include <boost/algorithm/string.hpp>
36 #include <boost/algorithm/string/predicate.hpp>
38 #include "RtypesCore.h"
41 #include "TGeoBoolNode.h"
42 #include "TGeoCompositeShape.h"
43 #include "TGeoMatrix.h"
44 #include "TGeoShape.h"
49 std::tuple<std::shared_ptr<const Acts::CylinderBounds>,
const Acts::Transform3,
52 const Double_t* rotation,
55 double scalor) noexcept(
false) {
56 std::shared_ptr<const CylinderBounds>
bounds =
nullptr;
61 auto tube =
dynamic_cast<const TGeoTube*
>(&tgShape);
62 if (tube !=
nullptr) {
63 if (not boost::istarts_with(axes,
"XY") and
64 not boost::istarts_with(axes,
"YX")) {
65 throw std::invalid_argument(
66 "TGeoShape -> CylinderSurface (full): can only be converted with "
67 "'(x/X)(y/Y)(*)' or '(y/Y)(x/X)(*) axes.");
71 int xs = std::islower(axes.at(0)) != 0 ? -1 : 1;
72 int ys = std::islower(axes.at(1)) != 0 ? -1 : 1;
76 scalor * translation[2]);
77 bool flipxy = not boost::istarts_with(axes,
"X");
79 : xs *
Vector3(rotation[0], rotation[3], rotation[6]);
80 Vector3 ay = flipxy ? ys *
Vector3(rotation[0], rotation[3], rotation[6])
81 : ys *
Vector3(rotation[1], rotation[4], rotation[7]);
82 Vector3 az = ax.cross(ay);
84 double minR = tube->GetRmin() * scalor;
85 double maxR = tube->GetRmax() * scalor;
87 double medR = 0.5 * (minR +
maxR);
88 double halfZ = tube->GetDz() * scalor;
90 transform = TGeoPrimitivesHelper::makeTransform(ax, ay, az, t);
91 double halfPhi = M_PI;
94 auto tubeSeg =
dynamic_cast<const TGeoTubeSeg*
>(tube);
95 if (tubeSeg !=
nullptr) {
96 double phi1 = toRadian(tubeSeg->GetPhi1());
97 double phi2 = toRadian(tubeSeg->GetPhi2());
98 if (std::abs(phi2 - phi1) < M_PI * (1. -
s_epsilon)) {
99 if (not boost::starts_with(axes,
"X")) {
100 throw std::invalid_argument(
101 "TGeoShape -> CylinderSurface (sectorial): can only be "
104 "'(X)(y/Y)(*)' axes.");
106 halfPhi = 0.5 * (std::max(phi1, phi2) -
std::min(phi1, phi2));
107 avgPhi = 0.5 * (phi1 + phi2);
110 bounds = std::make_shared<CylinderBounds>(medR, halfZ, halfPhi, avgPhi);
120 const Double_t* rotation,
123 double scalor) noexcept(
false) {
124 using Line2D = Eigen::Hyperplane<double, 2>;
125 std::shared_ptr<const DiscBounds>
bounds =
nullptr;
130 auto compShape =
dynamic_cast<const TGeoCompositeShape*
>(&tgShape);
131 if (compShape !=
nullptr) {
132 if (not boost::istarts_with(axes,
"XY")) {
133 throw std::invalid_argument(
134 "TGeoShape -> DiscSurface (Annulus): can only be converted with "
141 scalor * translation[2]);
142 Vector3 ax(rotation[0], rotation[3], rotation[6]);
143 Vector3 ay(rotation[1], rotation[4], rotation[7]);
144 Vector3 az(rotation[2], rotation[5], rotation[8]);
146 transform = TGeoPrimitivesHelper::makeTransform(ax, ay, az, t);
148 auto interNode =
dynamic_cast<TGeoIntersection*
>(compShape->GetBoolNode());
149 if (interNode !=
nullptr) {
150 auto baseTube =
dynamic_cast<TGeoTubeSeg*
>(interNode->GetLeftShape());
151 if (baseTube !=
nullptr) {
152 double rMin = baseTube->GetRmin() * scalor;
153 double rMax = baseTube->GetRmax() * scalor;
154 auto maskShape =
dynamic_cast<TGeoArb8*
>(interNode->GetRightShape());
155 if (maskShape !=
nullptr) {
156 auto maskTransform = interNode->GetRightMatrix();
158 const Double_t* polyVrt = maskShape->GetVertices();
165 for (
unsigned int v = 0;
v < 8;
v += 2) {
166 std::array<double, 3> local{polyVrt[
v + 0], polyVrt[
v + 1], 0.};
167 std::array<double, 3> global{};
168 maskTransform->LocalToMaster(local.data(), global.data());
170 vertices.push_back(vtx);
173 std::vector<std::pair<Vector2, Vector2>> boundLines;
174 for (
size_t i = 0;
i < vertices.size(); ++
i) {
176 Vector2 b = vertices.at((
i + 1) % vertices.size());
180 if (std::abs(phi) > 3 * M_PI / 4. || std::abs(phi) < M_PI / 4.) {
181 if (a.norm() < b.norm()) {
182 boundLines.push_back(std::make_pair(a, b));
184 boundLines.push_back(std::make_pair(b, a));
189 if (boundLines.size() != 2) {
190 throw std::logic_error(
191 "Input DiscPoly bounds type does not have sensible edges.");
195 Line2D::Through(boundLines[0].first, boundLines[0].second);
197 Line2D::Through(boundLines[1].first, boundLines[1].second);
198 Vector2 ix = lA.intersection(lB);
200 const Eigen::Translation3d originTranslation(ix.x(), ix.y(), 0.);
201 const Vector2 originShift = -ix;
204 transform = transform * originTranslation;
210 double phiMax = std::max(phi1, phi2);
212 double phiShift = 0.;
215 auto annulusBounds = std::make_shared<const AnnulusBounds>(
216 rMin, rMax,
phiMin, phiMax, originShift, phiShift);
218 thickness = maskShape->GetDZ() * scalor;
219 bounds = annulusBounds;
225 auto tube =
dynamic_cast<const TGeoTube*
>(&tgShape);
226 if (tube !=
nullptr) {
227 if (not boost::istarts_with(axes,
"XY") and
228 not boost::istarts_with(axes,
"YX")) {
229 throw std::invalid_argument(
230 "TGeoShape -> DiscSurface: can only be converted with "
231 "'(x/X)(y/Y)(*)' or '(y/Y)(x/X)(*) axes.");
235 int xs = std::islower(axes.at(0)) != 0 ? -1 : 1;
236 int ys = std::islower(axes.at(1)) != 0 ? -1 : 1;
240 scalor * translation[2]);
242 Vector3 ay = ys *
Vector3(rotation[1], rotation[4], rotation[7]);
243 Vector3 az = ax.cross(ay);
244 transform = TGeoPrimitivesHelper::makeTransform(ax, ay, az, t);
246 double minR = tube->GetRmin() * scalor;
247 double maxR = tube->GetRmax() * scalor;
248 double halfZ = tube->GetDz() * scalor;
249 double halfPhi = M_PI;
252 auto tubeSeg =
dynamic_cast<const TGeoTubeSeg*
>(tube);
253 if (tubeSeg !=
nullptr) {
254 double phi1 = toRadian(tubeSeg->GetPhi1());
255 double phi2 = toRadian(tubeSeg->GetPhi2());
256 if (std::abs(phi2 - phi1) < 2 * M_PI * (1. -
s_epsilon)) {
257 if (not boost::starts_with(axes,
"X")) {
258 throw std::invalid_argument(
259 "TGeoShape -> CylinderSurface (sectorial): can only be "
262 "'(X)(y/Y)(*)' axes.");
264 halfPhi = 0.5 * (std::max(phi1, phi2) -
std::min(phi1, phi2));
265 avgPhi = 0.5 * (phi1 + phi2);
268 bounds = std::make_shared<RadialBounds>(
minR,
maxR, halfPhi, avgPhi);
269 thickness = 2 * halfZ;
275 std::tuple<std::shared_ptr<const Acts::PlanarBounds>,
const Acts::Transform3,
278 const Double_t* rotation,
281 double scalor) noexcept(
false) {
284 scalor * translation[2]);
285 Vector3 ax(rotation[0], rotation[3], rotation[6]);
286 Vector3 ay(rotation[1], rotation[4], rotation[7]);
287 Vector3 az(rotation[2], rotation[5], rotation[8]);
289 std::shared_ptr<const PlanarBounds>
bounds =
nullptr;
292 const TGeoBBox*
box =
dynamic_cast<const TGeoBBox*
>(&tgShape);
295 const TGeoTrd1* trapezoid1 =
dynamic_cast<const TGeoTrd1*
>(&tgShape);
296 if ((trapezoid1 !=
nullptr) and not boost::istarts_with(axes,
"XZ")) {
297 throw std::invalid_argument(
298 "TGeoTrd1 -> PlaneSurface: can only be converted with '(x/X)(z/Z)(*)' "
303 const TGeoTrd2* trapezoid2 =
dynamic_cast<const TGeoTrd2*
>(&tgShape);
304 if (trapezoid2 !=
nullptr) {
305 if (not boost::istarts_with(axes,
"X") and
306 std::abs(trapezoid2->GetDx1() - trapezoid2->GetDx2()) >
s_epsilon) {
307 throw std::invalid_argument(
308 "TGeoTrd2 -> PlaneSurface: dx1 must be be equal to dx2 if not taken "
309 "as trapezoidal side.");
310 }
else if (not boost::istarts_with(axes,
"Y") and
311 std::abs(trapezoid2->GetDy1() - trapezoid2->GetDy2()) >
313 throw std::invalid_argument(
314 "TGeoTrd2 -> PlaneSurface: dy1 must be be equal to dy2 if not taken "
315 "as trapezoidal side.");
318 if (boost::istarts_with(axes,
"XY") or boost::istarts_with(axes,
"YX")) {
319 throw std::invalid_argument(
320 "TGeoTrd2 -> PlaneSurface: only works with (x/X)(z/Z) and "
326 const TGeoArb8* polygon8c =
dynamic_cast<const TGeoArb8*
>(&tgShape);
327 TGeoArb8* polygon8 =
nullptr;
328 if (polygon8c !=
nullptr) {
330 polygon8 =
const_cast<TGeoArb8*
>(polygon8c);
333 if ((polygon8c !=
nullptr) and
334 not(boost::istarts_with(axes,
"XY") or boost::istarts_with(axes,
"YX"))) {
335 throw std::invalid_argument(
336 "TGeoArb8 -> PlaneSurface: dz must be normal component of Surface.");
343 int xs = std::islower(axes.at(0)) != 0 ? -1 : 1;
344 int ys = std::islower(axes.at(1)) != 0 ? -1 : 1;
349 if (boost::istarts_with(axes,
"XY")) {
350 if (trapezoid2 !=
nullptr) {
351 double dx1 = (ys < 0) ? trapezoid1->GetDx2() : trapezoid1->GetDx1();
352 double dx2 = (ys < 0) ? trapezoid1->GetDx1() : trapezoid1->GetDx2();
353 bounds = std::make_shared<const TrapezoidBounds>(
354 scalor * dx1, scalor * dx2, scalor * trapezoid2->GetDy1());
355 thickness = 2 * scalor * trapezoid2->GetDz();
356 }
else if (polygon8 !=
nullptr) {
357 Double_t* tgverts = polygon8->GetVertices();
358 std::vector<Vector2> pVertices;
359 for (
unsigned int ivtx = 0; ivtx < 4; ++ivtx) {
360 pVertices.push_back(
Vector2(scalor * xs * tgverts[ivtx * 2],
361 scalor * ys * tgverts[ivtx * 2 + 1]));
363 bounds = std::make_shared<ConvexPolygonBounds<4>>(pVertices);
364 thickness = 2 * scalor * polygon8->GetDz();
365 }
else if (box !=
nullptr) {
366 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDX(),
367 scalor * box->GetDY());
368 thickness = 2 * scalor * box->GetDZ();
370 }
else if (boost::istarts_with(axes,
"YZ")) {
373 if (trapezoid1 !=
nullptr) {
374 throw std::invalid_argument(
375 "TGeoTrd1 can only be converted with '(x/X)(z/Z)(y/Y)' axes");
376 }
else if (trapezoid2 !=
nullptr) {
377 double dx1 = (ys < 0) ? trapezoid2->GetDy2() : trapezoid2->GetDy1();
378 double dx2 = (ys < 0) ? trapezoid2->GetDy1() : trapezoid2->GetDy2();
379 bounds = std::make_shared<const TrapezoidBounds>(
380 scalor * dx1, scalor * dx2, scalor * trapezoid2->GetDz());
381 thickness = 2 * scalor * trapezoid2->GetDx1();
382 }
else if (box !=
nullptr) {
383 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDY(),
384 scalor * box->GetDZ());
385 thickness = 2 * scalor * box->GetDX();
387 }
else if (boost::istarts_with(axes,
"ZX")) {
390 if (box !=
nullptr) {
391 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDZ(),
392 scalor * box->GetDX());
393 thickness = 2 * scalor * box->GetDY();
395 }
else if (boost::istarts_with(axes,
"XZ")) {
398 if (trapezoid1 !=
nullptr) {
399 double dx1 = (ys < 0) ? trapezoid1->GetDx2() : trapezoid1->GetDx1();
400 double dx2 = (ys < 0) ? trapezoid1->GetDx1() : trapezoid1->GetDx2();
401 bounds = std::make_shared<const TrapezoidBounds>(
402 scalor * dx1, scalor * dx2, scalor * trapezoid1->GetDz());
403 thickness = 2 * scalor * trapezoid1->GetDy();
404 }
else if (trapezoid2 !=
nullptr) {
405 double dx1 = (ys < 0) ? trapezoid2->GetDx2() : trapezoid2->GetDx1();
406 double dx2 = (ys < 0) ? trapezoid2->GetDx1() : trapezoid2->GetDx2();
407 bounds = std::make_shared<const TrapezoidBounds>(
408 scalor * dx1, scalor * dx2, scalor * trapezoid2->GetDz());
409 thickness = 2 * scalor * trapezoid2->GetDy1();
410 }
else if (box !=
nullptr) {
411 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDX(),
412 scalor * box->GetDZ());
413 thickness = 2 * scalor * box->GetDY();
415 }
else if (boost::istarts_with(axes,
"YX")) {
418 if (trapezoid2 !=
nullptr) {
419 double dx1 = (ys < 0) ? trapezoid2->GetDy2() : trapezoid2->GetDy1();
420 double dx2 = (ys < 0) ? trapezoid2->GetDy1() : trapezoid2->GetDy2();
421 bounds = std::make_shared<const TrapezoidBounds>(
422 scalor * dx1, scalor * dx2, scalor * trapezoid2->GetDx1());
423 thickness = 2 * scalor * trapezoid2->GetDz();
424 }
else if (polygon8 !=
nullptr) {
425 const Double_t* tgverts = polygon8->GetVertices();
426 std::vector<Vector2> pVertices;
427 for (
unsigned int ivtx = 0; ivtx < 4; ++ivtx) {
428 pVertices.push_back(
Vector2(scalor * xs * tgverts[ivtx * 2 + 1],
429 scalor * ys * tgverts[ivtx * 2]));
431 bounds = std::make_shared<ConvexPolygonBounds<4>>(pVertices);
432 thickness = 2 * scalor * polygon8->GetDz();
433 }
else if (box !=
nullptr) {
434 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDY(),
435 scalor * box->GetDX());
436 thickness = 2 * scalor * box->GetDZ();
438 }
else if (boost::istarts_with(axes,
"ZY")) {
441 if (box !=
nullptr) {
442 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDZ(),
443 scalor * box->GetDY());
444 thickness = 2 * scalor * box->GetDX();
447 throw std::invalid_argument(
448 "TGeoConverter: axes definition must be permutation of "
449 "'(x/X)(y/Y)(z/Z)'");
453 auto cz = cx.cross(cy);
454 auto transform = TGeoPrimitivesHelper::makeTransform(cx, cy, cz, t);
461 const TGeoMatrix& tgMatrix,
463 double scalor) noexcept(
false) {
465 const Double_t* rotation = tgMatrix.GetRotationMatrix();
466 const Double_t*
translation = tgMatrix.GetTranslation();
468 auto [cBounds, cTransform, cThickness] =
469 cylinderComponents(tgShape, rotation, translation, axes, scalor);
470 if (cBounds !=
nullptr) {
471 return {Surface::makeShared<CylinderSurface>(cTransform, cBounds),
475 auto [dBounds, dTransform, dThickness] =
476 discComponents(tgShape, rotation, translation, axes, scalor);
477 if (dBounds !=
nullptr) {
478 return {Surface::makeShared<DiscSurface>(dTransform, dBounds), dThickness};
481 auto [pBounds, pTransform, pThickness] =
482 planeComponents(tgShape, rotation, translation, axes, scalor);
483 if (pBounds !=
nullptr) {
484 return {Surface::makeShared<PlaneSurface>(pTransform, pBounds), pThickness};
487 return {
nullptr, 0.};