Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
G4BSplineSurface.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//
27// $Id$
28//
29// ----------------------------------------------------------------------
30// GEANT 4 class source file
31//
32// G4BSplineSurface.cc
33//
34// ----------------------------------------------------------------------
35
36#include "G4BSplineSurface.hh"
37#include "G4BezierSurface.hh"
38#include "G4ControlPoints.hh"
39#include "G4BoundingBox3D.hh"
40
42 : ord(0), k_index(0), param(0.), Rational(0)
43{
44 distance = kInfinity;
45 dir=ROW;
46 first_hit = Hit = (G4UVHit*)0;
47 order[0] = 0; order[1] = 0;
48 ctl_points = (G4ControlPoints*)0;
49 u_knots = v_knots = tmp_knots = (G4KnotVector*)0;
50}
51
52
54 : dir(0), ord(0), k_index(0), param(0.), Rational(0)
55{
56 distance = kInfinity;
57 first_hit = Hit = (G4UVHit*)0;
58 order[0] = 0; order[1] = 0;
59 ctl_points = (G4ControlPoints*)0;
60 u_knots = v_knots = tmp_knots = (G4KnotVector*)0;
61}
62
63
66 : dir(0), ord(0), k_index(0), param(0.), Rational(0)
67{
68 first_hit = Hit = (G4UVHit*)0;
69
70 order[0] = u+1; order[1] = v+1;
71
72 u_knots = new G4KnotVector(u_kv);
73 v_knots = new G4KnotVector(v_kv);
74 tmp_knots = (G4KnotVector*)0;
75
76 ctl_points = new G4ControlPoints(cp);
77}
78
79
81{
82 delete u_knots;
83 delete v_knots;
84 delete ctl_points;
85 G4UVHit* temphit=Hit;
86 Hit = first_hit;
87 while(Hit!=(G4UVHit*)0)
88 {
89 Hit=Hit->GetNext();
90 delete temphit;
91 temphit=Hit;
92 }
93 // delete temphit;// remove last
94
95}
96
97
99{
100 Intersected = 1;
101 FindIntersections(rayref);
102 G4BezierSurface *bez_ptr;
103 bezier_list.MoveToFirst();
104 distance = kInfinity;
105
106 while( bezier_list.GetSurface() != (G4Surface*)0)
107 {
108 bez_ptr = (G4BezierSurface*)bezier_list.GetSurface();
109
110 if(bez_ptr->IsActive())
111 {
112 if(distance > bez_ptr->GetDistance())
113 {
114 // Put data from closest bezier to b-spline data struct
115 closest_hit = bez_ptr->AveragePoint();
116 distance = bez_ptr->GetDistance();
117 }
118 else
119 {
120 // Set other beziers as inactive
121 bez_ptr->SetActive(0);
122
123 // Remove beziers that are not closest
124 // bezier_list.RemoveSurface(bez_ptr);
125 }
126 }
127
128 bezier_list.Step();
129 }
130
131 bezier_list.MoveToFirst();
132
133 if(bezier_list.GetSize())
134 return 1;
135 else
136 {
137 active=0;
138 return 0;
139 }
140}
141
142
143G4Point3D G4BSplineSurface::FinalIntersection()
144{
145 // Compute the real intersection point.
146 G4BezierSurface* bez_ptr;
147 while ( bezier_list.GetSize() > 0 &&
148 bezier_list.GetSurface() != (G4Surface*)0)
149 {
150 bez_ptr = (G4BezierSurface*)bezier_list.GetSurface();
151 G4int tmp = 0;
152
153 // L. Broglia
154 // Modify G4BezierSurface intersection function name
155 // tmp = bez_ptr->Intersect( bezier_list);
156 tmp = bez_ptr->BIntersect( bezier_list);
157
158 if(!tmp)
159 {
160 bezier_list.RemoveSurface(bez_ptr);
161 if(bezier_list.GetSurface() != (G4Surface*)0)
162 bezier_list.GetSurface()->SetActive(1);
163 }
164 else
165 if(tmp==1)
166 {
167 active=1;
168 // Hit found
169 AddHit(bez_ptr->GetU(), bez_ptr->GetV());
170
171 // Delete beziers
172 bezier_list.EmptyList();
173 }
174 else
175 if(tmp==2)
176 {
177 // The bezier was split so the last
178 // two surfaces in the List should
179 // be bbox tested and if passed
180 // clipped in both dirs.
181
182 // Move to first
183 bezier_list.MoveToFirst();
184 // Find the second last.
185// What!? Casting a G4Surface* to a G4SurfaceList* !?!?!? - GC
186//
187// if(bezier_list.index != bezier_list.last)
188// while ( ((G4SurfaceList*)bezier_list.index)->next !=
189// bezier_list.last) bezier_list.Step();
190//
191// Try the following instead (if that's the wished behavior)...
192//
193 if(bezier_list.GetSurface() != bezier_list.GetLastSurface())
194 while (bezier_list.GetNext() != bezier_list.GetLastSurface())
195 bezier_list.Step();
196
197 G4BezierSurface* tmpbz = (G4BezierSurface*) bezier_list.GetSurface();
198 tmpbz->CalcBBox();
199
200// L. Broglia tmpbz->bbox->Test();
201
202 G4int result=0;
203 if(tmpbz->bbox->GetTestResult())
204 {
205 // Clip
206 while(!result)
207 result = tmpbz->ClipBothDirs();
208 }
209 else
210 {
211 bezier_list.RemoveSurface(tmpbz);
212 }
213 // Second surface
214 tmpbz = (G4BezierSurface*) bezier_list.GetLastSurface();
215 tmpbz->CalcBBox();
216
217// L. Broglia tmpbz->bbox->Test();
218
219 if(tmpbz->bbox->GetTestResult())
220 {
221 result = 0;
222 while(!result)
223 result = tmpbz->ClipBothDirs();
224 }
225 else
226 {
227 bezier_list.RemoveSurface(tmpbz);
228 }
229
230 bezier_list.RemoveSurface(bez_ptr);
231 bezier_list.MoveToFirst();
232 }
233
234 bezier_list.Step();
235 }//While....
236
237 Hit = first_hit;
238 G4Point3D result;
239 if(Hit == (G4UVHit*)0)
240 active = 0;
241 else
242 {
243 while(Hit != (G4UVHit*)0)
244 {
245 // L. Broglia
246 // Modify function name
247 // result = Evaluate();
248 result = BSEvaluate();
249
250 Hit = Hit->GetNext();
251 }
252
253 Hit = first_hit;
254 }
255
256 return result;
257}
258
259
261{
262
263 // Finds the bounds of the b-spline surface iow
264 // calculates the bounds for a bounding box
265 // to the surface. The bounding box is used
266 // for a preliminary check of intersection.
267
268 G4Point3D box_min = G4Point3D( PINFINITY);
269 G4Point3D box_max = G4Point3D(-PINFINITY);
270
271 // Loop to search the whole control point mesh
272 // for the minimum and maximum values for x, y and z.
273
274 for(register int a = ctl_points->GetRows()-1; a>=0;a--)
275 for(register int b = ctl_points->GetCols()-1; b>=0;b--)
276 {
277 G4Point3D tmp = ctl_points->Get3D(a,b);
278 if((box_min.x()) > (tmp.x())) box_min.setX(tmp.x());
279 if((box_min.y()) > (tmp.y())) box_min.setY(tmp.y());
280 if((box_min.z()) > (tmp.z())) box_min.setZ(tmp.z());
281 if((box_max.x()) < (tmp.x())) box_max.setX(tmp.x());
282 if((box_max.y()) < (tmp.y())) box_max.setY(tmp.y());
283 if((box_max.z()) < (tmp.z())) box_max.setZ(tmp.z());
284 }
285 bbox = new G4BoundingBox3D( box_min, box_max);
286}
287
288
289G4ProjectedSurface* G4BSplineSurface::CopyToProjectedSurface
290(const G4Ray& rayref)
291{
292 G4ProjectedSurface* proj_srf = new G4ProjectedSurface() ;
293 proj_srf->PutOrder(0,GetOrder(0));
294 proj_srf->PutOrder(1,GetOrder(1));
295 proj_srf->dir = dir;
296
297 proj_srf->u_knots = new G4KnotVector(*u_knots);
298 proj_srf->v_knots = new G4KnotVector(*v_knots);
299 proj_srf->ctl_points = new G4ControlPoints
300 (2, ctl_points->GetRows(), ctl_points->GetCols());
301
302 const G4Plane& plane1 = rayref.GetPlane(1);
303 const G4Plane& plane2 = rayref.GetPlane(2);
304 ProjectNURBSurfaceTo2D(plane1, plane2, proj_srf);
305
306 return proj_srf;
307}
308
309
310void G4BSplineSurface::FindIntersections(const G4Ray& rayref)
311{
312 // Do the projection to 2D
313 G4ProjectedSurface* proj_srf = CopyToProjectedSurface(rayref);
314
315 // Put surface in projected List
316 projected_list.AddSurface(proj_srf);
317
318 // Loop through List of projected surfaces
319 while(projected_list.GetSize() > 0)
320 {
321 // Get first in List
322 proj_srf = (G4ProjectedSurface*)projected_list.GetSurface();
323
324 // Create the bounding box for the projected surface.
325 proj_srf->CalcBBox();
326
327// L. Broglia proj_srf->bbox->Test();
328
329 // Check bbox test result is ok
330 if(proj_srf->bbox->GetTestResult())
331 // Convert the projected surface to a bezier. Split if necessary.
332 proj_srf->ConvertToBezier(projected_list, bezier_list);
333
334 // Remove projected surface
335 projected_list.RemoveSurface(proj_srf);
336 }
337
338 // Loop through the bezier List
339 G4BezierSurface* bez_ptr;
340 distance = kInfinity;
341
342 while(bezier_list.GetSurface() != (G4Surface*)0)
343 {
344 bez_ptr = (G4BezierSurface*)bezier_list.GetSurface();
345
346 // Add a temporary Hit
347 AddHit(bez_ptr->UAverage(), bez_ptr->VAverage());
348
349 // Evaluate Hit
350
351 // L. Broglia
352 // Modify function name
353 // bez_ptr->SetAveragePoint(Evaluate());
354 bez_ptr->SetAveragePoint(BSEvaluate());
355
356 // Calculate distance to ray origin
357 bez_ptr->CalcDistance(rayref.GetStart());
358
359 // Put closest to b_splines distance value
360 if(bez_ptr->GetDistance() < distance) distance = bez_ptr->GetDistance();
361
362 // Remove the temporary Hit
363 if (first_hit == Hit) first_hit = (G4UVHit*)0;
364 delete Hit;
365 Hit = (G4UVHit*)0;
366
367 // Move to next in the List
368 bezier_list.Step();
369 }
370
371 bezier_list.MoveToFirst();
372 if(bezier_list.GetSize() == 0)
373 {
374 active=0;
375 return;
376 }
377
378 // Check that approx Hit is in direction of ray
379 const G4Point3D& Pt = rayref.GetStart();
380 const G4Vector3D& Dir = rayref.GetDir();
381 G4Point3D TestPoint = G4Point3D( (0.00001*Dir) + Pt );
382 G4BezierSurface* Bsrf = (G4BezierSurface*)bezier_list.GetSurface(0);
383
384 G4Point3D AveragePoint = Bsrf->AveragePoint();
385 G4double TestDistance = TestPoint.distance2(AveragePoint);
386
387 if(TestDistance > distance)
388 // Hit behind ray starting point, no intersection.
389 active=0;
390}
391
392
393void G4BSplineSurface::AddHit(G4double u, G4double v)
394{
395 if(Hit == (G4UVHit*)0)
396 {
397 first_hit = new G4UVHit(u,v);
398 first_hit->SetNext(0);
399 Hit = first_hit;
400 }
401 else
402 {
403 Hit->SetNext(new G4UVHit(u,v));
404 Hit = Hit->GetNext();
405 Hit->SetNext(0);
406 }
407}
408
409
410void G4BSplineSurface::ProjectNURBSurfaceTo2D
411 (const G4Plane& plane1, const G4Plane& plane2,
412 register G4ProjectedSurface* proj_srf)
413{
414 // Projects the nurb surface so that the z-axis = ray.
415
416 /* L. Broglia
417 G4Point* tmp = (G4Point*)&ctl_points->get(0,0);
418 */
419
420 G4PointRat tmp = ctl_points->GetRat(0,0);
421 G4int rational = tmp.GetType();// Get the type of control point
422 G4Point3D psrfcoords;
423 register int rows = ctl_points->GetRows();
424 register int cols = ctl_points->GetCols();
425
426 for (register int i=0; i< rows; i++)
427 for(register int j=0; j < cols;j++)
428 {
429 if ( rational==4 ) // 4 coordinates
430 {
431 G4PointRat& srfcoords = ctl_points->GetRat(i, j);
432
433// L. Broglia
434// Changes for new G4PointRat
435
436 // Calculate the x- and y-coordinates for the new
437 // 2-D surface.
438 psrfcoords.setX(( srfcoords.x() * plane1.a
439 +srfcoords.y() * plane1.b
440 +srfcoords.z() * plane1.c
441 -srfcoords.w() * plane1.d));
442 psrfcoords.setY(( srfcoords.x() * plane2.a
443 +srfcoords.y() * plane2.b
444 +srfcoords.z() * plane2.c
445 -srfcoords.w() * plane2.d));
446
447 proj_srf->ctl_points->put(i,j,psrfcoords);
448 }
449 else // 3 coordinates
450 {
451 G4Point3D srfcoords = ctl_points->Get3D(i, j);
452
453 psrfcoords.setX(( srfcoords.x() * plane1.a
454 +srfcoords.y() * plane1.b
455 +srfcoords.z() * plane1.c
456 - plane1.d));
457
458 psrfcoords.setY(( srfcoords.x() * plane2.a
459 +srfcoords.y() * plane2.b
460 +srfcoords.z() * plane2.c
461 - plane2.d));
462
463 proj_srf->ctl_points->put(i,j,psrfcoords);
464 }
465 }
466}
467
468/* L. Broglia
469 Changes for new G4PointRat
470G4Point& G4BSplineSurface::InternalEvalCrv(G4int i, G4ControlPoints* crv)*/
471
472G4PointRat& G4BSplineSurface::InternalEvalCrv(G4int i, G4ControlPoints* crv)
473{
474 if ( ord <= 1 )
475 return crv->GetRat(i, k_index);
476
477 register int j = k_index;
478
479 while ( j > (k_index - ord + 1))
480 {
481 register G4double k1, k2;
482
483 k1 = tmp_knots->GetKnot((j + ord - 1));
484 k2 = tmp_knots->GetKnot(j);
485
486 if ((std::abs(k1 - k2)) > kCarTolerance )
487 {
488 /* L. Broglia
489 register G4PointRat* pts1 = &crv->get(i,j-1);
490 register G4PointRat* pts2 = &crv->get(i,j );
491 if(pts1->GetType()==3)
492 {
493 crv->CalcValues(k1, param, *(G4Point3D*)pts1, k2, *(G4Point3D*)pts2);
494 crv->put(0, j, *(G4Point3D*)pts2);
495 }
496 else
497 {
498 crv->CalcValues(k1, param, *(G4PointRat*)pts1, k2, *(G4PointRat*)pts2);
499 crv->put(0, j, *(G4PointRat*)pts2);
500 }
501 register G4PointRat* pts1 = &crv->GetRat(i,j-1);
502 register G4PointRat* pts2 = &crv->GetRat(i,j );
503 */
504 }
505
506 j--;
507 }
508
509 ord = ord-1;
510 return InternalEvalCrv(0, crv); // Recursion
511}
512
513
514G4Point3D G4BSplineSurface::BSEvaluate()
515{
516 register int i;
517 register int row_size = ctl_points->GetRows();
518 register G4ControlPoints *diff_curve;
519 register G4ControlPoints* curves;
520 G4Point3D result;
521
522 /* L. Broglia
523 G4Point* tmp = (G4Point*)&ctl_points->get(0,0);
524 */
525
526 G4PointRat* tmp = &ctl_points->GetRat(0,0);
527
528 register int point_type = tmp->GetType();
529 diff_curve = new G4ControlPoints(point_type, row_size, 1);
530 k_index = u_knots->GetKnotIndex(Hit->GetU(), GetOrder(ROW) );
531
532 ord = GetOrder(ROW);
533 if(k_index==-1)
534 {
535 delete diff_curve;
536 active = 0;
537 return result;
538 }
539
540 curves=new G4ControlPoints(*ctl_points);
541 tmp_knots = u_knots;
542 param = Hit->GetU();
543
544 if(point_type == 4)
545 {
546 for ( i = 0; i < row_size; i++)
547 {
548 ord = GetOrder(ROW);
549 G4PointRat rtr_pt = InternalEvalCrv(i, curves);
550 diff_curve->put(0,i,rtr_pt);
551 }
552
553 k_index = v_knots->GetKnotIndex( Hit->GetV(), GetOrder(COL) );
554 if(k_index==-1)
555 {
556 delete diff_curve;
557 delete curves;
558 active = 0;
559 return result;
560 }
561
562 ord = GetOrder(COL);
563 tmp_knots = v_knots;
564 param = Hit->GetV();
565
566 // Evaluate the diff_curve...
567 // G4PointRat rat_result = (G4PointRat&) InternalEvalCrv(0, diff_curve);
568 G4PointRat rat_result(InternalEvalCrv(0, diff_curve));
569
570 // Calc the 3D values.
571 // L. Broglia
572 // Changes for new G4PointRat
573 result.setX(rat_result.x()/rat_result.w());
574 result.setY(rat_result.y()/rat_result.w());
575 result.setZ(rat_result.z()/rat_result.w());
576 }
577 else
578 if(point_type == 3)
579 {
580 for ( i = 0; i < row_size; i++)
581 {
582 ord = GetOrder(ROW);
583 // G4Point3D rtr_pt = (G4Point3D&) InternalEvalCrv(i, curves);
584 G4Point3D rtr_pt = (InternalEvalCrv(i, curves)).pt();
585 diff_curve->put(0,i,rtr_pt);
586 }
587
588 k_index = v_knots->GetKnotIndex( Hit->GetV(), GetOrder(COL) );
589 if(k_index==-1)
590 {
591 delete diff_curve;
592 delete curves;
593 active = 0;
594 return result;
595 }
596
597 ord = GetOrder(COL);
598 tmp_knots = v_knots;
599 param = Hit->GetV();
600
601 // Evaluate the diff_curve...
602 result = (InternalEvalCrv(0, diff_curve)).pt();
603 }
604
605 delete diff_curve;
606 delete curves;
607 closest_hit = result;
608 return result;
609}
610
611
612G4Point3D G4BSplineSurface::Evaluation(const G4Ray&)
613{
614 // Delete old UVhits
615 G4UVHit* temphit=Hit;
616 while(Hit!=(G4UVHit*)0)
617 {
618 Hit=Hit->GetNext();
619 delete temphit;
620 temphit=Hit;
621 }
622
623 // delete temphit;
624
625 // Get the real Hit point
626 closest_hit = FinalIntersection();
627
628 // The following part (commented out) is old bullshit
629 // Check that Hit is not in a void i.e. InnerBoundary.
630 // for(int a=0; a<NumberOfInnerBoundaries;a++)
631 // if(InnerBoundary[a]->Inside(closest_hit, rayref))
632 // {
633 // Active(0);
634 // Distance(kInfinity);
635 // return closest_hit;
636 // }
637 return closest_hit;
638}
639
640
642{
643 G4double PointDistance=0;
644 PointDistance = ctl_points->ClosestDistanceToPoint(Pt);
645 return PointDistance;
646}
HepGeom::Point3D< G4double > G4Point3D
Definition: G4Point3D.hh:35
const G4Point3D PINFINITY(kInfinity, kInfinity, kInfinity)
#define COL
Definition: G4PointRat.hh:52
#define ROW
Definition: G4PointRat.hh:51
double G4double
Definition: G4Types.hh:64
int G4int
Definition: G4Types.hh:66
G4double ClosestDistanceToPoint(const G4Point3D &)
virtual ~G4BSplineSurface()
G4int Intersect(const G4Ray &)
void SetAveragePoint(G4Point3D p)
G4double GetU() const
G4double UAverage() const
G4Point3D AveragePoint() const
G4double VAverage() const
G4double GetV() const
G4int BIntersect(G4SurfaceList &)
G4int GetTestResult() const
G4int GetCols() const
G4int GetRows() const
G4Point3D Get3D(G4int i, G4int j) const
G4double ClosestDistanceToPoint(const G4Point3D &)
G4PointRat & GetRat(G4int i, G4int j) const
void put(G4int i, G4int j, const G4Point3D &tmp)
G4double GetKnot(G4int knot_number) const
G4int GetKnotIndex(G4double k_value, G4int order) const
Definition: G4KnotVector.cc:83
G4double d
Definition: G4Plane.hh:52
G4double a
Definition: G4Plane.hh:52
G4double c
Definition: G4Plane.hh:52
G4double b
Definition: G4Plane.hh:52
G4double x() const
G4int GetType(void) const
G4double y() const
G4double w() const
G4double z() const
G4ControlPoints * ctl_points
Definition: G4Ray.hh:49
const G4Plane & GetPlane(G4int number_of_plane) const
Definition: G4Ray.cc:54
const G4Vector3D & GetDir() const
const G4Point3D & GetStart() const
G4int GetSize() const
G4Surface * GetSurface()
void MoveToFirst(G4Surface *srf)
void AddSurface(G4Surface *srf)
const G4Surface * GetLastSurface() const
const G4Surface * GetNext() const
void RemoveSurface(G4Surface *srf)
G4int IsActive() const
G4double distance
Definition: G4Surface.hh:203
void SetActive(G4int act)
G4BoundingBox3D * bbox
Definition: G4Surface.hh:185
G4int Intersected
Definition: G4Surface.hh:194
G4Point3D closest_hit
Definition: G4Surface.hh:186
G4int active
Definition: G4Surface.hh:202
G4double GetDistance() const
G4double kCarTolerance
Definition: G4Surface.hh:192
void SetNext(G4UVHit *n)
Definition: G4UVHit.hh:51
G4UVHit * GetNext()
Definition: G4UVHit.hh:52
G4double GetV() const
Definition: G4UVHit.hh:54
G4double GetU() const
Definition: G4UVHit.hh:53