source: trunk/source/geometry/solids/specific/src/G4TwistTubsSide.cc @ 1315

Last change on this file since 1315 was 1228, checked in by garnier, 14 years ago

update geant4.9.3 tag

File size: 34.9 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: G4TwistTubsSide.cc,v 1.6 2009/11/11 12:23:37 gcosmo Exp $
28// GEANT4 tag $Name: geant4-09-03 $
29//
30//
31// --------------------------------------------------------------------
32// GEANT 4 class source file
33//
34//
35// G4TwistTubsSide.cc
36//
37// Author:
38//   01-Aug-2002 - Kotoyo Hoshina (hoshina@hepburn.s.chiba-u.ac.jp)
39//
40// History:
41//   13-Nov-2003 - O.Link (Oliver.Link@cern.ch), Integration in Geant4
42//                 from original version in Jupiter-2.5.02 application.
43//   29-Apr-2004 - O.Link. Bug fixed in GetAreaCode
44// --------------------------------------------------------------------
45
46#include "G4TwistTubsSide.hh"
47
48//=====================================================================
49//* constructors ------------------------------------------------------
50
51G4TwistTubsSide::G4TwistTubsSide(const G4String         &name,
52                                   const G4RotationMatrix &rot,
53                                   const G4ThreeVector    &tlate,
54                                         G4int             handedness,
55                                   const G4double          kappa,
56                                   const EAxis             axis0,
57                                   const EAxis             axis1,
58                                         G4double          axis0min,
59                                         G4double          axis1min,
60                                         G4double          axis0max,
61                                         G4double          axis1max)
62   : G4VTwistSurface(name, rot, tlate, handedness, axis0, axis1,
63                axis0min, axis1min, axis0max, axis1max),
64     fKappa(kappa)
65{
66   if (axis0 == kZAxis && axis1 == kXAxis) {
67      G4Exception("G4TwistTubsSide::G4TwistTubsSide()", "InvalidSetup",
68                  FatalException, "Should swap axis0 and axis1!");
69   }
70   fIsValidNorm = false;
71   SetCorners();
72   SetBoundaries();
73}
74
75G4TwistTubsSide::G4TwistTubsSide(const G4String     &name,
76                                         G4double      EndInnerRadius[2],
77                                         G4double      EndOuterRadius[2],
78                                         G4double      DPhi,
79                                         G4double      EndPhi[2],
80                                         G4double      EndZ[2], 
81                                         G4double      InnerRadius,
82                                         G4double      OuterRadius,
83                                         G4double      Kappa,
84                                         G4int         handedness)
85  : G4VTwistSurface(name)
86{ 
87   fHandedness = handedness;   // +z = +ve, -z = -ve
88   fAxis[0]    = kXAxis; // in local coordinate system
89   fAxis[1]    = kZAxis;
90   fAxisMin[0] = InnerRadius;  // Inner-hype radius at z=0
91   fAxisMax[0] = OuterRadius;  // Outer-hype radius at z=0
92   fAxisMin[1] = EndZ[0];
93   fAxisMax[1] = EndZ[1];
94
95   fKappa = Kappa;
96   fRot.rotateZ( fHandedness > 0
97                 ? -0.5*DPhi
98                 :  0.5*DPhi );
99   fTrans.set(0, 0, 0);
100   fIsValidNorm = false;
101   
102   SetCorners( EndInnerRadius, EndOuterRadius, EndPhi, EndZ) ;
103   SetBoundaries();
104}
105
106
107//=====================================================================
108//* Fake default constructor ------------------------------------------
109
110G4TwistTubsSide::G4TwistTubsSide( __void__& a )
111  : G4VTwistSurface(a)
112{
113}
114
115
116//=====================================================================
117//* destructor --------------------------------------------------------
118
119G4TwistTubsSide::~G4TwistTubsSide()
120{
121}
122
123//=====================================================================
124//* GetNormal ---------------------------------------------------------
125
126G4ThreeVector G4TwistTubsSide::GetNormal(const G4ThreeVector &tmpxx, 
127                                                G4bool isGlobal) 
128{
129   // GetNormal returns a normal vector at a surface (or very close
130   // to surface) point at tmpxx.
131   // If isGlobal=true, it returns the normal in global coordinate.
132   //
133   G4ThreeVector xx;
134   if (isGlobal) {
135      xx = ComputeLocalPoint(tmpxx);
136      if ((xx - fCurrentNormal.p).mag() < 0.5 * kCarTolerance) {
137         return ComputeGlobalDirection(fCurrentNormal.normal);
138      }
139   } else {
140      xx = tmpxx;
141      if (xx == fCurrentNormal.p) {
142         return fCurrentNormal.normal;
143      }
144   }
145   
146   G4ThreeVector er(1, fKappa * xx.z(), 0);
147   G4ThreeVector ez(0, fKappa * xx.x(), 1);
148   G4ThreeVector normal = fHandedness*(er.cross(ez));
149
150   if (isGlobal) {
151      fCurrentNormal.normal = ComputeGlobalDirection(normal.unit());
152   } else {
153      fCurrentNormal.normal = normal.unit();
154   }
155   return fCurrentNormal.normal;
156}
157
158//=====================================================================
159//* DistanceToSurface -------------------------------------------------
160
161G4int G4TwistTubsSide::DistanceToSurface(const G4ThreeVector &gp,
162                                          const G4ThreeVector &gv,
163                                                G4ThreeVector  gxx[],
164                                                G4double       distance[],
165                                                G4int          areacode[],
166                                                G4bool         isvalid[],
167                                                EValidate      validate)
168{
169   // Coordinate system:
170   //
171   //    The coordinate system is so chosen that the intersection of
172   //    the twisted surface with the z=0 plane coincides with the
173   //    x-axis.
174   //    Rotation matrix from this coordinate system (local system)
175   //    to global system is saved in fRot field.
176   //    So the (global) particle position and (global) velocity vectors,
177   //    p and v, should be rotated fRot.inverse() in order to convert
178   //    to local vectors.
179   //
180   // Equation of a twisted surface:
181   //
182   //    x(rho(z=0), z) = rho(z=0)
183   //    y(rho(z=0), z) = rho(z=0)*K*z
184   //    z(rho(z=0), z) = z
185   //    with
186   //       K = std::tan(fPhiTwist/2)/fZHalfLen
187   //
188   // Equation of a line:
189   //
190   //    gxx = p + t*v
191   //    with
192   //       p = fRot.inverse()*gp 
193   //       v = fRot.inverse()*gv
194   //
195   // Solution for intersection:
196   //
197   //    Required time for crossing is given by solving the
198   //    following quadratic equation:
199   //
200   //       a*t^2 + b*t + c = 0
201   //
202   //    where
203   //
204   //       a = K*v_x*v_z
205   //       b = K*(v_x*p_z + v_z*p_x) - v_y
206   //       c = K*p_x*p_z - p_y
207   //
208   //    Out of the possible two solutions you must choose
209   //    the one that gives a positive rho(z=0).
210   //
211   //
212     
213   fCurStatWithV.ResetfDone(validate, &gp, &gv);
214
215   if (fCurStatWithV.IsDone()) {
216      G4int i;
217      for (i=0; i<fCurStatWithV.GetNXX(); i++) {
218         gxx[i] = fCurStatWithV.GetXX(i);
219         distance[i] = fCurStatWithV.GetDistance(i);
220         areacode[i] = fCurStatWithV.GetAreacode(i);
221         isvalid[i]  = fCurStatWithV.IsValid(i);
222      }
223      return fCurStatWithV.GetNXX();
224   } else {
225      // initialize
226      G4int i;
227      for (i=0; i<2; i++) {
228         distance[i] = kInfinity;
229         areacode[i] = sOutside;
230         isvalid[i]  = false;
231         gxx[i].set(kInfinity, kInfinity, kInfinity);
232      }
233   }
234
235   G4ThreeVector p = ComputeLocalPoint(gp);
236   G4ThreeVector v = ComputeLocalDirection(gv);
237   G4ThreeVector xx[2]; 
238
239
240   //
241   // special case!
242   // p is origin or
243   //
244
245   G4double absvz = std::fabs(v.z());
246
247   if ((absvz < DBL_MIN) && (std::fabs(p.x() * v.y() - p.y() * v.x()) < DBL_MIN)) {
248      // no intersection
249
250      isvalid[0] = false;
251      fCurStat.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
252                                isvalid[0], 0, validate, &gp, &gv);
253      return 0;
254   } 
255   
256   //
257   // special case end
258   //
259
260   
261   G4double a = fKappa * v.x() * v.z();
262   G4double b = fKappa * (v.x() * p.z() + v.z() * p.x()) - v.y();
263   G4double c = fKappa * p.x() * p.z() - p.y();
264   G4double D = b * b - 4 * a * c;             // discriminant
265
266   if (std::fabs(a) < DBL_MIN) {
267      if (std::fabs(b) > DBL_MIN) { 
268
269         // single solution
270
271         distance[0] = - c / b;
272         xx[0]       = p + distance[0]*v;
273         gxx[0]      = ComputeGlobalPoint(xx[0]);
274
275         if (validate == kValidateWithTol) {
276            areacode[0] = GetAreaCode(xx[0]);
277            if (!IsOutside(areacode[0])) {
278               if (distance[0] >= 0) isvalid[0] = true;
279            }
280         } else if (validate == kValidateWithoutTol) {
281            areacode[0] = GetAreaCode(xx[0], false);
282            if (IsInside(areacode[0])) {
283               if (distance[0] >= 0) isvalid[0] = true;
284            }
285         } else { // kDontValidate                       
286            // we must omit x(rho,z) = rho(z=0) < 0
287            if (xx[0].x() > 0) {
288               areacode[0] = sInside;
289               if (distance[0] >= 0) isvalid[0] = true;
290            } else {
291               distance[0] = kInfinity;
292               fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0],
293                                              areacode[0], isvalid[0],
294                                              0, validate, &gp, &gv);
295               return 0;
296            } 
297         }
298                 
299         fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
300                                        isvalid[0], 1, validate, &gp, &gv);
301         return 1;
302
303      } else {
304         // if a=b=0 , v.y=0 and (v.x=0 && p.x=0) or (v.z=0 && p.z=0) .
305         //    if v.x=0 && p.x=0, no intersection unless p is on z-axis
306         //    (in that case, v is paralell to surface).
307         //    if v.z=0 && p.z=0, no intersection unless p is on x-axis
308         //    (in that case, v is paralell to surface).
309         // return distance = infinity.
310
311         fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
312                                        isvalid[0], 0, validate, &gp, &gv);
313
314         return 0;
315      }
316     
317   } else if (D > DBL_MIN) {   
318
319      // double solutions
320
321      D = std::sqrt(D);
322      G4double      factor = 0.5/a;
323      G4double      tmpdist[2] = {kInfinity, kInfinity};
324      G4ThreeVector tmpxx[2];
325      G4int         tmpareacode[2] = {sOutside, sOutside};
326      G4bool        tmpisvalid[2]  = {false, false};
327      G4int i;
328
329      for (i=0; i<2; i++) {
330         G4double bminusD = - b - D;
331
332         // protection against round off error 
333         //G4double protection = 1.0e-6;
334         G4double protection = 0;
335         if ( b * D < 0 && std::fabs(bminusD / D) < protection ) {
336            G4double acovbb = (a*c)/(b*b);
337            tmpdist[i] = - c/b * ( 1 - acovbb * (1 + 2*acovbb));
338         } else { 
339            tmpdist[i] = factor * bminusD;
340         }
341
342         D = -D;
343         tmpxx[i] = p + tmpdist[i]*v;
344         
345         if (validate == kValidateWithTol) {
346            tmpareacode[i] = GetAreaCode(tmpxx[i]);
347            if (!IsOutside(tmpareacode[i])) {
348               if (tmpdist[i] >= 0) tmpisvalid[i] = true;
349               continue;
350            }
351         } else if (validate == kValidateWithoutTol) {
352            tmpareacode[i] = GetAreaCode(tmpxx[i], false);
353            if (IsInside(tmpareacode[i])) {
354               if (tmpdist[i] >= 0) tmpisvalid[i] = true;
355               continue;
356            }
357         } else { // kDontValidate
358            // we must choose x(rho,z) = rho(z=0) > 0
359            if (tmpxx[i].x() > 0) {
360               tmpareacode[i] = sInside;
361               if (tmpdist[i] >= 0) tmpisvalid[i] = true;
362               continue;
363            } else {
364               tmpdist[i] = kInfinity;
365               continue;
366            }                     
367         }
368      }
369     
370      if (tmpdist[0] <= tmpdist[1]) {
371         distance[0] = tmpdist[0];
372         distance[1] = tmpdist[1];
373         xx[0]       = tmpxx[0];
374         xx[1]       = tmpxx[1];
375         gxx[0]      = ComputeGlobalPoint(tmpxx[0]);
376         gxx[1]      = ComputeGlobalPoint(tmpxx[1]);
377         areacode[0] = tmpareacode[0];
378         areacode[1] = tmpareacode[1];
379         isvalid[0]  = tmpisvalid[0];
380         isvalid[1]  = tmpisvalid[1];
381      } else {
382         distance[0] = tmpdist[1];
383         distance[1] = tmpdist[0];
384         xx[0]       = tmpxx[1];
385         xx[1]       = tmpxx[0];
386         gxx[0]      = ComputeGlobalPoint(tmpxx[1]);
387         gxx[1]      = ComputeGlobalPoint(tmpxx[0]);
388         areacode[0] = tmpareacode[1];
389         areacode[1] = tmpareacode[0];
390         isvalid[0]  = tmpisvalid[1];
391         isvalid[1]  = tmpisvalid[0];
392      }
393         
394      fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
395                                     isvalid[0], 2, validate, &gp, &gv);
396      fCurStatWithV.SetCurrentStatus(1, gxx[1], distance[1], areacode[1],
397                                     isvalid[1], 2, validate, &gp, &gv);
398
399      // protection against roundoff error
400
401      for (G4int k=0; k<2; k++) {
402         if (!isvalid[k]) continue;
403
404         G4ThreeVector xxonsurface(xx[k].x(), fKappa * std::fabs(xx[k].x())
405                                              * xx[k].z() , xx[k].z());
406         G4double      deltaY  =  (xx[k] - xxonsurface).mag();
407
408         if ( deltaY > 0.5*kCarTolerance ) {
409
410           G4int maxcount = 10;
411           G4int l;
412           G4double      lastdeltaY = deltaY; 
413           for (l=0; l<maxcount; l++) {
414             G4ThreeVector surfacenormal = GetNormal(xxonsurface); 
415             distance[k] = DistanceToPlaneWithV(p, v, xxonsurface,
416                                                surfacenormal, xx[k]);
417             deltaY      = (xx[k] - xxonsurface).mag();
418             if (deltaY > lastdeltaY) {
419               
420             }
421             gxx[k]      = ComputeGlobalPoint(xx[k]);
422
423               if (deltaY <= 0.5*kCarTolerance) {
424           
425                 break;
426               }
427               xxonsurface.set(xx[k].x(),
428                               fKappa * std::fabs(xx[k].x()) * xx[k].z(),
429                               xx[k].z());
430            }
431            if (l == maxcount) {
432               G4cerr << "ERROR - G4TwistTubsSide::DistanceToSurface(p,v)"
433                      << G4endl
434                      << "        maxloop count " << maxcount << G4endl;
435               G4Exception("G4TwistTubsFlatSide::DistanceToSurface(p,v)",
436                           "InvalidSetup",  FatalException,
437                           "Exceeded maxloop count!");
438            }
439         }
440
441      }
442      return 2;
443   } else {
444      // if D<0, no solution
445      // if D=0, just grazing the surfaces, return kInfinity
446
447      fCurStatWithV.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
448                                     isvalid[0], 0, validate, &gp, &gv);
449
450      return 0;
451   }
452   G4Exception("G4TwistTubsSide::DistanceToSurface(p,v)",
453               "InvalidCondition", FatalException, "Illegal operation !");
454   return 1;
455}
456
457//=====================================================================
458//* DistanceToSurface -------------------------------------------------
459
460G4int G4TwistTubsSide::DistanceToSurface(const G4ThreeVector &gp,
461                                                G4ThreeVector  gxx[],
462                                                G4double       distance[],
463                                                G4int          areacode[])
464{ 
465   fCurStat.ResetfDone(kDontValidate, &gp);
466   G4int i = 0;
467   if (fCurStat.IsDone()) {
468      for (i=0; i<fCurStat.GetNXX(); i++) {
469         gxx[i] = fCurStat.GetXX(i);
470         distance[i] = fCurStat.GetDistance(i);
471         areacode[i] = fCurStat.GetAreacode(i);
472      }
473      return fCurStat.GetNXX();
474   } else {
475      // initialize
476      for (i=0; i<2; i++) {
477         distance[i] = kInfinity;
478         areacode[i] = sOutside;
479         gxx[i].set(kInfinity, kInfinity, kInfinity);
480      }
481   }
482   
483   static const G4double halftol = 0.5 * kCarTolerance; 
484
485   G4ThreeVector  p       = ComputeLocalPoint(gp);
486   G4ThreeVector  xx;
487   G4int          parity  = (fKappa >= 0 ? 1 : -1);
488 
489   //
490   // special case!
491   // If p is on surface, or
492   // p is on z-axis,
493   // return here immediatery.
494   //
495   
496   G4ThreeVector  lastgxx[2];
497   G4double       distfromlast[2];
498   for (i=0; i<2; i++) {
499      lastgxx[i] = fCurStatWithV.GetXX(i);
500      distfromlast[i] = (gp - lastgxx[i]).mag();
501   } 
502
503   if  ((gp - lastgxx[0]).mag() < halftol
504     || (gp - lastgxx[1]).mag() < halftol) { 
505      // last winner, or last poststep point is on the surface.
506      xx = p;
507      distance[0] = 0;
508      gxx[0] = gp;
509
510      G4bool isvalid = true;
511      fCurStat.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
512                             isvalid, 1, kDontValidate, &gp);
513      return 1;
514   }
515         
516   if (p.getRho() == 0) { 
517      // p is on z-axis. Namely, p is on twisted surface (invalid area).
518      // We must return here, however, returning distance to x-minimum
519      // boundary is better than return 0-distance.
520      //
521      G4bool isvalid = true;
522      if (fAxis[0] == kXAxis && fAxis[1] == kZAxis) {
523         distance[0] = DistanceToBoundary(sAxis0 & sAxisMin, xx, p);
524         areacode[0] = sInside;
525      } else {
526         distance[0] = 0;
527         xx.set(0., 0., 0.);
528      }
529      gxx[0] = ComputeGlobalPoint(xx);
530      fCurStat.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
531                                isvalid, 0, kDontValidate, &gp);
532      return 1;
533   } 
534
535   //
536   // special case end
537   //
538
539   // set corner points of quadrangle try area ...
540
541   G4ThreeVector A;  // foot of normal from p to boundary of sAxis0 & sAxisMin
542   G4ThreeVector C;  // foot of normal from p to boundary of sAxis0 & sAxisMax
543   G4ThreeVector B;       // point on boundary sAxis0 & sAxisMax at z = A.z()
544   G4ThreeVector D;       // point on boundary sAxis0 & sAxisMin at z = C.z()
545   G4double      distToA; // distance from p to A
546   G4double      distToC; // distance from p to C
547
548   distToA = DistanceToBoundary(sAxis0 & sAxisMin, A, p);
549   distToC = DistanceToBoundary(sAxis0 & sAxisMax, C, p);
550   
551   // is p.z between a.z and c.z?
552   // p.z must be bracketed a.z and c.z.
553   if (A.z() > C.z()) {
554      if (p.z() > A.z()) {
555         A = GetBoundaryAtPZ(sAxis0 & sAxisMin, p);
556      } else if (p.z() < C.z()) {
557         C = GetBoundaryAtPZ(sAxis0 & sAxisMax, p);
558      }
559   } else {
560      if (p.z() > C.z()) {
561         C = GetBoundaryAtPZ(sAxis0 & sAxisMax, p);
562      } else if (p.z() < A.z()) {
563         A = GetBoundaryAtPZ(sAxis0 & sAxisMin, p);
564      }
565   }
566
567   G4ThreeVector  d[2];     // direction vectors of boundary
568   G4ThreeVector  x0[2];    // foot of normal from line to p
569   G4int          btype[2]; // boundary type
570
571   for (i=0; i<2; i++) {
572      if (i == 0) {
573         GetBoundaryParameters((sAxis0 & sAxisMax), d[i], x0[i], btype[i]);
574         B = x0[i] + ((A.z() - x0[i].z()) / d[i].z()) * d[i]; 
575         // x0 + t*d , d is direction unit vector.
576      } else {
577         GetBoundaryParameters((sAxis0 & sAxisMin), d[i], x0[i], btype[i]);
578         D = x0[i] + ((C.z() - x0[i].z()) / d[i].z()) * d[i]; 
579      }
580   }
581
582   // In order to set correct diagonal, swap A and D, C and B if needed. 
583   G4ThreeVector pt(p.x(), p.y(), 0.);
584   G4double      rc = std::fabs(p.x());
585   G4ThreeVector surfacevector(rc, rc * fKappa * p.z(), 0.); 
586   G4int         pside = AmIOnLeftSide(pt, surfacevector); 
587   G4double      test  = (A.z() - C.z()) * parity * pside; 
588
589   if (test == 0) {
590      if (pside == 0) {
591         // p is on surface.
592         xx = p;
593         distance[0] = 0;
594         gxx[0] = gp;
595
596         G4bool isvalid = true;
597         fCurStat.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
598                                isvalid, 1, kDontValidate, &gp);
599         return 1;
600      } else {
601         // A.z = C.z(). return distance to line.
602         d[0] = C - A;
603         distance[0] = DistanceToLine(p, A, d[0], xx);
604         areacode[0] = sInside;
605         gxx[0] = ComputeGlobalPoint(xx);
606         G4bool isvalid = true;
607         fCurStat.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
608                                isvalid, 1, kDontValidate, &gp);
609         return 1;
610      } 
611
612   } else if (test < 0) {
613
614      // wrong diagonal. vector AC is crossing the surface! 
615      // swap A and D, C and B
616      G4ThreeVector tmp;
617      tmp = A;
618      A = D;
619      D = tmp;
620      tmp = C;
621      C = B;
622      B = tmp; 
623
624   } else {
625      // correct diagonal. nothing to do. 
626   }
627
628   // Now, we chose correct diaglnal.
629   // First try. divide quadrangle into double triangle by diagonal and
630   // calculate distance to both surfaces.
631
632   G4ThreeVector xxacb;   // foot of normal from plane ACB to p
633   G4ThreeVector nacb;    // normal of plane ACD
634   G4ThreeVector xxcad;   // foot of normal from plane CAD to p
635   G4ThreeVector ncad;    // normal of plane CAD
636   G4ThreeVector AB(A.x(), A.y(), 0);
637   G4ThreeVector DC(C.x(), C.y(), 0);
638
639   G4double distToACB = G4VTwistSurface::DistanceToPlane(p, A, C-A, AB, xxacb, nacb) * parity;
640   G4double distToCAD = G4VTwistSurface::DistanceToPlane(p, C, C-A, DC, xxcad, ncad) * parity;
641
642   // if calculated distance = 0, return 
643
644   if (std::fabs(distToACB) <= halftol || std::fabs(distToCAD) <= halftol) {
645      xx = (std::fabs(distToACB) < std::fabs(distToCAD) ? xxacb : xxcad); 
646      areacode[0] = sInside;
647      gxx[0] = ComputeGlobalPoint(xx);
648      distance[0] = 0;
649      G4bool isvalid = true;
650      fCurStat.SetCurrentStatus(0, gxx[0], distance[0] , areacode[0],
651                                isvalid, 1, kDontValidate, &gp);
652      return 1;
653   }
654   
655   if (distToACB * distToCAD > 0 && distToACB < 0) {
656      // both distToACB and distToCAD are negative.
657      // divide quadrangle into double triangle by diagonal
658      G4ThreeVector normal;
659      distance[0] = DistanceToPlane(p, A, B, C, D, parity, xx, normal);
660   } else {
661      if (distToACB * distToCAD > 0) {
662         // both distToACB and distToCAD are positive.
663         // Take smaller one.
664         if (distToACB <= distToCAD) {
665            distance[0] = distToACB;
666            xx   = xxacb;
667         } else {
668            distance[0] = distToCAD;
669            xx   = xxcad;
670         }
671      } else {
672         // distToACB * distToCAD is negative.
673         // take positive one
674         if (distToACB > 0) {
675            distance[0] = distToACB;
676            xx   = xxacb;
677         } else {
678            distance[0] = distToCAD;
679            xx   = xxcad;
680         }
681      }
682     
683   }
684   areacode[0] = sInside;
685   gxx[0]      = ComputeGlobalPoint(xx);
686   G4bool isvalid = true;
687   fCurStat.SetCurrentStatus(0, gxx[0], distance[0], areacode[0],
688                             isvalid, 1, kDontValidate, &gp);
689   return 1;
690}
691
692//=====================================================================
693//* DistanceToPlane ---------------------------------------------------
694
695G4double G4TwistTubsSide::DistanceToPlane(const G4ThreeVector &p,
696                                           const G4ThreeVector &A,
697                                           const G4ThreeVector &B,
698                                           const G4ThreeVector &C,
699                                           const G4ThreeVector &D,
700                                           const G4int          parity,
701                                                 G4ThreeVector &xx,
702                                                 G4ThreeVector &n)
703{
704   static const G4double halftol = 0.5 * kCarTolerance;
705   
706   G4ThreeVector M = 0.5*(A + B);
707   G4ThreeVector N = 0.5*(C + D);
708   G4ThreeVector xxanm;  // foot of normal from p to plane ANM
709   G4ThreeVector nanm;   // normal of plane ANM
710   G4ThreeVector xxcmn;  // foot of normal from p to plane CMN
711   G4ThreeVector ncmn;   // normal of plane CMN
712
713   G4double distToanm = G4VTwistSurface::DistanceToPlane(p, A, (N - A), (M - A), xxanm, nanm) * parity;
714   G4double distTocmn = G4VTwistSurface::DistanceToPlane(p, C, (M - C), (N - C), xxcmn, ncmn) * parity;
715
716   // if p is behind of both surfaces, abort.
717   if (distToanm * distTocmn > 0 && distToanm < 0) {
718     G4Exception("G4TwistTubsSide::DistanceToPlane()",
719                 "InvalidCondition", FatalException,
720                 "Point p is behind the surfaces.");
721   }
722
723   // if p is on surface, return 0.
724   if (std::fabs(distToanm) <= halftol) {
725      xx = xxanm;
726      n  = nanm * parity;
727      return 0;
728   } else if (std::fabs(distTocmn) <= halftol) {
729      xx = xxcmn;
730      n  = ncmn * parity;
731      return 0;
732   }
733   
734   if (distToanm <= distTocmn) {
735      if (distToanm > 0) {
736         // both distanses are positive. take smaller one.
737         xx = xxanm;
738         n  = nanm * parity;
739         return distToanm;
740      } else {
741         // take -ve distance and call the function recursively.
742         return DistanceToPlane(p, A, M, N, D, parity, xx, n);
743      }
744   } else {
745      if (distTocmn > 0) {
746         // both distanses are positive. take smaller one.
747         xx = xxcmn;
748         n  = ncmn * parity;
749         return distTocmn;
750      } else {
751         // take -ve distance and call the function recursively.
752         return DistanceToPlane(p, C, N, M, B, parity, xx, n);
753      }
754   }
755}
756
757//=====================================================================
758//* GetAreaCode -------------------------------------------------------
759
760G4int G4TwistTubsSide::GetAreaCode(const G4ThreeVector &xx, 
761                                          G4bool withTol)
762{
763   // We must use the function in local coordinate system.
764   // See the description of DistanceToSurface(p,v).
765   
766   static const G4double ctol = 0.5 * kCarTolerance;
767   G4int areacode = sInside;
768   
769   if (fAxis[0] == kXAxis && fAxis[1] == kZAxis) {
770      G4int xaxis = 0;
771      G4int zaxis = 1;
772     
773      if (withTol) {
774
775         G4bool isoutside   = false;
776
777         // test boundary of xaxis
778
779         if (xx.x() < fAxisMin[xaxis] + ctol) {
780            areacode |= (sAxis0 & (sAxisX | sAxisMin)) | sBoundary; 
781            if (xx.x() <= fAxisMin[xaxis] - ctol) isoutside = true;
782
783         } else if (xx.x() > fAxisMax[xaxis] - ctol) {
784            areacode |= (sAxis0 & (sAxisX | sAxisMax)) | sBoundary;
785            if (xx.x() >= fAxisMax[xaxis] + ctol)  isoutside = true;
786         }
787
788         // test boundary of z-axis
789
790         if (xx.z() < fAxisMin[zaxis] + ctol) {
791            areacode |= (sAxis1 & (sAxisZ | sAxisMin)); 
792
793            if   (areacode & sBoundary) areacode |= sCorner;  // xx is on the corner.
794            else                        areacode |= sBoundary;
795            if (xx.z() <= fAxisMin[zaxis] - ctol) isoutside = true;
796
797         } else if (xx.z() > fAxisMax[zaxis] - ctol) {
798            areacode |= (sAxis1 & (sAxisZ | sAxisMax));
799
800            if   (areacode & sBoundary) areacode |= sCorner;  // xx is on the corner.
801            else                        areacode |= sBoundary; 
802            if (xx.z() >= fAxisMax[zaxis] + ctol) isoutside = true;
803         }
804
805         // if isoutside = true, clear inside bit.             
806         // if not on boundary, add axis information.             
807         
808         if (isoutside) {
809            G4int tmpareacode = areacode & (~sInside);
810            areacode = tmpareacode;
811         } else if ((areacode & sBoundary) != sBoundary) {
812            areacode |= (sAxis0 & sAxisX) | (sAxis1 & sAxisZ);
813         }           
814         
815      } else {
816
817         // boundary of x-axis
818
819         if (xx.x() < fAxisMin[xaxis] ) {
820            areacode |= (sAxis0 & (sAxisX | sAxisMin)) | sBoundary;
821         } else if (xx.x() > fAxisMax[xaxis]) {
822            areacode |= (sAxis0 & (sAxisX | sAxisMax)) | sBoundary;
823         }
824         
825         // boundary of z-axis
826
827         if (xx.z() < fAxisMin[zaxis]) {
828            areacode |= (sAxis1 & (sAxisZ | sAxisMin));
829            if   (areacode & sBoundary) areacode |= sCorner;  // xx is on the corner.
830            else                        areacode |= sBoundary; 
831           
832         } else if (xx.z() > fAxisMax[zaxis]) {
833            areacode |= (sAxis1 & (sAxisZ | sAxisMax)) ;
834            if   (areacode & sBoundary) areacode |= sCorner;  // xx is on the corner.
835            else                        areacode |= sBoundary; 
836         }
837
838         if ((areacode & sBoundary) != sBoundary) {
839            areacode |= (sAxis0 & sAxisX) | (sAxis1 & sAxisZ);
840         }           
841      }
842      return areacode;
843   } else {
844      G4Exception("G4TwistTubsSide::GetAreaCode()",
845                  "NotImplemented", FatalException,
846                  "Feature NOT implemented !");
847   }
848   return areacode;
849}
850
851//=====================================================================
852//* SetCorners( arglist ) -------------------------------------------------
853
854void G4TwistTubsSide::SetCorners(
855                                  G4double      endInnerRad[2],
856                                  G4double      endOuterRad[2],
857                                  G4double      endPhi[2],
858                                  G4double      endZ[2])
859{
860   // Set Corner points in local coodinate.   
861
862   if (fAxis[0] == kXAxis && fAxis[1] == kZAxis) {
863   
864      G4int zmin = 0 ;  // at -ve z
865      G4int zmax = 1 ;  // at +ve z
866
867      G4double x, y, z;
868     
869      // corner of Axis0min and Axis1min
870      x = endInnerRad[zmin]*std::cos(endPhi[zmin]);
871      y = endInnerRad[zmin]*std::sin(endPhi[zmin]);
872      z = endZ[zmin];
873      SetCorner(sC0Min1Min, x, y, z);
874     
875      // corner of Axis0max and Axis1min
876      x = endOuterRad[zmin]*std::cos(endPhi[zmin]);
877      y = endOuterRad[zmin]*std::sin(endPhi[zmin]);
878      z = endZ[zmin];
879      SetCorner(sC0Max1Min, x, y, z);
880     
881      // corner of Axis0max and Axis1max
882      x = endOuterRad[zmax]*std::cos(endPhi[zmax]);
883      y = endOuterRad[zmax]*std::sin(endPhi[zmax]);
884      z = endZ[zmax];
885      SetCorner(sC0Max1Max, x, y, z);
886     
887      // corner of Axis0min and Axis1max
888      x = endInnerRad[zmax]*std::cos(endPhi[zmax]);
889      y = endInnerRad[zmax]*std::sin(endPhi[zmax]);
890      z = endZ[zmax];
891      SetCorner(sC0Min1Max, x, y, z);
892
893   } else {
894      G4cerr << "ERROR - G4TwistTubsFlatSide::SetCorners()" << G4endl
895             << "        fAxis[0] = " << fAxis[0] << G4endl
896             << "        fAxis[1] = " << fAxis[1] << G4endl;
897      G4Exception("G4TwistTubsSide::SetCorners()",
898                  "NotImplemented", FatalException,
899                  "Feature NOT implemented !");
900   }
901}
902
903//=====================================================================
904//* SetCorners() ------------------------------------------------------
905
906void G4TwistTubsSide::SetCorners()
907{
908   G4Exception("G4TwistTubsSide::SetCorners()",
909               "NotImplemented", FatalException,
910               "Method NOT implemented !");
911}
912
913//=====================================================================
914//* SetBoundaries() ---------------------------------------------------
915
916void G4TwistTubsSide::SetBoundaries()
917{
918   // Set direction-unit vector of boundary-lines in local coodinate.
919   //   
920   G4ThreeVector direction;
921   
922   if (fAxis[0] == kXAxis && fAxis[1] == kZAxis) {
923     
924      // sAxis0 & sAxisMin
925      direction = GetCorner(sC0Min1Max) - GetCorner(sC0Min1Min);
926      direction = direction.unit();
927      SetBoundary(sAxis0 & (sAxisX | sAxisMin), direction, 
928                  GetCorner(sC0Min1Min), sAxisZ) ;
929     
930      // sAxis0 & sAxisMax
931      direction = GetCorner(sC0Max1Max) - GetCorner(sC0Max1Min);
932      direction = direction.unit();
933      SetBoundary(sAxis0 & (sAxisX | sAxisMax), direction, 
934                  GetCorner(sC0Max1Min), sAxisZ);
935                 
936      // sAxis1 & sAxisMin
937      direction = GetCorner(sC0Max1Min) - GetCorner(sC0Min1Min);
938      direction = direction.unit();
939      SetBoundary(sAxis1 & (sAxisZ | sAxisMin), direction, 
940                  GetCorner(sC0Min1Min), sAxisX);
941                 
942      // sAxis1 & sAxisMax
943      direction = GetCorner(sC0Max1Max) - GetCorner(sC0Min1Max);
944      direction = direction.unit();
945      SetBoundary(sAxis1 & (sAxisZ | sAxisMax), direction, 
946                  GetCorner(sC0Min1Max), sAxisX);
947                 
948   } else {
949      G4cerr << "ERROR - G4TwistTubsFlatSide::SetBoundaries()" << G4endl
950             << "        fAxis[0] = " << fAxis[0] << G4endl
951             << "        fAxis[1] = " << fAxis[1] << G4endl;
952      G4Exception("G4TwistTubsSide::SetCorners()",
953                  "NotImplemented", FatalException,
954                  "Feature NOT implemented !");
955   }
956}
957
958//=====================================================================
959//* GetFacets() -------------------------------------------------------
960
961void G4TwistTubsSide::GetFacets( G4int m, G4int n, G4double xyz[][3],
962                                 G4int faces[][4], G4int iside ) 
963{
964
965  G4double z ;     // the two parameters for the surface equation
966  G4double x,xmin,xmax ;
967
968  G4ThreeVector p ;  // a point on the surface, given by (z,u)
969
970  G4int nnode ;
971  G4int nface ;
972
973  // calculate the (n-1)*(m-1) vertices
974
975  G4int i,j ;
976
977  for ( i = 0 ; i<n ; i++ )
978  {
979
980    z = fAxisMin[1] + i*(fAxisMax[1]-fAxisMin[1])/(n-1) ;
981
982    for ( j = 0 ; j<m ; j++ ) {
983
984      nnode = GetNode(i,j,m,n,iside) ;
985
986      xmin = GetBoundaryMin(z) ; 
987      xmax = GetBoundaryMax(z) ;
988
989      if (fHandedness < 0) { 
990        x = xmin + j*(xmax-xmin)/(m-1) ;
991      } else {               
992        x = xmax - j*(xmax-xmin)/(m-1) ;
993      }
994
995      p = SurfacePoint(x,z,true) ;  // surface point in global coord.system
996
997      xyz[nnode][0] = p.x() ;
998      xyz[nnode][1] = p.y() ;
999      xyz[nnode][2] = p.z() ;
1000
1001      if ( i<n-1 && j<m-1 ) {   // clock wise filling
1002       
1003        nface = GetFace(i,j,m,n,iside) ;
1004
1005        faces[nface][0] = GetEdgeVisibility(i,j,m,n,0,1) * ( GetNode(,,m,n,iside)+1) ; 
1006        faces[nface][1] = GetEdgeVisibility(i,j,m,n,1,1) * ( GetNode(i+1,,m,n,iside)+1) ;
1007        faces[nface][2] = GetEdgeVisibility(i,j,m,n,2,1) * ( GetNode(i+1,j+1,m,n,iside)+1) ;
1008        faces[nface][3] = GetEdgeVisibility(i,j,m,n,3,1) * ( GetNode(,j+1,m,n,iside)+1) ;
1009
1010      }
1011    }
1012  }
1013}
Note: See TracBrowser for help on using the repository browser.