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

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

tag geant4.9.4 beta 1 + modifs locales

File size: 12.6 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: G4ClippablePolygon.cc,v 1.12 2007/05/11 13:54:28 gcosmo Exp $
28// GEANT4 tag $Name: geant4-09-04-beta-01 $
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.