26 double outerAlpha,
double outerOffsetZ,
27 double halflengthZ,
double averagePhi,
28 double halfPhiSector) noexcept(
false)
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;
42 double offsetZ,
double halflengthZ,
44 double halfPhiSector) noexcept(
false)
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;
56 double zmin = offsetZ - halflengthZ;
57 double zmax = offsetZ + halflengthZ;
61 if (rmin >= cylinderR) {
63 m_innerRmin = cylinderR;
64 m_innerRmax = cylinderR;
68 m_values[eOuterAlpha] =
alpha;
69 m_values[eOuterOffsetZ] = offsetZ;
70 }
else if (rmax <= cylinderR) {
72 m_outerRmin = cylinderR;
73 m_outerRmax = cylinderR;
77 m_values[eInnerAlpha] =
alpha;
78 m_values[eInnerOffsetZ] = offsetZ;
80 throw std::domain_error(
81 "Cylinder and Cone are intersecting, not possible.");
108 auto outerConeTrans =
122 auto negativeDiscTrans =
124 auto negativeDisc = Surface::makeShared<DiscSurface>(negativeDiscTrans,
137 sectorRotation.col(0) = Vector3D::UnitZ();
138 sectorRotation.col(1) = Vector3D::UnitX();
139 sectorRotation.col(2) = Vector3D::UnitY();
142 negSectorRelTrans.prerotate(
144 auto negSectorAbsTrans = transform * negSectorRelTrans;
145 auto negSectorPlane =
146 Surface::makeShared<PlaneSurface>(negSectorAbsTrans,
m_sectorBounds);
150 posSectorRelTrans.prerotate(
152 auto posSectorAbsTrans = transform * posSectorRelTrans;
153 auto posSectorPlane =
154 Surface::makeShared<PlaneSurface>(posSectorAbsTrans,
m_sectorBounds);
162 if (innerRmin() > outerRmin() or innerRmax() > outerRmax()) {
163 throw std::invalid_argument(
"ConeVolumeBounds: invalid radial input.");
165 if (
get(eHalfLengthZ) <= 0) {
166 throw std::invalid_argument(
167 "ConeVolumeBounds: invalid longitudinal input.");
169 if (
get(eHalfPhiSector) < 0. or
get(eHalfPhiSector) >
M_PI) {
170 throw std::invalid_argument(
"ConeVolumeBounds: invalid phi sector setup.");
173 throw std::invalid_argument(
"ConeVolumeBounds: invalid phi positioning.");
175 if (
get(eInnerAlpha) == 0. and
get(eOuterAlpha) == 0.) {
176 throw std::invalid_argument(
177 "ConeVolumeBounds: neither inner nor outer cone.");
183 double zmin = z + tol;
184 double zmax = z - tol;
186 if (zmin < -
get(eHalfLengthZ) or zmax >
get(eHalfLengthZ)) {
192 double phitol = tol / r;
194 double phimin = phi - phitol;
195 double phimax = phi + phitol;
196 if (phimin <
get(eAveragePhi) -
get(eHalfPhiSector) or
197 phimax >
get(eAveragePhi) +
get(eHalfPhiSector)) {
202 double rmin = r + tol;
203 double rmax = r - tol;
204 if (rmin > innerRmax() and rmax < outerRmin()) {
208 if (m_innerConeBounds !=
nullptr) {
209 double innerConeR = m_innerConeBounds->r(
std::abs(z +
get(eInnerOffsetZ)));
210 if (innerConeR > rmin) {
213 }
else if (innerRmax() > rmin) {
217 if (m_outerConeBounds !=
nullptr) {
218 double outerConeR = m_outerConeBounds->r(
std::abs(z +
get(eOuterOffsetZ)));
219 if (outerConeR < rmax) {
222 }
else if (outerRmax() < rmax) {
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;
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));
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;
251 std::make_shared<ConeBounds>(
get(eOuterAlpha), outerZmin, outerZmax,
252 get(eHalfPhiSector),
get(eAveragePhi));
254 }
else if (m_outerRmin == m_outerRmax) {
255 m_outerCylinderBounds = std::make_shared<CylinderBounds>(
256 m_outerRmax,
get(eHalfLengthZ),
get(eHalfPhiSector),
get(eAveragePhi));
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));
264 m_positiveDiscBounds = std::make_shared<RadialBounds>(
265 m_innerRmax, m_outerRmax,
get(eHalfPhiSector),
get(eAveragePhi));
270 std::vector<Vector2D> polyVertices = {{-
get(eHalfLengthZ), m_innerRmin},
271 {
get(eHalfLengthZ), m_innerRmax},
272 {
get(eHalfLengthZ), m_outerRmax},
273 {-
get(eHalfLengthZ), m_outerRmin}};
275 std::make_shared<ConvexPolygonBounds<4>>(std::move(polyVertices));
286 const Volume* entity)
const {
287 Vector3D vmin(-outerRmax(), -outerRmax(), -0.5 *
get(eHalfLengthZ));
288 Vector3D vmax(outerRmax(), outerRmax(), 0.5 *
get(eHalfLengthZ));
290 return trf ==
nullptr ? box : box.
transformed(*trf);