source: trunk/source/geometry/solids/specific/src/G4TessellatedSolid.cc@ 1305

Last change on this file since 1305 was 1228, checked in by garnier, 16 years ago

update geant4.9.3 tag

File size: 35.5 KB
Line 
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 and of QinetiQ Ltd, *
20// * subject to DEFCON 705 IPR conditions. *
21// * By using, copying, modifying or distributing the software (or *
22// * any work based on the software) you agree to acknowledge its *
23// * use in resulting scientific publications, and indicate your *
24// * acceptance of all terms of the Geant4 Software license. *
25// ********************************************************************
26//
27// $Id: G4TessellatedSolid.cc,v 1.19 2009/04/27 08:06:27 gcosmo Exp $
28// GEANT4 tag $Name: geant4-09-03 $
29//
30// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31//
32// MODULE: G4TessellatedSolid.cc
33//
34// Date: 15/06/2005
35// Author: P R Truscott
36// Organisation: QinetiQ Ltd, UK
37// Customer: UK Ministry of Defence : RAO CRP TD Electronic Systems
38// Contract: C/MAT/N03517
39//
40// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41//
42// CHANGE HISTORY
43// --------------
44//
45// 14 November 2007 P R Truscott, QinetiQ & Stan Seibert, U Texas
46// Bug fixes to CalculateExtent
47//
48// 17 September 2007, P R Truscott, QinetiQ Ltd & Richard Holmberg
49// Updated extensively prior to this date to deal with
50// concaved tessellated surfaces, based on the algorithm
51// of Richard Holmberg. This had been slightly modified
52// to determine with inside the geometry by projecting
53// random rays from the point provided. Now random rays
54// are predefined rather than making use of random
55// number generator at run-time.
56//
57// 22 November 2005, F Lei
58// - Changed ::DescribeYourselfTo(), line 464
59// - added GetPolyHedron()
60//
61// 31 October 2004, P R Truscott, QinetiQ Ltd, UK
62// - Created.
63//
64// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65
66#include "G4TessellatedSolid.hh"
67#include "G4PolyhedronArbitrary.hh"
68#include "globals.hh"
69#include "Randomize.hh"
70
71#include <iostream>
72
73///////////////////////////////////////////////////////////////////////////////
74//
75// Standard contructor has blank name and defines no facets.
76//
77G4TessellatedSolid::G4TessellatedSolid ()
78 : G4VSolid("dummy"), fpPolyhedron(0), cubicVolume(0.), surfaceArea(0.)
79{
80 dirTolerance = 1.0E-14;
81
82 geometryType = "G4TessellatedSolid";
83 facets.clear();
84 solidClosed = false;
85
86 xMinExtent = kInfinity;
87 xMaxExtent = -kInfinity;
88 yMinExtent = kInfinity;
89 yMaxExtent = -kInfinity;
90 zMinExtent = kInfinity;
91 zMaxExtent = -kInfinity;
92
93 SetRandomVectorSet();
94}
95
96///////////////////////////////////////////////////////////////////////////////
97//
98// Alternative constructor. Simple define name and geometry type - no facets
99// to detine.
100//
101G4TessellatedSolid::G4TessellatedSolid (const G4String &name)
102 : G4VSolid(name), fpPolyhedron(0), cubicVolume(0.), surfaceArea(0.)
103{
104 dirTolerance = 1.0E-14;
105
106 geometryType = "G4TessellatedSolid";
107 facets.clear();
108 solidClosed = false;
109
110 xMinExtent = kInfinity;
111 xMaxExtent = -kInfinity;
112 yMinExtent = kInfinity;
113 yMaxExtent = -kInfinity;
114 zMinExtent = kInfinity;
115 zMaxExtent = -kInfinity;
116
117 SetRandomVectorSet();
118}
119
120///////////////////////////////////////////////////////////////////////////////
121//
122// Fake default constructor - sets only member data and allocates memory
123// for usage restricted to object persistency.
124//
125G4TessellatedSolid::G4TessellatedSolid( __void__& a )
126 : G4VSolid(a), fpPolyhedron(0), facets(0),
127 geometryType("G4TessellatedSolid"), cubicVolume(0.), surfaceArea(0.),
128 vertexList(), xMinExtent(0.), xMaxExtent(0.),
129 yMinExtent(0.), yMaxExtent(0.), zMinExtent(0.), zMaxExtent(0.),
130 solidClosed(false)
131{
132 SetRandomVectorSet();
133}
134
135///////////////////////////////////////////////////////////////////////////////
136//
137// Destructor.
138//
139G4TessellatedSolid::~G4TessellatedSolid ()
140{
141 DeleteObjects ();
142}
143
144///////////////////////////////////////////////////////////////////////////////
145//
146// Define copy constructor.
147//
148G4TessellatedSolid::G4TessellatedSolid (const G4TessellatedSolid &s)
149 : G4VSolid(s)
150{
151 if (&s == this) { return; }
152
153 dirTolerance = 1.0E-14;
154
155 geometryType = "G4TessellatedSolid";
156 facets.clear();
157 solidClosed = false;
158
159 xMinExtent = kInfinity;
160 xMaxExtent = -kInfinity;
161 yMinExtent = kInfinity;
162 yMaxExtent = -kInfinity;
163 zMinExtent = kInfinity;
164 zMaxExtent = -kInfinity;
165
166 SetRandomVectorSet();
167
168 CopyObjects (s);
169}
170
171///////////////////////////////////////////////////////////////////////////////
172//
173// Define assignment operator.
174//
175const G4TessellatedSolid &
176G4TessellatedSolid::operator= (const G4TessellatedSolid &s)
177{
178 if (&s == this) { return *this; }
179
180 DeleteObjects ();
181 CopyObjects (s);
182
183 return *this;
184}
185
186///////////////////////////////////////////////////////////////////////////////
187//
188void G4TessellatedSolid::DeleteObjects ()
189{
190 for (std::vector<G4VFacet *>::iterator f=facets.begin(); f!=facets.end(); f++)
191 {
192 delete *f;
193 }
194 facets.clear();
195}
196
197///////////////////////////////////////////////////////////////////////////////
198//
199void G4TessellatedSolid::CopyObjects (const G4TessellatedSolid &s)
200{
201 size_t n = s.GetNumberOfFacets();
202 for (size_t i=0; i<n; i++)
203 {
204 G4VFacet *facetClone = (s.GetFacet(i))->GetClone();
205 AddFacet(facetClone);
206 }
207
208 if ( s.GetSolidClosed() ) { SetSolidClosed(true); }
209
210// cubicVolume = s.GetCubicVolume();
211}
212
213///////////////////////////////////////////////////////////////////////////////
214//
215// Add a facet to the facet list. Note that you can add, but you cannot
216// delete.
217//
218G4bool G4TessellatedSolid::AddFacet (G4VFacet *aFacet)
219{
220 // Add the facet to the vector.
221
222 if (solidClosed)
223 {
224 G4Exception("G4TessellatedSolid::AddFacet()", "InvalidSetup",
225 JustWarning, "Attempt to add facets when solid is closed.");
226 return false;
227 }
228 else if (aFacet->IsDefined())
229 {
230 if (facets.size() == 0)
231 {
232 facets.push_back(aFacet);
233 }
234 else
235 {
236 G4bool found = false;
237 FacetI it = facets.begin();
238 do
239 {
240 found = (**it == *aFacet);
241 } while (!found && ++it!=facets.end());
242
243 if (found)
244 {
245 delete *it;
246 facets.erase(it);
247 }
248 else
249 {
250 facets.push_back(aFacet);
251 }
252 }
253
254 return true;
255 }
256 else
257 {
258 G4Exception("G4TessellatedSolid::AddFacet()", "InvalidSetup",
259 JustWarning, "Attempt to add facet not properly defined.");
260 G4cerr << "Facet attributes:" << G4endl;
261 aFacet->StreamInfo(G4cerr);
262 G4cerr << G4endl;
263
264 return false;
265 }
266}
267
268///////////////////////////////////////////////////////////////////////////////
269//
270void G4TessellatedSolid::SetSolidClosed (const G4bool t)
271{
272 if (t)
273 {
274 vertexList.clear();
275 for (FacetCI it=facets.begin(); it!=facets.end(); it++)
276 {
277 size_t m = vertexList.size();
278 G4ThreeVector p(0.0,0.0,0.0);
279 for (size_t i=0; i<(*it)->GetNumberOfVertices(); i++)
280 {
281 p = (*it)->GetVertex(i);
282 G4bool found = false;
283 size_t j = 0;
284 while (j < m && !found)
285 {
286 G4ThreeVector q = vertexList[j];
287 found = (q-p).mag() < 0.5*kCarTolerance;
288 if (!found) j++;
289 }
290
291 if (!found)
292 {
293 vertexList.push_back(p);
294 (*it)->SetVertexIndex(i,vertexList.size()-1);
295 }
296 else
297 {
298 (*it)->SetVertexIndex(i,j);
299 }
300 }
301 }
302 //
303 // Now update the maximum x, y and z limits of the volume.
304 //
305 for (size_t i=0; i<vertexList.size(); i++)
306 {
307 G4ThreeVector p = vertexList[i];
308 G4double x = p.x();
309 G4double y = p.y();
310 G4double z = p.z();
311
312 if (i > 0)
313 {
314 if (x > xMaxExtent) xMaxExtent = x;
315 if (x < xMinExtent) xMinExtent = x;
316 if (y > yMaxExtent) yMaxExtent = y;
317 if (y < yMinExtent) yMinExtent = y;
318 if (z > zMaxExtent) zMaxExtent = z;
319 if (z < zMinExtent) zMinExtent = z;
320 }
321 else
322 {
323 xMaxExtent = x;
324 xMinExtent = x;
325 yMaxExtent = y;
326 yMinExtent = y;
327 zMaxExtent = z;
328 zMinExtent = z;
329 }
330 }
331//
332//
333// Compute extremeFacets, i.e. find those facets that have surface
334// planes that bound the volume.
335// Note that this is going to reject concaved surfaces as being extreme. Also
336// note that if the vertex is on the facet, displacement is zero, so IsInside
337// returns true. So will this work?? Need non-equality
338// "G4bool inside = displacement < 0.0;"
339// or
340// "G4bool inside = displacement <= -0.5*kCarTolerance"
341// (Notes from PT 13/08/2007).
342//
343 for (FacetCI it=facets.begin(); it!=facets.end(); it++)
344 {
345 G4bool isExtreme = true;
346 for (size_t i=0; i<vertexList.size(); i++)
347 {
348 if (!(*it)->IsInside(vertexList[i]))
349 {
350 isExtreme = false;
351 break;
352 }
353 }
354 if (isExtreme)
355 extremeFacets.insert(*it);
356 }
357 solidClosed = true;
358 }
359 else
360 {
361 solidClosed = false;
362 }
363}
364
365///////////////////////////////////////////////////////////////////////////////
366//
367// GetSolidClosed
368//
369// Used to determine whether the solid is closed to adding further facets.
370//
371G4bool G4TessellatedSolid::GetSolidClosed () const
372 {return solidClosed;}
373
374///////////////////////////////////////////////////////////////////////////////
375//
376// operator+=
377//
378// This operator allows the user to add two tessellated solids together, so
379// that the solid on the left then includes all of the facets in the solid
380// on the right. Note that copies of the facets are generated, rather than
381// using the original facet set of the solid on the right.
382//
383const G4TessellatedSolid &G4TessellatedSolid::operator+=
384 (const G4TessellatedSolid &right)
385{
386 for (size_t i=0; i<right.GetNumberOfFacets(); i++)
387 AddFacet(right.GetFacet(i)->GetClone());
388 return *this;
389}
390
391///////////////////////////////////////////////////////////////////////////////
392//
393// GetFacet
394//
395// Access pointer to facet in solid, indexed by integer i.
396//
397G4VFacet *G4TessellatedSolid::GetFacet (size_t i) const
398{
399 return facets[i];
400}
401
402///////////////////////////////////////////////////////////////////////////////
403//
404// GetNumberOfFacets
405//
406size_t G4TessellatedSolid::GetNumberOfFacets () const
407{
408 return facets.size();
409}
410
411///////////////////////////////////////////////////////////////////////////////
412//
413// EInside G4TessellatedSolid::Inside (const G4ThreeVector &p) const
414//
415// This method must return:
416// * kOutside if the point at offset p is outside the shape
417// boundaries plus kCarTolerance/2,
418// * kSurface if the point is <= kCarTolerance/2 from a surface, or
419// * kInside otherwise.
420//
421EInside G4TessellatedSolid::Inside (const G4ThreeVector &p) const
422{
423//
424// First the simple test - check if we're outside of the X-Y-Z extremes
425// of the tessellated solid.
426//
427 if ( p.x() < xMinExtent - kCarTolerance ||
428 p.x() > xMaxExtent + kCarTolerance ||
429 p.y() < yMinExtent - kCarTolerance ||
430 p.y() > yMaxExtent + kCarTolerance ||
431 p.z() < zMinExtent - kCarTolerance ||
432 p.z() > zMaxExtent + kCarTolerance )
433 {
434 return kOutside;
435 }
436
437 G4double minDist = kInfinity;
438//
439//
440// Check if we are close to a surface
441//
442 for (FacetCI f=facets.begin(); f!=facets.end(); f++)
443 {
444 G4double dist = (*f)->Distance(p,minDist);
445 if (dist < minDist) minDist = dist;
446 if (dist <= 0.5*kCarTolerance)
447 {
448 return kSurface;
449 }
450 }
451//
452//
453// The following is something of an adaptation of the method implemented by
454// Rickard Holmberg augmented with information from Schneider & Eberly,
455// "Geometric Tools for Computer Graphics," pp700-701, 2003. In essence, we're
456// trying to determine whether we're inside the volume by projecting a few rays
457// and determining if the first surface crossed is has a normal vector between
458// 0 to pi/2 (out-going) or pi/2 to pi (in-going). We should also avoid rays
459// which are nearly within the plane of the tessellated surface, and therefore
460// produce rays randomly. For the moment, this is a bit over-engineered
461// (belt-braces-and-ducttape).
462//
463#if G4SPECSDEBUG
464 G4int nTry = 7;
465#else
466 G4int nTry = 3;
467#endif
468 G4double distOut = kInfinity;
469 G4double distIn = kInfinity;
470 G4double distO = 0.0;
471 G4double distI = 0.0;
472 G4double distFromSurfaceO = 0.0;
473 G4double distFromSurfaceI = 0.0;
474 G4ThreeVector normalO(0.0,0.0,0.0);
475 G4ThreeVector normalI(0.0,0.0,0.0);
476 G4bool crossingO = false;
477 G4bool crossingI = false;
478 EInside location = kOutside;
479 EInside locationprime = kOutside;
480 G4int m = 0;
481
482 for (G4int i=0; i<nTry; i++)
483 {
484 G4bool nearParallel = false;
485 do
486 {
487//
488//
489// We loop until we find direction where the vector is not nearly parallel
490// to the surface of any facet since this causes ambiguities. The usual
491// case is that the angles should be sufficiently different, but there are 20
492// random directions to select from - hopefully sufficient.
493//
494 distOut = kInfinity;
495 distIn = kInfinity;
496 G4ThreeVector v = randir[m];
497 m++;
498 FacetCI f = facets.begin();
499 do
500 {
501//
502//
503// Here we loop through the facets to find out if there is an intersection
504// between the ray and that facet. The test if performed separately whether
505// the ray is entering the facet or exiting.
506//
507 crossingO = ((*f)->Intersect(p,v,true,distO,distFromSurfaceO,normalO));
508 crossingI = ((*f)->Intersect(p,v,false,distI,distFromSurfaceI,normalI));
509 if (crossingO || crossingI)
510 {
511 nearParallel = (crossingO && std::abs(normalO.dot(v))<dirTolerance) ||
512 (crossingI && std::abs(normalI.dot(v))<dirTolerance);
513 if (!nearParallel)
514 {
515 if (crossingO && distO > 0.0 && distO < distOut) distOut = distO;
516 if (crossingI && distI > 0.0 && distI < distIn) distIn = distI;
517 }
518 }
519 } while (!nearParallel && ++f!=facets.end());
520 } while (nearParallel && m!=maxTries);
521
522#ifdef G4VERBOSE
523 if (m == maxTries)
524 {
525//
526//
527// We've run out of random vector directions. If nTries is set sufficiently
528// low (nTries <= 0.5*maxTries) then this would indicate that there is
529// something wrong with geometry.
530//
531 G4cout.precision(16) ;
532 G4cout << G4endl ;
533 G4cout << "Solid name = " << GetName() << G4endl;
534 G4cout << "Geometry Type = " << geometryType << G4endl;
535 G4cout << "Number of facets = " << facets.size() << G4endl;
536 G4cout << "Position:" << G4endl << G4endl ;
537 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
538 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
539 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
540 G4Exception("G4TessellatedSolid::Inside()",
541 "UnknownInsideOutside-MaxTries", JustWarning,
542 "Cannot determine whether point is inside or outside volume!");
543 }
544#endif
545//
546//
547// In the next if-then-elseif string the logic is as follows:
548// (1) You don't hit anything so cannot be inside volume, provided volume
549// constructed correctly!
550// (2) Distance to inside (ie. nearest facet such that you enter facet) is
551// shorter than distance to outside (nearest facet such that you exit
552// facet) - on condition of safety distance - therefore we're outside.
553// (3) Distance to outside is shorter than distance to inside therefore we're
554// inside.
555//
556 if (distIn == kInfinity && distOut == kInfinity)
557 locationprime = kOutside;
558 else if (distIn <= distOut - kCarTolerance*0.5)
559 locationprime = kOutside;
560 else if (distOut <= distIn - kCarTolerance*0.5)
561 locationprime = kInside;
562
563 if (i == 0) { location = locationprime; }
564#ifdef G4VERBOSE
565 else if (locationprime != location)
566 {
567//
568//
569// Different ray directions result in different answer. Seems like the
570// geometry is not constructed correctly.
571//
572 G4cout.precision(16) ;
573 G4cout << G4endl ;
574 G4cout << "Solid name = " << GetName() << G4endl;
575 G4cout << "Geometry Type = " << geometryType << G4endl;
576 G4cout << "Number of facets = " << facets.size() << G4endl;
577 G4cout << "Position:" << G4endl << G4endl ;
578 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
579 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
580 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
581 G4Exception("G4TessellatedSolid::Inside()",
582 "UnknownInsideOutside", JustWarning,
583 "Cannot determine whether point is inside or outside volume!");
584 }
585#endif
586 }
587
588 return location;
589}
590
591///////////////////////////////////////////////////////////////////////////////
592//
593// G4ThreeVector G4TessellatedSolid::SurfaceNormal (const G4ThreeVector &p) const
594//
595// Return the outwards pointing unit normal of the shape for the
596// surface closest to the point at offset p.
597
598G4ThreeVector G4TessellatedSolid::SurfaceNormal (const G4ThreeVector &p) const
599{
600 FacetCI minFacet;
601 G4double minDist = kInfinity;
602 G4double dist = 0.0;
603 G4ThreeVector normal;
604
605 for (FacetCI f=facets.begin(); f!=facets.end(); f++)
606 {
607 dist = (*f)->Distance(p,minDist);
608 if (dist < minDist)
609 {
610 minDist = dist;
611 minFacet = f;
612 }
613 }
614
615 if (minDist != kInfinity)
616 {
617 normal = (*minFacet)->GetSurfaceNormal();
618 }
619 else
620 {
621#ifdef G4VERBOSE
622 G4cout << "WARNING - G4TessellatedSolid::SurfaceNormal(p)" << G4endl
623 << " No facets found for point: " << p << " !" << G4endl
624 << " Returning approximated value for normal." << G4endl;
625 G4Exception("G4TessellatedSolid::SurfaceNormal(p)", "Notification",
626 JustWarning, "Point p is not on surface !?" );
627#endif
628 normal = (p.z()>0 ? G4ThreeVector(0,0,1) : G4ThreeVector(0,0,-1));
629 }
630
631 return normal;
632}
633
634///////////////////////////////////////////////////////////////////////////////
635//
636// G4double DistanceToIn(const G4ThreeVector& p, const G4ThreeVector& v)
637//
638// Return the distance along the normalised vector v to the shape,
639// from the point at offset p. If there is no intersection, return
640// kInfinity. The first intersection resulting from ‘leaving’ a
641// surface/volume is discarded. Hence, this is tolerant of points on
642// surface of shape.
643
644G4double G4TessellatedSolid::DistanceToIn (const G4ThreeVector &p,
645 const G4ThreeVector &v) const
646{
647 G4double minDist = kInfinity;
648 G4double dist = 0.0;
649 G4double distFromSurface = 0.0;
650 G4ThreeVector normal(0.0,0.0,0.0);
651
652#if G4SPECSDEBUG
653 if ( Inside(p) == kInside )
654 {
655 G4cout.precision(16) ;
656 G4cout << G4endl ;
657 // DumpInfo();
658 G4cout << "Position:" << G4endl << G4endl ;
659 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
660 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
661 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
662 G4cout << "DistanceToOut(p) == " << DistanceToOut(p) << G4endl;
663 G4Exception("G4TriangularFacet::DistanceToIn(p,v)", "Notification", JustWarning,
664 "Point p is already inside!?" );
665 }
666#endif
667
668 for (FacetCI f=facets.begin(); f!=facets.end(); f++)
669 {
670 if ((*f)->Intersect(p,v,false,dist,distFromSurface,normal))
671 {
672 if (distFromSurface > 0.5*kCarTolerance && dist >= 0.0 && dist < minDist)
673 {
674 minDist = dist;
675 }
676 }
677 }
678
679 return minDist;
680}
681
682///////////////////////////////////////////////////////////////////////////////
683//
684// G4double DistanceToIn(const G4ThreeVector& p)
685//
686// Calculate distance to nearest surface of shape from an outside point p. The
687// distance can be an underestimate.
688
689G4double G4TessellatedSolid::DistanceToIn (const G4ThreeVector &p) const
690{
691 G4double minDist = kInfinity;
692 G4double dist = 0.0;
693
694#if G4SPECSDEBUG
695 if ( Inside(p) == kInside )
696 {
697 G4cout.precision(16) ;
698 G4cout << G4endl ;
699 // DumpInfo();
700 G4cout << "Position:" << G4endl << G4endl ;
701 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
702 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
703 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
704 G4cout << "DistanceToOut(p) == " << DistanceToOut(p) << G4endl;
705 G4Exception("G4TriangularFacet::DistanceToIn(p)", "Notification", JustWarning,
706 "Point p is already inside!?" );
707 }
708#endif
709
710 for (FacetCI f=facets.begin(); f!=facets.end(); f++)
711 {
712 dist = (*f)->Distance(p,minDist,false);
713 if (dist < minDist) { minDist = dist; }
714 }
715
716 return minDist;
717}
718
719///////////////////////////////////////////////////////////////////////////////
720//
721// G4double DistanceToOut(const G4ThreeVector& p, const G4ThreeVector& v,
722// const G4bool calcNorm=false,
723// G4bool *validNorm=0, G4ThreeVector *n=0);
724//
725// Return distance along the normalised vector v to the shape, from a
726// point at an offset p inside or on the surface of the
727// shape. Intersections with surfaces, when the point is not greater
728// than kCarTolerance/2 from a surface, must be ignored.
729// If calcNorm is true, then it must also set validNorm to either
730// * true, if the solid lies entirely behind or on the exiting
731// surface. Then it must set n to the outwards normal vector
732// (the Magnitude of the vector is not defined).
733// * false, if the solid does not lie entirely behind or on the
734// exiting surface.
735// If calcNorm is false, then validNorm and n are unused.
736
737G4double G4TessellatedSolid::DistanceToOut (const G4ThreeVector &p,
738 const G4ThreeVector &v, const G4bool calcNorm,
739 G4bool *validNorm, G4ThreeVector *n) const
740{
741 G4double minDist = kInfinity;
742 G4double dist = 0.0;
743 G4double distFromSurface = 0.0;
744 G4ThreeVector normal(0.0,0.0,0.0);
745 G4ThreeVector minNormal(0.0,0.0,0.0);
746
747#if G4SPECSDEBUG
748 if ( Inside(p) == kOutside )
749 {
750 G4cout.precision(16) ;
751 G4cout << G4endl ;
752 // DumpInfo();
753 G4cout << "Position:" << G4endl << G4endl ;
754 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
755 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
756 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
757 G4cout << "DistanceToIn(p) == " << DistanceToIn(p) << G4endl;
758 G4Exception("G4TriangularFacet::DistanceToOut(p)", "Notification", JustWarning,
759 "Point p is already outside !?" );
760 }
761#endif
762
763 G4bool isExtreme = false;
764 for (FacetCI f=facets.begin(); f!=facets.end(); f++)
765 {
766 if ((*f)->Intersect(p,v,true,dist,distFromSurface,normal))
767 {
768 if (distFromSurface > 0.0 && distFromSurface <= 0.5*kCarTolerance &&
769 (*f)->Distance(p,kCarTolerance) <= 0.5*kCarTolerance)
770 {
771 // We are on a surface. Return zero.
772 if (calcNorm) {
773 *validNorm = extremeFacets.count(*f);
774 *n = SurfaceNormal(p);
775 }
776 return 0.0;
777 }
778 if (dist >= 0.0 && dist < minDist)
779 {
780 minDist = dist;
781 minNormal = normal;
782 isExtreme = extremeFacets.count(*f);
783 }
784 }
785 }
786
787 if (minDist < kInfinity)
788 {
789 if (calcNorm)
790 {
791 *validNorm = isExtreme;
792 *n = minNormal;
793 }
794 return minDist;
795 }
796 else
797 {
798 // No intersection found
799 if (calcNorm)
800 {
801 *validNorm = false;
802 *n = SurfaceNormal(p);
803 }
804 return 0.0;
805 }
806}
807
808///////////////////////////////////////////////////////////////////////////////
809//
810// G4double DistanceToOut(const G4ThreeVector& p)
811//
812// Calculate distance to nearest surface of shape from an inside
813// point. The distance can be an underestimate.
814
815G4double G4TessellatedSolid::DistanceToOut (const G4ThreeVector &p) const
816{
817 G4double minDist = kInfinity;
818 G4double dist = 0.0;
819
820#if G4SPECSDEBUG
821 if ( Inside(p) == kOutside )
822 {
823 G4cout.precision(16) ;
824 G4cout << G4endl ;
825 // DumpInfo();
826 G4cout << "Position:" << G4endl << G4endl ;
827 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
828 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
829 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
830 G4cout << "DistanceToIn(p) == " << DistanceToIn(p) << G4endl;
831 G4Exception("G4TriangularFacet::DistanceToOut(p)", "Notification", JustWarning,
832 "Point p is already outside !?" );
833 }
834#endif
835
836 for (FacetCI f=facets.begin(); f!=facets.end(); f++)
837 {
838 dist = (*f)->Distance(p,minDist,true);
839 if (dist < minDist) minDist = dist;
840 }
841
842 return minDist;
843}
844
845///////////////////////////////////////////////////////////////////////////////
846//
847// G4GeometryType GetEntityType() const;
848//
849// Provide identification of the class of an object (required for
850// persistency and STEP interface).
851//
852G4GeometryType G4TessellatedSolid::GetEntityType () const
853{
854 return geometryType;
855}
856
857///////////////////////////////////////////////////////////////////////////////
858//
859void G4TessellatedSolid::DescribeYourselfTo (G4VGraphicsScene& scene) const
860{
861 scene.AddSolid (*this);
862}
863
864///////////////////////////////////////////////////////////////////////////////
865//
866// Dispatch to parameterisation for replication mechanism dimension
867// computation & modification.
868//
869//void G4TessellatedSolid::ComputeDimensions (G4VPVParameterisation* p,
870// const G4int n, const G4VPhysicalVolume* pRep) const
871//{
872// G4VSolid *ptr = 0;
873// ptr = *this;
874// p->ComputeDimensions(ptr,n,pRep);
875//}
876
877///////////////////////////////////////////////////////////////////////////////
878//
879std::ostream &G4TessellatedSolid::StreamInfo(std::ostream &os) const
880{
881 os << G4endl;
882 os << "Geometry Type = " << geometryType << G4endl;
883 os << "Number of facets = " << facets.size() << G4endl;
884
885 for (FacetCI f = facets.begin(); f != facets.end(); f++)
886 {
887 os << "FACET # = " << f-facets.begin()+1 << G4endl;
888 (*f)->StreamInfo(os);
889 }
890 os <<G4endl;
891
892 return os;
893}
894
895///////////////////////////////////////////////////////////////////////////////
896//
897G4Polyhedron *G4TessellatedSolid::CreatePolyhedron () const
898{
899 size_t nVertices = vertexList.size();
900 size_t nFacets = facets.size();
901 G4PolyhedronArbitrary *polyhedron =
902 new G4PolyhedronArbitrary (nVertices, nFacets);
903 for (G4ThreeVectorList::const_iterator v = vertexList.begin();
904 v!=vertexList.end(); v++) polyhedron->AddVertex(*v);
905
906 for (FacetCI f=facets.begin(); f != facets.end(); f++)
907 {
908 size_t v[4];
909 for (size_t j=0; j<4; j++)
910 {
911 size_t i = (*f)->GetVertexIndex(j);
912 if (i == 999999999) v[j] = 0;
913 else v[j] = i+1;
914 }
915 if ((*f)->GetEntityType() == "G4RectangularFacet")
916 {
917 size_t i = v[3];
918 v[3] = v[2];
919 v[2] = i;
920 }
921 polyhedron->AddFacet(v[0],v[1],v[2],v[3]);
922 }
923
924 return (G4Polyhedron*) polyhedron;
925}
926
927///////////////////////////////////////////////////////////////////////////////
928//
929G4NURBS *G4TessellatedSolid::CreateNURBS () const
930{
931 return 0;
932}
933
934///////////////////////////////////////////////////////////////////////////////
935//
936// GetPolyhedron
937//
938G4Polyhedron* G4TessellatedSolid::GetPolyhedron () const
939{
940 if (!fpPolyhedron ||
941 fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() !=
942 fpPolyhedron->GetNumberOfRotationSteps())
943 {
944 delete fpPolyhedron;
945 fpPolyhedron = CreatePolyhedron();
946 }
947 return fpPolyhedron;
948}
949
950///////////////////////////////////////////////////////////////////////////////
951//
952// CalculateExtent
953//
954// Based on correction provided by Stan Seibert, University of Texas.
955//
956G4bool
957G4TessellatedSolid::CalculateExtent(const EAxis pAxis,
958 const G4VoxelLimits& pVoxelLimit,
959 const G4AffineTransform& pTransform,
960 G4double& pMin, G4double& pMax) const
961{
962 G4ThreeVectorList transVertexList(vertexList);
963
964 // Put solid into transformed frame
965 for (size_t i=0; i<vertexList.size(); i++)
966 { pTransform.ApplyPointTransform(transVertexList[i]); }
967
968 // Find min and max extent in each dimension
969 G4ThreeVector minExtent(kInfinity, kInfinity, kInfinity);
970 G4ThreeVector maxExtent(-kInfinity, -kInfinity, -kInfinity);
971 for (size_t i=0; i<transVertexList.size(); i++)
972 {
973 for (G4int axis=G4ThreeVector::X; axis < G4ThreeVector::SIZE; axis++)
974 {
975 G4double coordinate = transVertexList[i][axis];
976 if (coordinate < minExtent[axis])
977 { minExtent[axis] = coordinate; }
978 if (coordinate > maxExtent[axis])
979 { maxExtent[axis] = coordinate; }
980 }
981 }
982
983 // Check for containment and clamp to voxel boundaries
984 for (G4int axis=G4ThreeVector::X; axis < G4ThreeVector::SIZE; axis++)
985 {
986 EAxis geomAxis = kXAxis; // G4 geom classes use different index type
987 switch(axis)
988 {
989 case G4ThreeVector::X: geomAxis = kXAxis; break;
990 case G4ThreeVector::Y: geomAxis = kYAxis; break;
991 case G4ThreeVector::Z: geomAxis = kZAxis; break;
992 }
993 G4bool isLimited = pVoxelLimit.IsLimited(geomAxis);
994 G4double voxelMinExtent = pVoxelLimit.GetMinExtent(geomAxis);
995 G4double voxelMaxExtent = pVoxelLimit.GetMaxExtent(geomAxis);
996
997 if (isLimited)
998 {
999 if ( minExtent[axis] > voxelMaxExtent+kCarTolerance ||
1000 maxExtent[axis] < voxelMinExtent-kCarTolerance )
1001 {
1002 return false ;
1003 }
1004 else
1005 {
1006 if (minExtent[axis] < voxelMinExtent)
1007 {
1008 minExtent[axis] = voxelMinExtent ;
1009 }
1010 if (maxExtent[axis] > voxelMaxExtent)
1011 {
1012 maxExtent[axis] = voxelMaxExtent;
1013 }
1014 }
1015 }
1016 }
1017
1018 // Convert pAxis into G4ThreeVector index
1019 G4int vecAxis=0;
1020 switch(pAxis)
1021 {
1022 case kXAxis: vecAxis = G4ThreeVector::X; break;
1023 case kYAxis: vecAxis = G4ThreeVector::Y; break;
1024 case kZAxis: vecAxis = G4ThreeVector::Z; break;
1025 default: break;
1026 }
1027
1028 pMin = minExtent[vecAxis] - kCarTolerance;
1029 pMax = maxExtent[vecAxis] + kCarTolerance;
1030
1031 return true;
1032}
1033
1034///////////////////////////////////////////////////////////////////////////////
1035//
1036G4double G4TessellatedSolid::GetMinXExtent () const
1037 {return xMinExtent;}
1038
1039///////////////////////////////////////////////////////////////////////////////
1040//
1041G4double G4TessellatedSolid::GetMaxXExtent () const
1042 {return xMaxExtent;}
1043
1044///////////////////////////////////////////////////////////////////////////////
1045//
1046G4double G4TessellatedSolid::GetMinYExtent () const
1047 {return yMinExtent;}
1048
1049///////////////////////////////////////////////////////////////////////////////
1050//
1051G4double G4TessellatedSolid::GetMaxYExtent () const
1052 {return yMaxExtent;}
1053
1054///////////////////////////////////////////////////////////////////////////////
1055//
1056G4double G4TessellatedSolid::GetMinZExtent () const
1057 {return zMinExtent;}
1058
1059///////////////////////////////////////////////////////////////////////////////
1060//
1061G4double G4TessellatedSolid::GetMaxZExtent () const
1062 {return zMaxExtent;}
1063
1064///////////////////////////////////////////////////////////////////////////////
1065//
1066G4VisExtent G4TessellatedSolid::GetExtent () const
1067{
1068 return G4VisExtent (xMinExtent, xMaxExtent, yMinExtent, yMaxExtent,
1069 zMinExtent, zMaxExtent);
1070}
1071
1072///////////////////////////////////////////////////////////////////////////////
1073//
1074G4double G4TessellatedSolid::GetCubicVolume ()
1075{
1076 if(cubicVolume != 0.) {;}
1077 else { cubicVolume = G4VSolid::GetCubicVolume(); }
1078 return cubicVolume;
1079}
1080
1081///////////////////////////////////////////////////////////////////////////////
1082//
1083G4double G4TessellatedSolid::GetSurfaceArea ()
1084{
1085 if(surfaceArea != 0.) { return surfaceArea; }
1086
1087 for (FacetI f=facets.begin(); f!=facets.end(); f++)
1088 {
1089 surfaceArea += (*f)->GetArea();
1090 }
1091 return surfaceArea;
1092}
1093
1094///////////////////////////////////////////////////////////////////////////////
1095//
1096G4ThreeVector G4TessellatedSolid::GetPointOnSurface() const
1097{
1098 // Select randomly a facet and return a random point on it
1099
1100 G4int i = CLHEP::RandFlat::shootInt(facets.size());
1101 return facets[i]->GetPointOnFace();
1102}
1103///////////////////////////////////////////////////////////////////////////////
1104//
1105// SetRandomVectorSet
1106//
1107// This is a set of predefined random vectors (if that isn't a contradition
1108// in terms!) used to generate rays from a user-defined point. The member
1109// function Inside uses these to determine whether the point is inside or
1110// outside of the tessellated solid. All vectors should be unit vectors.
1111//
1112void G4TessellatedSolid::SetRandomVectorSet()
1113{
1114 randir[0] = G4ThreeVector(-0.9577428892113370, 0.2732676269591740, 0.0897405271949221);
1115 randir[1] = G4ThreeVector(-0.8331264504940770,-0.5162067214954600,-0.1985722492445700);
1116 randir[2] = G4ThreeVector(-0.1516671651108820, 0.9666292616127460, 0.2064580868390110);
1117 randir[3] = G4ThreeVector( 0.6570250350323190,-0.6944539025883300, 0.2933460081893360);
1118 randir[4] = G4ThreeVector(-0.4820456281280320,-0.6331060000098690,-0.6056474264406270);
1119 randir[5] = G4ThreeVector( 0.7629032554236800, 0.1016854697539910,-0.6384658864065180);
1120 randir[6] = G4ThreeVector( 0.7689540409061150, 0.5034929891988220, 0.3939600142169160);
1121 randir[7] = G4ThreeVector( 0.5765188359255740, 0.5997271636278330,-0.5549354566343150);
1122 randir[8] = G4ThreeVector( 0.6660632777862070,-0.6362809868288380, 0.3892379937580790);
1123 randir[9] = G4ThreeVector( 0.3824415020414780, 0.6541792713761380,-0.6525243125110690);
1124 randir[10] = G4ThreeVector(-0.5107726564526760, 0.6020905056811610, 0.6136760679616570);
1125 randir[11] = G4ThreeVector( 0.7459135439578050, 0.6618796061649330, 0.0743530220183488);
1126 randir[12] = G4ThreeVector( 0.1536405855311580, 0.8117477913978260,-0.5634359711967240);
1127 randir[13] = G4ThreeVector( 0.0744395301705579,-0.8707110101772920,-0.4861286795736560);
1128 randir[14] = G4ThreeVector(-0.1665874645185400, 0.6018553940549240,-0.7810369397872780);
1129 randir[15] = G4ThreeVector( 0.7766902003633100, 0.6014617505959970,-0.1870724331097450);
1130 randir[16] = G4ThreeVector(-0.8710128685847430,-0.1434320216603030,-0.4698551243971010);
1131 randir[17] = G4ThreeVector( 0.8901082092766820,-0.4388411398893870, 0.1229871120030100);
1132 randir[18] = G4ThreeVector(-0.6430417431544370,-0.3295938228697690, 0.6912779675984150);
1133 randir[19] = G4ThreeVector( 0.6331124368380410, 0.6306211461665000, 0.4488714875425340);
1134
1135 maxTries = 20;
1136}
Note: See TracBrowser for help on using the repository browser.