Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4BezierSurface.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 // G4BezierSurface.cc
33 //
34 // ----------------------------------------------------------------------
35 // History:
36 // -------
37 // - Replaced addition of coordinates by addition of 2 points
38 // (L. Broglia, 10/10/98)
39 // ----------------------------------------------------------------------
40 
41 #include "G4BezierSurface.hh"
42 #include "G4ConvexHull.hh"
43 
47 
49  : G4Surface(), bezier_list(0), smin(0.), smax(0.),
50  average_u(0.), average_v(0.), dir(0), u_knots(0), v_knots(0),
51  ctl_points(0), new_knots(0), ord(0), oslo_m(0), lower(0), upper(0),
52  u_min(0.), u_max(0.), v_min(0.), v_max(0.), old_points(0)
53 {
54  order[0]=0; order[1]=0;
55  u[0]=0.; u[1]=0.;
56  v[0]=0.; v[1]=0.;
57 }
58 
60 {
61  delete u_knots;
62  delete v_knots;
63  delete new_knots;
64  delete ctl_points;
65  delete old_points;
66 
67  G4OsloMatrix* temp_oslo = oslo_m;
68 
69  while(oslo_m != (G4OsloMatrix*)0)
70  {
71  oslo_m = oslo_m->GetNextNode();
72  delete temp_oslo;
73  temp_oslo = oslo_m;
74  }
75 
76  delete oslo_m;
77  delete bbox;
78 }
79 
81  : G4Surface(), bezier_list(0), smin(0.), smax(0.),
82  average_u(0.), average_v(0.), dir(0), u_knots(0), v_knots(0),
83  ctl_points(0), new_knots(0), ord(0), oslo_m(0), lower(0), upper(0),
84  u_min(0.), u_max(0.), v_min(0.), v_max(0.), old_points(0)
85 {
86  order[0]=0; order[1]=0;
87  u[0]=0.; u[1]=0.;
88  v[0]=0.; v[1]=0.;
89 }
90 
92 {
93  return G4Vector3D(0,0,0);
94 }
95 
97 {
98  dir = ROW;
99  ClipSurface();
100 
101  // G4cout << "\n CLIP BOTH DIRS 1: " << smin << " " << smax;
102 
103  if(smin > 1.0 || smax < 0.0)
104  {
105  bezier_list->RemoveSurface(this);
106  return 1;
107  }
108  else
109  if((smax - smin) > 0.8)
110  {
111  SplitNURBSurface();
112  return 0;
113  }
114 
115  LocalizeClipValues();
116  SetValues();
117 
118  // Other G4Vector3D clipping and testing.
119  dir = COL;
120  ClipSurface();
121  // G4cout << "\n CLIP BOTH DIRS 2: " << smin << " " << smax;
122 
123  if(smin > 1.0 || smax < 0.0)
124  {
125  bezier_list->RemoveSurface(this);
126  return 1;
127  }
128  else
129  if((smax - smin) > 0.8)
130  {
131  SplitNURBSurface();
132  return 0;
133  }
134 
135  LocalizeClipValues();
136  SetValues();
137  CalcAverage();
138  return 1;
139 }
140 
141 
143 {
144  // Finds the bounds of the 2D-projected nurb iow
145  // calculates the bounds for a bounding rectangle
146  // to the surface. The bounding rectangle is used
147  // for a preliminary check of intersection.
148  G4Point3D box_min = G4Point3D(PINFINITY);
149  G4Point3D box_max = G4Point3D(-PINFINITY);
150 
151 
152  // Loop to search the whole control point mesh
153  // for the minimum and maximum values for.X() and y.
154  for(register G4int a = ctl_points->GetRows()-1; a>=0;a--)
155  for(register G4int b = ctl_points->GetCols()-1; b>=0;b--)
156  {
157 /* L. Broglia
158  G4Point2d& tmp = (G4Point2d&)ctl_points->get(a,b);
159  if((box_min.X()) > (tmp.X())) box_min.X(tmp.X());
160  if((box_max.X()) < (tmp.X())) box_max.X(tmp.X());
161  if((box_min.Y()) > (tmp.Y())) box_min.Y(tmp.Y());
162  if((box_max.Y()) < (tmp.Y())) box_max.Y(tmp.Y());
163 */
164  G4Point3D tmp = ctl_points->Get3D(a,b);
165  if((box_min.x()) > (tmp.x())) box_min.setX(tmp.x());
166  if((box_max.x()) < (tmp.x())) box_max.setX(tmp.x());
167  if((box_min.y()) > (tmp.y())) box_min.setY(tmp.y());
168  if((box_max.y()) < (tmp.y())) box_max.setY(tmp.y());
169  }
170 
171  bbox = new G4BoundingBox3D(box_min, box_max);
172 }
173 
174 
175 void G4BezierSurface::CalcAverage()
176 {
177  // Calculate the average point from the average clip-values.
178  average_u = (u_min + u_max)/2.0;
179  average_v = (v_min + v_max)/2.0;
180 }
181 
182 
183 void G4BezierSurface::CalcDistance(const G4Point3D& ray_start)
184 {
185  // Calculate the distance between the average point and
186  // the ray starting point.
187  distance = ((((ray_start.x() - average_pt.x())*
188  (ray_start.x() - average_pt.x()))+
189  ((ray_start.y() - average_pt.y())*
190  (ray_start.y() - average_pt.y()))+
191  ((ray_start.z() - average_pt.z())*
192  (ray_start.z() - average_pt.z()))));
193 }
194 
195 
196 void G4BezierSurface::SetValues()
197 {
198  if(dir)
199  {
200  v_min = smin;
201  v_max = smax;
202  }
203  else
204  {
205  u_min = smin;
206  u_max = smax;
207  }
208 }
209 
210 
212 {
213  bezier_list = &bez_list;
214  G4int clip_regions = 0; // Used for tolerance/efficiency-testing
215 
216  do
217  {
218  // Calc bbox
219  CalcBBox();
220 
221  // Test bbox
222 /* L. Broglia
223  bbox->Test2dBBox();
224 */
225  // bbox->Test();
226 
227  // Check result
228  if(!bbox->GetTestResult())
229  return 0;
230 
231  // The first clipping has already been Done
232  // previously so we continue by doing the
233  // actual clip.
234 
235  // Cut out the clipped region of the surface
236  GetClippedRegionFromSurface();
237  clip_regions++;
238 
239  // Calculate the knot vectors and control points
240  // for the clipped surface
241  RefineSurface();
242 
243  // Gets the u- and v-bounds for the clipped surface
244  u_min = u_knots->GetKnot(0);
245  u_max = u_knots->GetKnot(u_knots->GetSize() - 1);
246  v_min = v_knots->GetKnot(0);
247  v_max = v_knots->GetKnot(v_knots->GetSize() - 1);
248 
249  // Choose the G4Vector3D for the next() clipping so that
250  // the larger side will be clipped.
251  if( (u_max - u_min) < (v_max - v_min) )
252  dir = 1;
253  else
254  dir = 0;
255 
256  // Calculate the clip points
257  ClipSurface();
258  // G4cout << "\n SMINMAX : " << smin << " " << smax;
259 
260  // The ray intersects with the bounding box
261  // but not with the surface itself.
262  if( smin > 1.0 || smax < 0.0 )
263  {
264  // G4cout << "\nG4BezierSurface::Intersect : bezier missed!";
265  // bezier_list->RemoveSurface(this);
266  return 0;
267  }
268 
269  if( (smax - smin) > 0.8)
270  {
271  // Multiple intersections
272  // G4cout << "\nG4BezierSurface::Intersect : Bezier split.";
273  SplitNURBSurface();
274  // Now the two new surfaces should also be
275  // clipped in both G4Vector3Ds i.e the
276  // last and the second last surface
277  // in the List. This is Done after returning
278  // from this function.
279  // G4cout << "\n\n BEZ SPLIT in final Calc! \n\n";
280 
281 
282  return 2;
283  }
284 
285  // Calculate the smin and smax values on the
286  // b_spline.
287  LocalizeClipValues();
288 
289  // Check if the size of the remaining surface is within the
290  // Tolerance .
291  } while ((u_max - u_min > Tolerance) || (v_max - v_min) > Tolerance);
292 
293  SetValues();
294  // G4cout << "\nG4BezierSurface::Intersect :Regions were cut "
295  // << clip_regions << " Times.\n";
296 
297  return 1;
298 }
299 
300 
302 {
303  // This routine is described in Computer Graphics, Volume 24,
304  // Number 4, August 1990 under the title Ray Tracing Trimmed
305  // Rational Surface Patches.
306 
307 
308  // G4cout << "\nBezier clip.";
309 
310  register G4int i,j;
311  register G4int col_size = ctl_points->GetCols();
312  register G4int row_size = ctl_points->GetRows();
313 
314  G4ConvexHull *ch_tmp= new G4ConvexHull(0,1.0e8,-1.0e8);
315  G4ConvexHull *ch_ptr=0, *ch_first=0;
316 
317  // The four cornerpoints of the controlpoint mesh.
318 
319 /* L. Broglia
320  G4Point2d pt1 = ctl_points->get(0,0);
321  G4Point2d pt2 = ctl_points->get(0,col_size-1);
322  G4Point2d pt3 = ctl_points->get(row_size-1,0);
323  G4Point2d pt4 = ctl_points->get(row_size-1,col_size-1);
324  G4Point2d v1,v2,v3;
325 */
326  G4Point3D pt1 = ctl_points->Get3D(0,0);
327  G4Point3D pt2 = ctl_points->Get3D(0,col_size-1);
328  G4Point3D pt3 = ctl_points->Get3D(row_size-1,0);
329  G4Point3D pt4 = ctl_points->Get3D(row_size-1,col_size-1);
330  G4Point3D v1,v2,v3;
331 
332  if ( dir == ROW)
333  {
334  // Vectors from cornerpoints
335  v1 = (pt1 - pt3);
336  // v1.X() = pt1.X() - pt3.X();
337  // v1.Y() = pt1.Y() - pt3.Y();
338  v2 = (pt2 - pt4);
339  // v2.X() = pt2.X() - pt4.X();
340  // v2.Y() = pt2.Y() - pt4.Y();
341  }
342  else
343  {
344  v1 = pt1 - pt2;
345  v2 = pt3 - pt4;
346  // v1.X() = pt1.X() - pt2.X();
347  // v1.Y() = pt1.Y() - pt2.Y();
348  // v2.X() = pt3.X() - pt4.X();
349  // v2.Y() = pt3.Y() - pt4.Y();
350  }
351 /* L. Broglia
352  v3.X(v1.X() + v2.X());
353  v3.Y(v1.Y() + v1.Y());
354 */
355  v3 = v1 + v2 ;
356 
357  smin = 1.0e8;
358  smax = -1.0e8;
359 
360  G4double norm = std::sqrt(v3.x() * v3.x() + v3.y() * v3.y());
361  if(!norm)
362  {
363  G4cout << "\nNormal zero!";
364  G4cout << "\nLINE & DIR: " << line.x() << " " << line.y() << " " << dir;
365  G4cout << "\n";
366 
367  if((std::abs(line.x())) > kCarTolerance)
368  line.setX(-line.x());
369  else
370  if((std::abs(line.y())) > kCarTolerance)
371  line.setY(-line.y());
372  else
373  {
374  G4cout << "\n RETURNING FROm CLIP..";
375  smin = 0; smax = 1; delete ch_tmp;
376  return;
377  }
378 
379  G4cout << "\nCHANGED LINE & DIR: " << line.x() << " "
380  << line.y() << " " << dir;
381  }
382  else
383  {
384  line.setX( v3.y() / norm);
385  line.setY(-v3.x() / norm);
386  }
387 
388  // smin = 1.0e8;
389  // smax = -1.0e8;
390  // G4cout << "\n FINAL LINE & DIR: " << line.X() << " "
391  // << line.Y() << " " << dir;
392 
393  if( dir == ROW)
394  {
395  // Create a Convex() hull List
396  for(G4int a = 0; a < col_size; a++)
397  {
398  ch_ptr = new G4ConvexHull(a/(col_size - 1.0),1.0e8,-1.0e8);
399  if(! a)
400  {
401  ch_first=ch_ptr; delete ch_tmp;
402  }
403  else ch_tmp->SetNextHull(ch_ptr);
404 
405  ch_tmp=ch_ptr;
406  }
407 
408  ch_ptr=ch_first;
409  register G4double value;
410 
411  // Loops through the control point mesh and calculates
412  // the nvex() hull for the surface.
413 
414  for( G4int h = 0; h < row_size; h++)
415  {
416  for(G4int k = 0; k < col_size; k++)
417  {
418 /* L. Broglia
419  G4Point2d& coordstmp = (G4Point2d&)ctl_points->get(h,k);
420  value = - ((coordstmp.X() * line.X() + coordstmp.Y() * line.Y()));
421 */
422  G4Point3D coordstmp = ctl_points->Get3D(h,k);
423  value = - ((coordstmp.x() * line.x() + coordstmp.y() * line.y()));
424 
425  if( value <= (ch_ptr->GetMin()+kCarTolerance)) ch_ptr->SetMin(value);
426  if( value >= (ch_ptr->GetMax()-kCarTolerance)) ch_ptr->SetMax(value);
427 
428  ch_ptr=ch_ptr->GetNextHull();
429  }
430 
431  ch_ptr=ch_first;
432  }
433 
434  ch_ptr=ch_first;
435  // Finds the points where the nvex() hull intersects
436  // with the coordinate .X()is. These points are the
437  // minimum and maximum values to where to clip the
438  // surface.
439 
440  for(G4int l = 0; l < col_size - 1; l++)
441  {
442  ch_tmp=ch_ptr->GetNextHull();
443  for(G4int q = l+1; q < col_size; q++)
444  {
445  register G4double d, param1, param2;
446  param1 = ch_ptr->GetParam();
447  param2 = ch_tmp->GetParam();
448 
449  if(ch_tmp->GetMax() - ch_ptr->GetMax())
450  {
451  d = Findzero( param1, param2, ch_ptr->GetMax(), ch_tmp->GetMax());
452  if( d <= (smin + kCarTolerance) ) smin = d * .99;
453  if( d >= (smax - kCarTolerance) ) smax = d * .99 + .01;
454  }
455 
456  if(ch_tmp->GetMin() - ch_ptr->GetMin())
457  {
458  d = Findzero( param1, param2, ch_ptr->GetMin(), ch_tmp->GetMin());
459  if( d <= (smin + kCarTolerance)) smin = d * .99;
460  if( d >= (smax - kCarTolerance)) smax = d * .99 + .01;
461  }
462 
463  ch_tmp=ch_tmp->GetNextHull();
464  }
465 
466  ch_ptr=ch_ptr->GetNextHull();
467  }
468 
469  ch_ptr=ch_first;
470 
471  if (smin <= 0.0) smin = 0.0;
472  if (smax >= 1.0) smax = 1.0;
473 
474  if ( (ch_ptr)
475  && (Sign(ch_ptr->GetMin()) != Sign(ch_ptr->GetMax()))) smin = 0.0;
476 
477  i = Sign(ch_tmp->GetMin()); // ch_tmp points to last nvex()_hull in List
478  j = Sign(ch_tmp->GetMax());
479 
480  if ( std::abs(i-j) > kCarTolerance ) smax = 1.0;
481  // if ( i != j) smax = 1.0;
482 
483  }
484  else // Other G4Vector3D
485  {
486  for(G4int n = 0; n < row_size; n++)
487  {
488  ch_ptr = new G4ConvexHull(n/(row_size - 1.0),1.0e8,-1.0e8);
489  if(!n)
490  {
491  ch_first=ch_ptr; delete ch_tmp;
492  }
493  else ch_tmp->SetNextHull(ch_ptr);
494 
495  ch_tmp=ch_ptr;
496  }
497 
498  ch_ptr=ch_first;
499 
500  for( G4int o = 0; o < col_size; o++)
501  {
502  for(G4int p = 0; p < row_size; p++)
503  {
504  register G4double value;
505 
506 /* L. Broglia
507  G4Point2d& coordstmp =(G4Point2d&) ctl_points->get(p,o);
508  value = - ((coordstmp.X() * line.X() + coordstmp.Y() * line.Y()));
509 */
510  G4Point3D coordstmp = ctl_points->Get3D(p,o);
511  value = - ((coordstmp.x() * line.x() + coordstmp.y() * line.y()));
512 
513  if( value <= (ch_ptr->GetMin()+kCarTolerance)) ch_ptr->SetMin(value);
514  if( value >= (ch_ptr->GetMax()-kCarTolerance)) ch_ptr->SetMax(value);
515 
516  ch_ptr=ch_ptr->GetNextHull();
517  }
518 
519  ch_ptr=ch_first;
520  }
521 
522  ch_ptr=ch_first;
523  delete ch_tmp;
524 
525  for(G4int q = 0; q < row_size - 1; q++)
526  {
527  ch_tmp=ch_ptr->GetNextHull();
528  for(G4int r = q+1; r < row_size; r++)
529  {
530  register G4double param1 = ch_ptr->GetParam();
531  register G4double param2 = ch_tmp->GetParam();
532  register G4double d;
533 
534  if(ch_tmp->GetMax() - ch_ptr->GetMax())
535  {
536  d = Findzero( param1, param2, ch_ptr->GetMax(), ch_tmp->GetMax());
537  if( d <= (smin + kCarTolerance) ) smin = d * .99;
538  if( d >= (smax - kCarTolerance) ) smax = d * .99 + .01;
539  }
540 
541  if(ch_tmp->GetMin()-ch_ptr->GetMin())
542  {
543  d = Findzero( param1, param2, ch_ptr->GetMin(), ch_tmp->GetMin());
544  if( d <= (smin + kCarTolerance) ) smin = d * .99;
545  if( d >= (smax - kCarTolerance) ) smax = d * .99 + .01;
546  }
547 
548  ch_tmp=ch_tmp->GetNextHull();
549  }
550 
551  ch_ptr=ch_ptr->GetNextHull();
552  }
553 
554  ch_tmp=ch_ptr;
555  ch_ptr=ch_first;
556 
557  if (smin <= 0.0) smin = 0.0;
558  if (smax >= 1.0) smax = 1.0;
559 
560  if ( (ch_ptr)
561  && (Sign(ch_ptr->GetMin()) != Sign(ch_ptr->GetMax()))) smin = 0.0;
562 
563  if ( ch_tmp )
564  {
565  i = Sign(ch_tmp->GetMin()); // ch_tmp points to last nvex()_hull in List
566  j = Sign(ch_tmp->GetMax());
567  if ( (std::abs(i-j) > kCarTolerance)) smax = 1.0;
568  }
569  }
570 
571  ch_ptr=ch_first;
572  while(ch_ptr && (ch_ptr!=ch_ptr->GetNextHull()))
573  {
574  ch_tmp=ch_ptr;
575  ch_ptr=ch_ptr->GetNextHull();
576  delete ch_tmp;
577  }
578 
579  delete ch_ptr;
580 
581  // Testing...
582  Clips++;
583 }
584 
585 
586 void G4BezierSurface::GetClippedRegionFromSurface()
587 {
588  // Returns the clipped part of the surface. First calculates the
589  // length of the new knotvector. Then uses the refinement function to
590  // get the new knotvector and controlmesh.
591 
592  // G4cout << "\nBezier region clipped.";
593 
594  delete new_knots;
595  if ( dir == ROW)
596  {
597  new_knots = new G4KnotVector(GetOrder(0) * 2);
598  for (register G4int i = 0; i < GetOrder(0); i++)
599  {
600  new_knots->PutKnot(i, smin);
601  new_knots->PutKnot(i+ GetOrder(0), smax);
602  }
603  }
604  else
605  {
606  new_knots = new G4KnotVector( GetOrder(1) * 2);
607  for ( register G4int i = 0; i < GetOrder(1); i++)
608  {
609  new_knots->PutKnot(i, smin);
610  new_knots->PutKnot(i+ GetOrder(1), smax);
611  }
612  }
613 } // NURB_REGION_FROM_SURFACE
614 
615 
616 void G4BezierSurface::RefineSurface()
617 {
618  // Returns the new clipped surface. Calculates the new controlmesh
619  // and knotvectorvalues for the surface by using the Oslo-algorithm
620 
621  delete old_points;
622  if (dir == ROW)
623  {
624  // Row (u) G4Vector3D
625  ord = GetOrder(0);
626  CalcOsloMatrix();
627  for(register G4int a=0;a<new_knots->GetSize();a++)
628  u_knots->PutKnot(a, new_knots->GetKnot(a));
629 
630  lower = 0;
631  upper = new_knots->GetSize() - GetOrder(0);
632 
633  // Copy of the old points.
634  old_points = new G4ControlPoints(*ctl_points);
635  MapSurface(this);
636  }
637  else
638  {
639  ord = GetOrder(1);
640  CalcOsloMatrix ();
641  for(register G4int a=0;a < new_knots->GetSize();a++)
642  v_knots->PutKnot(a, new_knots->GetKnot(a));
643 
644  // Copy of the old points.
645  old_points = new G4ControlPoints(*ctl_points);
646 
647  // Make new controlpoint matrix,
648  register G4int cols = ctl_points->GetCols();
649  delete ctl_points;
650 
651  ctl_points = new G4ControlPoints(2,(new_knots->GetSize()-
652  GetOrder(1)),cols);
653  lower = 0;
654  upper = new_knots->GetSize() - GetOrder(1);
655  MapSurface(this);
656  }
657 }// REFINE_SURFACE
658 
659 
660 void G4BezierSurface::CalcOsloMatrix()
661 {
662  // This algorithm is described in the paper "Making the Oslo-algorithm
663  // more efficient" in SIAM J.NUMER.ANAL. Vol.23, No. 3, June '86
664  // Calculates the oslo-matrix , which is used in mapping the new
665  // knotvector- and controlpoint-values.
666 
667  register G4KnotVector *ah;
668  register G4KnotVector *newknots;
669  register G4int i;
670  register G4int j;
671  register G4int mu, muprim;
672  register G4int vv, p;
673  register G4int iu, il, ih, n1;
674  register G4int ahi;
675  register G4double beta1;
676  register G4double tj;
677 
678  ah = new G4KnotVector(ord*(ord + 1)/2);
679  newknots = new G4KnotVector(ord * 2 );
680 
681  n1 = new_knots->GetSize() - ord;
682  mu = 0;
683 
684  if(oslo_m!=(G4OsloMatrix*)0)
685  {
686  G4OsloMatrix* tmp;
687 
688  // while(oslo_m!=oslo_m->next)
689  while(oslo_m!=(G4OsloMatrix*)0)
690  {
691  tmp=oslo_m->GetNextNode();delete oslo_m; oslo_m=tmp;
692  }
693  }
694 
695  delete oslo_m;
696  oslo_m = new G4OsloMatrix();
697 
698  register G4OsloMatrix* o_ptr = oslo_m;
699 
700  register G4KnotVector* old_knots;
701  if(dir)
702  old_knots = v_knots;
703  else
704  old_knots = u_knots;
705 
706  for (j = 0; j < n1; j++)
707  {
708  if ( j != 0 )
709  {
710  oslo_m->SetNextNode(new G4OsloMatrix());
711  oslo_m = oslo_m->GetNextNode();
712  }
713 
714  while (old_knots->GetKnot(mu + 1) <= new_knots->GetKnot(j))
715  mu = mu + 1; // find the bounding mu
716 
717  i = j + 1;
718  muprim = mu;
719 
720  while ((new_knots->GetKnot(i) == old_knots->GetKnot(muprim)) &&
721  i < (j + ord))
722  {
723  i++;
724  muprim--;
725  }
726 
727  ih = muprim + 1;
728 
729  for (vv = 0, p = 1; p < ord; p++)
730  {
731  if (new_knots->GetKnot(j + p) == old_knots->GetKnot(ih))
732  ih++;
733  else
734  newknots->PutKnot(++vv - 1,new_knots->GetKnot(j + p));
735  }
736 
737  ahi = AhIndex(0, ord - 1,ord);
738  ah->PutKnot(ahi, 1.0);
739 
740  for (p = 1; p <= vv; p++)
741  {
742  beta1 = 0.0;
743  tj = newknots->GetKnot(p-1);
744 
745  if (p - 1 >= muprim)
746  {
747  beta1 = AhIndex(p - 1, ord - muprim,ord);
748  beta1 = ((tj - old_knots->GetKnot(0)) * beta1) /
749  (old_knots->GetKnot(p + ord - vv) - old_knots->GetKnot(0));
750  }
751 
752  i = muprim - p + 1;
753  il = Amax (1, i);
754  i = n1 - 1 + vv - p;
755  iu = Amin (muprim, i);
756 
757  for (i = il; i <= iu; i++)
758  {
759  register G4double d1, d2;
760  register G4double beta;
761 
762  d1 = tj - old_knots->GetKnot(i);
763  d2 = old_knots->GetKnot(i + p + ord - vv - 1) - tj;
764 
765  beta = ah->GetKnot(AhIndex(p - 1, i + ord - muprim - 1,ord)) /
766  (d1 + d2);
767 
768 
769  ah->PutKnot(AhIndex(p, i + ord - muprim - 2,ord), d2 * beta + beta1) ;
770  beta1 = d1 * beta;
771  }
772 
773  ah->PutKnot(AhIndex(p, iu + ord - muprim - 1,ord), beta1);
774 
775  if (iu < muprim)
776  {
777  register G4double kkk;
778  register G4double ahv;
779 
780  kkk = old_knots->GetKnot(n1 - 1 + ord);
781  ahv = AhIndex (p - 1, iu + ord - muprim,ord);
782  ah->PutKnot(AhIndex(p, iu + ord - muprim - 1,ord),
783  beta1 + (kkk - tj) * ahv /
784  (kkk - old_knots->GetKnot(iu + 1)));
785  }
786  }
787 
788  // Remove the oslo matrix List
789  G4OsloMatrix* temp_oslo = oslo_m;
790 
791 /*
792  if(oslo_m != (G4OsloMatrix*)0)
793  while(oslo_m->next != oslo_m)
794  {
795  oslo_m = oslo_m->next;
796  delete temp_oslo;
797  temp_oslo = oslo_m;
798  }
799 
800  // Remove the last
801  delete oslo_m;
802 */
803 
804  while(oslo_m != (G4OsloMatrix*)0)
805  {
806  oslo_m = oslo_m->GetNextNode();
807  delete temp_oslo;
808  temp_oslo = oslo_m;
809  }
810 
811  delete oslo_m;
812 
813  // Create a new oslo matrix
814  oslo_m = new G4OsloMatrix(vv+1, Amax(muprim - vv,0), vv);
815 
816  for ( i = vv, p = 0; i >= 0; i--)
817  oslo_m->GetKnotVector()
818  ->PutKnot ( p++, ah->GetKnot(AhIndex (vv, (ord-1) - i,ord)));
819 
820  }
821 
822  delete ah;
823  delete newknots;
824  oslo_m->SetNextNode(0);
825  oslo_m = o_ptr;
826 }
827 
828 
829 void G4BezierSurface::MapSurface(G4Surface*)
830 {
831  // This algorithm is described in the paper Making the Oslo-algorithm
832  // more efficient in SIAM J.NUMER.ANAL. Vol.23, No. 3, June '86
833  // Maps the new controlpoints into the new surface.
834 
835  register G4ControlPoints *c_ptr;
836  register G4OsloMatrix *o_ptr;
837  register G4ControlPoints* new_pts;
838  register G4ControlPoints* old_pts;
839 
840  new_pts = ctl_points;
841 
842  // Copy the old points so they can be used in calculating the new ones.
843  // old_pts = new G4ControlPoints(*ctl_points);
844  old_pts = old_points;
845  register G4int j, // j loop
846  i; // oslo loop
847 
848  c_ptr = new_pts;
849  register G4int size; // The number of rows or columns,
850  // depending on processing order
851 
852  if(!dir)
853  size=new_pts->GetRows();
854  else
855  size=new_pts->GetCols();
856 
857  for(G4int a=0; a<size;a++)
858  {
859  if ( lower != 0)
860  {
861  for ( i = 0, o_ptr = oslo_m;
862  i < lower;
863  i++, o_ptr = o_ptr->GetNextNode()){;}
864  }
865  else
866  {
867  o_ptr = oslo_m;
868  }
869 
870  if(!dir)// Direction ROW
871  {
872  for ( j = lower; j < upper; j++, o_ptr = o_ptr->GetNextNode())
873  {
874  register G4double o_scale;
875  register G4int x;
876  x=a;
877 
878 /* L. Broglia
879  G4Point2d o_pts= (G4Point2d&)old_pts->Get2d(x, o_ptr->GetOffset());
880  G4Point2d tempc= (G4Point2d&)c_ptr->Get2d(j/upper,(j)%upper-lower);
881 */
882  G4Point3D o_pts = old_pts->Get3D(x, o_ptr->GetOffset());
883  G4Point3D tempc = c_ptr->Get3D(j/upper, (j)%upper-lower);
884 
885  o_scale = o_ptr->GetKnotVector()->GetKnot(0);
886 
887  tempc.setX(o_pts.x() * o_scale);
888  tempc.setY(o_pts.x() * o_scale);
889 
890  for ( i = 1; i <= o_ptr->GetSize(); i++)
891  {
892  o_scale = o_ptr->GetKnotVector()->GetKnot(i);
893 
894 /* L. Broglia
895  o_pts = (G4Point2d&)old_pts->get(x, i+o_ptr->GetOffset());
896  tempc.X(tempc.X() + o_scale * o_pts.X());
897  tempc.Y(tempc.Y() + o_scale * o_pts.Y());
898 */
899  o_pts = old_pts->Get3D(x, i+o_ptr->GetOffset());
900  tempc.setX(tempc.x() + o_scale * o_pts.x());
901  tempc.setY(tempc.y() + o_scale * o_pts.y());
902 
903  }
904 
905  c_ptr->put(a,(j)%upper-lower,tempc);
906  }
907  }
908  else // dir = COL
909  {
910  for ( j = lower; j < upper; j++, o_ptr = o_ptr->GetNextNode())
911  {
912  register G4double o_scale;
913  register G4int x;
914  x=a;
915 
916 /* L. Broglia
917  G4Point2d o_pts= (G4Point2d&)old_pts->Get2d(o_ptr->GetOffset(), x);
918  G4Point2d tempc = (G4Point2d&)c_ptr->Get2d((j)%upper-lower,j/upper);
919 */
920  G4Point3D o_pts = old_pts->Get3D(o_ptr->GetOffset(), x);
921  G4Point3D tempc = c_ptr->Get3D((j)%upper-lower,j/upper);
922 
923  o_scale = o_ptr->GetKnotVector()->GetKnot(0);
924 
925  tempc.setX(o_pts.x() * o_scale);
926  tempc.setY(o_pts.y() * o_scale);
927 
928  for ( i = 1; i <= o_ptr->GetSize(); i++)
929  {
930  o_scale = o_ptr->GetKnotVector()->GetKnot(i);
931 /* L. Broglia
932  o_pts= (G4Point2d&)old_pts->get(i+o_ptr->GetOffset(),a);
933 */
934  o_pts= old_pts->Get3D(i+o_ptr->GetOffset(),a);
935  tempc.setX(tempc.x() + o_scale * o_pts.x());
936  tempc.setY(tempc.y() + o_scale * o_pts.y());
937  }
938 
939  c_ptr->put((j)%upper-lower,a,tempc);
940  }
941  }
942  }
943 }
944 
945 
946 void G4BezierSurface::SplitNURBSurface()
947 {
948  // Divides the surface in two parts. Uses the oslo-algorithm to calculate
949  // the new knotvectors and controlpoints for the subsurfaces.
950 
951  // G4cout << "\nBezier splitted.";
952 
953  register G4double value;
954  register G4int i;
955  register G4int k_index=0;
956  G4BezierSurface *srf1, *srf2;
957  G4int nr,nc;
958 
959  if ( dir == ROW )
960  {
961  value = u_knots->GetKnot((u_knots->GetSize()-1)/2);
962 
963  for( i = 0; i < u_knots->GetSize(); i++)
964  if( value == u_knots->GetKnot(i) )
965  {
966  k_index = i;
967  break;
968  }
969 
970  if ( k_index == 0)
971  {
972  value = ( value + u_knots->GetKnot(u_knots->GetSize() -1))/2.0;
973  k_index = GetOrder(ROW);
974  }
975 
976  new_knots = u_knots->MultiplyKnotVector(GetOrder(ROW), value);
977 
978  ord = GetOrder(ROW);
979  CalcOsloMatrix();
980 
981  srf1 = new G4BezierSurface(*this);
982  // srf1->dir=ROW;
983  srf1->dir=COL;
984 
985  new_knots->ExtractKnotVector(srf1->u_knots, k_index +
986  srf1->GetOrder(ROW),0);
987 
988  nr= srf1->v_knots->GetSize() - srf1->GetOrder(COL);
989  nc= srf1->u_knots->GetSize() - srf1->GetOrder(ROW);
990  delete srf1->ctl_points;
991 
992  srf1->ctl_points= new G4ControlPoints(2, nr, nc);
993  srf2 = new G4BezierSurface(*this);
994 
995  // srf2->dir = ROW;
996  srf2->dir = COL;
997 
998  new_knots->ExtractKnotVector(srf2->u_knots,
999  new_knots->GetSize(), k_index);
1000 
1001  nr= srf2->v_knots->GetSize() - srf2->GetOrder(COL);
1002  nc= srf2->u_knots->GetSize() - srf2->GetOrder(ROW);
1003 
1004  delete srf2->ctl_points;
1005  srf2->ctl_points = new G4ControlPoints(2, nr, nc);
1006 
1007  lower = 0;
1008  upper = k_index;
1009  MapSurface(srf1);
1010 
1011  lower = k_index;
1012  upper = new_knots->GetSize() - srf2->GetOrder(ROW);
1013  MapSurface(srf2);
1014  }
1015  else // G4Vector3D = col
1016  {
1017  value = v_knots->GetKnot((v_knots->GetSize() -1)/2);
1018 
1019  for( i = 0; i < v_knots->GetSize(); i++)
1020  if( value == v_knots->GetKnot(i))
1021  {
1022  k_index = i;
1023  break;
1024  }
1025  if ( k_index == 0)
1026  {
1027  value = ( value + v_knots->GetKnot(v_knots->GetSize() -1))/2.0;
1028  k_index = GetOrder(COL);
1029  }
1030 
1031  new_knots = v_knots->MultiplyKnotVector( GetOrder(COL), value );
1032  ord = GetOrder(COL);
1033 
1034  CalcOsloMatrix();
1035 
1036  srf1 = new G4BezierSurface(*this);
1037  // srf1->dir = COL;
1038  srf1->dir = ROW;
1039 
1040  new_knots->ExtractKnotVector(srf1->v_knots,
1041  k_index + srf1->GetOrder(COL), 0);
1042 
1043  nr = srf1->v_knots->GetSize() - srf1->GetOrder(COL);
1044  nc = srf1->u_knots->GetSize() - srf1->GetOrder(ROW);
1045 
1046  delete srf1->ctl_points;
1047  srf1->ctl_points = new G4ControlPoints(2, nr, nc);
1048 
1049  srf2 = new G4BezierSurface(*this);
1050  // srf2->dir = COL;
1051  srf2->dir = ROW;
1052 
1053  new_knots->ExtractKnotVector(srf2->v_knots, new_knots->GetSize(), k_index);
1054 
1055  nr = srf2->v_knots->GetSize() - srf2->GetOrder(COL);
1056  nc = srf2->u_knots->GetSize() - srf2->GetOrder(ROW);
1057 
1058  delete srf2->ctl_points;
1059  srf2->ctl_points = new G4ControlPoints(2,nr, nc);
1060 
1061  lower = 0;
1062  upper = k_index;
1063  MapSurface(srf1);
1064 
1065  // next->oslo_m = oslo_m;
1066  lower = k_index;
1067  upper = new_knots->GetSize() - srf2->GetOrder(COL);
1068  MapSurface(srf2);
1069  }
1070 
1071  bezier_list->AddSurface(srf1);
1072  bezier_list->AddSurface(srf2);
1073  delete new_knots;
1074 
1075  // Testing
1076  Splits++;
1077 }