File indexing completed on 2025-01-18 10:14:00
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef VECGEOM_VOLUMES_KERNEL_BOXIMPLEMENTATION_H_
0011 #define VECGEOM_VOLUMES_KERNEL_BOXIMPLEMENTATION_H_
0012
0013 #include "VecGeom/base/Vector3D.h"
0014 #include "VecGeom/volumes/BoxStruct.h"
0015 #include "VecGeom/volumes/kernel/GenericKernels.h"
0016 #include <VecCore/VecCore>
0017
0018 #include <cstdio>
0019
0020 namespace vecgeom {
0021
0022 VECGEOM_DEVICE_FORWARD_DECLARE(struct BoxImplementation;);
0023 VECGEOM_DEVICE_DECLARE_CONV(struct, BoxImplementation);
0024
0025 inline namespace VECGEOM_IMPL_NAMESPACE {
0026
0027 class PlacedBox;
0028 template <typename T>
0029 struct BoxStruct;
0030 class UnplacedBox;
0031
0032 struct BoxImplementation {
0033
0034 using PlacedShape_t = PlacedBox;
0035 using UnplacedStruct_t = BoxStruct<Precision>;
0036 using UnplacedVolume_t = UnplacedBox;
0037
0038 VECCORE_ATT_HOST_DEVICE
0039 static void PrintType()
0040 {
0041
0042 }
0043
0044 template <typename Stream>
0045 static void PrintType(Stream &st, int transCodeT = translation::kGeneric, int rotCodeT = rotation::kGeneric)
0046 {
0047 st << "SpecializedBox<" << transCodeT << "," << rotCodeT << ">";
0048 }
0049
0050 template <typename Stream>
0051 static void PrintImplementationType(Stream &st)
0052 {
0053 (void)st;
0054
0055 }
0056
0057 template <typename Stream>
0058 static void PrintUnplacedType(Stream &st)
0059 {
0060 (void)st;
0061
0062
0063 }
0064
0065 template <typename Real_v>
0066 VECGEOM_FORCE_INLINE
0067 VECCORE_ATT_HOST_DEVICE
0068 static Vector3D<Real_v> HalfSize(const UnplacedStruct_t &box)
0069 {
0070 return Vector3D<Real_v>(box.fDimensions[0], box.fDimensions[1], box.fDimensions[2]);
0071 }
0072
0073 template <typename Real_v, typename Bool_v>
0074 VECGEOM_FORCE_INLINE
0075 VECCORE_ATT_HOST_DEVICE
0076 static void Contains(UnplacedStruct_t const &box, Vector3D<Real_v> const &point, Bool_v &inside)
0077 {
0078 inside = (point.Abs() - HalfSize<Real_v>(box)).Max() < Real_v(0.0);
0079 }
0080
0081 template <typename Real_v, typename Inside_v>
0082 VECGEOM_FORCE_INLINE
0083 VECCORE_ATT_HOST_DEVICE
0084 static void Inside(UnplacedStruct_t const &box, Vector3D<Real_v> const &point, Inside_v &inside)
0085 {
0086 Real_v dist = (point.Abs() - HalfSize<Real_v>(box)).Max();
0087
0088 inside = vecCore::Blend(dist < Real_v(0.0), Inside_v(kInside), Inside_v(kOutside));
0089 vecCore__MaskedAssignFunc(inside, Abs(dist) < Real_v(kHalfTolerance), Inside_v(kSurface));
0090 }
0091
0092 template <typename Real_v, bool ForInside>
0093 VECGEOM_FORCE_INLINE
0094 VECCORE_ATT_HOST_DEVICE
0095 static void GenericKernelForContainsAndInside(Vector3D<Real_v> const &halfsize, Vector3D<Real_v> const &point,
0096 vecCore::Mask<Real_v> &completelyinside,
0097 vecCore::Mask<Real_v> &completelyoutside)
0098 {
0099 Real_v dist = (point.Abs() - halfsize).Max();
0100
0101 if (ForInside) completelyinside = dist < Real_v(-kHalfTolerance);
0102
0103 completelyoutside = dist > Real_v(kHalfTolerance);
0104 }
0105
0106 template <typename Real_v>
0107 VECGEOM_FORCE_INLINE
0108 VECCORE_ATT_HOST_DEVICE
0109 static void DistanceToIn(UnplacedStruct_t const &box, Vector3D<Real_v> const &point,
0110 Vector3D<Real_v> const &direction, Real_v const & , Real_v &distance)
0111 {
0112 const Vector3D<Real_v> invDir(Real_v(1.0) / NonZero(direction[0]), Real_v(1.0) / NonZero(direction[1]),
0113 Real_v(1.0) / NonZero(direction[2]));
0114
0115 const Vector3D<Real_v> signDir(Sign(direction[0]), Sign(direction[1]), Sign(direction[2]));
0116
0117 const Vector3D<Real_v> tempIn = -signDir * box.fDimensions - point;
0118 const Vector3D<Real_v> tempOut = signDir * box.fDimensions - point;
0119
0120
0121 const Real_v absOrthogOut = Abs((signDir * tempOut).Min());
0122
0123 const Real_v distOut = (tempOut * invDir).Min();
0124
0125
0126 distance = (tempIn * invDir).Max();
0127
0128 vecCore__MaskedAssignFunc(
0129 distance, distance >= distOut || distOut <= Real_v(kHalfTolerance) || absOrthogOut <= Real_v(kHalfTolerance),
0130 InfinityLength<Real_v>());
0131 }
0132
0133 template <typename Real_v>
0134 VECGEOM_FORCE_INLINE
0135 VECCORE_ATT_HOST_DEVICE
0136 static void DistanceToOut(UnplacedStruct_t const &box, Vector3D<Real_v> const &point,
0137 Vector3D<Real_v> const &direction, Real_v const & , Real_v &distance)
0138 {
0139 const Vector3D<Real_v> invDir(Real_v(1.0) / NonZero(direction[0]), Real_v(1.0) / NonZero(direction[1]),
0140 Real_v(1.0) / NonZero(direction[2]));
0141
0142 const Vector3D<Real_v> signDir(Sign(direction[0]), Sign(direction[1]), Sign(direction[2]));
0143
0144 const Real_v safetyIn = (point.Abs() - HalfSize<Real_v>(box)).Max();
0145
0146 const Vector3D<Real_v> tempOut = signDir * box.fDimensions - point;
0147
0148 distance = (tempOut * invDir).Min();
0149
0150 vecCore__MaskedAssignFunc(distance, safetyIn > Real_v(kHalfTolerance), Real_v(-1.0));
0151 }
0152
0153 template <typename Real_v>
0154 VECGEOM_FORCE_INLINE
0155 VECCORE_ATT_HOST_DEVICE
0156 static void SafetyToIn(UnplacedStruct_t const &box, Vector3D<Real_v> const &point, Real_v &safety)
0157 {
0158 safety = (point.Abs() - HalfSize<Real_v>(box)).Max();
0159 }
0160
0161 template <typename Real_v>
0162 VECGEOM_FORCE_INLINE
0163 VECCORE_ATT_HOST_DEVICE
0164 static void SafetyToOut(UnplacedStruct_t const &box, Vector3D<Real_v> const &point, Real_v &safety)
0165 {
0166 safety = (HalfSize<Real_v>(box) - point.Abs()).Min();
0167 }
0168
0169 template <typename Real_v>
0170 VECGEOM_FORCE_INLINE
0171 VECCORE_ATT_HOST_DEVICE
0172 static Vector3D<Real_v> NormalKernel(UnplacedStruct_t const &box, Vector3D<Real_v> const &point,
0173 typename vecCore::Mask_v<Real_v> &valid)
0174 {
0175
0176
0177
0178
0179
0180
0181 const Vector3D<Real_v> safety((point.Abs() - HalfSize<Real_v>(box)).Abs());
0182 const Real_v safmin = safety.Min();
0183 valid = safmin < kHalfTolerance;
0184
0185 Vector3D<Real_v> normal(0.);
0186 vecCore__MaskedAssignFunc(normal[0], safety[0] - safmin < kHalfTolerance, Sign(point[0]));
0187 vecCore__MaskedAssignFunc(normal[1], safety[1] - safmin < kHalfTolerance, Sign(point[1]));
0188 vecCore__MaskedAssignFunc(normal[2], safety[2] - safmin < kHalfTolerance, Sign(point[2]));
0189 if (normal.Mag2() > 1.0) normal.Normalize();
0190
0191 return normal;
0192 }
0193
0194
0195
0196
0197 VECCORE_ATT_HOST_DEVICE
0198 VECGEOM_FORCE_INLINE
0199 static bool Intersect(Vector3D<Precision> const *corners, Vector3D<Precision> const &point,
0200 Vector3D<Precision> const &ray, Precision , Precision )
0201 {
0202
0203 Precision tmin, tmax, tymin, tymax, tzmin, tzmax;
0204
0205
0206 Precision inverserayx = 1. / ray[0];
0207 Precision inverserayy = 1. / ray[1];
0208
0209
0210 int sign[3];
0211 sign[0] = inverserayx < 0;
0212 sign[1] = inverserayy < 0;
0213
0214 tmin = (corners[sign[0]].x() - point.x()) * inverserayx;
0215 tmax = (corners[1 - sign[0]].x() - point.x()) * inverserayx;
0216 tymin = (corners[sign[1]].y() - point.y()) * inverserayy;
0217 tymax = (corners[1 - sign[1]].y() - point.y()) * inverserayy;
0218
0219 if ((tmin > tymax) || (tymin > tmax)) return false;
0220
0221 Precision inverserayz = 1. / ray.z();
0222 sign[2] = inverserayz < 0;
0223
0224 if (tymin > tmin) tmin = tymin;
0225 if (tymax < tmax) tmax = tymax;
0226
0227 tzmin = (corners[sign[2]].z() - point.z()) * inverserayz;
0228 tzmax = (corners[1 - sign[2]].z() - point.z()) * inverserayz;
0229
0230 if ((tmin > tzmax) || (tzmin > tmax)) return false;
0231
0232
0233
0234
0235 return true;
0236 }
0237
0238
0239
0240 template <int signx, int signy, int signz>
0241 VECGEOM_FORCE_INLINE
0242 VECCORE_ATT_HOST_DEVICE
0243
0244 static Precision IntersectCached(Vector3D<Precision> const *corners, Vector3D<Precision> const &point,
0245 Vector3D<Precision> const &inverseray, Precision t0, Precision t1)
0246 {
0247
0248
0249
0250
0251 Precision tmin, tmax, tymin, tymax, tzmin, tzmax;
0252
0253
0254
0255
0256 tmin = (corners[signx].x() - point.x()) * inverseray.x();
0257 tmax = (corners[1 - signx].x() - point.x()) * inverseray.x();
0258 tymin = (corners[signy].y() - point.y()) * inverseray.y();
0259 tymax = (corners[1 - signy].y() - point.y()) * inverseray.y();
0260 if ((tmin > tymax) || (tymin > tmax)) return InfinityLength<Precision>();
0261
0262 if (tymin > tmin) tmin = tymin;
0263 if (tymax < tmax) tmax = tymax;
0264
0265 tzmin = (corners[signz].z() - point.z()) * inverseray.z();
0266 tzmax = (corners[1 - signz].z() - point.z()) * inverseray.z();
0267
0268 if ((tmin > tzmax) || (tzmin > tmax)) return InfinityLength<Precision>();
0269 if ((tzmin > tmin)) tmin = tzmin;
0270 if (tzmax < tmax) tmax = tzmax;
0271
0272 if (!((tmin < t1) && (tmax > t0))) return InfinityLength<Precision>();
0273 return tmin;
0274 }
0275
0276
0277
0278 template <typename Real_v, int signx, int signy, int signz>
0279 VECGEOM_FORCE_INLINE
0280 VECCORE_ATT_HOST_DEVICE
0281 static Real_v IntersectCachedKernel(Vector3D<Real_v> const *corners, Vector3D<Precision> const &point,
0282 Vector3D<Precision> const &inverseray, Precision t0, Precision t1)
0283 {
0284
0285 using Bool_v = vecCore::Mask_v<Real_v>;
0286
0287 Real_v tmin = (corners[signx].x() - point.x()) * inverseray.x();
0288 Real_v tmax = (corners[1 - signx].x() - point.x()) * inverseray.x();
0289 Real_v tymin = (corners[signy].y() - point.y()) * inverseray.y();
0290 Real_v tymax = (corners[1 - signy].y() - point.y()) * inverseray.y();
0291
0292
0293 Bool_v done = (tmin > tymax) || (tymin > tmax);
0294 if (vecCore::MaskFull(done)) return InfinityLength<Real_v>();
0295
0296
0297
0298
0299 tmin = Max(tmin, tymin);
0300 tmax = Min(tmax, tymax);
0301
0302 Real_v tzmin = (corners[signz].z() - point.z()) * inverseray.z();
0303 Real_v tzmax = (corners[1 - signz].z() - point.z()) * inverseray.z();
0304
0305 done |= (tmin > tzmax) || (tzmin > tmax);
0306
0307
0308 if (vecCore::MaskFull(done)) return InfinityLength<Real_v>();
0309
0310
0311 tmin = Max(tmin, tzmin);
0312 tmax = Min(tmax, tzmax);
0313
0314 done |= !((tmin < t1) && (tmax > t0));
0315
0316
0317 vecCore__MaskedAssignFunc(tmin, done, InfinityLength<Real_v>());
0318 return tmin;
0319 }
0320
0321
0322
0323 template <typename Real_v, typename basep>
0324 VECGEOM_FORCE_INLINE
0325 VECCORE_ATT_HOST_DEVICE
0326 static Real_v IntersectCachedKernel2(Vector3D<Real_v> const *corners, Vector3D<basep> const &point,
0327 Vector3D<basep> const &inverseray, int signx, int signy, int signz, basep t0,
0328 basep t1)
0329 {
0330
0331 using Bool_v = vecCore::Mask_v<Real_v>;
0332
0333 Real_v tmin = (corners[signx].x() - Real_v(point.x())) * inverseray.x();
0334 Real_v tymax = (corners[1 - signy].y() - Real_v(point.y())) * inverseray.y();
0335 Bool_v done = tmin > tymax;
0336 if (vecCore::MaskFull(done)) return InfinityLength<Real_v>();
0337
0338 Real_v tmax = (corners[1 - signx].x() - Real_v(point.x())) * inverseray.x();
0339 Real_v tymin = (corners[signy].y() - Real_v(point.y())) * inverseray.y();
0340
0341
0342 done |= (tymin > tmax);
0343 if (vecCore::MaskFull(done)) return InfinityLength<Real_v>();
0344
0345
0346
0347
0348
0349 tmin = Max(tmin, tymin);
0350 tmax = Min(tmax, tymax);
0351
0352 Real_v tzmin = (corners[signz].z() - point.z()) * inverseray.z();
0353 Real_v tzmax = (corners[1 - signz].z() - point.z()) * inverseray.z();
0354
0355 done |= (Real_v(tmin) > Real_v(tzmax)) || (Real_v(tzmin) > Real_v(tmax));
0356
0357
0358 if (vecCore::MaskFull(done)) return InfinityLength<Real_v>();
0359
0360
0361 tmin = Max(tmin, tzmin);
0362 tmax = Min(tmax, tzmax);
0363
0364 done |= !((tmin <= Real_v(t1 + kTolerance)) && (tmax > Real_v(t0 - kTolerance)));
0365
0366
0367 vecCore__MaskedAssignFunc(tmin, done, InfinityLength<Real_v>());
0368 return tmin;
0369 }
0370
0371
0372
0373
0374
0375
0376
0377 template <typename Real_v>
0378 VECGEOM_FORCE_INLINE
0379 VECCORE_ATT_HOST_DEVICE
0380 static Precision IntersectMultiple(Vector3D<Real_v> const lowercorners, Vector3D<Real_v> const uppercorners,
0381 Vector3D<Precision> const &point, Vector3D<Precision> const &inverseray,
0382 Precision t0, Precision t1)
0383 {
0384
0385
0386 typedef Real_v Float_t;
0387
0388 Float_t tmin, tmax, tymin, tymax, tzmin, tzmax;
0389
0390
0391
0392
0393
0394
0395 Float_t sign[3];
0396 sign[0] = inverseray.x() < 0;
0397 sign[1] = inverseray.y() < 0;
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407 Precision x0 = (lowercorners.x() - point.x()) * inverseray.x();
0408 Precision x1 = (uppercorners.x() - point.x()) * inverseray.x();
0409 Precision y0 = (lowercorners.y() - point.y()) * inverseray.y();
0410 Precision y1 = (uppercorners.y() - point.y()) * inverseray.y();
0411
0412
0413
0414
0415
0416
0417
0418
0419 tmin = (1 - sign[0]) * x0 + sign[0] * x1;
0420 tmax = sign[0] * x0 + (1 - sign[0]) * x1;
0421 tymin = (1 - sign[1]) * y0 + sign[1] * y1;
0422 tymax = sign[1] * y0 + (1 - sign[1]) * y1;
0423
0424
0425
0426
0427
0428 if ((tmin > tymax) || (tymin > tmax)) return InfinityLength<Precision>();
0429
0430
0431 sign[2] = inverseray.z() < 0;
0432
0433 if (tymin > tmin) tmin = tymin;
0434 if (tymax < tmax) tmax = tymax;
0435
0436
0437
0438
0439
0440 if ((tmin > tzmax) || (tzmin > tmax)) return InfinityLength<Precision>();
0441 if ((tzmin > tmin)) tmin = tzmin;
0442 if (tzmax < tmax) tmax = tzmax;
0443
0444 if (!((tmin < t1) && (tmax > t0))) return InfinityLength<Precision>();
0445
0446
0447 return tmin;
0448 }
0449 };
0450
0451 struct ABBoxImplementation {
0452
0453
0454
0455
0456
0457 template <typename Real_v, typename Bool_v = typename vecCore::Mask_v<Real_v>>
0458 VECGEOM_FORCE_INLINE
0459 VECCORE_ATT_HOST_DEVICE
0460 static void ABBoxContainsKernel(Vector3D<Real_v> const &lowercorner, Vector3D<Real_v> const &uppercorner,
0461 Vector3D<Precision> const &point, Bool_v &inside)
0462 {
0463
0464 inside = lowercorner.x() < Real_v(point.x());
0465 inside &= uppercorner.x() > Real_v(point.x());
0466 if (vecCore::MaskEmpty(inside)) return;
0467
0468 inside &= lowercorner.y() < Real_v(point.y());
0469 inside &= uppercorner.y() > Real_v(point.y());
0470 if (vecCore::MaskEmpty(inside)) return;
0471
0472 inside &= lowercorner.z() < Real_v(point.z());
0473 inside &= uppercorner.z() > Real_v(point.z());
0474 }
0475
0476
0477
0478 template <typename T1, typename T2, typename Bool_v>
0479 VECGEOM_FORCE_INLINE
0480 VECCORE_ATT_HOST_DEVICE
0481 static void ABBoxContainsKernelGeneric(Vector3D<T1> const &lowercorner, Vector3D<T1> const &uppercorner,
0482 Vector3D<T2> const &point, Bool_v &inside)
0483 {
0484 inside = lowercorner.x() < T1(point.x());
0485 inside &= uppercorner.x() > T1(point.x());
0486 if (vecCore::MaskEmpty(inside)) return;
0487
0488 inside &= lowercorner.y() < T1(point.y());
0489 inside &= uppercorner.y() > T1(point.y());
0490 if (vecCore::MaskEmpty(inside)) return;
0491
0492 inside &= lowercorner.z() < T1(point.z());
0493 inside &= uppercorner.z() > T1(point.z());
0494 }
0495
0496
0497
0498
0499
0500 template <typename Real_v, typename Real_s = typename vecCore::TypeTraits<Real_v>::ScalarType>
0501 VECGEOM_FORCE_INLINE
0502 VECCORE_ATT_HOST_DEVICE
0503 static Real_v ABBoxSafetySqr(Vector3D<Real_v> const &lowercorner, Vector3D<Real_v> const &uppercorner,
0504 Vector3D<Real_s> const &point)
0505 {
0506
0507 using Vector3D_v = Vector3D<Real_v>;
0508 using Bool_v = vecCore::Mask_v<Real_v>;
0509
0510 const Vector3D_v kHalf(Real_v(static_cast<Real_s>(0.5)));
0511 const Vector3D_v origin((uppercorner + lowercorner) * kHalf);
0512 const Vector3D_v delta((uppercorner - lowercorner) * kHalf);
0513
0514 const Vector3D_v promotedpoint(Real_v(point.x()), Real_v(point.y()), Real_v(point.z()));
0515
0516
0517 const Vector3D_v safety = ((promotedpoint - origin).Abs()) - delta;
0518 const Bool_v outsidex = safety.x() > Real_s(0.);
0519 const Bool_v outsidey = safety.y() > Real_s(0.);
0520 const Bool_v outsidez = safety.z() > Real_s(0.);
0521
0522 Real_v runningsafetysqr(0.);
0523 Real_v runningmax(-InfinityLength<Real_v>());
0524
0525
0526
0527 {
0528
0529 Real_v tmp(0.);
0530 vecCore__MaskedAssignFunc(tmp, outsidex, safety.x() * safety.x());
0531 runningsafetysqr += tmp;
0532 runningmax = Max(runningmax, safety.x());
0533 }
0534
0535
0536 {
0537 Real_v tmp(0.);
0538 vecCore__MaskedAssignFunc(tmp, outsidey, safety.y() * safety.y());
0539 runningsafetysqr += tmp;
0540 runningmax = Max(runningmax, safety.y());
0541 }
0542
0543
0544 {
0545 Real_v tmp(0.);
0546 vecCore__MaskedAssignFunc(tmp, outsidez, safety.z() * safety.z());
0547 runningsafetysqr += tmp;
0548 runningmax = Max(runningmax, safety.z());
0549 }
0550
0551 Bool_v inside = !(outsidex || outsidey || outsidez);
0552 if (!vecCore::MaskEmpty(inside)) vecCore__MaskedAssignFunc(runningsafetysqr, inside, -runningmax * runningmax);
0553 return runningsafetysqr;
0554 }
0555
0556
0557
0558
0559
0560 template <typename Real_v, typename Real_s = typename vecCore::TypeTraits<Real_v>::ScalarType>
0561 VECGEOM_FORCE_INLINE
0562 VECCORE_ATT_HOST_DEVICE
0563 static Real_v ABBoxSafetyRangeSqr(Vector3D<Real_v> const &lowercorner, Vector3D<Real_v> const &uppercorner,
0564 Vector3D<Real_s> const &point, Real_v &safetymaxsqr)
0565 {
0566
0567 using Vector3D_v = Vector3D<Real_v>;
0568 using Bool_v = vecCore::Mask_v<Real_v>;
0569
0570 const Vector3D_v kHalf(Real_v(static_cast<Real_s>(0.5)));
0571 const Vector3D_v origin((uppercorner + lowercorner) * kHalf);
0572 const Vector3D_v delta((uppercorner - lowercorner) * kHalf);
0573
0574 const Vector3D_v promotedpoint(Real_v(point.x()), Real_v(point.y()), Real_v(point.z()));
0575
0576
0577 const Vector3D_v safety = ((promotedpoint - origin).Abs()) - delta;
0578 const Vector3D_v safetyp = ((promotedpoint - origin).Abs()) + delta;
0579 const Bool_v outsidex = safety.x() > Real_s(0.);
0580 const Bool_v outsidey = safety.y() > Real_s(0.);
0581 const Bool_v outsidez = safety.z() > Real_s(0.);
0582
0583 Real_v runningsafetysqr(0.);
0584 safetymaxsqr = safetyp.Mag2();
0585 Real_v runningmax(-InfinityLength<Real_v>());
0586
0587
0588
0589 {
0590
0591 Real_v tmp(0.);
0592 vecCore__MaskedAssignFunc(tmp, outsidex, safety.x() * safety.x());
0593 runningsafetysqr += tmp;
0594 runningmax = Max(runningmax, safety.x());
0595
0596
0597 }
0598
0599
0600 {
0601 Real_v tmp(0.);
0602 vecCore__MaskedAssignFunc(tmp, outsidey, safety.y() * safety.y());
0603 runningsafetysqr += tmp;
0604 runningmax = Max(runningmax, safety.y());
0605
0606
0607 }
0608
0609
0610 {
0611 Real_v tmp(0.);
0612 vecCore__MaskedAssignFunc(tmp, outsidez, safety.z() * safety.z());
0613 runningsafetysqr += tmp;
0614 runningmax = Max(runningmax, safety.z());
0615
0616
0617 }
0618
0619 Bool_v inside = !(outsidex || outsidey || outsidez);
0620 if (!vecCore::MaskEmpty(inside)) vecCore__MaskedAssignFunc(runningsafetysqr, inside, -runningmax * runningmax);
0621 return runningsafetysqr;
0622 }
0623
0624 };
0625 }
0626 }
0627
0628 #endif