source: trunk/source/geometry/solids/specific/src/G4ClippablePolygon.cc@ 1358

Last change on this file since 1358 was 1337, checked in by garnier, 15 years ago

tag geant4.9.4 beta 1 + modifs locales

File size: 12.6 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: G4ClippablePolygon.cc,v 1.12 2007/05/11 13:54:28 gcosmo Exp $
[1337]28// GEANT4 tag $Name: geant4-09-04-beta-01 $
[831]29//
30//
31// --------------------------------------------------------------------
32// GEANT 4 class source file
33//
34//
35// G4ClippablePolygon.cc
36//
37// Includes code from G4VSolid (P.Kent, V.Grichine, J.Allison)
38//
39// --------------------------------------------------------------------
40
41#include "G4ClippablePolygon.hh"
42
43#include "G4VoxelLimits.hh"
44#include "G4GeometryTolerance.hh"
45
46//
47// Constructor
48//
49G4ClippablePolygon::G4ClippablePolygon()
50 : normal(0.,0.,0.)
51{
52 kCarTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
53}
54
55
56//
57// Destructor
58//
59G4ClippablePolygon::~G4ClippablePolygon()
60{
61}
62
63
64//
65// AddVertexInOrder
66//
67void G4ClippablePolygon::AddVertexInOrder( const G4ThreeVector vertex )
68{
69 vertices.push_back( vertex );
70}
71
72
73//
74// ClearAllVertices
75//
76void G4ClippablePolygon::ClearAllVertices()
77{
78 vertices.clear();
79}
80
81
82//
83// Clip
84//
85G4bool G4ClippablePolygon::Clip( const G4VoxelLimits &voxelLimit )
86{
87 if (voxelLimit.IsLimited()) {
88 ClipAlongOneAxis( voxelLimit, kXAxis );
89 ClipAlongOneAxis( voxelLimit, kYAxis );
90 ClipAlongOneAxis( voxelLimit, kZAxis );
91 }
92
93 return (vertices.size() > 0);
94}
95
96
97//
98// PartialClip
99//
100// Clip, while ignoring the indicated axis
101//
102G4bool G4ClippablePolygon::PartialClip( const G4VoxelLimits &voxelLimit,
103 const EAxis IgnoreMe )
104{
105 if (voxelLimit.IsLimited()) {
106 if (IgnoreMe != kXAxis) ClipAlongOneAxis( voxelLimit, kXAxis );
107 if (IgnoreMe != kYAxis) ClipAlongOneAxis( voxelLimit, kYAxis );
108 if (IgnoreMe != kZAxis) ClipAlongOneAxis( voxelLimit, kZAxis );
109 }
110
111 return (vertices.size() > 0);
112}
113
114
115//
116// GetExtent
117//
118G4bool G4ClippablePolygon::GetExtent( const EAxis axis,
119 G4double &min,
120 G4double &max ) const
121{
122 //
123 // Okay, how many entries do we have?
124 //
125 G4int noLeft = vertices.size();
126
127 //
128 // Return false if nothing is left
129 //
130 if (noLeft == 0) return false;
131
132 //
133 // Initialize min and max to our first vertex
134 //
135 min = max = vertices[0].operator()( axis );
136
137 //
138 // Compare to the rest
139 //
140 G4int i;
141 for( i=1; i<noLeft; i++ )
142 {
143 G4double component = vertices[i].operator()( axis );
144 if (component < min )
145 min = component;
146 else if (component > max )
147 max = component;
148 }
149
150 return true;
151}
152
153
154//
155// GetMinPoint
156//
157// Returns pointer to minimum point along the specified axis.
158// Take care! Do not use pointer after destroying parent polygon.
159//
160const G4ThreeVector *G4ClippablePolygon::GetMinPoint( const EAxis axis ) const
161{
162 G4int noLeft = vertices.size();
163 if (noLeft==0)
164 G4Exception("G4ClippablePolygon::GetMinPoint()",
165 "InvalidSetup", FatalException, "Empty polygon.");
166
167 const G4ThreeVector *answer = &(vertices[0]);
168 G4double min = answer->operator()(axis);
169
170 G4int i;
171 for( i=1; i<noLeft; i++ )
172 {
173 G4double component = vertices[i].operator()( axis );
174 if (component < min)
175 {
176 answer = &(vertices[i]);
177 min = component;
178 }
179 }
180
181 return answer;
182}
183
184
185//
186// GetMaxPoint
187//
188// Returns pointer to maximum point along the specified axis.
189// Take care! Do not use pointer after destroying parent polygon.
190//
191const G4ThreeVector *G4ClippablePolygon::GetMaxPoint( const EAxis axis ) const
192{
193 G4int noLeft = vertices.size();
194 if (noLeft==0)
195 G4Exception("G4ClippablePolygon::GetMaxPoint()",
196 "InvalidSetup", FatalException, "Empty polygon.");
197
198 const G4ThreeVector *answer = &(vertices[0]);
199 G4double max = answer->operator()(axis);
200
201 G4int i;
202 for( i=1; i<noLeft; i++ )
203 {
204 G4double component = vertices[i].operator()( axis );
205 if (component > max)
206 {
207 answer = &(vertices[i]);
208 max = component;
209 }
210 }
211
212 return answer;
213}
214
215
216//
217// InFrontOf
218//
219// Decide if this polygon is in "front" of another when
220// viewed along the specified axis. For our purposes here,
221// it is sufficient to use the minimum extent of the
222// polygon along the axis to determine this.
223//
224// In case the minima of the two polygons are equal,
225// we use a more sophisticated test.
226//
227// Note that it is possible for the two following
228// statements to both return true or both return false:
229// polygon1.InFrontOf(polygon2)
230// polygon2.BehindOf(polygon1)
231//
232G4bool G4ClippablePolygon::InFrontOf( const G4ClippablePolygon &other,
233 EAxis axis ) const
234{
235 //
236 // If things are empty, do something semi-sensible
237 //
238 G4int noLeft = vertices.size();
239 if (noLeft==0) return false;
240
241 if (other.Empty()) return true;
242
243 //
244 // Get minimum of other polygon
245 //
246 const G4ThreeVector *minPointOther = other.GetMinPoint( axis );
247 const G4double minOther = minPointOther->operator()(axis);
248
249 //
250 // Get minimum of this polygon
251 //
252 const G4ThreeVector *minPoint = GetMinPoint( axis );
253 const G4double min = minPoint->operator()(axis);
254
255 //
256 // Easy decision
257 //
258 if (min < minOther-kCarTolerance) return true; // Clear winner
259
260 if (minOther < min-kCarTolerance) return false; // Clear loser
261
262 //
263 // We have a tie (this will not be all that rare since our
264 // polygons are connected)
265 //
266 // Check to see if there is a vertex in the other polygon
267 // that is behind this one (or vice versa)
268 //
269 G4bool answer;
270 G4ThreeVector normalOther = other.GetNormal();
271
272 if (std::fabs(normalOther(axis)) > std::fabs(normal(axis)))
273 {
274 G4double minP, maxP;
275 GetPlanerExtent( *minPointOther, normalOther, minP, maxP );
276
277 answer = (normalOther(axis) > 0) ? (minP < -kCarTolerance)
278 : (maxP > +kCarTolerance);
279 }
280 else
281 {
282 G4double minP, maxP;
283 other.GetPlanerExtent( *minPoint, normal, minP, maxP );
284
285 answer = (normal(axis) > 0) ? (maxP > +kCarTolerance)
286 : (minP < -kCarTolerance);
287 }
288 return answer;
289}
290
291//
292// BehindOf
293//
294// Decide if this polygon is behind another.
295// See notes in method "InFrontOf"
296//
297G4bool G4ClippablePolygon::BehindOf( const G4ClippablePolygon &other,
298 EAxis axis ) const
299{
300 //
301 // If things are empty, do something semi-sensible
302 //
303 G4int noLeft = vertices.size();
304 if (noLeft==0) return false;
305
306 if (other.Empty()) return true;
307
308 //
309 // Get minimum of other polygon
310 //
311 const G4ThreeVector *maxPointOther = other.GetMaxPoint( axis );
312 const G4double maxOther = maxPointOther->operator()(axis);
313
314 //
315 // Get minimum of this polygon
316 //
317 const G4ThreeVector *maxPoint = GetMaxPoint( axis );
318 const G4double max = maxPoint->operator()(axis);
319
320 //
321 // Easy decision
322 //
323 if (max > maxOther+kCarTolerance) return true; // Clear winner
324
325 if (maxOther > max+kCarTolerance) return false; // Clear loser
326
327 //
328 // We have a tie (this will not be all that rare since our
329 // polygons are connected)
330 //
331 // Check to see if there is a vertex in the other polygon
332 // that is in front of this one (or vice versa)
333 //
334 G4bool answer;
335 G4ThreeVector normalOther = other.GetNormal();
336
337 if (std::fabs(normalOther(axis)) > std::fabs(normal(axis)))
338 {
339 G4double minP, maxP;
340 GetPlanerExtent( *maxPointOther, normalOther, minP, maxP );
341
342 answer = (normalOther(axis) > 0) ? (maxP > +kCarTolerance)
343 : (minP < -kCarTolerance);
344 }
345 else
346 {
347 G4double minP, maxP;
348 other.GetPlanerExtent( *maxPoint, normal, minP, maxP );
349
350 answer = (normal(axis) > 0) ? (minP < -kCarTolerance)
351 : (maxP > +kCarTolerance);
352 }
353 return answer;
354}
355
356
357//
358// GetPlanerExtent
359//
360// Get min/max distance in or out of a plane
361//
362G4bool G4ClippablePolygon::GetPlanerExtent( const G4ThreeVector &pointOnPlane,
363 const G4ThreeVector &planeNormal,
364 G4double &min,
365 G4double &max ) const
366{
367 //
368 // Okay, how many entries do we have?
369 //
370 G4int noLeft = vertices.size();
371
372 //
373 // Return false if nothing is left
374 //
375 if (noLeft == 0) return false;
376
377 //
378 // Initialize min and max to our first vertex
379 //
380 min = max = planeNormal.dot(vertices[0]-pointOnPlane);
381
382 //
383 // Compare to the rest
384 //
385 G4int i;
386 for( i=1; i<noLeft; i++ )
387 {
388 G4double component = planeNormal.dot(vertices[i] - pointOnPlane);
389 if (component < min )
390 min = component;
391 else if (component > max )
392 max = component;
393 }
394
395 return true;
396}
397
398
399//
400// Clip along just one axis, as specified in voxelLimit
401//
402void G4ClippablePolygon::ClipAlongOneAxis( const G4VoxelLimits &voxelLimit,
403 const EAxis axis )
404{
405 if (!voxelLimit.IsLimited(axis)) return;
406
407 G4ThreeVectorList tempPolygon;
408
409 //
410 // Build a "simple" voxelLimit that includes only the min extent
411 // and apply this to our vertices, producing result in tempPolygon
412 //
413 G4VoxelLimits simpleLimit1;
414 simpleLimit1.AddLimit( axis, voxelLimit.GetMinExtent(axis), kInfinity );
415 ClipToSimpleLimits( vertices, tempPolygon, simpleLimit1 );
416
417 //
418 // If nothing is left from the above clip, we might as well return now
419 // (but with an empty vertices)
420 //
421 if (tempPolygon.size() == 0)
422 {
423 vertices.clear();
424 return;
425 }
426
427 //
428 // Now do the same, but using a "simple" limit that includes only the max
429 // extent. Apply this to out tempPolygon, producing result in vertices.
430 //
431 G4VoxelLimits simpleLimit2;
432 simpleLimit2.AddLimit( axis, -kInfinity, voxelLimit.GetMaxExtent(axis) );
433 ClipToSimpleLimits( tempPolygon, vertices, simpleLimit2 );
434
435 //
436 // If nothing is left, return now
437 //
438 if (vertices.size() == 0) return;
439}
440
441
442//
443// pVoxelLimits must be only limited along one axis, and either the maximum
444// along the axis must be +kInfinity, or the minimum -kInfinity
445//
446void G4ClippablePolygon::ClipToSimpleLimits( G4ThreeVectorList& pPolygon,
447 G4ThreeVectorList& outputPolygon,
448 const G4VoxelLimits& pVoxelLimit )
449{
450 G4int i;
451 G4int noVertices=pPolygon.size();
452 G4ThreeVector vEnd,vStart;
453
454 outputPolygon.clear();
455
456 for (i=0;i<noVertices;i++)
457 {
458 vStart=pPolygon[i];
459 if (i==noVertices-1)
460 {
461 vEnd=pPolygon[0];
462 }
463 else
464 {
465 vEnd=pPolygon[i+1];
466 }
467
468 if (pVoxelLimit.Inside(vStart))
469 {
470 if (pVoxelLimit.Inside(vEnd))
471 {
472 // vStart and vEnd inside -> output end point
473 //
474 outputPolygon.push_back(vEnd);
475 }
476 else
477 {
478 // vStart inside, vEnd outside -> output crossing point
479 //
480 pVoxelLimit.ClipToLimits(vStart,vEnd);
481 outputPolygon.push_back(vEnd);
482 }
483 }
484 else
485 {
486 if (pVoxelLimit.Inside(vEnd))
487 {
488 // vStart outside, vEnd inside -> output inside section
489 //
490 pVoxelLimit.ClipToLimits(vStart,vEnd);
491 outputPolygon.push_back(vStart);
492 outputPolygon.push_back(vEnd);
493 }
494 else // Both point outside -> no output
495 {
496 }
497 }
498 }
499}
Note: See TracBrowser for help on using the repository browser.