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