EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ConeVolumeBounds.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file ConeVolumeBounds.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-2018 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
21 
22 #include <cmath>
23 #include <iostream>
24 
25 Acts::ConeVolumeBounds::ConeVolumeBounds(double innerAlpha, double innerOffsetZ,
26  double outerAlpha, double outerOffsetZ,
27  double halflengthZ, double averagePhi,
28  double halfPhiSector) noexcept(false)
29  : VolumeBounds(), m_values() {
30  m_values[eInnerAlpha] = innerAlpha;
31  m_values[eInnerOffsetZ] = innerOffsetZ;
32  m_values[eOuterAlpha] = outerAlpha;
33  m_values[eOuterOffsetZ] = outerOffsetZ;
34  m_values[eHalfLengthZ] = halflengthZ;
35  m_values[eAveragePhi] = averagePhi;
36  m_values[eHalfPhiSector] = halfPhiSector;
38  checkConsistency();
39 }
40 
42  double offsetZ, double halflengthZ,
43  double averagePhi,
44  double halfPhiSector) noexcept(false)
45  : VolumeBounds(), m_values() {
46  m_values[eInnerAlpha] = 0.;
47  m_values[eInnerOffsetZ] = 0.;
48  m_values[eOuterAlpha] = 0.;
49  m_values[eOuterOffsetZ] = 0.;
50  m_values[eHalfLengthZ] = halflengthZ;
51  m_values[eAveragePhi] = averagePhi;
52  m_values[eHalfPhiSector] = halfPhiSector;
53 
54  // Cone parameters
55  double tanAlpha = std::tan(alpha);
56  double zmin = offsetZ - halflengthZ;
57  double zmax = offsetZ + halflengthZ;
58  double rmin = std::abs(zmin) * tanAlpha;
59  double rmax = std::abs(zmax) * tanAlpha;
60 
61  if (rmin >= cylinderR) {
62  // Cylindrical cut-out of a cone
63  m_innerRmin = cylinderR;
64  m_innerRmax = cylinderR;
65  m_outerTanAlpha = tanAlpha;
66  m_outerRmin = rmin;
67  m_outerRmax = rmax;
68  m_values[eOuterAlpha] = alpha;
69  m_values[eOuterOffsetZ] = offsetZ;
70  } else if (rmax <= cylinderR) {
71  // Conical cut-out of a cylinder
72  m_outerRmin = cylinderR;
73  m_outerRmax = cylinderR;
74  m_innerTanAlpha = tanAlpha;
75  m_innerRmin = rmin;
76  m_innerRmax = rmax;
77  m_values[eInnerAlpha] = alpha;
78  m_values[eInnerOffsetZ] = offsetZ;
79  } else {
80  throw std::domain_error(
81  "Cylinder and Cone are intersecting, not possible.");
82  }
84  checkConsistency();
85 }
86 
88  const Transform3D& transform) const {
89  OrientedSurfaces oSurfaces;
90  oSurfaces.reserve(6);
91 
92  // Create an inner Cone
93  if (m_innerConeBounds != nullptr) {
94  auto innerConeTrans =
95  transform * Translation3D(0., 0., -get(eInnerOffsetZ));
96  auto innerCone =
97  Surface::makeShared<ConeSurface>(innerConeTrans, m_innerConeBounds);
98  oSurfaces.push_back(OrientedSurface(std::move(innerCone), forward));
99  } else if (m_innerCylinderBounds != nullptr) {
100  // Or alternatively the inner Cylinder
101  auto innerCylinder =
102  Surface::makeShared<CylinderSurface>(transform, m_innerCylinderBounds);
103  oSurfaces.push_back(OrientedSurface(std::move(innerCylinder), forward));
104  }
105 
106  // Create an outer Cone
107  if (m_outerConeBounds != nullptr) {
108  auto outerConeTrans =
109  transform * Translation3D(0., 0., -get(eOuterOffsetZ));
110  auto outerCone =
111  Surface::makeShared<ConeSurface>(outerConeTrans, m_outerConeBounds);
112  oSurfaces.push_back(OrientedSurface(std::move(outerCone), backward));
113  } else if (m_outerCylinderBounds != nullptr) {
114  // or alternatively an outer Cylinder
115  auto outerCylinder =
116  Surface::makeShared<CylinderSurface>(transform, m_outerCylinderBounds);
117  oSurfaces.push_back(OrientedSurface(std::move(outerCylinder), backward));
118  }
119 
120  // Set a disc at Zmin
121  if (m_negativeDiscBounds != nullptr) {
122  auto negativeDiscTrans =
123  transform * Translation3D(0., 0., -get(eHalfLengthZ));
124  auto negativeDisc = Surface::makeShared<DiscSurface>(negativeDiscTrans,
126  oSurfaces.push_back(OrientedSurface(std::move(negativeDisc), forward));
127  }
128 
129  // Set a disc at Zmax
130  auto positiveDiscTrans = transform * Translation3D(0., 0., get(eHalfLengthZ));
131  auto positiveDisc =
132  Surface::makeShared<DiscSurface>(positiveDiscTrans, m_positiveDiscBounds);
133  oSurfaces.push_back(OrientedSurface(std::move(positiveDisc), backward));
134 
135  if (m_sectorBounds) {
136  RotationMatrix3D sectorRotation;
137  sectorRotation.col(0) = Vector3D::UnitZ();
138  sectorRotation.col(1) = Vector3D::UnitX();
139  sectorRotation.col(2) = Vector3D::UnitY();
140 
141  Transform3D negSectorRelTrans{sectorRotation};
142  negSectorRelTrans.prerotate(
143  AngleAxis3D(get(eAveragePhi) - get(eHalfPhiSector), Vector3D::UnitZ()));
144  auto negSectorAbsTrans = transform * negSectorRelTrans;
145  auto negSectorPlane =
146  Surface::makeShared<PlaneSurface>(negSectorAbsTrans, m_sectorBounds);
147  oSurfaces.push_back(OrientedSurface(std::move(negSectorPlane), forward));
148 
149  Transform3D posSectorRelTrans{sectorRotation};
150  posSectorRelTrans.prerotate(
151  AngleAxis3D(get(eAveragePhi) + get(eHalfPhiSector), Vector3D::UnitZ()));
152  auto posSectorAbsTrans = transform * posSectorRelTrans;
153  auto posSectorPlane =
154  Surface::makeShared<PlaneSurface>(posSectorAbsTrans, m_sectorBounds);
155 
156  oSurfaces.push_back(OrientedSurface(std::move(posSectorPlane), backward));
157  }
158  return oSurfaces;
159 }
160 
162  if (innerRmin() > outerRmin() or innerRmax() > outerRmax()) {
163  throw std::invalid_argument("ConeVolumeBounds: invalid radial input.");
164  }
165  if (get(eHalfLengthZ) <= 0) {
166  throw std::invalid_argument(
167  "ConeVolumeBounds: invalid longitudinal input.");
168  }
169  if (get(eHalfPhiSector) < 0. or get(eHalfPhiSector) > M_PI) {
170  throw std::invalid_argument("ConeVolumeBounds: invalid phi sector setup.");
171  }
172  if (get(eAveragePhi) != detail::radian_sym(get(eAveragePhi))) {
173  throw std::invalid_argument("ConeVolumeBounds: invalid phi positioning.");
174  }
175  if (get(eInnerAlpha) == 0. and get(eOuterAlpha) == 0.) {
176  throw std::invalid_argument(
177  "ConeVolumeBounds: neither inner nor outer cone.");
178  }
179 }
180 
181 bool Acts::ConeVolumeBounds::inside(const Vector3D& pos, double tol) const {
182  double z = pos.z();
183  double zmin = z + tol;
184  double zmax = z - tol;
185  // Quick check ouside z
186  if (zmin < -get(eHalfLengthZ) or zmax > get(eHalfLengthZ)) {
187  return false;
188  }
189  double r = VectorHelpers::perp(pos);
190  if (std::abs(get(eHalfPhiSector) - M_PI) > s_onSurfaceTolerance) {
191  // need to check the phi sector - approximate phi tolerance
192  double phitol = tol / r;
193  double phi = VectorHelpers::phi(pos);
194  double phimin = phi - phitol;
195  double phimax = phi + phitol;
196  if (phimin < get(eAveragePhi) - get(eHalfPhiSector) or
197  phimax > get(eAveragePhi) + get(eHalfPhiSector)) {
198  return false;
199  }
200  }
201  // We are within phi sector check box r quickly
202  double rmin = r + tol;
203  double rmax = r - tol;
204  if (rmin > innerRmax() and rmax < outerRmin()) {
205  return true;
206  }
207  // Finally we need to check the cone
208  if (m_innerConeBounds != nullptr) {
209  double innerConeR = m_innerConeBounds->r(std::abs(z + get(eInnerOffsetZ)));
210  if (innerConeR > rmin) {
211  return false;
212  }
213  } else if (innerRmax() > rmin) {
214  return false;
215  }
216  // And the outer cone
217  if (m_outerConeBounds != nullptr) {
218  double outerConeR = m_outerConeBounds->r(std::abs(z + get(eOuterOffsetZ)));
219  if (outerConeR < rmax) {
220  return false;
221  }
222  } else if (outerRmax() < rmax) {
223  return false;
224  }
225  return true;
226 }
227 
229  // Build inner cone or inner cylinder
230  if (get(eInnerAlpha) > s_epsilon) {
231  m_innerTanAlpha = std::tan(get(eInnerAlpha));
232  double innerZmin = get(eInnerOffsetZ) - get(eHalfLengthZ);
233  double innerZmax = get(eInnerOffsetZ) + get(eHalfLengthZ);
234  m_innerRmin = std::abs(innerZmin) * m_innerTanAlpha;
235  m_innerRmax = std::abs(innerZmax) * m_innerTanAlpha;
236  m_innerConeBounds =
237  std::make_shared<ConeBounds>(get(eInnerAlpha), innerZmin, innerZmax,
238  get(eHalfPhiSector), get(eAveragePhi));
239  } else if (m_innerRmin == m_innerRmax and m_innerRmin > s_epsilon) {
240  m_innerCylinderBounds = std::make_shared<CylinderBounds>(
241  m_innerRmin, get(eHalfLengthZ), get(eHalfPhiSector), get(eAveragePhi));
242  }
243 
244  if (get(eOuterAlpha) > s_epsilon) {
245  m_outerTanAlpha = std::tan(get(eOuterAlpha));
246  double outerZmin = get(eOuterOffsetZ) - get(eHalfLengthZ);
247  double outerZmax = get(eOuterOffsetZ) + get(eHalfLengthZ);
248  m_outerRmin = std::abs(outerZmin) * m_outerTanAlpha;
249  m_outerRmax = std::abs(outerZmax) * m_outerTanAlpha;
250  m_outerConeBounds =
251  std::make_shared<ConeBounds>(get(eOuterAlpha), outerZmin, outerZmax,
252  get(eHalfPhiSector), get(eAveragePhi));
253 
254  } else if (m_outerRmin == m_outerRmax) {
255  m_outerCylinderBounds = std::make_shared<CylinderBounds>(
256  m_outerRmax, get(eHalfLengthZ), get(eHalfPhiSector), get(eAveragePhi));
257  }
258 
259  if (get(eHalfLengthZ) < std::max(get(eInnerOffsetZ), get(eOuterOffsetZ))) {
260  m_negativeDiscBounds = std::make_shared<RadialBounds>(
261  m_innerRmin, m_outerRmin, get(eHalfPhiSector), get(eAveragePhi));
262  }
263 
264  m_positiveDiscBounds = std::make_shared<RadialBounds>(
265  m_innerRmax, m_outerRmax, get(eHalfPhiSector), get(eAveragePhi));
266 
267  // Create the sector bounds
268  if (std::abs(get(eHalfPhiSector) - M_PI) > s_epsilon) {
269  // The 4 points building the sector
270  std::vector<Vector2D> polyVertices = {{-get(eHalfLengthZ), m_innerRmin},
271  {get(eHalfLengthZ), m_innerRmax},
272  {get(eHalfLengthZ), m_outerRmax},
273  {-get(eHalfLengthZ), m_outerRmin}};
274  m_sectorBounds =
275  std::make_shared<ConvexPolygonBounds<4>>(std::move(polyVertices));
276  }
277 }
278 
279 // ostream operator overload
280 std::ostream& Acts::ConeVolumeBounds::toStream(std::ostream& sl) const {
281  return dumpT(sl);
282 }
283 
285  const Acts::Transform3D* trf, const Vector3D& envelope,
286  const Volume* entity) const {
287  Vector3D vmin(-outerRmax(), -outerRmax(), -0.5 * get(eHalfLengthZ));
288  Vector3D vmax(outerRmax(), outerRmax(), 0.5 * get(eHalfLengthZ));
289  Volume::BoundingBox box(entity, vmin - envelope, vmax + envelope);
290  return trf == nullptr ? box : box.transformed(*trf);
291 }