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

Last change on this file since 1202 was 1058, checked in by garnier, 17 years ago

file release beta

File size: 12.5 KB
RevLine 
[831]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 $
[1058]28// GEANT4 tag $Name: geant4-09-02-ref-02 $
[831]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.