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