source: trunk/source/geometry/navigation/src/G4GeomTestSegment.cc @ 1347

Last change on this file since 1347 was 1347, checked in by garnier, 13 years ago

geant4 tag 9.4

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