30 #include <boost/algorithm/string.hpp>
31 #include <boost/algorithm/string/predicate.hpp>
35 #include "TGeoBoolNode.h"
36 #include "TGeoCompositeShape.h"
37 #include "TGeoMatrix.h"
38 #include "TGeoShape.h"
46 const Double_t* rotation,
47 const Double_t* translation,
48 const std::string& axes,
49 double scalor) noexcept(
false) {
50 std::shared_ptr<const CylinderBounds> bounds =
nullptr;
55 auto tube =
dynamic_cast<const TGeoTube*
>(&tgShape);
57 if (not boost::istarts_with(axes,
"XY") and
58 not boost::istarts_with(axes,
"YX")) {
59 throw std::invalid_argument(
60 "TGeoShape -> CylinderSurface (full): can only be converted with "
61 "'(x/X)(y/Y)(*)' or '(y/Y)(x/X)(*) axes.");
65 int xs = islower(axes.at(0)) ? -1 : 1;
66 int ys = islower(axes.at(1)) ? -1 : 1;
69 Vector3D t(scalor * translation[0], scalor * translation[1],
70 scalor * translation[2]);
71 bool flipxy = not boost::istarts_with(axes,
"X");
73 : xs *
Vector3D(rotation[0], rotation[3], rotation[6]);
74 Vector3D ay = flipxy ? ys *
Vector3D(rotation[0], rotation[3], rotation[6])
75 : ys *
Vector3D(rotation[1], rotation[4], rotation[7]);
76 Vector3D az = ax.cross(ay);
78 double minR = tube->GetRmin() * scalor;
79 double maxR = tube->GetRmax() * scalor;
80 double deltaR = maxR - minR;
81 double medR = 0.5 * (minR + maxR);
82 double halfZ = tube->GetDz() * scalor;
84 transform = TGeoPrimitivesHelper::makeTransform(ax, ay, az, t);
85 double halfPhi =
M_PI;
88 auto tubeSeg =
dynamic_cast<const TGeoTubeSeg*
>(tube);
90 double phi1 = toRadian(tubeSeg->GetPhi1());
91 double phi2 = toRadian(tubeSeg->GetPhi2());
92 if (not boost::starts_with(axes,
"X")) {
93 throw std::invalid_argument(
94 "TGeoShape -> CylinderSurface (sectorial): can only be converted "
96 "'(X)(y/Y)(*)' axes.");
99 avgPhi = 0.5 * (phi1 + phi2);
101 bounds = std::make_shared<CylinderBounds>(medR, halfZ, halfPhi, avgPhi);
111 const Double_t* rotation,
112 const Double_t* translation,
113 const std::string& axes,
114 double scalor) noexcept(
false) {
115 using Line2D = Eigen::Hyperplane<double, 2>;
116 std::shared_ptr<const DiscBounds> bounds =
nullptr;
121 auto compShape =
dynamic_cast<const TGeoCompositeShape*
>(&tgShape);
122 if (compShape !=
nullptr) {
123 if (not boost::istarts_with(axes,
"XY")) {
124 throw std::invalid_argument(
125 "TGeoShape -> DiscSurface (Annulus): can only be converted with "
131 Vector3D t(scalor * translation[0], scalor * translation[1],
132 scalor * translation[2]);
133 Vector3D ax(rotation[0], rotation[3], rotation[6]);
134 Vector3D ay(rotation[1], rotation[4], rotation[7]);
135 Vector3D az(rotation[2], rotation[5], rotation[8]);
137 transform = TGeoPrimitivesHelper::makeTransform(ax, ay, az, t);
139 auto interNode =
dynamic_cast<TGeoIntersection*
>(compShape->GetBoolNode());
140 if (interNode !=
nullptr) {
141 auto baseTube =
dynamic_cast<TGeoTubeSeg*
>(interNode->GetLeftShape());
142 if (baseTube !=
nullptr) {
143 double rMin = baseTube->GetRmin() * scalor;
144 double rMax = baseTube->GetRmax() * scalor;
145 auto maskShape =
dynamic_cast<TGeoArb8*
>(interNode->GetRightShape());
146 if (maskShape !=
nullptr) {
147 auto maskTransform = interNode->GetRightMatrix();
149 const Double_t* polyVrt = maskShape->GetVertices();
152 const Double_t* polyTrl =
nullptr;
153 polyTrl = (maskTransform->GetTranslation());
154 std::vector<Vector2D> vertices;
155 for (
unsigned int v = 0;
v < 8;
v += 2) {
157 (polyTrl[1] + polyVrt[
v + 1]) * scalor);
158 vertices.push_back(vtx);
161 std::vector<std::pair<Vector2D, Vector2D>> boundLines;
162 for (
size_t i = 0; i < vertices.size(); ++i) {
164 Vector2D b = vertices.at((i + 1) % vertices.size());
169 if (a.norm() < b.norm()) {
170 boundLines.push_back(std::make_pair(a, b));
172 boundLines.push_back(std::make_pair(b, a));
177 if (boundLines.size() != 2) {
178 throw std::logic_error(
179 "Input DiscPoly bounds type does not have sensible edges.");
183 Line2D::Through(boundLines[0].first, boundLines[0].second);
185 Line2D::Through(boundLines[1].first, boundLines[1].second);
188 const Eigen::Translation3d originTranslation(ix.x(), ix.y(), 0.);
192 transform = transform * originTranslation;
198 double phiMax =
std::max(phi1, phi2);
200 double phiShift = 0.;
203 auto annulusBounds = std::make_shared<const AnnulusBounds>(
204 rMin, rMax,
phiMin, phiMax, originShift, phiShift);
206 thickness = maskShape->GetDZ() * scalor;
207 bounds = annulusBounds;
213 auto tube =
dynamic_cast<const TGeoTube*
>(&tgShape);
215 if (not boost::istarts_with(axes,
"XY") and
216 not boost::istarts_with(axes,
"YX")) {
217 throw std::invalid_argument(
218 "TGeoShape -> DiscSurface: can only be converted with "
219 "'(x/X)(y/Y)(*)' or '(y/Y)(x/X)(*) axes.");
223 int xs = islower(axes.at(0)) ? -1 : 1;
224 int ys = islower(axes.at(1)) ? -1 : 1;
227 Vector3D t(scalor * translation[0], scalor * translation[1],
228 scalor * translation[2]);
230 Vector3D ay = ys *
Vector3D(rotation[1], rotation[4], rotation[7]);
231 Vector3D az = ax.cross(ay);
232 transform = TGeoPrimitivesHelper::makeTransform(ax, ay, az, t);
234 double minR = tube->GetRmin() * scalor;
235 double maxR = tube->GetRmax() * scalor;
236 double halfZ = tube->GetDz() * scalor;
237 double halfPhi =
M_PI;
240 auto tubeSeg =
dynamic_cast<const TGeoTubeSeg*
>(tube);
242 double phi1 = toRadian(tubeSeg->GetPhi1());
243 double phi2 = toRadian(tubeSeg->GetPhi2());
244 if (not boost::starts_with(axes,
"X")) {
245 throw std::invalid_argument(
246 "TGeoShape -> CylinderSurface (sectorial): can only be converted "
248 "'(X)(y/Y)(*)' axes.");
251 avgPhi = 0.5 * (phi1 + phi2);
253 bounds = std::make_shared<RadialBounds>(minR, maxR, halfPhi, avgPhi);
254 thickness = 2 * halfZ;
263 const Double_t* rotation,
264 const Double_t* translation,
265 const std::string& axes,
266 double scalor) noexcept(
false) {
268 Vector3D t(scalor * translation[0], scalor * translation[1],
269 scalor * translation[2]);
270 Vector3D ax(rotation[0], rotation[3], rotation[6]);
271 Vector3D ay(rotation[1], rotation[4], rotation[7]);
272 Vector3D az(rotation[2], rotation[5], rotation[8]);
274 std::shared_ptr<const PlanarBounds> bounds =
nullptr;
277 const TGeoBBox*
box =
dynamic_cast<const TGeoBBox*
>(&tgShape);
280 const TGeoTrd1* trapezoid1 =
dynamic_cast<const TGeoTrd1*
>(&tgShape);
281 if (trapezoid1 and not boost::istarts_with(axes,
"XZ")) {
282 throw std::invalid_argument(
283 "TGeoTrd1 -> PlaneSurface: can only be converted with '(x/X)(z/Z)(*)' "
288 const TGeoTrd2* trapezoid2 =
dynamic_cast<const TGeoTrd2*
>(&tgShape);
290 if (not boost::istarts_with(axes,
"X") and
292 throw std::invalid_argument(
293 "TGeoTrd2 -> PlaneSurface: dx1 must be be equal to dx2 if not taken "
294 "as trapezoidal side.");
295 }
else if (not boost::istarts_with(axes,
"Y") and
296 std::abs(trapezoid2->GetDy1() - trapezoid2->GetDy2()) >
298 throw std::invalid_argument(
299 "TGeoTrd2 -> PlaneSurface: dy1 must be be equal to dy2 if not taken "
300 "as trapezoidal side.");
303 if (boost::istarts_with(axes,
"XY") or boost::istarts_with(axes,
"YX")) {
304 throw std::invalid_argument(
305 "TGeoTrd2 -> PlaneSurface: only works with (x/X)(z/Z) and "
311 const TGeoArb8* polygon8c =
dynamic_cast<const TGeoArb8*
>(&tgShape);
312 TGeoArb8* polygon8 =
nullptr;
315 polygon8 =
const_cast<TGeoArb8*
>(polygon8c);
319 not(boost::istarts_with(axes,
"XY") or boost::istarts_with(axes,
"YX"))) {
320 throw std::invalid_argument(
321 "TGeoArb8 -> PlaneSurface: dz must be normal component of Surface.");
328 int xs = islower(axes.at(0)) ? -1 : 1;
329 int ys = islower(axes.at(1)) ? -1 : 1;
334 if (boost::istarts_with(axes,
"XY")) {
336 double dx1 = (ys < 0) ? trapezoid1->GetDx2() : trapezoid1->GetDx1();
337 double dx2 = (ys < 0) ? trapezoid1->GetDx1() : trapezoid1->GetDx2();
338 bounds = std::make_shared<const TrapezoidBounds>(
339 scalor * dx1, scalor * dx2, scalor * trapezoid2->GetDy1());
340 thickness = scalor * trapezoid2->GetDz();
341 }
else if (polygon8) {
342 Double_t* tgverts = polygon8->GetVertices();
343 std::vector<Vector2D> pVertices;
344 for (
unsigned int ivtx = 0; ivtx < 4; ++ivtx) {
345 pVertices.push_back(
Vector2D(scalor * xs * tgverts[ivtx * 2],
346 scalor * ys * tgverts[ivtx * 2 + 1]));
348 bounds = std::make_shared<ConvexPolygonBounds<4>>(pVertices);
349 thickness = scalor * polygon8->GetDz();
351 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDX(),
352 scalor * box->GetDY());
353 thickness = scalor * box->GetDZ();
355 }
else if (boost::istarts_with(axes,
"YZ")) {
359 throw std::invalid_argument(
360 "TGeoTrd1 can only be converted with '(x/X)(z/Z)(y/Y)' axes");
361 }
else if (trapezoid2) {
362 double dx1 = (ys < 0) ? trapezoid2->GetDy2() : trapezoid2->GetDy1();
363 double dx2 = (ys < 0) ? trapezoid2->GetDy1() : trapezoid2->GetDy2();
364 bounds = std::make_shared<const TrapezoidBounds>(
365 scalor * dx1, scalor * dx2, scalor * trapezoid2->GetDz());
366 thickness = scalor * trapezoid2->GetDx1();
368 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDY(),
369 scalor * box->GetDZ());
370 thickness = scalor * box->GetDX();
372 }
else if (boost::istarts_with(axes,
"ZX")) {
376 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDZ(),
377 scalor * box->GetDX());
378 thickness = scalor * box->GetDY();
380 }
else if (boost::istarts_with(axes,
"XZ")) {
384 double dx1 = (ys < 0) ? trapezoid1->GetDx2() : trapezoid1->GetDx1();
385 double dx2 = (ys < 0) ? trapezoid1->GetDx1() : trapezoid1->GetDx2();
386 bounds = std::make_shared<const TrapezoidBounds>(
387 scalor * dx1, scalor * dx2, scalor * trapezoid1->GetDz());
388 thickness = scalor * trapezoid1->GetDy();
389 }
else if (trapezoid2) {
390 double dx1 = (ys < 0) ? trapezoid2->GetDx2() : trapezoid2->GetDx1();
391 double dx2 = (ys < 0) ? trapezoid2->GetDx1() : trapezoid2->GetDx2();
392 bounds = std::make_shared<const TrapezoidBounds>(
393 scalor * dx1, scalor * dx2, scalor * trapezoid2->GetDz());
394 thickness = scalor * trapezoid2->GetDy1();
396 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDX(),
397 scalor * box->GetDZ());
398 thickness = scalor * box->GetDY();
400 }
else if (boost::istarts_with(axes,
"YX")) {
404 double dx1 = (ys < 0) ? trapezoid2->GetDy2() : trapezoid2->GetDy1();
405 double dx2 = (ys < 0) ? trapezoid2->GetDy1() : trapezoid2->GetDy2();
406 bounds = std::make_shared<const TrapezoidBounds>(
407 scalor * dx1, scalor * dx2, scalor * trapezoid2->GetDx1());
408 thickness = scalor * trapezoid2->GetDz();
409 }
else if (polygon8) {
410 const Double_t* tgverts = polygon8->GetVertices();
411 std::vector<Vector2D> pVertices;
412 for (
unsigned int ivtx = 0; ivtx < 4; ++ivtx) {
413 pVertices.push_back(
Vector2D(scalor * xs * tgverts[ivtx * 2 + 1],
414 scalor * ys * tgverts[ivtx * 2]));
416 bounds = std::make_shared<ConvexPolygonBounds<4>>(pVertices);
417 thickness = scalor * polygon8->GetDz();
419 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDY(),
420 scalor * box->GetDX());
421 thickness = scalor * box->GetDZ();
423 }
else if (boost::istarts_with(axes,
"ZY")) {
427 bounds = std::make_shared<const RectangleBounds>(scalor * box->GetDZ(),
428 scalor * box->GetDY());
429 thickness = scalor * box->GetDX();
432 throw std::invalid_argument(
433 "TGeoConverter: axes definition must be permutation of "
434 "'(x/X)(y/Y)(z/Z)'");
438 auto cz = cx.cross(cy);
439 auto transform = TGeoPrimitivesHelper::makeTransform(cx, cy, cz, t);
445 const TGeoShape& tgShape,
const TGeoMatrix& tgMatrix,
446 const std::string& axes,
double scalor) noexcept(
false) {
448 const Double_t* rotation = tgMatrix.GetRotationMatrix();
449 const Double_t* translation = tgMatrix.GetTranslation();
452 cylinderComponents(tgShape, rotation, translation, axes, scalor);
453 auto cylinderBounds = std::get<0>(cylinderComps);
454 if (cylinderBounds !=
nullptr) {
455 auto cylinderTrf = std::get<1>(cylinderComps);
456 return Surface::makeShared<CylinderSurface>(cylinderTrf, cylinderBounds);
459 auto discComps = discComponents(tgShape, rotation, translation, axes, scalor);
460 auto discBounds = std::get<0>(discComps);
461 if (discBounds !=
nullptr) {
462 auto discTrf = std::get<1>(discComps);
463 return Surface::makeShared<DiscSurface>(discTrf, discBounds);
467 planeComponents(tgShape, rotation, translation, axes, scalor);
468 auto planeBounds = std::get<0>(planeComps);
469 if (planeBounds !=
nullptr) {
470 auto planeTrf = std::get<1>(planeComps);
471 return Surface::makeShared<PlaneSurface>(planeTrf, planeBounds);