Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4BoundingEnvelope.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// Implementation of G4BoundingEnvelope
27//
28// Author: Evgueni Tcherniaev (CERN), 25.05.2016 - Initial version
29// --------------------------------------------------------------------
30
31#include <cmath>
32
33#include "globals.hh"
34#include "G4BoundingEnvelope.hh"
36#include "G4Normal3D.hh"
37
40
41///////////////////////////////////////////////////////////////////////
42//
43// Constructor from an axis aligned bounding box
44//
46 const G4ThreeVector& pMax)
47 : fMin(pMin), fMax(pMax)
48{
49 // Check correctness of bounding box
50 //
51 CheckBoundingBox();
52}
53
54///////////////////////////////////////////////////////////////////////
55//
56// Constructor from a sequence of polygons
57//
59G4BoundingEnvelope(const std::vector<const G4ThreeVectorList*>& polygons)
60 : fPolygons(&polygons)
61{
62 // Check correctness of polygons
63 //
64 CheckBoundingPolygons();
65
66 // Set bounding box
67 //
68 G4double xmin = kInfinity, ymin = kInfinity, zmin = kInfinity;
69 G4double xmax = -kInfinity, ymax = -kInfinity, zmax = -kInfinity;
70 for (const auto & polygon : *fPolygons)
71 {
72 for (const auto & ipoint : *polygon)
73 {
74 G4double x = ipoint.x();
75 if (x < xmin) { xmin = x; }
76 if (x > xmax) { xmax = x; }
77 G4double y = ipoint.y();
78 if (y < ymin) { ymin = y; }
79 if (y > ymax) { ymax = y; }
80 G4double z = ipoint.z();
81 if (z < zmin) { zmin = z; }
82 if (z > zmax) { zmax = z; }
83 }
84 }
85 fMin.set(xmin,ymin,zmin);
86 fMax.set(xmax,ymax,zmax);
87
88 // Check correctness of bounding box
89 //
90 CheckBoundingBox();
91}
92
93///////////////////////////////////////////////////////////////////////
94//
95// Constructor from a bounding box and a sequence of polygons
96//
99 const G4ThreeVector& pMax,
100 const std::vector<const G4ThreeVectorList*>& polygons)
101 : fMin(pMin), fMax(pMax), fPolygons(&polygons)
102{
103 // Check correctness of bounding box and polygons
104 //
105 CheckBoundingBox();
106 CheckBoundingPolygons();
107}
108
109///////////////////////////////////////////////////////////////////////
110//
111// Check correctness of the axis aligned bounding box
112//
113void G4BoundingEnvelope::CheckBoundingBox()
114{
115 if (fMin.x() >= fMax.x() || fMin.y() >= fMax.y() || fMin.z() >= fMax.z())
116 {
117 std::ostringstream message;
118 message << "Badly defined bounding box (min >= max)!"
119 << "\npMin = " << fMin
120 << "\npMax = " << fMax;
121 G4Exception("G4BoundingEnvelope::CheckBoundingBox()",
122 "GeomMgt0001", JustWarning, message);
123 }
124}
125
126///////////////////////////////////////////////////////////////////////
127//
128// Check correctness of the sequence of bounding polygons.
129// Firsf and last polygons may consist of a single vertex
130//
131void G4BoundingEnvelope::CheckBoundingPolygons()
132{
133 std::size_t nbases = fPolygons->size();
134 if (nbases < 2)
135 {
136 std::ostringstream message;
137 message << "Wrong number of polygons in the sequence: " << nbases
138 << "\nShould be at least two!";
139 G4Exception("G4BoundingEnvelope::CheckBoundingPolygons()",
140 "GeomMgt0001", FatalException, message);
141 return;
142 }
143
144 std::size_t nsize = std::max((*fPolygons)[0]->size(),(*fPolygons)[1]->size());
145 if (nsize < 3)
146 {
147 std::ostringstream message;
148 message << "Badly constructed polygons!"
149 << "\nNumber of polygons: " << nbases
150 << "\nPolygon #0 size: " << (*fPolygons)[0]->size()
151 << "\nPolygon #1 size: " << (*fPolygons)[1]->size()
152 << "\n...";
153 G4Exception("G4BoundingEnvelope::CheckBoundingPolygons()",
154 "GeomMgt0001", FatalException, message);
155 return;
156 }
157
158 for (std::size_t k=0; k<nbases; ++k)
159 {
160 std::size_t np = (*fPolygons)[k]->size();
161 if (np == nsize) { continue; }
162 if (np == 1 && k==0) { continue; }
163 if (np == 1 && k==nbases-1) { continue; }
164 std::ostringstream message;
165 message << "Badly constructed polygons!"
166 << "\nNumber of polygons: " << nbases
167 << "\nPolygon #" << k << " size: " << np
168 << "\nexpected size: " << nsize;
169 G4Exception("G4BoundingEnvelope::SetBoundingPolygons()",
170 "GeomMgt0001", FatalException, message);
171 return;
172 }
173}
174
175///////////////////////////////////////////////////////////////////////
176//
177// Quick comparison: bounding box vs voxel, it return true if further
178// calculations are not needed
179//
180G4bool
183 const G4VoxelLimits& pVoxelLimits,
184 const G4Transform3D& pTransform3D,
185 G4double& pMin, G4double& pMax) const
186{
187 pMin = kInfinity;
188 pMax = -kInfinity;
189 G4double xminlim = pVoxelLimits.GetMinXExtent();
190 G4double xmaxlim = pVoxelLimits.GetMaxXExtent();
191 G4double yminlim = pVoxelLimits.GetMinYExtent();
192 G4double ymaxlim = pVoxelLimits.GetMaxYExtent();
193 G4double zminlim = pVoxelLimits.GetMinZExtent();
194 G4double zmaxlim = pVoxelLimits.GetMaxZExtent();
195
196 // Special case of pure translation
197 //
198 if (pTransform3D.xx()==1 && pTransform3D.yy()==1 && pTransform3D.zz()==1)
199 {
200 G4double xmin = fMin.x() + pTransform3D.dx();
201 G4double xmax = fMax.x() + pTransform3D.dx();
202 G4double ymin = fMin.y() + pTransform3D.dy();
203 G4double ymax = fMax.y() + pTransform3D.dy();
204 G4double zmin = fMin.z() + pTransform3D.dz();
205 G4double zmax = fMax.z() + pTransform3D.dz();
206
207 if (xmin-kCarTolerance > xmaxlim) { return true; }
208 if (xmax+kCarTolerance < xminlim) { return true; }
209 if (ymin-kCarTolerance > ymaxlim) { return true; }
210 if (ymax+kCarTolerance < yminlim) { return true; }
211 if (zmin-kCarTolerance > zmaxlim) { return true; }
212 if (zmax+kCarTolerance < zminlim) { return true; }
213
214 if (xmin >= xminlim && xmax <= xmaxlim &&
215 ymin >= yminlim && ymax <= ymaxlim &&
216 zmin >= zminlim && zmax <= zmaxlim)
217 {
218 if (pAxis == kXAxis)
219 {
220 pMin = (xmin-kCarTolerance < xminlim) ? xminlim : xmin;
221 pMax = (xmax+kCarTolerance > xmaxlim) ? xmaxlim : xmax;
222 }
223 else if (pAxis == kYAxis)
224 {
225 pMin = (ymin-kCarTolerance < yminlim) ? yminlim : ymin;
226 pMax = (ymax+kCarTolerance > ymaxlim) ? ymaxlim : ymax;
227 }
228 else if (pAxis == kZAxis)
229 {
230 pMin = (zmin-kCarTolerance < zminlim) ? zminlim : zmin;
231 pMax = (zmax+kCarTolerance > zmaxlim) ? zmaxlim : zmax;
232 }
233 pMin -= kCarTolerance;
234 pMax += kCarTolerance;
235 return true;
236 }
237 }
238
239 // Find max scale factor of the transformation, set delta
240 // equal to kCarTolerance multiplied by the scale factor
241 //
242 G4double scale = FindScaleFactor(pTransform3D);
243 G4double delta = kCarTolerance*scale;
244
245 // Set the sphere surrounding the bounding box
246 //
247 G4Point3D center = pTransform3D*G4Point3D(0.5*(fMin+fMax));
248 G4double radius = 0.5*scale*(fMax-fMin).mag() + delta;
249
250 // Check if the sphere surrounding the bounding box is outside
251 // the voxel limits
252 //
253 if (center.x()-radius > xmaxlim) { return true; }
254 if (center.y()-radius > ymaxlim) { return true; }
255 if (center.z()-radius > zmaxlim) { return true; }
256 if (center.x()+radius < xminlim) { return true; }
257 if (center.y()+radius < yminlim) { return true; }
258 if (center.z()+radius < zminlim) { return true; }
259 return false;
260}
261
262///////////////////////////////////////////////////////////////////////
263//
264// Calculate extent of the specified bounding envelope
265//
266G4bool
268 const G4VoxelLimits& pVoxelLimits,
269 const G4Transform3D& pTransform3D,
270 G4double& pMin, G4double& pMax) const
271{
272 pMin = kInfinity;
273 pMax = -kInfinity;
274 G4double xminlim = pVoxelLimits.GetMinXExtent();
275 G4double xmaxlim = pVoxelLimits.GetMaxXExtent();
276 G4double yminlim = pVoxelLimits.GetMinYExtent();
277 G4double ymaxlim = pVoxelLimits.GetMaxYExtent();
278 G4double zminlim = pVoxelLimits.GetMinZExtent();
279 G4double zmaxlim = pVoxelLimits.GetMaxZExtent();
280
281 // Special case of pure translation
282 //
283 if (pTransform3D.xx()==1 && pTransform3D.yy()==1 && pTransform3D.zz()==1)
284 {
285 G4double xmin = fMin.x() + pTransform3D.dx();
286 G4double xmax = fMax.x() + pTransform3D.dx();
287 G4double ymin = fMin.y() + pTransform3D.dy();
288 G4double ymax = fMax.y() + pTransform3D.dy();
289 G4double zmin = fMin.z() + pTransform3D.dz();
290 G4double zmax = fMax.z() + pTransform3D.dz();
291
292 if (xmin-kCarTolerance > xmaxlim) { return false; }
293 if (xmax+kCarTolerance < xminlim) { return false; }
294 if (ymin-kCarTolerance > ymaxlim) { return false; }
295 if (ymax+kCarTolerance < yminlim) { return false; }
296 if (zmin-kCarTolerance > zmaxlim) { return false; }
297 if (zmax+kCarTolerance < zminlim) { return false; }
298
299 if (fPolygons == nullptr)
300 {
301 if (pAxis == kXAxis)
302 {
303 pMin = (xmin-kCarTolerance < xminlim) ? xminlim : xmin;
304 pMax = (xmax+kCarTolerance > xmaxlim) ? xmaxlim : xmax;
305 }
306 else if (pAxis == kYAxis)
307 {
308 pMin = (ymin-kCarTolerance < yminlim) ? yminlim : ymin;
309 pMax = (ymax+kCarTolerance > ymaxlim) ? ymaxlim : ymax;
310 }
311 else if (pAxis == kZAxis)
312 {
313 pMin = (zmin-kCarTolerance < zminlim) ? zminlim : zmin;
314 pMax = (zmax+kCarTolerance > zmaxlim) ? zmaxlim : zmax;
315 }
316 pMin -= kCarTolerance;
317 pMax += kCarTolerance;
318 return true;
319 }
320 }
321
322 // Find max scale factor of the transformation, set delta
323 // equal to kCarTolerance multiplied by the scale factor
324 //
325 G4double scale = FindScaleFactor(pTransform3D);
326 G4double delta = kCarTolerance*scale;
327
328 // Set the sphere surrounding the bounding box
329 //
330 G4Point3D center = pTransform3D*G4Point3D(0.5*(fMin+fMax));
331 G4double radius = 0.5*scale*(fMax-fMin).mag() + delta;
332
333 // Check if the sphere surrounding the bounding box is within
334 // the voxel limits, if so then transform only one coordinate
335 //
336 if (center.x()-radius >= xminlim && center.x()+radius <= xmaxlim &&
337 center.y()-radius >= yminlim && center.y()+radius <= ymaxlim &&
338 center.z()-radius >= zminlim && center.z()+radius <= zmaxlim )
339 {
340 G4double cx, cy, cz, cd;
341 if (pAxis == kXAxis)
342 {
343 cx = pTransform3D.xx();
344 cy = pTransform3D.xy();
345 cz = pTransform3D.xz();
346 cd = pTransform3D.dx();
347 }
348 else if (pAxis == kYAxis)
349 {
350 cx = pTransform3D.yx();
351 cy = pTransform3D.yy();
352 cz = pTransform3D.yz();
353 cd = pTransform3D.dy();
354 }
355 else if (pAxis == kZAxis)
356 {
357 cx = pTransform3D.zx();
358 cy = pTransform3D.zy();
359 cz = pTransform3D.zz();
360 cd = pTransform3D.dz();
361 }
362 else
363 {
364 cx = cy = cz = cd = kInfinity;
365 }
366 G4double emin = kInfinity, emax = -kInfinity;
367 if (fPolygons == nullptr)
368 {
369 G4double coor;
370 coor = cx*fMin.x() + cy*fMin.y() + cz*fMin.z() + cd;
371 if (coor < emin) { emin = coor; }
372 if (coor > emax) { emax = coor; }
373 coor = cx*fMax.x() + cy*fMin.y() + cz*fMin.z() + cd;
374 if (coor < emin) { emin = coor; }
375 if (coor > emax) { emax = coor; }
376 coor = cx*fMax.x() + cy*fMax.y() + cz*fMin.z() + cd;
377 if (coor < emin) { emin = coor; }
378 if (coor > emax) { emax = coor; }
379 coor = cx*fMin.x() + cy*fMax.y() + cz*fMin.z() + cd;
380 if (coor < emin) { emin = coor; }
381 if (coor > emax) { emax = coor; }
382 coor = cx*fMin.x() + cy*fMin.y() + cz*fMax.z() + cd;
383 if (coor < emin) { emin = coor; }
384 if (coor > emax) { emax = coor; }
385 coor = cx*fMax.x() + cy*fMin.y() + cz*fMax.z() + cd;
386 if (coor < emin) { emin = coor; }
387 if (coor > emax) { emax = coor; }
388 coor = cx*fMax.x() + cy*fMax.y() + cz*fMax.z() + cd;
389 if (coor < emin) { emin = coor; }
390 if (coor > emax) { emax = coor; }
391 coor = cx*fMin.x() + cy*fMax.y() + cz*fMax.z() + cd;
392 if (coor < emin) { emin = coor; }
393 if (coor > emax) { emax = coor; }
394 }
395 else
396 {
397 for (const auto & polygon : *fPolygons)
398 {
399 for (const auto & ipoint : *polygon)
400 {
401 G4double coor = ipoint.x()*cx + ipoint.y()*cy + ipoint.z()*cz + cd;
402 if (coor < emin) { emin = coor; }
403 if (coor > emax) { emax = coor; }
404 }
405 }
406 }
407 pMin = emin - delta;
408 pMax = emax + delta;
409 return true;
410 }
411
412 // Check if the sphere surrounding the bounding box is outside
413 // the voxel limits
414 //
415 if (center.x()-radius > xmaxlim) { return false; }
416 if (center.y()-radius > ymaxlim) { return false; }
417 if (center.z()-radius > zmaxlim) { return false; }
418 if (center.x()+radius < xminlim) { return false; }
419 if (center.y()+radius < yminlim) { return false; }
420 if (center.z()+radius < zminlim) { return false; }
421
422 // Transform polygons
423 //
424 std::vector<G4Point3D> vertices;
425 std::vector<std::pair<G4int, G4int>> bases;
426 TransformVertices(pTransform3D, vertices, bases);
427 std::size_t nbases = bases.size();
428
429 // Create adjusted G4VoxelLimits box. New limits are extended by
430 // delta, kCarTolerance multiplied by max scale factor of
431 // the transformation
432 //
433 EAxis axes[] = { kXAxis, kYAxis, kZAxis };
434 G4VoxelLimits limits; // default is unlimited
435 for (const auto & iAxis : axes)
436 {
437 if (pVoxelLimits.IsLimited(iAxis))
438 {
439 G4double emin = pVoxelLimits.GetMinExtent(iAxis) - delta;
440 G4double emax = pVoxelLimits.GetMaxExtent(iAxis) + delta;
441 limits.AddLimit(iAxis, emin, emax);
442 }
443 }
444
445 // Main loop along the set of prisms
446 //
447 G4Polygon3D baseA, baseB;
448 G4Segment3D extent;
449 extent.first = G4Point3D( kInfinity, kInfinity, kInfinity);
450 extent.second = G4Point3D(-kInfinity,-kInfinity,-kInfinity);
451 for (std::size_t k=0; k<nbases-1; ++k)
452 {
453 baseA.resize(bases[k].second);
454 for (G4int i = 0; i < bases[k].second; ++i)
455 {
456 baseA[i] = vertices[bases[k].first + i];
457 }
458
459 baseB.resize(bases[k+1].second);
460 for (G4int i = 0; i < bases[k+1].second; ++i)
461 {
462 baseB[i] = vertices[bases[k+1].first + i];
463 }
464
465 // Find bounding box of current prism
466 G4Segment3D prismAABB;
467 GetPrismAABB(baseA, baseB, prismAABB);
468
469 // Check if prismAABB is completely within the voxel limits
470 if (prismAABB.first.x() >= limits.GetMinXExtent() &&
471 prismAABB.first.y() >= limits.GetMinYExtent() &&
472 prismAABB.first.z() >= limits.GetMinZExtent() &&
473 prismAABB.second.x()<= limits.GetMaxXExtent() &&
474 prismAABB.second.y()<= limits.GetMaxYExtent() &&
475 prismAABB.second.z()<= limits.GetMaxZExtent())
476 {
477 if (extent.first.x() > prismAABB.first.x())
478 {
479 extent.first.setX( prismAABB.first.x() );
480 }
481 if (extent.first.y() > prismAABB.first.y())
482 {
483 extent.first.setY( prismAABB.first.y() );
484 }
485 if (extent.first.z() > prismAABB.first.z())
486 {
487 extent.first.setZ( prismAABB.first.z() );
488 }
489 if (extent.second.x() < prismAABB.second.x())
490 {
491 extent.second.setX(prismAABB.second.x());
492 }
493 if (extent.second.y() < prismAABB.second.y())
494 {
495 extent.second.setY(prismAABB.second.y());
496 }
497 if (extent.second.z() < prismAABB.second.z())
498 {
499 extent.second.setZ(prismAABB.second.z());
500 }
501 continue;
502 }
503
504 // Check if prismAABB is outside the voxel limits
505 if (prismAABB.first.x() > limits.GetMaxXExtent()) { continue; }
506 if (prismAABB.first.y() > limits.GetMaxYExtent()) { continue; }
507 if (prismAABB.first.z() > limits.GetMaxZExtent()) { continue; }
508 if (prismAABB.second.x() < limits.GetMinXExtent()) { continue; }
509 if (prismAABB.second.y() < limits.GetMinYExtent()) { continue; }
510 if (prismAABB.second.z() < limits.GetMinZExtent()) { continue; }
511
512 // Clip edges of the prism by adjusted G4VoxelLimits box
513 std::vector<G4Segment3D> vecEdges;
514 CreateListOfEdges(baseA, baseB, vecEdges);
515 if (ClipEdgesByVoxel(vecEdges, limits, extent)) { continue; }
516
517 // Some edges of the prism are completely outside of the voxel
518 // limits, clip selected edges (see bits) of adjusted G4VoxelLimits
519 // by the prism
520 G4int bits = 0x000;
521 if (limits.GetMinXExtent() < prismAABB.first.x())
522 {
523 bits |= 0x988; // 1001 1000 1000
524 }
525 if (limits.GetMaxXExtent() > prismAABB.second.x())
526 {
527 bits |= 0x622; // 0110 0010 0010
528 }
529
530 if (limits.GetMinYExtent() < prismAABB.first.y())
531 {
532 bits |= 0x311; // 0011 0001 0001
533 }
534 if (limits.GetMaxYExtent() > prismAABB.second.y())
535 {
536 bits |= 0xC44; // 1100 0100 0100
537 }
538
539 if (limits.GetMinZExtent() < prismAABB.first.z())
540 {
541 bits |= 0x00F; // 0000 0000 1111
542 }
543 if (limits.GetMaxZExtent() > prismAABB.second.z())
544 {
545 bits |= 0x0F0; // 0000 1111 0000
546 }
547 if (bits == 0xFFF) { continue; }
548
549 std::vector<G4Plane3D> vecPlanes;
550 CreateListOfPlanes(baseA, baseB, vecPlanes);
551 ClipVoxelByPlanes(bits, limits, vecPlanes, prismAABB, extent);
552 } // End of the main loop
553
554 // Final adjustment of the extent
555 //
556 G4double emin = 0, emax = 0;
557 if (pAxis == kXAxis) { emin = extent.first.x(); emax = extent.second.x(); }
558 if (pAxis == kYAxis) { emin = extent.first.y(); emax = extent.second.y(); }
559 if (pAxis == kZAxis) { emin = extent.first.z(); emax = extent.second.z(); }
560
561 if (emin > emax) { return false; }
562 emin -= delta;
563 emax += delta;
564 G4double minlim = pVoxelLimits.GetMinExtent(pAxis);
565 G4double maxlim = pVoxelLimits.GetMaxExtent(pAxis);
566 pMin = (emin < minlim) ? minlim-kCarTolerance : emin;
567 pMax = (emax > maxlim) ? maxlim+kCarTolerance : emax;
568 return true;
569}
570
571///////////////////////////////////////////////////////////////////////
572//
573// Find max scale factor of the transformation
574//
576G4BoundingEnvelope::FindScaleFactor(const G4Transform3D& pTransform3D) const
577{
578 if (pTransform3D.xx() == 1. &&
579 pTransform3D.yy() == 1. &&
580 pTransform3D.zz() == 1.) { return 1.; }
581
582 G4double xx = pTransform3D.xx();
583 G4double yx = pTransform3D.yx();
584 G4double zx = pTransform3D.zx();
585 G4double sxsx = xx*xx + yx*yx + zx*zx;
586 G4double xy = pTransform3D.xy();
587 G4double yy = pTransform3D.yy();
588 G4double zy = pTransform3D.zy();
589 G4double sysy = xy*xy + yy*yy + zy*zy;
590 G4double xz = pTransform3D.xz();
591 G4double yz = pTransform3D.yz();
592 G4double zz = pTransform3D.zz();
593 G4double szsz = xz*xz + yz*yz + zz*zz;
594 G4double ss = std::max(std::max(sxsx,sysy),szsz);
595 return (ss <= 1.) ? 1. : std::sqrt(ss);
596}
597
598///////////////////////////////////////////////////////////////////////
599//
600// Transform polygonal bases
601//
602void
603G4BoundingEnvelope::
604TransformVertices(const G4Transform3D& pTransform3D,
605 std::vector<G4Point3D>& pVertices,
606 std::vector<std::pair<G4int, G4int>>& pBases) const
607{
608 G4ThreeVectorList baseA(4), baseB(4);
609 std::vector<const G4ThreeVectorList*> aabb(2);
610 aabb[0] = &baseA;
611 aabb[1] = &baseB;
612 if (fPolygons == nullptr)
613 {
614 baseA[0].set(fMin.x(),fMin.y(),fMin.z());
615 baseA[1].set(fMax.x(),fMin.y(),fMin.z());
616 baseA[2].set(fMax.x(),fMax.y(),fMin.z());
617 baseA[3].set(fMin.x(),fMax.y(),fMin.z());
618 baseB[0].set(fMin.x(),fMin.y(),fMax.z());
619 baseB[1].set(fMax.x(),fMin.y(),fMax.z());
620 baseB[2].set(fMax.x(),fMax.y(),fMax.z());
621 baseB[3].set(fMin.x(),fMax.y(),fMax.z());
622 }
623 auto ia = (fPolygons == nullptr) ? aabb.cbegin() : fPolygons->cbegin();
624 auto iaend = (fPolygons == nullptr) ? aabb.cend() : fPolygons->cend();
625
626 // Fill vector of bases
627 //
628 G4int index = 0;
629 for (auto i = ia; i != iaend; ++i)
630 {
631 auto nv = (G4int)(*i)->size();
632 pBases.emplace_back(index, nv);
633 index += nv;
634 }
635
636 // Fill vector of transformed vertices
637 //
638 if (pTransform3D.xx() == 1. &&
639 pTransform3D.yy() == 1. &&
640 pTransform3D.zz() == 1.)
641 {
642 G4ThreeVector offset = pTransform3D.getTranslation();
643 for (auto i = ia; i != iaend; ++i)
644 {
645 for (const auto & k : **i)
646 {
647 pVertices.emplace_back(k + offset);
648 }
649 }
650 }
651 else
652 {
653 for (auto i = ia; i != iaend; ++i)
654 {
655 for (const auto & k : **i)
656 {
657 pVertices.push_back(pTransform3D*G4Point3D(k));
658 }
659 }
660 }
661}
662
663///////////////////////////////////////////////////////////////////////
664//
665// Find bounding box of a prism
666//
667void
668G4BoundingEnvelope::GetPrismAABB(const G4Polygon3D& pBaseA,
669 const G4Polygon3D& pBaseB,
670 G4Segment3D& pAABB) const
671{
672 G4double xmin = kInfinity, ymin = kInfinity, zmin = kInfinity;
673 G4double xmax = -kInfinity, ymax = -kInfinity, zmax = -kInfinity;
674
675 // First base
676 //
677 for (const auto & it1 : pBaseA)
678 {
679 G4double x = it1.x();
680 if (x < xmin) { xmin = x; }
681 if (x > xmax) { xmax = x; }
682 G4double y = it1.y();
683 if (y < ymin) { ymin = y; }
684 if (y > ymax) { ymax = y; }
685 G4double z = it1.z();
686 if (z < zmin) { zmin = z; }
687 if (z > zmax) { zmax = z; }
688 }
689
690 // Second base
691 //
692 for (const auto & it2 : pBaseB)
693 {
694 G4double x = it2.x();
695 if (x < xmin) { xmin = x; }
696 if (x > xmax) { xmax = x; }
697 G4double y = it2.y();
698 if (y < ymin) { ymin = y; }
699 if (y > ymax) { ymax = y; }
700 G4double z = it2.z();
701 if (z < zmin) { zmin = z; }
702 if (z > zmax) { zmax = z; }
703 }
704
705 // Set bounding box
706 //
707 pAABB.first = G4Point3D(xmin,ymin,zmin);
708 pAABB.second = G4Point3D(xmax,ymax,zmax);
709}
710
711///////////////////////////////////////////////////////////////////////
712//
713// Create list of edges of a prism
714//
715void
716G4BoundingEnvelope::CreateListOfEdges(const G4Polygon3D& baseA,
717 const G4Polygon3D& baseB,
718 std::vector<G4Segment3D>& pEdges) const
719{
720 std::size_t na = baseA.size();
721 std::size_t nb = baseB.size();
722 pEdges.clear();
723 if (na == nb)
724 {
725 pEdges.resize(3*na);
726 std::size_t k = na - 1;
727 for (std::size_t i=0; i<na; ++i)
728 {
729 pEdges.emplace_back(baseA[i],baseB[i]);
730 pEdges.emplace_back(baseA[i],baseA[k]);
731 pEdges.emplace_back(baseB[i],baseB[k]);
732 k = i;
733 }
734 }
735 else if (nb == 1)
736 {
737 pEdges.resize(2*na);
738 std::size_t k = na - 1;
739 for (std::size_t i=0; i<na; ++i)
740 {
741 pEdges.emplace_back(baseA[i],baseA[k]);
742 pEdges.emplace_back(baseA[i],baseB[0]);
743 k = i;
744 }
745 }
746 else if (na == 1)
747 {
748 pEdges.resize(2*nb);
749 std::size_t k = nb - 1;
750 for (std::size_t i=0; i<nb; ++i)
751 {
752 pEdges.emplace_back(baseB[i],baseB[k]);
753 pEdges.emplace_back(baseB[i],baseA[0]);
754 k = i;
755 }
756 }
757}
758
759///////////////////////////////////////////////////////////////////////
760//
761// Create list of planes bounding a prism
762//
763void
764G4BoundingEnvelope::CreateListOfPlanes(const G4Polygon3D& baseA,
765 const G4Polygon3D& baseB,
766 std::vector<G4Plane3D>& pPlanes) const
767{
768 // Find centers of the bases and internal point of the prism
769 //
770 std::size_t na = baseA.size();
771 std::size_t nb = baseB.size();
772 G4Point3D pa(0.,0.,0.), pb(0.,0.,0.), p0;
773 G4Normal3D norm;
774 for (std::size_t i=0; i<na; ++i) { pa += baseA[i]; }
775 for (std::size_t i=0; i<nb; ++i) { pb += baseB[i]; }
776 pa /= na; pb /= nb; p0 = (pa+pb)/2.;
777
778 // Create list of planes
779 //
780 pPlanes.clear();
781 if (na == nb) // bases with equal number of vertices
782 {
783 std::size_t k = na - 1;
784 for (std::size_t i=0; i<na; ++i)
785 {
786 norm = (baseB[k]-baseA[i]).cross(baseA[k]-baseB[i]);
787 if (norm.mag2() > kCarTolerance)
788 {
789 pPlanes.emplace_back(norm,baseA[i]);
790 }
791 k = i;
792 }
793 norm = (baseA[2]-baseA[0]).cross(baseA[1]-pa);
794 if (norm.mag2() > kCarTolerance)
795 {
796 pPlanes.emplace_back(norm,pa);
797 }
798 norm = (baseB[2]-baseB[0]).cross(baseB[1]-pb);
799 if (norm.mag2() > kCarTolerance)
800 {
801 pPlanes.emplace_back(norm,pb);
802 }
803 }
804 else if (nb == 1) // baseB has one vertex
805 {
806 std::size_t k = na - 1;
807 for (std::size_t i=0; i<na; ++i)
808 {
809 norm = (baseA[i]-baseB[0]).cross(baseA[k]-baseB[0]);
810 if (norm.mag2() > kCarTolerance)
811 {
812 pPlanes.emplace_back(norm,baseB[0]);
813 }
814 k = i;
815 }
816 norm = (baseA[2]-baseA[0]).cross(baseA[1]-pa);
817 if (norm.mag2() > kCarTolerance)
818 {
819 pPlanes.emplace_back(norm,pa);
820 }
821 }
822 else if (na == 1) // baseA has one vertex
823 {
824 std::size_t k = nb - 1;
825 for (std::size_t i=0; i<nb; ++i)
826 {
827 norm = (baseB[i]-baseA[0]).cross(baseB[k]-baseA[0]);
828 if (norm.mag2() > kCarTolerance)
829 {
830 pPlanes.emplace_back(norm,baseA[0]);
831 }
832 k = i;
833 }
834 norm = (baseB[2]-baseB[0]).cross(baseB[1]-pb);
835 if (norm.mag2() > kCarTolerance)
836 {
837 pPlanes.emplace_back(norm,pb);
838 }
839 }
840
841 // Ensure that normals of the planes point to outside
842 //
843 std::size_t nplanes = pPlanes.size();
844 for (std::size_t i=0; i<nplanes; ++i)
845 {
846 pPlanes[i].normalize();
847 if (pPlanes[i].distance(p0) > 0)
848 {
849 pPlanes[i] = G4Plane3D(-pPlanes[i].a(),-pPlanes[i].b(),
850 -pPlanes[i].c(),-pPlanes[i].d());
851 }
852 }
853}
854
855///////////////////////////////////////////////////////////////////////
856//
857// Clip edges of a prism by G4VoxelLimits box. Return true if all edges
858// are inside or intersect the voxel, in this case further calculations
859// are not needed
860//
861G4bool
862G4BoundingEnvelope::ClipEdgesByVoxel(const std::vector<G4Segment3D>& pEdges,
863 const G4VoxelLimits& pBox,
864 G4Segment3D& pExtent) const
865{
866 G4bool done = true;
867 G4Point3D emin = pExtent.first;
868 G4Point3D emax = pExtent.second;
869
870 std::size_t nedges = pEdges.size();
871 for (std::size_t k=0; k<nedges; ++k)
872 {
873 G4Point3D p1 = pEdges[k].first;
874 G4Point3D p2 = pEdges[k].second;
875 if (std::abs(p1.x()-p2.x())+
876 std::abs(p1.y()-p2.y())+
877 std::abs(p1.z()-p2.z()) < kCarTolerance) { continue; }
878 G4double d1, d2;
879 // Clip current edge by X min
880 d1 = pBox.GetMinXExtent() - p1.x();
881 d2 = pBox.GetMinXExtent() - p2.x();
882 if (d1 > 0.0)
883 {
884 if (d2 > 0.0) { done = false; continue; } // go to next edge
885 p1 = (p2*d1-p1*d2)/(d1-d2); // move p1
886 }
887 else
888 {
889 if (d2 > 0.0) { p2 = (p1*d2-p2*d1)/(d2-d1); } // move p2
890 }
891
892 // Clip current edge by X max
893 d1 = p1.x() - pBox.GetMaxXExtent();
894 d2 = p2.x() - pBox.GetMaxXExtent();
895 if (d1 > 0.)
896 {
897 if (d2 > 0.) { done = false; continue; } // go to next edge
898 p1 = (p2*d1-p1*d2)/(d1-d2);
899 }
900 else
901 {
902 if (d2 > 0.) { p2 = (p1*d2-p2*d1)/(d2-d1); }
903 }
904
905 // Clip current edge by Y min
906 d1 = pBox.GetMinYExtent() - p1.y();
907 d2 = pBox.GetMinYExtent() - p2.y();
908 if (d1 > 0.)
909 {
910 if (d2 > 0.) { done = false; continue; } // go to next edge
911 p1 = (p2*d1-p1*d2)/(d1-d2);
912 }
913 else
914 {
915 if (d2 > 0.) { p2 = (p1*d2-p2*d1)/(d2-d1); }
916 }
917
918 // Clip current edge by Y max
919 d1 = p1.y() - pBox.GetMaxYExtent();
920 d2 = p2.y() - pBox.GetMaxYExtent();
921 if (d1 > 0.)
922 {
923 if (d2 > 0.) { done = false; continue; } // go to next edge
924 p1 = (p2*d1-p1*d2)/(d1-d2);
925 }
926 else
927 {
928 if (d2 > 0.) { p2 = (p1*d2-p2*d1)/(d2-d1); }
929 }
930
931 // Clip current edge by Z min
932 d1 = pBox.GetMinZExtent() - p1.z();
933 d2 = pBox.GetMinZExtent() - p2.z();
934 if (d1 > 0.)
935 {
936 if (d2 > 0.) { done = false; continue; } // go to next edge
937 p1 = (p2*d1-p1*d2)/(d1-d2);
938 }
939 else
940 {
941 if (d2 > 0.) { p2 = (p1*d2-p2*d1)/(d2-d1); }
942 }
943
944 // Clip current edge by Z max
945 d1 = p1.z() - pBox.GetMaxZExtent();
946 d2 = p2.z() - pBox.GetMaxZExtent();
947 if (d1 > 0.)
948 {
949 if (d2 > 0.) { done = false; continue; } // go to next edge
950 p1 = (p2*d1-p1*d2)/(d1-d2);
951 }
952 else
953 {
954 if (d2 > 0.) { p2 = (p1*d2-p2*d1)/(d2-d1); }
955 }
956
957 // Adjust current extent
958 emin.setX(std::min(std::min(p1.x(),p2.x()),emin.x()));
959 emin.setY(std::min(std::min(p1.y(),p2.y()),emin.y()));
960 emin.setZ(std::min(std::min(p1.z(),p2.z()),emin.z()));
961
962 emax.setX(std::max(std::max(p1.x(),p2.x()),emax.x()));
963 emax.setY(std::max(std::max(p1.y(),p2.y()),emax.y()));
964 emax.setZ(std::max(std::max(p1.z(),p2.z()),emax.z()));
965 }
966
967 // Return true if all edges (at least partially) are inside
968 // the voxel limits, otherwise return false
969 pExtent.first = emin;
970 pExtent.second = emax;
971
972 return done;
973}
974
975///////////////////////////////////////////////////////////////////////
976//
977// Clip G4VoxelLimits by set of planes bounding a prism
978//
979void
980G4BoundingEnvelope::ClipVoxelByPlanes(G4int pBits,
981 const G4VoxelLimits& pBox,
982 const std::vector<G4Plane3D>& pPlanes,
983 const G4Segment3D& pAABB,
984 G4Segment3D& pExtent) const
985{
986 G4Point3D emin = pExtent.first;
987 G4Point3D emax = pExtent.second;
988
989 // Create edges of the voxel limits box reducing them where
990 // appropriate to avoid calculations with big numbers (kInfinity)
991 //
992 G4double xmin = std::max(pBox.GetMinXExtent(),pAABB.first.x() -1.);
993 G4double xmax = std::min(pBox.GetMaxXExtent(),pAABB.second.x()+1.);
994
995 G4double ymin = std::max(pBox.GetMinYExtent(),pAABB.first.y() -1.);
996 G4double ymax = std::min(pBox.GetMaxYExtent(),pAABB.second.y()+1.);
997
998 G4double zmin = std::max(pBox.GetMinZExtent(),pAABB.first.z() -1.);
999 G4double zmax = std::min(pBox.GetMaxZExtent(),pAABB.second.z()+1.);
1000
1001 std::vector<G4Segment3D> edges(12);
1002 G4int i = 0, bits = pBits;
1003 if ((bits & 0x001) == 0)
1004 {
1005 edges[i ].first.set( xmin,ymin,zmin);
1006 edges[i++].second.set(xmax,ymin,zmin);
1007 }
1008 if ((bits & 0x002) == 0)
1009 {
1010 edges[i ].first.set( xmax,ymin,zmin);
1011 edges[i++].second.set(xmax,ymax,zmin);
1012 }
1013 if ((bits & 0x004) == 0)
1014 {
1015 edges[i ].first.set( xmax,ymax,zmin);
1016 edges[i++].second.set(xmin,ymax,zmin);
1017 }
1018 if ((bits & 0x008) == 0)
1019 {
1020 edges[i ].first.set( xmin,ymax,zmin);
1021 edges[i++].second.set(xmin,ymin,zmin);
1022 }
1023
1024 if ((bits & 0x010) == 0)
1025 {
1026 edges[i ].first.set( xmin,ymin,zmax);
1027 edges[i++].second.set(xmax,ymin,zmax);
1028 }
1029 if ((bits & 0x020) == 0)
1030 {
1031 edges[i ].first.set( xmax,ymin,zmax);
1032 edges[i++].second.set(xmax,ymax,zmax);
1033 }
1034 if ((bits & 0x040) == 0)
1035 {
1036 edges[i ].first.set( xmax,ymax,zmax);
1037 edges[i++].second.set(xmin,ymax,zmax);
1038 }
1039 if ((bits & 0x080) == 0)
1040 {
1041 edges[i ].first.set( xmin,ymax,zmax);
1042 edges[i++].second.set(xmin,ymin,zmax);
1043 }
1044
1045 if ((bits & 0x100) == 0)
1046 {
1047 edges[i ].first.set( xmin,ymin,zmin);
1048 edges[i++].second.set(xmin,ymin,zmax);
1049 }
1050 if ((bits & 0x200) == 0)
1051 {
1052 edges[i ].first.set( xmax,ymin,zmin);
1053 edges[i++].second.set(xmax,ymin,zmax);
1054 }
1055 if ((bits & 0x400) == 0)
1056 {
1057 edges[i ].first.set( xmax,ymax,zmin);
1058 edges[i++].second.set(xmax,ymax,zmax);
1059 }
1060 if ((bits & 0x800) == 0)
1061 {
1062 edges[i ].first.set( xmin,ymax,zmin);
1063 edges[i++].second.set(xmin,ymax,zmax);
1064 }
1065 edges.resize(i);
1066
1067 // Clip the edges by the planes
1068 //
1069 for (const auto & edge : edges)
1070 {
1071 G4bool exist = true;
1072 G4Point3D p1 = edge.first;
1073 G4Point3D p2 = edge.second;
1074 for (const auto & plane : pPlanes)
1075 {
1076 // Clip current edge
1077 G4double d1 = plane.distance(p1);
1078 G4double d2 = plane.distance(p2);
1079 if (d1 > 0.0)
1080 {
1081 if (d2 > 0.0) { exist = false; break; } // go to next edge
1082 p1 = (p2*d1-p1*d2)/(d1-d2); // move p1
1083 }
1084 else
1085 {
1086 if (d2 > 0.0) { p2 = (p1*d2-p2*d1)/(d2-d1); } // move p2
1087 }
1088 }
1089 // Adjust the extent
1090 if (exist)
1091 {
1092 emin.setX(std::min(std::min(p1.x(),p2.x()),emin.x()));
1093 emin.setY(std::min(std::min(p1.y(),p2.y()),emin.y()));
1094 emin.setZ(std::min(std::min(p1.z(),p2.z()),emin.z()));
1095
1096 emax.setX(std::max(std::max(p1.x(),p2.x()),emax.x()));
1097 emax.setY(std::max(std::max(p1.y(),p2.y()),emax.y()));
1098 emax.setZ(std::max(std::max(p1.z(),p2.z()),emax.z()));
1099 }
1100 }
1101
1102 // Copy the extent back
1103 //
1104 pExtent.first = emin;
1105 pExtent.second = emax;
1106}
const G4double kCarTolerance
std::pair< G4Point3D, G4Point3D > G4Segment3D
std::vector< G4Point3D > G4Polygon3D
std::vector< G4ThreeVector > G4ThreeVectorList
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
G4ThreadLocal T * G4GeomSplitter< T >::offset
HepGeom::Normal3D< G4double > G4Normal3D
Definition G4Normal3D.hh:34
HepGeom::Plane3D< G4double > G4Plane3D
Definition G4Plane3D.hh:34
HepGeom::Point3D< G4double > G4Point3D
Definition G4Point3D.hh:34
CLHEP::Hep3Vector G4ThreeVector
HepGeom::Transform3D G4Transform3D
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
double z() const
double x() const
double y() const
G4bool BoundingBoxVsVoxelLimits(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4BoundingEnvelope(const G4ThreeVector &pMin, const G4ThreeVector &pMax)
G4double GetSurfaceTolerance() const
static G4GeometryTolerance * GetInstance()
G4VoxelLimits represents limitation/restrictions of space, where restrictions are only made perpendic...
G4double GetMinExtent(const EAxis pAxis) const
G4double GetMinZExtent() const
void AddLimit(const EAxis pAxis, const G4double pMin, const G4double pMax)
G4double GetMaxExtent(const EAxis pAxis) const
G4double GetMaxYExtent() const
G4double GetMaxZExtent() const
G4double GetMinYExtent() const
G4double GetMinXExtent() const
G4bool IsLimited() const
G4double GetMaxXExtent() const
double dy() const
double zz() const
double yz() const
double dz() const
double dx() const
double xy() const
CLHEP::Hep3Vector getTranslation() const
double zx() const
double yx() const
double zy() const
double xx() const
double yy() const
double xz() const
EAxis
Definition geomdefs.hh:54
@ kYAxis
Definition geomdefs.hh:56
@ kXAxis
Definition geomdefs.hh:55
@ kZAxis
Definition geomdefs.hh:57