source: trunk/source/geometry/solids/BREPS/src/G4BSplineSurface.cc@ 1350

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

tag geant4.9.4 beta 1 + modifs locales

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