Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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"
41 #include "G4GeometryTolerance.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 //
62 const G4VSolid * G4GeomTestSegment::GetSolid() const { return solid; }
63 
64 const G4ThreeVector &G4GeomTestSegment::GetP() const { return p0; }
65 
66 const 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 //
92 void 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 //
107 void 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 //
266 void 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 }