File: PolygonalShell.h

package info (click to toggle)
vecgeom 1.2.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 23,928 kB
  • sloc: cpp: 88,717; ansic: 6,894; python: 1,035; sh: 582; sql: 538; makefile: 29
file content (369 lines) | stat: -rw-r--r-- 13,133 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
#ifndef VECGEOM_POLYGONAL_SHELL_H
#define VECGEOM_POLYGONAL_SHELL_H

#include "VecGeom/base/Global.h"
#include "VecGeom/volumes/PlanarPolygon.h"

namespace vecgeom {

VECGEOM_DEVICE_FORWARD_DECLARE(class PolygonalShell;);
VECGEOM_DEVICE_DECLARE_CONV(class, PolygonalShell);

inline namespace VECGEOM_IMPL_NAMESPACE {

// a set of z-axis aligned rectangles
// looking from the z - direction the rectangles form a convex or concave polygon
class PolygonalShell : AlignedBase {

private:
  // the polygon (with friend access)
  PlanarPolygon fPolygon;
  Precision fLowerZ; // lower z plane
  Precision fUpperZ; // upper z plane

  friend class SimpleExtruPolygon;
  friend struct SExtruImplementation;
  friend class UnplacedSExtruVolume;

public:
  VECCORE_ATT_HOST_DEVICE
  PolygonalShell() : fPolygon() {}

  VECCORE_ATT_HOST_DEVICE
  PolygonalShell(int nvertices, Precision *x, Precision *y, Precision lowerz, Precision upperz)
      : fPolygon(nvertices, x, y), fLowerZ(lowerz), fUpperZ(upperz)
  {
  }

  VECCORE_ATT_HOST_DEVICE
  void Init(int nvertices, Precision *x, Precision *y, Precision lowerz, Precision upperz)
  {
    fPolygon.Init(nvertices, x, y);
    fLowerZ = lowerz;
    fUpperZ = upperz;
  }

  // the area of the shell ( does not include the area of the planar polygon )
  VECCORE_ATT_HOST_DEVICE
  Precision SurfaceArea() const
  {
    const auto kS = fPolygon.fVertices.size();
    Precision area(0.);
    for (size_t i = 0; i < kS; ++i) {
      // vertex lengh x (fUpperZ - fLowerZ)
      area += fPolygon.fLengthSqr[i];
    }
    return std::sqrt(area) * (fUpperZ - fLowerZ);
  }

  VECCORE_ATT_HOST_DEVICE
  PlanarPolygon const &GetPolygon() const { return fPolygon; }

  VECCORE_ATT_HOST_DEVICE
  Precision GetLowerZ() const { return fLowerZ; }

  VECCORE_ATT_HOST_DEVICE
  Precision GetUpperZ() const { return fUpperZ; }

  template <typename Real_v>
  VECCORE_ATT_HOST_DEVICE
  void Extent(Vector3D<Real_v> &aMin, Vector3D<Real_v> &aMax) const
  {
    aMin[0] = Real_v(fPolygon.GetMinX());
    aMin[1] = Real_v(fPolygon.GetMinY());
    aMin[2] = Real_v(fLowerZ);

    aMax[0] = Real_v(fPolygon.GetMaxX());
    aMax[1] = Real_v(fPolygon.GetMaxY());
    aMax[2] = Real_v(fUpperZ);
  }

  template <typename Real_v>
  VECCORE_ATT_HOST_DEVICE
  Real_v DistanceToIn(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
  {
    return fPolygon.IsConvex() ? DistanceToInConvex(point, dir) : DistanceToInConcave(point, dir);
  }

  template <typename Real_v>
  VECCORE_ATT_HOST_DEVICE
  Real_v DistanceToInConvex(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
  {
    using Bool_v = vecCore::Mask_v<Real_v>;
    Bool_v done(false);
    Real_v result(kInfLength);
    const auto S = fPolygon.fVertices.size();

    for (size_t i = 0; i < S; ++i) { // side/rectangle index
      // approaching from right side?
      // under the assumption that surface normals points "inwards"
      const Real_v proj        = fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y();
      const Bool_v sidecorrect = proj >= -kTolerance;
      if (vecCore::MaskEmpty(sidecorrect)) {
        continue;
      }

      // the distance to the plane (specialized for fNormalsZ == 0)
      const Real_v pdist = fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i];

      const Bool_v moving_away = pdist > kTolerance;
      if (vecCore::MaskFull(moving_away)) {
        continue;
      }

      const Real_v dist = -pdist / NonZero(proj);

      // propagate to plane (first just z)
      const Real_v zInters(point.z() + dist * dir.z());
      const Bool_v zRangeOk = (zInters <= fUpperZ) && (zInters >= fLowerZ);
      if (!vecCore::MaskEmpty(zRangeOk)) {
        // check intersection with rest of rectangle
        const Real_v xInters(point.x() + dist * dir.x());
        const Real_v yInters(point.y() + dist * dir.y());

        // we could already check if intersection within the known extent
        const Bool_v intersects = fPolygon.OnSegment<Real_v, Precision, Bool_v>(i, xInters, yInters);

        vecCore::MaskedAssign(result, !done && intersects, dist);
        done |= intersects;
      }
      if (vecCore::MaskFull(done)) {
        return result;
      }
    }
    return result;
  }

  template <typename Real_v>
  VECCORE_ATT_HOST_DEVICE
  Real_v DistanceToInConcave(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
  {
    using Bool_v = vecCore::Mask_v<Real_v>;
    Real_v result(kInfLength);
    const auto S = fPolygon.fVertices.size();

    for (size_t i = 0; i < S; ++i) { // side/rectangle index
      // approaching from right side?
      // under the assumption that surface normals points "inwards"
      const Real_v proj        = fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y();
      const Bool_v sidecorrect = proj >= -kTolerance;
      if (vecCore::MaskEmpty(sidecorrect)) {
        continue;
      }

      // the distance to the plane (specialized for fNormalsZ == 0)
      const Real_v pdist = fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i];

      const Bool_v moving_away = pdist > kTolerance;
      if (vecCore::MaskFull(moving_away)) {
        continue;
      }

      const Real_v dist = -pdist / NonZero(proj);

      // propagate to plane (first just z)
      const Real_v zInters(point.z() + dist * dir.z());
      const Bool_v zRangeOk = (zInters <= fUpperZ) && (zInters >= fLowerZ);
      if (!vecCore::MaskEmpty(zRangeOk)) {
        // check intersection with rest of rectangle
        const Real_v xInters(point.x() + dist * dir.x());
        const Real_v yInters(point.y() + dist * dir.y());

        // we could already check if intersection within the known extent
        const Bool_v intersects = fPolygon.OnSegment<Real_v, Precision, Bool_v>(i, xInters, yInters);

        vecCore__MaskedAssignFunc(result, intersects, Min(dist, result));
      }
      // if (vecCore::MaskFull(done)) {
      //        return result;
      //      }
    }
    return result;
  }

  // -- DistanceToOut --

  template <typename Real_v>
  VECCORE_ATT_HOST_DEVICE
  Real_v DistanceToOut(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
  {
    return fPolygon.IsConvex() ? DistanceToOutConvex(point, dir) : DistanceToOutConcave(point, dir);
  }

  // convex distance to out; checks for hits and aborts loop if hit found
  // NOTE: this kernel is the same as DistanceToIn apart from the comparisons for early return
  // these could become a template parameter
  template <typename Real_v>
  VECCORE_ATT_HOST_DEVICE
  Real_v DistanceToOutConvex(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
  {
    using Bool_v = vecCore::Mask_v<Real_v>;
    Bool_v done(false);
    Real_v result(kInfLength);
    const auto S = fPolygon.fVertices.size();

    for (size_t i = 0; i < S; ++i) { // side/rectangle index
      // approaching from right side?
      // under the assumption that surface normals points "inwards"
      const Real_v proj        = fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y();
      const Bool_v sidecorrect = proj <= kTolerance;
      if (vecCore::MaskEmpty(sidecorrect)) {
        continue;
      }

      // the distance to the plane (specialized for fNormalsZ == 0)
      const Real_v pdist = fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i];

      const Bool_v moving_away = pdist < -kTolerance;
      if (vecCore::MaskFull(moving_away)) {
        continue;
      }

      const Real_v dist = -pdist / NonZero(proj);

      // propagate to plane (first just z)
      const Real_v zInters(point.z() + dist * dir.z());
      const Bool_v zRangeOk = (zInters <= fUpperZ) && (zInters >= fLowerZ) && sidecorrect && !moving_away;
      if (!vecCore::MaskEmpty(zRangeOk)) {
        // check intersection with rest of rectangle
        const Real_v xInters(point.x() + dist * dir.x());
        const Real_v yInters(point.y() + dist * dir.y());

        // we could already check if intersection within the known extent
        const Bool_v intersects = fPolygon.OnSegment<Real_v, Precision, Bool_v>(i, xInters, yInters) && zRangeOk &&
                                  (dist >= -Real_v(kTolerance));

        vecCore::MaskedAssign(result, !done && intersects, dist);
        done |= intersects;
      }
      if (vecCore::MaskFull(done)) {
        return result;
      }
    }
    return result;
  }

  // DistanceToOut for the concave case
  // we should ideally combine this with the other kernel
  template <typename Real_v>
  VECCORE_ATT_HOST_DEVICE
  Real_v DistanceToOutConcave(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
  {
    using Bool_v = vecCore::Mask_v<Real_v>;
    Real_v result(kInfLength);
    const auto S = fPolygon.fVertices.size();

    for (size_t i = 0; i < S; ++i) { // side/rectangle index
      // approaching from right side?
      // under the assumption that surface normals points "inwards"
      const Real_v proj        = fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y();
      const Bool_v sidecorrect = proj <= kTolerance;
      if (vecCore::MaskEmpty(sidecorrect)) {
        continue;
      }

      // the distance to the plane (specialized for fNormalsZ == 0)
      const Real_v pdist = fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i];

      const Bool_v moving_away = pdist < -kTolerance;
      if (vecCore::MaskFull(moving_away)) {
        continue;
      }

      const Real_v dist = -pdist / NonZero(proj);

      // propagate to plane (first just z)
      const Real_v zInters(point.z() + dist * dir.z());
      const Bool_v zRangeOk = (zInters <= fUpperZ) && (zInters >= fLowerZ) && sidecorrect && !moving_away;
      if (!vecCore::MaskEmpty(zRangeOk)) {
        // check intersection with rest of rectangle
        const Real_v xInters(point.x() + dist * dir.x());
        const Real_v yInters(point.y() + dist * dir.y());

        // we could already check if intersection within the known extent
        const Bool_v intersects = fPolygon.OnSegment<Real_v, Precision, Bool_v>(i, xInters, yInters) && zRangeOk &&
                                  (dist >= -Real_v(kTolerance));

        vecCore__MaskedAssignFunc(result, intersects, Min(dist, result));
        // done |= intersects;
      }
      // if (vecCore::MaskFull(done)) {
      //  return result;
      //}
    }
    return result;
  }

}; // end class

#define SPECIALIZATION
#ifdef SPECIALIZATION
// template specialization for Distance functions
template <>
VECCORE_ATT_HOST_DEVICE
inline Precision PolygonalShell::DistanceToOutConvex(Vector3D<Precision> const &point,
                                                     Vector3D<Precision> const &dir) const
{
  Precision dz         = 0.5 * (fUpperZ - fLowerZ);
  Precision pz         = point.z() - 0.5 * (fLowerZ + fUpperZ);
  const Precision safz = vecCore::math::Abs(pz) - dz;
  if (safz > kTolerance) return -kTolerance;

  Precision vz   = dir.z();
  Precision tmax = (vecCore::math::CopySign(dz, vz) - point.z()) / NonZero(vz);
  const auto S   = fPolygon.fVertices.size();
  for (size_t i = 0; i < S; ++i) { // side/rectangle index

    const Precision proj = -(fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y());
    // normals pointing inwards
    const Precision pdist = -(fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i]);
    if (pdist > kTolerance) return -kTolerance;
    if (proj > 0) {
      const Precision dist = -pdist / NonZero(proj);
      if (tmax > dist) tmax = dist;
    }
  }
  return tmax;
}

// template specialization for Distance functions
template <>
VECCORE_ATT_HOST_DEVICE
inline Precision PolygonalShell::DistanceToInConvex(Vector3D<Precision> const &point,
                                                    Vector3D<Precision> const &dir) const
{
  Precision dz = 0.5 * (fUpperZ - fLowerZ);
  Precision pz = point.z() - 0.5 * (fLowerZ + fUpperZ);
  if ((vecCore::math::Abs(pz) - dz) > -kTolerance && pz * dir.z() >= 0) return kInfLength;
  const Precision invz = -1. / NonZero(dir.z());
  const Precision ddz  = (invz < 0) ? dz : -dz;
  Precision tmin       = (pz + ddz) * invz;
  Precision tmax       = (pz - ddz) * invz;
  const auto S         = fPolygon.fVertices.size();
  for (size_t i = 0; i < S; ++i) { // side/rectangle index

    const Precision proj = -(fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y());
    // normals pointing inwards
    const bool moving_away = proj > -kTolerance;
    // the distance to the plane (specialized for fNormalsZ == 0)
    const Precision pdist   = -(fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i]);
    const bool side_correct = pdist > -kTolerance;
    if (side_correct) {
      if (moving_away) return kInfLength;
      const Precision dist = -pdist / NonZero(proj);
      if (dist > tmin) tmin = dist;
    } else if (moving_away) {
      const Precision dist = -pdist / NonZero(proj);
      if (dist < tmax) tmax = dist;
    }
  }
  if (tmax < tmin + kTolerance) return kInfLength;
  return tmin;
}

#endif

} // namespace VECGEOM_IMPL_NAMESPACE
} // namespace vecgeom

#endif