28 #include <type_traits>
32 double outerAlpha,
double outerOffsetZ,
33 double halflengthZ,
double averagePhi,
34 double halfPhiSector) noexcept(
false)
36 m_values[eInnerAlpha] = innerAlpha;
37 m_values[eInnerOffsetZ] = innerOffsetZ;
38 m_values[eOuterAlpha] = outerAlpha;
39 m_values[eOuterOffsetZ] = outerOffsetZ;
40 m_values[eHalfLengthZ] = halflengthZ;
41 m_values[eAveragePhi] = averagePhi;
42 m_values[eHalfPhiSector] = halfPhiSector;
48 double offsetZ,
double halflengthZ,
50 double halfPhiSector) noexcept(
false)
52 m_values[eInnerAlpha] = 0.;
53 m_values[eInnerOffsetZ] = 0.;
54 m_values[eOuterAlpha] = 0.;
55 m_values[eOuterOffsetZ] = 0.;
56 m_values[eHalfLengthZ] = halflengthZ;
57 m_values[eAveragePhi] = averagePhi;
58 m_values[eHalfPhiSector] = halfPhiSector;
62 double zmin = offsetZ - halflengthZ;
63 double zmax = offsetZ + halflengthZ;
64 double rmin = std::abs(zmin) *
tanAlpha;
65 double rmax = std::abs(zmax) *
tanAlpha;
67 if (rmin >= cylinderR) {
69 m_innerRmin = cylinderR;
70 m_innerRmax = cylinderR;
74 m_values[eOuterAlpha] =
alpha;
75 m_values[eOuterOffsetZ] = offsetZ;
76 }
else if (rmax <= cylinderR) {
78 m_outerRmin = cylinderR;
79 m_outerRmax = cylinderR;
83 m_values[eInnerAlpha] =
alpha;
84 m_values[eInnerOffsetZ] = offsetZ;
86 throw std::domain_error(
87 "Cylinder and Cone are intersecting, not possible.");
130 auto negativeDiscTrans =
132 auto negativeDisc = Surface::makeShared<DiscSurface>(negativeDiscTrans,
147 sectorRotation.col(0) = Vector3::UnitZ();
148 sectorRotation.col(1) = Vector3::UnitX();
149 sectorRotation.col(2) = Vector3::UnitY();
152 negSectorRelTrans.prerotate(
154 auto negSectorAbsTrans = transform * negSectorRelTrans;
155 auto negSectorPlane =
156 Surface::makeShared<PlaneSurface>(negSectorAbsTrans,
m_sectorBounds);
161 posSectorRelTrans.prerotate(
163 auto posSectorAbsTrans = transform * posSectorRelTrans;
164 auto posSectorPlane =
165 Surface::makeShared<PlaneSurface>(posSectorAbsTrans,
m_sectorBounds);
174 if (innerRmin() > outerRmin() or innerRmax() > outerRmax()) {
175 throw std::invalid_argument(
"ConeVolumeBounds: invalid radial input.");
177 if (
get(eHalfLengthZ) <= 0) {
178 throw std::invalid_argument(
179 "ConeVolumeBounds: invalid longitudinal input.");
181 if (
get(eHalfPhiSector) < 0. or
get(eHalfPhiSector) > M_PI) {
182 throw std::invalid_argument(
"ConeVolumeBounds: invalid phi sector setup.");
185 throw std::invalid_argument(
"ConeVolumeBounds: invalid phi positioning.");
187 if (
get(eInnerAlpha) == 0. and
get(eOuterAlpha) == 0.) {
188 throw std::invalid_argument(
189 "ConeVolumeBounds: neither inner nor outer cone.");
195 double zmin = z + tol;
196 double zmax = z - tol;
198 if (zmin < -
get(eHalfLengthZ) or zmax >
get(eHalfLengthZ)) {
204 double phitol = tol /
r;
206 double phimin = phi - phitol;
207 double phimax = phi + phitol;
208 if (phimin <
get(eAveragePhi) -
get(eHalfPhiSector) or
209 phimax >
get(eAveragePhi) +
get(eHalfPhiSector)) {
214 double rmin = r + tol;
215 double rmax = r - tol;
216 if (rmin > innerRmax() and rmax < outerRmin()) {
220 if (m_innerConeBounds !=
nullptr) {
221 double innerConeR = m_innerConeBounds->r(std::abs(z +
get(eInnerOffsetZ)));
222 if (innerConeR > rmin) {
225 }
else if (innerRmax() > rmin) {
229 if (m_outerConeBounds !=
nullptr) {
230 double outerConeR = m_outerConeBounds->r(std::abs(z +
get(eOuterOffsetZ)));
231 if (outerConeR < rmax) {
234 }
else if (outerRmax() < rmax) {
243 m_innerTanAlpha = std::tan(
get(eInnerAlpha));
244 double innerZmin =
get(eInnerOffsetZ) -
get(eHalfLengthZ);
245 double innerZmax =
get(eInnerOffsetZ) +
get(eHalfLengthZ);
246 m_innerRmin = std::abs(innerZmin) * m_innerTanAlpha;
247 m_innerRmax = std::abs(innerZmax) * m_innerTanAlpha;
249 std::make_shared<ConeBounds>(
get(eInnerAlpha), innerZmin, innerZmax,
250 get(eHalfPhiSector),
get(eAveragePhi));
251 }
else if (m_innerRmin == m_innerRmax and m_innerRmin >
s_epsilon) {
252 m_innerCylinderBounds = std::make_shared<CylinderBounds>(
253 m_innerRmin,
get(eHalfLengthZ),
get(eHalfPhiSector),
get(eAveragePhi));
257 m_outerTanAlpha = std::tan(
get(eOuterAlpha));
258 double outerZmin =
get(eOuterOffsetZ) -
get(eHalfLengthZ);
259 double outerZmax =
get(eOuterOffsetZ) +
get(eHalfLengthZ);
260 m_outerRmin = std::abs(outerZmin) * m_outerTanAlpha;
261 m_outerRmax = std::abs(outerZmax) * m_outerTanAlpha;
263 std::make_shared<ConeBounds>(
get(eOuterAlpha), outerZmin, outerZmax,
264 get(eHalfPhiSector),
get(eAveragePhi));
266 }
else if (m_outerRmin == m_outerRmax) {
267 m_outerCylinderBounds = std::make_shared<CylinderBounds>(
268 m_outerRmax,
get(eHalfLengthZ),
get(eHalfPhiSector),
get(eAveragePhi));
271 if (
get(eHalfLengthZ) < std::max(
get(eInnerOffsetZ),
get(eOuterOffsetZ))) {
272 m_negativeDiscBounds = std::make_shared<RadialBounds>(
273 m_innerRmin, m_outerRmin,
get(eHalfPhiSector),
get(eAveragePhi));
276 m_positiveDiscBounds = std::make_shared<RadialBounds>(
277 m_innerRmax, m_outerRmax,
get(eHalfPhiSector),
get(eAveragePhi));
280 if (std::abs(
get(eHalfPhiSector) - M_PI) >
s_epsilon) {
282 std::vector<Vector2> polyVertices = {{-
get(eHalfLengthZ), m_innerRmin},
283 {
get(eHalfLengthZ), m_innerRmax},
284 {
get(eHalfLengthZ), m_outerRmax},
285 {-
get(eHalfLengthZ), m_outerRmin}};
287 std::make_shared<ConvexPolygonBounds<4>>(
std::move(polyVertices));
298 const Volume* entity)
const {
299 Vector3 vmin(-outerRmax(), -outerRmax(), -0.5 *
get(eHalfLengthZ));
300 Vector3 vmax(outerRmax(), outerRmax(), 0.5 *
get(eHalfLengthZ));
302 return trf ==
nullptr ? box : box.
transformed(*trf);