G4ReduciblePolygon.cc

Go to the documentation of this file.
00001 //
00002 // ********************************************************************
00003 // * License and Disclaimer                                           *
00004 // *                                                                  *
00005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
00006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
00007 // * conditions of the Geant4 Software License,  included in the file *
00008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
00009 // * include a list of copyright holders.                             *
00010 // *                                                                  *
00011 // * Neither the authors of this software system, nor their employing *
00012 // * institutes,nor the agencies providing financial support for this *
00013 // * work  make  any representation or  warranty, express or implied, *
00014 // * regarding  this  software system or assume any liability for its *
00015 // * use.  Please see the license in the file  LICENSE  and URL above *
00016 // * for the full disclaimer and the limitation of liability.         *
00017 // *                                                                  *
00018 // * This  code  implementation is the result of  the  scientific and *
00019 // * technical work of the GEANT4 collaboration.                      *
00020 // * By using,  copying,  modifying or  distributing the software (or *
00021 // * any work based  on the software)  you  agree  to acknowledge its *
00022 // * use  in  resulting  scientific  publications,  and indicate your *
00023 // * acceptance of all terms of the Geant4 Software license.          *
00024 // ********************************************************************
00025 //
00026 //
00027 // $Id: G4ReduciblePolygon.cc 67011 2013-01-29 16:17:41Z gcosmo $
00028 //
00029 // 
00030 // --------------------------------------------------------------------
00031 // GEANT 4 class source file
00032 //
00033 //
00034 // G4ReduciblePolygon.cc
00035 //
00036 // Implementation of a utility class used to specify, test, reduce,
00037 // and/or otherwise manipulate a 2D polygon.
00038 //
00039 // See G4ReduciblePolygon.hh for more info.
00040 //
00041 // --------------------------------------------------------------------
00042 
00043 #include "G4ReduciblePolygon.hh"
00044 #include "globals.hh"
00045 
00046 //
00047 // Constructor: with simple arrays
00048 //
00049 G4ReduciblePolygon::G4ReduciblePolygon( const G4double a[],
00050                                         const G4double b[],
00051                                               G4int n )
00052   : aMin(0.), aMax(0.), bMin(0.), bMax(0.),
00053     vertexHead(0)
00054 {
00055   //
00056   // Do all of the real work in Create
00057   //
00058   Create( a, b, n );
00059 }
00060 
00061 
00062 //
00063 // Constructor: special PGON/PCON case
00064 //
00065 G4ReduciblePolygon::G4ReduciblePolygon( const G4double rmin[],
00066                                         const G4double rmax[], 
00067                                         const G4double z[], G4int n )
00068   : aMin(0.), aMax(0.), bMin(0.), bMax(0.),
00069     vertexHead(0)
00070 {
00071   //
00072   // Translate
00073   //
00074   G4double *a = new G4double[n*2];
00075   G4double *b = new G4double[n*2];
00076   
00077   G4double *rOut = a + n,
00078            *zOut = b + n,
00079             *rIn = rOut-1,
00080             *zIn = zOut-1;
00081   
00082   G4int i;   
00083   for( i=0; i < n; i++, rOut++, zOut++, rIn--, zIn-- )
00084   {
00085     *rOut = rmax[i];
00086     *rIn  = rmin[i];
00087     *zOut = *zIn = z[i];
00088   }
00089   
00090   Create( a, b, n*2 );
00091   
00092   delete [] a;
00093   delete [] b;
00094 }
00095 
00096 
00097 //
00098 // Create
00099 //
00100 // To be called by constructors, fill in the list and statistics for a new
00101 // polygon
00102 //
00103 void G4ReduciblePolygon::Create( const G4double a[],
00104                                  const G4double b[], G4int n )
00105 {
00106   if (n<3)
00107    G4Exception("G4ReduciblePolygon::Create()", "GeomSolids0002",
00108                FatalErrorInArgument, "Less than 3 vertices specified.");
00109   
00110   const G4double *anext = a, *bnext = b;
00111   ABVertex *prev = 0;
00112   do
00113   {
00114     ABVertex *newVertex = new ABVertex;
00115     newVertex->a = *anext;
00116     newVertex->b = *bnext;
00117     newVertex->next = 0;
00118     if (prev==0)
00119     {
00120       vertexHead = newVertex;
00121     }
00122     else
00123     {
00124       prev->next = newVertex;
00125     }
00126       
00127     prev = newVertex;
00128   } while( ++anext, ++bnext < b+n );
00129 
00130   numVertices = n;
00131   
00132   CalculateMaxMin();
00133 }
00134 
00135 
00136 //
00137 // Fake default constructor - sets only member data and allocates memory
00138 //                            for usage restricted to object persistency.
00139 //
00140 G4ReduciblePolygon::G4ReduciblePolygon( __void__& )
00141   : aMin(0.), aMax(0.), bMin(0.), bMax(0.), numVertices(0), vertexHead(0)
00142 {
00143 }
00144 
00145 
00146 //
00147 // Destructor
00148 //
00149 G4ReduciblePolygon::~G4ReduciblePolygon()
00150 {
00151   ABVertex *curr = vertexHead;
00152   while( curr )
00153   {
00154     ABVertex *toDelete = curr;
00155     curr = curr->next;
00156     delete toDelete;
00157   }
00158 }
00159 
00160 
00161 //
00162 // CopyVertices
00163 //
00164 // Copy contents into simple linear arrays.
00165 // ***** CAUTION ***** Be care to declare the arrays to a large
00166 // enough size!
00167 //
00168 void G4ReduciblePolygon::CopyVertices( G4double a[], G4double b[] ) const
00169 {
00170   G4double *anext = a, *bnext = b;
00171   ABVertex *curr = vertexHead;
00172   while( curr )
00173   {
00174     *anext++ = curr->a;
00175     *bnext++ = curr->b;
00176     curr = curr->next;
00177   }
00178 }
00179 
00180 
00181 //
00182 // ScaleA
00183 //
00184 // Multiply all a values by a common scale
00185 //
00186 void G4ReduciblePolygon::ScaleA( G4double scale )
00187 {
00188   ABVertex *curr = vertexHead;
00189   while( curr )
00190   {
00191     curr->a *= scale;
00192     curr = curr->next;
00193   }
00194 }  
00195 
00196 
00197 //
00198 // ScaleB
00199 //
00200 // Multiply all b values by a common scale
00201 //
00202 void G4ReduciblePolygon::ScaleB( G4double scale )
00203 {
00204   ABVertex *curr = vertexHead;
00205   while( curr )
00206   {
00207     curr->b *= scale;
00208     curr = curr->next;
00209   }
00210 }  
00211 
00212 
00213 //
00214 // RemoveDuplicateVertices
00215 //
00216 // Remove adjacent vertices that are equal. Returns "false" if there
00217 // is a problem (too few vertices remaining).
00218 //
00219 G4bool G4ReduciblePolygon::RemoveDuplicateVertices( G4double tolerance )
00220 {
00221   ABVertex *curr = vertexHead, 
00222            *prev = 0, *next = 0;
00223   while( curr )
00224   {
00225     next = curr->next;
00226     if (next == 0) next = vertexHead;
00227     
00228     if (std::fabs(curr->a-next->a) < tolerance &&
00229         std::fabs(curr->b-next->b) < tolerance     )
00230     {
00231       //
00232       // Duplicate found: do we have > 3 vertices?
00233       //
00234       if (numVertices <= 3)
00235       {
00236         CalculateMaxMin();
00237         return false;
00238       }
00239       
00240       //
00241       // Delete
00242       //
00243       ABVertex *toDelete = curr;
00244       curr = curr->next;
00245       delete toDelete;
00246       
00247       numVertices--;
00248       
00249       if (prev) prev->next = curr; else vertexHead = curr;
00250     }
00251     else
00252     {
00253       prev = curr;
00254       curr = curr->next;
00255     }
00256   }
00257   
00258   //
00259   // In principle, this is not needed, but why not just play it safe?
00260   //
00261   CalculateMaxMin();
00262   
00263   return true;
00264 }
00265 
00266 
00267 //
00268 // RemoveRedundantVertices
00269 //
00270 // Remove any unneeded vertices, i.e. those vertices which
00271 // are on the line connecting the previous and next vertices.
00272 //
00273 G4bool G4ReduciblePolygon::RemoveRedundantVertices( G4double tolerance )
00274 {
00275   //
00276   // Under these circumstances, we can quit now!
00277   //
00278   if (numVertices <= 2) return false;
00279   
00280   G4double tolerance2 = tolerance*tolerance;
00281 
00282   //
00283   // Loop over all vertices
00284   //
00285   ABVertex *curr = vertexHead, *next = 0;
00286   while( curr )
00287   {
00288     next = curr->next;
00289     if (next == 0) next = vertexHead;
00290     
00291     G4double da = next->a - curr->a,
00292              db = next->b - curr->b;
00293     
00294     //
00295     // Loop over all subsequent vertices, up to curr
00296     //
00297     for(;;)
00298     {
00299       //
00300       // Get vertex after next
00301       //
00302       ABVertex *test = next->next;
00303       if (test == 0) test = vertexHead;
00304       
00305       //
00306       // If we are back to the original vertex, stop
00307       //
00308       if (test==curr) break;
00309     
00310       //
00311       // Test for parallel line segments
00312       //
00313       G4double dat = test->a - curr->a,
00314                dbt = test->b - curr->b;
00315          
00316       if (std::fabs(dat*db-dbt*da)>tolerance2) break;
00317       
00318       //
00319       // Redundant vertex found: do we have > 3 vertices?
00320       // 
00321       if (numVertices <= 3)
00322       {
00323         CalculateMaxMin();
00324         return false;
00325       }
00326 
00327       //
00328       // Delete vertex pointed to by next. Carefully!
00329       //
00330       if (curr->next)
00331       {    // next is not head
00332         if (next->next)
00333           curr->next = test;  // next is not tail
00334         else
00335           curr->next = 0;    // New tail
00336       }
00337       else
00338         vertexHead = test;  // New head
00339         
00340       if ((curr != next) && (next != test)) delete next;
00341       
00342       numVertices--;
00343       
00344       //
00345       // Replace next by the vertex we just tested,
00346       // and keep on going...
00347       //
00348       next = test;
00349       da = dat; db = dbt;
00350     }
00351     curr = curr->next;
00352   }
00353   
00354   //
00355   // In principle, this is not needed, but why not just play it safe?
00356   //
00357   CalculateMaxMin();
00358   
00359   return true;
00360 }
00361 
00362 
00363 //
00364 // ReverseOrder
00365 //
00366 // Reverse the order of the vertices
00367 //
00368 void G4ReduciblePolygon::ReverseOrder()
00369 {
00370   //
00371   // Loop over all vertices
00372   //
00373   ABVertex *prev = vertexHead;
00374   if (prev==0) return;    // No vertices
00375   
00376   ABVertex *curr = prev->next;
00377   if (curr==0) return;    // Just one vertex
00378   
00379   //
00380   // Our new tail
00381   //
00382   vertexHead->next = 0;
00383   
00384   for(;;)
00385   {
00386     //
00387     // Save pointer to next vertex (in original order)
00388     //
00389     ABVertex *save = curr->next;
00390     
00391     //
00392     // Replace it with a pointer to the previous one
00393     // (in original order)
00394     //
00395     curr->next = prev;
00396     
00397     //
00398     // Last vertex?
00399     //
00400     if (save == 0) break;
00401     
00402     //
00403     // Next vertex
00404     //
00405     prev = curr;
00406     curr = save;
00407   }
00408   
00409   //
00410   // Our new head
00411   //
00412   vertexHead = curr;
00413 }
00414 
00415 
00416 //
00417 // CrossesItself
00418 //
00419 // Return "true" if the polygon crosses itself
00420 //
00421 // Warning: this routine is not very fast (runs as N**2)
00422 //
00423 G4bool G4ReduciblePolygon::CrossesItself( G4double tolerance )
00424 {
00425   G4double tolerance2 = tolerance*tolerance;
00426   G4double one  = 1.0-tolerance,
00427            zero = tolerance;
00428   //
00429   // Top loop over line segments. By the time we finish
00430   // with the second to last segment, we're done.
00431   //
00432   ABVertex *curr1 = vertexHead, *next1=0;
00433   while (curr1->next)
00434   {
00435     next1 = curr1->next;
00436     G4double da1 = next1->a-curr1->a,
00437              db1 = next1->b-curr1->b;
00438     
00439     //
00440     // Inner loop over subsequent line segments
00441     //
00442     ABVertex *curr2 = next1->next;
00443     while( curr2 )
00444     {
00445       ABVertex *next2 = curr2->next;
00446       if (next2==0) next2 = vertexHead;
00447       G4double da2 = next2->a-curr2->a,
00448                db2 = next2->b-curr2->b;
00449       G4double a12 = curr2->a-curr1->a,
00450                b12 = curr2->b-curr1->b;
00451          
00452       //
00453       // Calculate intersection of the two lines
00454       //
00455       G4double deter = da1*db2 - db1*da2;
00456       if (std::fabs(deter) > tolerance2)
00457       {
00458         G4double s1, s2;
00459         s1 = (a12*db2-b12*da2)/deter;
00460         
00461         if (s1 >= zero && s1 < one)
00462         {
00463           s2 = -(da1*b12-db1*a12)/deter;
00464           if (s2 >= zero && s2 < one) return true;
00465         }
00466       }
00467       curr2 = curr2->next;   
00468     }
00469     curr1 = next1;
00470   }
00471   return false;
00472 }
00473 
00474 
00475 
00476 //
00477 // BisectedBy
00478 //
00479 // Decide if a line through two points crosses the polygon, within tolerance
00480 //
00481 G4bool G4ReduciblePolygon::BisectedBy( G4double a1, G4double b1,
00482                                        G4double a2, G4double b2,
00483                                        G4double tolerance )
00484 {
00485   G4int nNeg = 0, nPos = 0;
00486   
00487   G4double a12 = a2-a1, b12 = b2-b1;
00488   G4double len12 = std::sqrt( a12*a12 + b12*b12 );
00489   a12 /= len12; b12 /= len12;
00490   
00491   ABVertex *curr = vertexHead;
00492   do
00493   {
00494     G4double av = curr->a - a1,
00495        bv = curr->b - b1;
00496        
00497     G4double cross = av*b12 - bv*a12;
00498     
00499     if (cross < -tolerance)
00500     {
00501       if (nPos) return true;
00502       nNeg++;
00503     }
00504     else if (cross > tolerance)
00505     {
00506       if (nNeg) return true;
00507       nPos++;
00508     }
00509     curr = curr->next;
00510   } while( curr );
00511     
00512   return false;
00513 }
00514 
00515 
00516 
00517 //
00518 // Area
00519 //
00520 // Calculated signed polygon area, where polygons specified in a
00521 // clockwise manner (where x==a, y==b) have negative area
00522 //
00523 //    References: [O' Rourke (C)] pp. 18-27; [Gems II] pp. 5-6:
00524 //    "The Area of a Simple Polygon", Jon Rokne.
00525 //
00526 G4double G4ReduciblePolygon::Area()
00527 {
00528   G4double answer = 0;
00529   
00530   ABVertex *curr = vertexHead, *next;
00531   do
00532   {
00533     next = curr->next;
00534     if (next==0) next = vertexHead;
00535     
00536     answer += curr->a*next->b - curr->b*next->a;
00537     curr = curr->next;
00538   } while( curr );
00539   
00540   return 0.5*answer;
00541 }
00542 
00543 
00544 //
00545 // Print
00546 //
00547 void G4ReduciblePolygon::Print()
00548 {
00549   ABVertex *curr = vertexHead;
00550   do
00551   {
00552     G4cerr << curr->a << " " << curr->b << G4endl;
00553     curr = curr->next;
00554   } while( curr );
00555 }
00556 
00557 
00558 //
00559 // CalculateMaxMin
00560 //
00561 // To be called when the vertices are changed, this
00562 // routine re-calculates global values
00563 //
00564 void G4ReduciblePolygon::CalculateMaxMin()
00565 {
00566   ABVertex *curr = vertexHead;
00567   aMin = aMax = curr->a;
00568   bMin = bMax = curr->b;
00569   curr = curr->next;
00570   while( curr )
00571   {
00572     if (curr->a < aMin)
00573       aMin = curr->a;
00574     else if (curr->a > aMax)
00575       aMax = curr->a;
00576 
00577     if (curr->b < bMin)
00578       bMin = curr->b;
00579     else if (curr->b > bMax)
00580       bMax = curr->b;
00581     
00582     curr = curr->next;
00583   }
00584 }

Generated on Mon May 27 17:49:42 2013 for Geant4 by  doxygen 1.4.7