source: trunk/source/geometry/solids/specific/src/G4ReduciblePolygon.cc

Last change on this file was 1337, checked in by garnier, 14 years ago

tag geant4.9.4 beta 1 + modifs locales

File size: 12.5 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: G4ReduciblePolygon.cc,v 1.11 2006/06/29 18:48:53 gunter Exp $
28// GEANT4 tag $Name: geant4-09-04-beta-01 $
29//
30//
31// --------------------------------------------------------------------
32// GEANT 4 class source file
33//
34//
35// G4ReduciblePolygon.cc
36//
37// Implementation of a utility class used to specify, test, reduce,
38// and/or otherwise manipulate a 2D polygon.
39//
40// See G4ReduciblePolygon.hh for more info.
41//
42// --------------------------------------------------------------------
43
44#include "G4ReduciblePolygon.hh"
45#include "globals.hh"
46
47//
48// Constructor: with simple arrays
49//
50G4ReduciblePolygon::G4ReduciblePolygon( const G4double a[],
51                                        const G4double b[],
52                                              G4int n )
53  : aMin(0.), aMax(0.), bMin(0.), bMax(0.),
54    vertexHead(0)
55{
56  //
57  // Do all of the real work in Create
58  //
59  Create( a, b, n );
60}
61
62
63//
64// Constructor: special PGON/PCON case
65//
66G4ReduciblePolygon::G4ReduciblePolygon( const G4double rmin[],
67                                        const G4double rmax[], 
68                                        const G4double z[], G4int n )
69  : aMin(0.), aMax(0.), bMin(0.), bMax(0.),
70    vertexHead(0)
71{
72  //
73  // Translate
74  //
75  G4double *a = new G4double[n*2];
76  G4double *b = new G4double[n*2];
77 
78  G4double *rOut = a + n,
79           *zOut = b + n,
80            *rIn = rOut-1,
81            *zIn = zOut-1;
82 
83  G4int i;   
84  for( i=0; i < n; i++, rOut++, zOut++, rIn--, zIn-- )
85  {
86    *rOut = rmax[i];
87    *rIn  = rmin[i];
88    *zOut = *zIn = z[i];
89  }
90 
91  Create( a, b, n*2 );
92 
93  delete [] a;
94  delete [] b;
95}
96
97
98//
99// Create
100//
101// To be called by constructors, fill in the list and statistics for a new
102// polygon
103//
104void G4ReduciblePolygon::Create( const G4double a[],
105                                 const G4double b[], G4int n )
106{
107  if (n<3)
108   G4Exception("G4ReduciblePolygon::Create()", "WrongArgumentValue",
109               FatalException, "Less than 3 vertices specified.");
110 
111  const G4double *anext = a, *bnext = b;
112  ABVertex *prev = 0;
113  do
114  {
115    ABVertex *newVertex = new ABVertex;
116    newVertex->a = *anext;
117    newVertex->b = *bnext;
118    newVertex->next = 0;
119    if (prev==0)
120    {
121      vertexHead = newVertex;
122    }
123    else
124    {
125      prev->next = newVertex;
126    }
127     
128    prev = newVertex;
129  } while( ++anext, ++bnext < b+n );
130
131  numVertices = n;
132 
133  CalculateMaxMin();
134}
135
136
137//
138// Fake default constructor - sets only member data and allocates memory
139//                            for usage restricted to object persistency.
140//
141G4ReduciblePolygon::G4ReduciblePolygon( __void__& )
142  : aMin(0.), aMax(0.), bMin(0.), bMax(0.), vertexHead(0)
143{
144}
145
146
147//
148// Destructor
149//
150G4ReduciblePolygon::~G4ReduciblePolygon()
151{
152  ABVertex *curr = vertexHead;
153  while( curr )
154  {
155    ABVertex *toDelete = curr;
156    curr = curr->next;
157    delete toDelete;
158  }
159}
160
161
162//
163// CopyVertices
164//
165// Copy contents into simple linear arrays.
166// ***** CAUTION ***** Be care to declare the arrays to a large
167// enough size!
168//
169void G4ReduciblePolygon::CopyVertices( G4double a[], G4double b[] ) const
170{
171  G4double *anext = a, *bnext = b;
172  ABVertex *curr = vertexHead;
173  while( curr )
174  {
175    *anext++ = curr->a;
176    *bnext++ = curr->b;
177    curr = curr->next;
178  }
179}
180
181
182//
183// ScaleA
184//
185// Multiply all a values by a common scale
186//
187void G4ReduciblePolygon::ScaleA( G4double scale )
188{
189  ABVertex *curr = vertexHead;
190  while( curr )
191  {
192    curr->a *= scale;
193    curr = curr->next;
194  }
195} 
196
197
198//
199// ScaleB
200//
201// Multiply all b values by a common scale
202//
203void G4ReduciblePolygon::ScaleB( G4double scale )
204{
205  ABVertex *curr = vertexHead;
206  while( curr )
207  {
208    curr->b *= scale;
209    curr = curr->next;
210  }
211} 
212
213
214//
215// RemoveDuplicateVertices
216//
217// Remove adjacent vertices that are equal. Returns "false" if there
218// is a problem (too few vertices remaining).
219//
220G4bool G4ReduciblePolygon::RemoveDuplicateVertices( G4double tolerance )
221{
222  ABVertex *curr = vertexHead, 
223           *prev = 0,
224           *next = curr->next;  // A little dangerous
225  while( curr )
226  {
227    next = curr->next;
228    if (next == 0) next = vertexHead;
229   
230    if (std::fabs(curr->a-next->a) < tolerance &&
231        std::fabs(curr->b-next->b) < tolerance     )
232    {
233      //
234      // Duplicate found: do we have > 3 vertices?
235      //
236      if (numVertices <= 3)
237      {
238        CalculateMaxMin();
239        return false;
240      }
241     
242      //
243      // Delete
244      //
245      ABVertex *toDelete = curr;
246      curr = curr->next;
247      delete toDelete;
248     
249      numVertices--;
250     
251      if (prev) prev->next = curr; else vertexHead = curr;
252    }
253    else
254    {
255      prev = curr;
256      curr = curr->next;
257    }
258  }
259 
260  //
261  // In principle, this is not needed, but why not just play it safe?
262  //
263  CalculateMaxMin();
264 
265  return true;
266}
267
268
269//
270// RemoveRedundantVertices
271//
272// Remove any unneeded vertices, i.e. those vertices which
273// are on the line connecting the previous and next vertices.
274//
275G4bool G4ReduciblePolygon::RemoveRedundantVertices( G4double tolerance )
276{
277  //
278  // Under these circumstances, we can quit now!
279  //
280  if (numVertices <= 2) return false;
281 
282  G4double tolerance2 = tolerance*tolerance;
283
284  //
285  // Loop over all vertices
286  //
287  ABVertex *curr = vertexHead, 
288           *next = curr->next;  // A little dangerous
289  while( curr )
290  {
291    next = curr->next;
292    if (next == 0) next = vertexHead;
293   
294    G4double da = next->a - curr->a,
295             db = next->b - curr->b;
296   
297    //
298    // Loop over all subsequent vertices, up to curr
299    //
300    for(;;)
301    {
302      //
303      // Get vertex after next
304      //
305      ABVertex *test = next->next;
306      if (test == 0) test = vertexHead;
307     
308      //
309      // If we are back to the original vertex, stop
310      //
311      if (test==curr) break;
312   
313      //
314      // Test for parallel line segments
315      //
316      G4double dat = test->a - curr->a,
317               dbt = test->b - curr->b;
318         
319      if (std::fabs(dat*db-dbt*da)>tolerance2) break;
320     
321      //
322      // Redundant vertex found: do we have > 3 vertices?
323      //
324      if (numVertices <= 3)
325      {
326        CalculateMaxMin();
327        return false;
328      }
329
330      //
331      // Delete vertex pointed to by next. Carefully!
332      //
333      if (curr->next)
334      {    // next is not head
335        if (next->next)
336          curr->next = test;  // next is not tail
337        else
338          curr->next = 0;    // New tail
339      }
340      else
341        vertexHead = test;  // New head
342       
343      delete next;
344     
345      numVertices--;
346     
347      //
348      // Replace next by the vertex we just tested,
349      // and keep on going...
350      //
351      next = test;
352      da = dat; db = dbt;
353    }
354    curr = curr->next;
355  }
356 
357  //
358  // In principle, this is not needed, but why not just play it safe?
359  //
360  CalculateMaxMin();
361 
362  return true;
363}
364
365
366//
367// ReverseOrder
368//
369// Reverse the order of the vertices
370//
371void G4ReduciblePolygon::ReverseOrder()
372{
373  //
374  // Loop over all vertices
375  //
376  ABVertex *prev = vertexHead;
377  if (prev==0) return;    // No vertices
378 
379  ABVertex *curr = prev->next;
380  if (curr==0) return;    // Just one vertex
381 
382  //
383  // Our new tail
384  //
385  vertexHead->next = 0;
386 
387  for(;;)
388  {
389    //
390    // Save pointer to next vertex (in original order)
391    //
392    ABVertex *save = curr->next;
393   
394    //
395    // Replace it with a pointer to the previous one
396    // (in original order)
397    //
398    curr->next = prev;
399   
400    //
401    // Last vertex?
402    //
403    if (save == 0) break;
404   
405    //
406    // Next vertex
407    //
408    prev = curr;
409    curr = save;
410  }
411 
412  //
413  // Our new head
414  //
415  vertexHead = curr;
416}
417
418
419//
420// CrossesItself
421//
422// Return "true" if the polygon crosses itself
423//
424// Warning: this routine is not very fast (runs as N**2)
425//
426G4bool G4ReduciblePolygon::CrossesItself( G4double tolerance )
427{
428  G4double tolerance2 = tolerance*tolerance;
429  G4double one = 1.0-tolerance,
430     zero = tolerance;
431  //
432  // Top loop over line segments. By the time we finish
433  // with the second to last segment, we're done.
434  //
435  ABVertex *curr1 = vertexHead, *next1=0;
436  while (curr1->next) {
437          next1 = curr1->next;
438    G4double da1 = next1->a-curr1->a,
439       db1 = next1->b-curr1->b;
440   
441    //
442    // Inner loop over subsequent line segments
443    //
444    ABVertex *curr2 = next1->next;
445    while( curr2 ) {
446      ABVertex *next2 = curr2->next;
447      if (next2==0) next2 = vertexHead;
448      G4double da2 = next2->a-curr2->a,
449         db2 = next2->b-curr2->b;
450      G4double a12 = curr2->a-curr1->a,
451         b12 = curr2->b-curr1->b;
452         
453      //
454      // Calculate intersection of the two lines
455      //
456      G4double deter = da1*db2 - db1*da2;
457      if (std::fabs(deter) > tolerance2) {
458        G4double s1, s2;
459        s1 = (a12*db2-b12*da2)/deter;
460       
461        if (s1 >= zero && s1 < one) {
462          s2 = -(da1*b12-db1*a12)/deter;
463          if (s2 >= zero && s2 < one) return true;
464        }
465      }
466      curr2 = curr2->next;   
467    }
468    curr1 = next1;
469  }
470  return false;
471}
472
473
474
475//
476// BisectedBy
477//
478// Decide if a line through two points crosses the polygon, within tolerance
479//
480G4bool G4ReduciblePolygon::BisectedBy( G4double a1, G4double b1,
481                                       G4double a2, G4double b2,
482                                       G4double tolerance )
483{
484  G4int nNeg = 0, nPos = 0;
485 
486  G4double a12 = a2-a1, b12 = b2-b1;
487  G4double len12 = std::sqrt( a12*a12 + b12*b12 );
488  a12 /= len12; b12 /= len12;
489 
490  ABVertex *curr = vertexHead;
491  do
492  {
493    G4double av = curr->a - a1,
494       bv = curr->b - b1;
495       
496    G4double cross = av*b12 - bv*a12;
497   
498    if (cross < -tolerance)
499    {
500      if (nPos) return true;
501      nNeg++;
502    }
503    else if (cross > tolerance)
504    {
505      if (nNeg) return true;
506      nPos++;
507    }
508    curr = curr->next;
509  } while( curr );
510   
511  return false;
512}
513
514
515
516//
517// Area
518//
519// Calculated signed polygon area, where polygons specified in a
520// clockwise manner (where x==a, y==b) have negative area
521//
522//    References: [O' Rourke (C)] pp. 18-27; [Gems II] pp. 5-6:
523//    "The Area of a Simple Polygon", Jon Rokne.
524//
525G4double G4ReduciblePolygon::Area()
526{
527  G4double answer = 0;
528 
529  ABVertex *curr = vertexHead, *next;
530  do
531  {
532    next = curr->next;
533    if (next==0) next = vertexHead;
534   
535    answer += curr->a*next->b - curr->b*next->a;
536    curr = curr->next;
537  } while( curr );
538 
539  return 0.5*answer;
540}
541
542
543//
544// Print
545//
546void G4ReduciblePolygon::Print()
547{
548  ABVertex *curr = vertexHead;
549  do
550  {
551    G4cerr << curr->a << " " << curr->b << G4endl;
552    curr = curr->next;
553  } while( curr );
554}
555
556
557//
558// CalculateMaxMin
559//
560// To be called when the vertices are changed, this
561// routine re-calculates global values
562//
563void G4ReduciblePolygon::CalculateMaxMin()
564{
565  ABVertex *curr = vertexHead;
566  aMin = aMax = curr->a;
567  bMin = bMax = curr->b;
568  curr = curr->next;
569  while( curr )
570  {
571    if (curr->a < aMin)
572      aMin = curr->a;
573    else if (curr->a > aMax)
574      aMax = curr->a;
575
576    if (curr->b < bMin)
577      bMin = curr->b;
578    else if (curr->b > bMax)
579      bMax = curr->b;
580   
581    curr = curr->next;
582  }
583}
Note: See TracBrowser for help on using the repository browser.