Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
G4GeomTestSegment.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//
27// $Id$
28//
29// --------------------------------------------------------------------
30// GEANT 4 class source file
31//
32// G4GeomTestSegment
33//
34// Author: D.C.Williams, UCSC (davidw@scipp.ucsc.edu)
35// --------------------------------------------------------------------
36
37#include "G4GeomTestSegment.hh"
38
39#include "G4VSolid.hh"
40#include "G4GeomTestLogger.hh"
42
43//
44// Constructor
45//
47 const G4ThreeVector &theP,
48 const G4ThreeVector &theV,
49 G4GeomTestLogger *logger )
50 : solid(theSolid),
51 p0(theP),
52 v(theV)
53{
55 FindPoints(logger);
56}
57
58
59//
60// Simple accessors
61//
62const G4VSolid * G4GeomTestSegment::GetSolid() const { return solid; }
63
64const G4ThreeVector &G4GeomTestSegment::GetP() const { return p0; }
65
66const G4ThreeVector &G4GeomTestSegment::GetV() const { return v; }
67
68
69//
70// Return number points
71//
73{
74 return points.size();
75}
76
77
78//
79// Return ith point
80//
82{
83 return points[i];
84}
85
86
87//
88// FindPoints
89//
90// Do the dirty work
91//
92void G4GeomTestSegment::FindPoints( G4GeomTestLogger *logger )
93{
94 FindSomePoints( logger, true );
95 FindSomePoints( logger, false );
96
97 PatchInconsistencies( logger );
98}
99
100
101//
102// PatchInconsistencies
103//
104// Search for inconsistancies in the hit list and patch
105// them up, if possible
106//
107void G4GeomTestSegment::PatchInconsistencies( G4GeomTestLogger *logger )
108{
109 if (points.size() == 0) return;
110
111 //
112 // Sort
113 //
114 std::sort( points.begin(), points.end() );
115
116 //
117 // Loop over entering/leaving pairs
118 //
119 std::vector<G4GeomTestPoint>::iterator curr = points.begin();
120 do {
121
122 std::vector<G4GeomTestPoint>::iterator next = curr + 1;
123
124 //
125 // Is the next point close by?
126 //
127 while (next != points.end() &&
128 next->GetDistance()-curr->GetDistance() < kCarTolerance) {
129 //
130 // Yup. If we have an entering/leaving pair, all is okay
131 //
132 if (next->Entering() != curr->Entering()) {
133 curr = next + 1;
134 next = curr + 1;
135
136 break;
137 }
138
139 //
140 // Otherwise, they are duplicate, and just delete one
141 //
142 next = points.erase(next);
143 curr = next - 1;
144
145 }
146
147 if (curr == points.end()) break;
148
149 //
150 // The next point should be entering...
151 //
152
153 if (!curr->Entering()) {
154 //
155 // Point is out of sequence:
156 // Test solid just before this point
157 //
158 G4double ds = curr->GetDistance();
159 G4ThreeVector p = p0 + ds*v;
160
161 G4ThreeVector p1 = p - 10*kCarTolerance*v;
162
163 if (solid->Inside(p1) == kOutside||(solid->Inside(p1)== kSurface)) {
164 //
165 // We are missing an entrance point near the current
166 // point. Add one.
167 //
168 curr = points.insert(curr, G4GeomTestPoint( p, ds, true ) );
169 ++curr;
170 break;
171 }
172
173 //
174 // Test solid just after last point
175 //
176 if (curr != points.begin()) {
177 std::vector<G4GeomTestPoint>::iterator prev = curr - 1;
178
179 ds = prev->GetDistance();
180 p = p0 + ds*v;
181
182 p1 = p + 10*kCarTolerance*v;
183 if ((solid->Inside(p1) == kOutside)||(solid->Inside(p1)== kSurface)) {
184
185 //
186 // We are missing an entrance point near the previous
187 // point. Add one.
188 //
189 curr = points.insert(curr, G4GeomTestPoint( p, ds, true ) );
190 ++curr;
191 break;
192 }
193 }
194
195 //
196 // Oh oh. No solution. Delete the current point and complain.
197 //
198 logger->SolidProblem( solid, "Spurious exiting intersection point", p );
199 curr = points.erase(curr);
200 break;
201 }
202
203 //
204 // The following point should be leaving
205 //
206
207 if (next == points.end() || next->Entering() ) {
208 //
209 // But is missing. Check immediately after this point.
210 //
211 G4double ds = curr->GetDistance();
212 G4ThreeVector p = p0 + ds*v;
213 G4ThreeVector p1 = p + 10*kCarTolerance*v;
214
215 if (solid->Inside(p1) == kOutside) {
216 //
217 // We are missing an exit point near the current
218 // point. Add one.
219 //
220 curr = points.insert(next, G4GeomTestPoint( p, ds, false ) );
221 break;
222 }
223
224 if (next != points.end()) {
225 //
226 // Check just before next point
227 //
228 ds = next->GetDistance();
229 p = p0 + ds*v;
230 p1 = p - 10*kCarTolerance*v;
231 if (solid->Inside(p1) == kOutside) {
232 //
233 // We are missing an exit point before the next
234 // point. Add one.
235 //
236 curr = points.insert(next, G4GeomTestPoint( p, ds, false ) );
237 break;
238 }
239 }
240
241 //
242 // Oh oh. Hanging entering point. Delete and complain.
243 //
244 logger->SolidProblem( solid, "Spurious entering intersection point", p );
245 curr = points.erase(curr);
246 }
247
248 if(curr!=points.end()){curr = next + 1;}
249
250 } while( curr != points.end() );
251
252 //
253 // Double check
254 //
255 if (points.size()&1)
256 logger->SolidProblem( solid,
257 "Solid has odd number of intersection points", p0 );
258
259 return;
260}
261
262
263//
264// Find intersections either in front or behind the point
265//
266void G4GeomTestSegment::FindSomePoints( G4GeomTestLogger *logger,
267 G4bool forward )
268{
269 G4double sign = forward ? +1 : -1;
270
271 G4ThreeVector p(p0);
272 G4ThreeVector vSearch(sign*v);
273 G4double ds(0);
274 G4bool entering;
275 G4double vSurfN;
276
277 // Look for nearest intersection point in the specified
278 // direction and return if there isn't one
279 //
280 G4double dist;
281 switch(solid->Inside(p)) {
282 case kInside:
283 dist = solid->DistanceToOut(p,vSearch);
284 if (dist >= kInfinity) {
285 logger->SolidProblem( solid,
286 "DistanceToOut(p,v) = kInfinity for point inside", p );
287 return;
288 }
289 ds += sign*dist;
290 entering = false;
291 break;
292 case kOutside:
293 dist = solid->DistanceToIn(p,vSearch);
294 if (dist >= kInfinity) return;
295 ds += sign*dist;
296 entering = true;
297 break;
298 case kSurface:
299 vSurfN=v.dot(solid->SurfaceNormal(p));
300 if(std::fabs(vSurfN)<kCarTolerance)vSurfN=0;
301 entering = (vSurfN < 0);
302 break;
303 default:
304 logger->SolidProblem( solid,
305 "Inside returns illegal enumerated value", p );
306 return;
307 }
308
309 //
310 // Loop
311 //
312 // nzero = the number of consecutive zeros
313 //
314 G4int nzero=0;
315
316 for(;;) {
317 //
318 // Locate point
319 //
320 p = p0 + ds*v;
321
322 if (nzero > 2) {
323 //
324 // Oops. In a loop. Probably along a spherical or cylindrical surface.
325 // Let's give the tool a little help with a push
326 //
327 G4double push = 1E-6;
328 ds += sign*push;
329 for(;;) {
330 p = p0 + ds*v;
331 EInside inside = solid->Inside(p);
332 if (inside == kInside) {
333 entering = true;
334 break;
335 }
336 else if (inside == kOutside) {
337 entering = false;
338 break;
339 }
340
341 push = 2*push;
342 if (push > 0.1) {
343 logger->SolidProblem( solid,
344 "Push fails to fix geometry inconsistency", p );
345 return;
346 }
347 ds += sign*push;
348 }
349 }
350 else {
351
352 //
353 // Record point
354 //
355 points.push_back( G4GeomTestPoint( p, ds, entering==forward ) );
356
357 }
358
359 //
360 // Find next intersection
361 //
362 if (entering) {
363 dist = solid->DistanceToOut(p,vSearch);
364 if (dist >= kInfinity) {
365 logger->SolidProblem( solid,
366 "DistanceToOut(p,v) = kInfinity for point inside", p );
367 return;
368 }
369
370 if ( (dist > kCarTolerance)
371 && (solid->Inside(p + (dist*0.999)*vSearch) == kOutside) ) {
372 //
373 // This shouldn't have happened
374 //
375 if (solid->Inside(p) == kOutside)
376 logger->SolidProblem(solid,
377 "Entering point is outside (possible roundoff error)",p);
378 else
379 logger->SolidProblem(solid,
380 "DistanceToOut(p,v) brings trajectory well outside solid",p);
381 return;
382 }
383
384 entering = false;
385 }
386 else {
387 dist = solid->DistanceToIn(p,vSearch);
388 if (dist >= kInfinity) return;
389
390 if ( (dist > kCarTolerance)
391 && (solid->Inside(p + (dist*0.999)*vSearch) == kInside) ) {
392 //
393 // This shouldn't have happened
394 //
395 if (solid->Inside(p) == kInside)
396 logger->SolidProblem(solid,
397 "Exiting point is inside (possible roundoff error)", p);
398 else
399 logger->SolidProblem(solid,
400 "DistanceToIn(p,v) brings trajectory well inside solid", p);
401 return;
402 }
403
404 entering = true;
405 }
406
407 //
408 // Update ds
409 //
410 if (dist <= 0) {
411 nzero++;
412 }
413 else {
414 nzero=0;
415 ds += sign*dist;
416 }
417 }
418}
double G4double
Definition: G4Types.hh:64
int G4int
Definition: G4Types.hh:66
bool G4bool
Definition: G4Types.hh:67
virtual void SolidProblem(const G4VSolid *solid, const G4String &message, const G4ThreeVector &point)=0
G4int GetNumberPoints() const
const G4ThreeVector & GetV() const
const G4VSolid * GetSolid() const
const G4ThreeVector & GetP() const
G4GeomTestSegment(const G4VSolid *theSolid, const G4ThreeVector &theP, const G4ThreeVector &theV, G4GeomTestLogger *logger)
const G4GeomTestPoint & GetPoint(G4int i) const
G4double GetSurfaceTolerance() const
static G4GeometryTolerance * GetInstance()
virtual EInside Inside(const G4ThreeVector &p) const =0
virtual G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=0, G4ThreeVector *n=0) const =0
virtual G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const =0
virtual G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const =0
EInside
Definition: geomdefs.hh:58
@ kInside
Definition: geomdefs.hh:58
@ kOutside
Definition: geomdefs.hh:58
@ kSurface
Definition: geomdefs.hh:58
G4int sign(T t)