Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4NURBS.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 // Olivier Crumeyrolle 12 September 1996
31 
32 // G4NURBS.cc
33 // Implementation of class G4NURBS
34 // OC 100796
35 
36 
37 #include "G4NURBS.hh"
38 
39 // G4NURBS.hh includes globals.hh which includes a lot of others
40 // so no more includes required here
41 
43 // Here start the real world. Please, check your armored jacket. //
45 
46 std::ostream & operator << (std::ostream & inout_outStream,
47  const G4NURBS & in_kNurb)
48 {
49  inout_outStream
50  // the magic could be changed for good reasons only
51  << "##ojc{NURBS}def[1.01.96.7] Just a magic. Could be added to /etc/magic"
52  << "\n# NURBS Definition File (human and computer readable format)"
53  << "\n# :" << in_kNurb.Whoami()
54  << "\n# U order\tV order : "
55  << '\n' << in_kNurb.GetUorder() << "\t\t" << in_kNurb.GetVorder();
56  // number of knots and knots themselves for U and V
58  /*(*(G4int *)(&dir))++*/ dir=(G4NURBS::t_direction)(((G4int)(dir))+1) )
59  {
60  inout_outStream
61  << "\n# Number of knots along " << G4NURBS::Tochar(dir)
62  << '\n' << in_kNurb.GetnbrKnots(dir)
63  << "\n# " << G4NURBS::Tochar(dir) << " knots vector (as a column)";
64  { // begin knots iteration
65  G4double oneKnot;
66  G4NURBS::KnotsIterator knotI(in_kNurb,dir);
67  G4bool otherKnots;
68  do
69  {
70  otherKnots = knotI.pick(&oneKnot);
71  inout_outStream << "\n\t\t" << oneKnot;
72  }
73  while (otherKnots);
74  } // end of knots iteration
75  } // end of direction loop
76 
77  // number of control points in U and V direction
78  // and controlpoints
79  inout_outStream
80  << "\n# Number of control points along U and V"
81  << '\n' << in_kNurb.GetUnbrCtrlPts()
82  << " " << in_kNurb.GetVnbrCtrlPts()
83  << "\n# Control Points (one by line, U increasing first)";
84  { // begin of control points iteration
86  G4NURBS::CtrlPtsIterator cpI(in_kNurb);
87  G4bool otherCPs;
88  do
89  {
90  otherCPs = cpI.pick(&oneCP);
91  inout_outStream
92  << "\n\t" << oneCP[G4NURBS::X]
93  << "\t" << oneCP[G4NURBS::Y]
94  << "\t" << oneCP[G4NURBS::Z]
95  << "\t" << oneCP[G4NURBS::W];
96  }
97  while (otherCPs);
98  } // end of control point iteration
99 
100  inout_outStream << "\n# That's all!"
101  << G4endl; // endl do an \n and a flush
102  return inout_outStream;
103 }
104 
105 // the CC compiler issue some "maybe no value returned"
106 // but everything is ok
107 
109 {
110  in_dir = (t_direction)(in_dir & DMask);
111  if ( in_index < m[in_dir].nbrKnots )
112  return ((G4float)(m[in_dir].pKnots[in_index]));
113  else
114  {
115  G4cerr << "\nERROR: G4NURBS::GetfloatKnot: index out of range\n"
116  << "\n\t in_dir : " << G4int(in_dir)
117  << ", in_index : " << G4int(in_index)
118  << "m[in_dir].nbrKnots : " << m[in_dir].nbrKnots << G4endl;
119  return ((G4float)m[in_dir].pKnots[m[in_dir].nbrKnots-1]);
120  }
121 }
122 
124 {
125  in_dir = (t_direction)(in_dir & DMask);
126  if ( in_index < m[in_dir].nbrKnots )
127  return (G4double)(m[in_dir].pKnots[in_index]);
128  else
129  {
130  G4cerr << "\nERROR: G4NURBS::GetdoubleKnot: index out of range"
131  << "\n\t in_dir : " << G4int(in_dir)
132  << ", in_index : " << G4int(in_index)
133  << "m[in_dir].nbrKnots : " << m[in_dir].nbrKnots
134  << G4endl;
135  return (G4double)(m[in_dir].pKnots[m[in_dir].nbrKnots-1]);
136  }
137 }
138 
141 {
142  if (in_onedimindex < mtotnbrCtrlPts)
143  return TofloatCtrlPt(mpCtrlPts[in_onedimindex]);
144  else
145  {
146  G4cerr << "\nERROR: G4NURBS::GetfloatCtrlPt: index out of range"
147  << "\n\t in_onedimindex : " << in_onedimindex
148  << " , mtotnbrCtrlPts : " << mtotnbrCtrlPts << G4endl;
150  }
151 }
152 
155 {
156  if ( (in_Uindex < m[U].nbrCtrlPts) && (in_Vindex < m[V].nbrCtrlPts) )
157  return TofloatCtrlPt(mpCtrlPts[To1d(in_Uindex, in_Vindex)]);
158  else
159  {
160  G4cerr << "\nERROR: G4NURBS::GetfloatCtrlPt: index(s) out of range"
161  << "\n\t in_Uindex : " << in_Uindex
162  << " , in_Vindex : " << in_Vindex
163  << " , UnbrCtrlPts : " << m[U].nbrCtrlPts
164  << " , VnbrCtrlPts : " << m[V].nbrCtrlPts << G4endl;
166  }
167 }
168 
171 {
172  if ( in_onedimindex < mtotnbrCtrlPts )
173  return TodoubleCtrlPt(mpCtrlPts[in_onedimindex]);
174  else
175  {
176  G4cerr << "\nERROR: G4NURBS::getdoubleCtrlPts: index out of range"
177  << "\n\t in_onedimindex : " << in_onedimindex
178  << " , mtotnbrCtrlPts : " << mtotnbrCtrlPts << G4endl;
180  }
181 }
182 
185 {
186  if ( (in_Uindex < m[U].nbrCtrlPts) && (in_Vindex < m[V].nbrCtrlPts) )
187  return TodoubleCtrlPt(mpCtrlPts[To1d(in_Uindex, in_Vindex)]);
188  else
189  {
190  G4cerr << "\nERROR: G4NURBS::GetdoubleCtrlPt: index(s) out of range"
191  << "\n\t in_Uindex : " << in_Uindex
192  << " , in_Vindex : " << in_Vindex
193  << " , UnbrCtrlPts : " << m[U].nbrCtrlPts
194  << " , VnbrCtrlPts : " << m[V].nbrCtrlPts << G4endl;
196  }
197 }
198 
199 // Total copy
201 {
202  in_dir = (t_direction)(in_dir & DMask);
203  G4float * p = new G4float [m[in_dir].nbrKnots];
204  for (t_indKnot i = 0; i < m[in_dir].nbrKnots; i++)
205  p[i] = (G4float)m[in_dir].pKnots[i];
206  return p;
207 }
208 
210 {
211  in_dir = (t_direction)(in_dir & DMask);
212  G4double * p = new G4double [m[in_dir].nbrKnots];
213  for (t_indKnot i = 0; i < m[in_dir].nbrKnots; i++)
214  p[i] = (G4double)m[in_dir].pKnots[i];
215  return p;
216 }
217 
219 {
220  G4float * p = new G4float [mtotnbrCtrlPts*NofC];
221  for (t_indKnot i = 0; i < mtotnbrCtrlPts*NofC; i++)
222  p[i] = (G4float)(((t_Coord *)mpCtrlPts)[i]);
223  return p;
224 }
225 
227 {
229  for (t_indKnot i = 0; i < mtotnbrCtrlPts*NofC; i++)
230  p[i] = (G4double)(((t_Coord *)mpCtrlPts)[i]);
231  return p;
232 }
233 
234 // Iterators
235 
237  G4NURBS::t_direction in_dir,
238  t_indKnot in_startIndex)
239  : kmdir((G4NURBS::t_direction)(in_dir & G4NURBS::DMask)),
240  kmpMax(in_rNurb.m[kmdir].pKnots + in_rNurb.m[kmdir].nbrKnots)
241 {
242  if (in_startIndex < in_rNurb.m[kmdir].nbrKnots)
243  mp = in_rNurb.m[kmdir].pKnots + in_startIndex;
244  else
245  {
246  G4cerr << "\nERROR: G4NURBS::KnotsIterator: in_startIndex out of range"
247  << "\n\tin_startIndex : " << in_startIndex
248  << ", nbr of knots : " << in_rNurb.m[kmdir].nbrKnots
249  << "\n\t mp set to NULL, calls to picking functions will fail"
250  << G4endl;
251  mp = 0;
252  }
253 }
254 
256 {
257  (*inout_pDbl) = (G4double)(*mp);
258  return (G4bool)((++mp)<kmpMax);
259 }
260 
262 {
263  (*inout_pFlt) = (G4float)(*mp);
264  return (G4bool)((++mp)<kmpMax);
265 }
266 
268  t_indCtrlPt in_startCtrlPtIndex)
269  : kmpMax((const t_Coord *)(in_rNurb.mpCtrlPts + in_rNurb.mtotnbrCtrlPts))
270 {
271  if (in_startCtrlPtIndex < in_rNurb.mtotnbrCtrlPts )
272  mp = (const t_Coord *)(in_rNurb.mpCtrlPts + in_startCtrlPtIndex);
273  else
274  {
275  G4cerr << "\nERROR: G4NURBS::CtrlPtsCoordsIterator: "
276  << "in_startCtrlPtIndex out of range"
277  << "\n\tin_startCtrlPtIndex : " << in_startCtrlPtIndex
278  << ", nbr of CtrlPts : " << in_rNurb.mtotnbrCtrlPts
279  << "\n\t mp set to NULL, calls to picking functions will fail"
280  << G4endl;
281  mp = 0;
282  }
283 }
284 
286 {
287  (*inout_pDbl) = (G4double)((*mp));
288  return (G4bool)((++mp)<kmpMax);
289 }
290 
292 {
293  (*inout_pFlt) = (G4float)((*mp));
294  return (G4bool)((++mp)<kmpMax);
295 }
296 
298  t_indCtrlPt in_startIndex)
299  : kmpMax(in_rNurb.mpCtrlPts + in_rNurb.mtotnbrCtrlPts)
300 {
301  if (in_startIndex < in_rNurb.mtotnbrCtrlPts )
302  mp = (in_rNurb.mpCtrlPts + in_startIndex);
303  else
304  {
305  G4cerr << "\nERROR: G4NURBS::CtrlPtsIterator: in_startIndex out of range"
306  << "\n\tin_startIndex : " << in_startIndex
307  << ", nbr of CtrlPts : " << in_rNurb.mtotnbrCtrlPts
308  << "\n\t mp set to NULL, calls to picking functions will fail"
309  << G4endl;
310  mp = 0;
311  }
312 }
313 
315 {
316  for (t_indCoord i = G4NURBS::X; i < G4NURBS::NofC; i++)
317  (*inout_pDblCtrlPt)[i] = (G4double)((*mp)[i]);
318  return (G4bool)((++mp)<kmpMax);
319 }
320 
322 {
323  for (t_indCoord i = G4NURBS::X; i < G4NURBS::NofC; i++)
324  (*inout_pFltCtrlPt)[i] = (G4float)((*mp)[i]);
325  return (G4bool)((++mp)<kmpMax);
326 }
327 
329 // Building functions
330 
332 {
333  G4bool isgood = (io_d.order + io_d.nbrCtrlPts == io_d.nbrKnots)
334  && (io_d.pKnots == 0);
335  if ( isgood )
336  {
337  io_d.pKnots = new t_Knot [io_d.nbrKnots];
338  if (in_KVGFlag != UserDefined)
339  { // let's do the knots
340  t_indKnot indKnot = 0;
341  t_index nbrCentralDistinctKnots = io_d.nbrCtrlPts-io_d.order;
342  if ( (nbrCentralDistinctKnots % in_KVGFlag) == 0)
343  {
344  nbrCentralDistinctKnots /= in_KVGFlag;
345  // first and last knots repeated 'order' Times
346  for (t_index i=0; i < io_d.order; indKnot++,i++)
347  {
348  io_d.pKnots[indKnot] = 0;
349  io_d.pKnots[indKnot+io_d.nbrCtrlPts] = 1;
350  }
351 
352  t_Knot stepKnot = 1.0/(t_Knot)(nbrCentralDistinctKnots+1);
353  t_Knot valKnot = stepKnot;
354 
355  // central knots
356  for (t_indKnot j=0; j<nbrCentralDistinctKnots; valKnot+=stepKnot, j++)
357  {
358  for (t_indKnot k=0; k<t_indKnot(in_KVGFlag); indKnot++, k++)
359  io_d.pKnots[indKnot] = valKnot;
360  }
361  }
362  else isgood = false;
363  } // end of knots making
364  }
365  return isgood;
366 }
367 
368 
369 std::ostream & operator << (std::ostream & io_ostr,
371 {
372  switch (in_f)
373  {
374  case G4NURBS::UserDefined: io_ostr << "UserDefined"; break;
375  case G4NURBS::Regular: io_ostr << "Regular"; break;
376  case G4NURBS::RegularRep: io_ostr << "RegularRep"; break;
377  default: io_ostr << (G4int)in_f;
378  }
379  return io_ostr;
380 }
381 
383 // Constructors and co
384 
385 void G4NURBS::Conscheck() const
386 {
387  G4int dummy;
389  for (dummy=0; (dummy?(dir=V):(dir=U)),(dummy < NofD); dummy++)
390  {
391  if (m[dir].order<=0)
392  {
394  ed << "The order in the "
395  << G4NURBS::Tochar(dir)
396  << " direction must be >= 1" << G4endl;
397  G4Exception("G4NURBS::Conscheck()",
398  "greps9001", FatalException, ed);
399  }
400  if (m[dir].nbrCtrlPts<=0)
401  {
403  ed << "The number of control points "
404  << G4NURBS::Tochar(dir)
405  << " direction must be >= 1" << G4endl;
406  G4Exception("G4NURBS::Conscheck()",
407  "greps9002", FatalException, ed);
408  }
409  } // end of dummy
410 }
411 
412 G4NURBS::G4NURBS ( t_order in_Uorder, t_order in_Vorder,
413  t_inddCtrlPt in_UnbrCtrlPts, t_inddCtrlPt in_VnbrCtrlPts,
414  t_CtrlPt * in_pCtrlPts,
415  t_Knot * in_pUKnots, t_Knot * in_pVKnots,
416  t_CheckFlag in_CheckFlag )
417 {
418  m[U].order=in_Uorder; m[V].order=in_Vorder;
419  m[U].nbrCtrlPts=in_UnbrCtrlPts; m[V].nbrCtrlPts=in_VnbrCtrlPts;
420 
422  m[U].nbrKnots = m[U].order + m[U].nbrCtrlPts;
423  m[V].nbrKnots = m[V].order + m[V].nbrCtrlPts;
424 
425  if (in_CheckFlag)
426  Conscheck();
427 
428  // CtrlPts
429  if (! (mpCtrlPts = in_pCtrlPts) )
430  {
432  ed << "A NURBS MUST HAVE CONTROL POINTS!\n"
433  << "\teven if they are defined later, the array must be allocated."
434  << G4endl;
435  G4Exception("G4NURBS::G4NURBS()",
436  "greps9003", FatalException, ed);
437  }
438  //mnbralias = 0;
439 
440  // Knots
442  G4int dummy;
443  for (dummy=0; (dummy?(dir=V):(dir=U)),(dummy < NofD); dummy++)
444  {
445  if ( !(m[dir].pKnots = (dummy?in_pVKnots:in_pUKnots)) )
446  { // make some regular knots between 0 & 1
447  if(!MakeKnotVector(m[dir], Regular))
448  {
450  ed << "Unable to make a Regular knot vector along "
451  << G4NURBS::Tochar(dir)
452  << " direction."
453  << G4endl;
454  G4Exception("G4NURBS::G4NURBS()",
455  "greps9004", FatalException, ed);
456  }
457  //m[dir].nbralias = 0;
458  } // end of knots-making
459  } // end for dummy
460 } // end of G4NURBS::G4NURBS
461 
462 // second constructor
463 
464 G4NURBS::G4NURBS( t_order in_Uorder, t_order in_Vorder,
465  t_inddCtrlPt in_UnbrCtrlPts, t_inddCtrlPt in_VnbrCtrlPts,
466  t_KnotVectorGenFlag in_UKVGFlag,
467  t_KnotVectorGenFlag in_VKVGFlag,
468  t_CheckFlag in_CheckFlag )
469 {
470  m[U].order=in_Uorder; m[V].order=in_Vorder;
471  m[U].nbrCtrlPts=in_UnbrCtrlPts; m[V].nbrCtrlPts=in_VnbrCtrlPts;
472 
474  m[U].nbrKnots = m[U].order + m[U].nbrCtrlPts;
475  m[V].nbrKnots = m[V].order + m[V].nbrCtrlPts;
476 
477  if (in_CheckFlag)
478  Conscheck();
479 
480  // Allocate CtrlPts
482  //mnbralias = 0;
483 
484  // Knots
486  G4int dummy;
487  for (dummy=0; (dummy?(dir=V):(dir=U)),(dummy < NofD); dummy++)
488  {
489  t_KnotVectorGenFlag flag = (dummy?in_VKVGFlag:in_UKVGFlag);
490  m[dir].pKnots = 0; // (allocation under our control)
491  if ( flag != UserDefined && !MakeKnotVector(m[dir], flag) )
492  {
494  ed << "Unable to make knot vector along "
495  << G4NURBS::Tochar(dir)
496  << " direction. (" << m[dir].nbrKnots
497  << " knots requested for a "
498  << flag
499  << " knots vector)"
500  << G4endl;
501  G4Exception("G4NURBS::G4NURBS()",
502  "greps9005", FatalException, ed);
503  }
504  //m[dir].nbralias = 0;
505  }
506 }
507 
508 G4NURBS::G4NURBS(const G4NURBS & in_krNurb)
509  : G4Visible(in_krNurb)
510 {
511  // we assume the in nurbs is ok
512 
513  // the number of CtrlPts can be copied straightly
514  mtotnbrCtrlPts = in_krNurb.mtotnbrCtrlPts;
515 
516  // the main datas
517 
518  // but as m is an array of t_Dir and as t_Dir
519  // is just a structure and not a class with a copy cons
520  // whe need to duplicate the knots
522  G4int dummy;
523  for (dummy=0; (dummy?(dir=V):(dir=U)),(dummy < NofD); dummy++)
524  {
525  // first we do a 'stupid' copy of m[dir]
526  m[dir] = in_krNurb.m[dir];
527  // but as m is an array of t_Dir and as t_Dir
528  // is just a structure and not a class with a copy cons
529  // whe need to duplicate the knots
530  m[dir].pKnots = new G4double [m[dir].nbrKnots];
531  // we copy the knots with memcpy. This function should be the fastest
532  memcpy(m[dir].pKnots, in_krNurb.m[dir].pKnots,
533  m[dir].nbrKnots * sizeof(G4double));
534  } // end of dummy loop
535 
536  // the control points
537  // once again we need to do the copy
539  memcpy(mpCtrlPts, in_krNurb.mpCtrlPts, mtotnbrCtrlPts*sizeof(t_CtrlPt));
540 
541  // and as it's very strange to copy a nurbs in G4
542  // we issue a warning :
543  G4cerr << "\nWARNING: G4NURBS::G4NURBS(const G4NURBS &) used" << G4endl;
544 }
545 
547 {
548  // we must free the two knots vector
550  G4int dummy;
551  for (dummy=0; (dummy?(dir=V):(dir=U)),(dummy < NofD); dummy++)
552  {
553  if (m[dir].pKnots)
554  delete m[dir].pKnots; // [m[dir].nbrKnots] if t_Knot become a class
555  m[dir].pKnots = 0;
556  }
557  // now we free the CtrlPts array
558  if (mpCtrlPts)
559  delete [] mpCtrlPts; // [mtotnbrCtrlPts] if t_CtrlPt become a class
560  mpCtrlPts = 0;
561 }
562 
563 /************************************************************************
564  * *
565  * Return the current knot the parameter u is less than or equal to. *
566  * Find this "breakpoint" allows the evaluation routines to concentrate *
567  * on only those control points actually effecting the curve around u.] *
568  * *
569  * np is the number of points on the curve (or surface direction) *
570  * k is the order of the curve (or surface direction) *
571  * kv is the knot vector ([0..np+k-1]) to find the break point in. *
572  * *
573  ************************************************************************/
574 static G4int FindBreakPoint(G4double u, const Float *kv, G4int np, G4int k)
575 {
576  G4int i;
577  if (u == kv[np+1]) return np; /* Special case for closed interval */
578  i = np + k;
579  while ((u < kv[i]) && (i > 0)) i--;
580  return(i);
581 }
582 
583 /************************************************************************
584  * *
585  * Compute Bi,k(u), for i = 0..k. *
586  * u the parameter of the spline to find the basis functions for*
587  * brkPoint the start of the knot interval ("segment") *
588  * kv the knot vector *
589  * k the order of the curve *
590  * bvals the array of returned basis values. *
591  * *
592  * (From Bartels, Beatty & Barsky, p.387) *
593  * *
594  ************************************************************************/
595 static void BasisFunctions(G4double u, G4int brkPoint,
596  const Float *kv, G4int k, G4double *bvals)
597 {
598  G4int r, q, i;
599  G4double omega;
600 
601  bvals[0] = 1.0;
602  for (r=2; r <= k; r++)
603  {
604  i = brkPoint - r + 1;
605  bvals[r-1] = 0.0;
606  for (q=r-2; q >= 0; q--)
607  {
608  i++;
609  if (i < 0)
610  {
611  omega = 0.0;
612  }
613  else
614  {
615  omega = (u - kv[i]) / (kv[i+r-1] - kv[i]);
616  }
617  bvals[q+1] = bvals[q+1] + (1.0-omega) * bvals[q];
618  bvals[q] = omega * bvals[q];
619  }
620  }
621 }
622 
623 /************************************************************************
624  * *
625  * Compute derivatives of the basis functions Bi,k(u)' *
626  * *
627  ************************************************************************/
628 static void BasisDerivatives(G4double u, G4int brkPoint,
629  const Float *kv, G4int k, G4double *dvals)
630 {
631  G4int q, i;
632  G4double omega, knotScale;
633 
634  BasisFunctions(u, brkPoint, kv, k-1, dvals);
635 
636  dvals[k-1] = 0.0; /* BasisFunctions misses this */
637 
638  knotScale = kv[brkPoint+1] - kv[brkPoint];
639 
640  i = brkPoint - k + 1;
641  for (q=k-2; q >= 0; q--)
642  {
643  i++;
644  omega = knotScale * ((G4double)(k-1)) / (kv[i+k-1] - kv[i]);
645  dvals[q+1] += -omega * dvals[q];
646  dvals[q] *= omega;
647  }
648 }
649 
650 /***********************************************************************
651  * *
652  * Calculate a point p on NurbSurface n at a specific u, v *
653  * using the tensor product. *
654  * *
655  * Note the valid parameter range for u and v is *
656  * (kvU[orderU] <= u < kvU[numU), (kvV[orderV] <= v < kvV[numV]) *
657  * *
658  ***********************************************************************/
660  G4Vector3D &utan, G4Vector3D &vtan) const
661 {
662 #define MAXORDER 50
663  struct Point4
664  {
665  G4double x, y, z, w;
666  };
667 
668  G4int i, j, ri, rj;
669  G4int ubrkPoint, ufirst;
670  G4double bu[MAXORDER], buprime[MAXORDER];
671  G4int vbrkPoint, vfirst;
672  G4double bv[MAXORDER], bvprime[MAXORDER];
673  Point4 r, rutan, rvtan;
674 
675  r.x = 0.0; r.y = 0.0; r.z = 0.0; r.w = 0.0;
676  rutan = r; rvtan = r;
677 
678  G4int numU = GetUnbrCtrlPts();
679  G4int numV = GetVnbrCtrlPts();
680  G4int orderU = GetUorder();
681  G4int orderV = GetVorder();
682 
683  /* Evaluate non-uniform basis functions (and derivatives) */
684 
685  ubrkPoint = FindBreakPoint(u, m[U].pKnots, numU-1, orderU);
686  ufirst = ubrkPoint - orderU + 1;
687  BasisFunctions (u, ubrkPoint, m[U].pKnots, orderU, bu);
688  BasisDerivatives(u, ubrkPoint, m[U].pKnots, orderU, buprime);
689 
690  vbrkPoint = FindBreakPoint(v, m[V].pKnots, numV-1, orderV);
691  vfirst = vbrkPoint - orderV + 1;
692  BasisFunctions (v, vbrkPoint, m[V].pKnots, orderV, bv);
693  BasisDerivatives(v, vbrkPoint, m[V].pKnots, orderV, bvprime);
694 
695  /* Weight control points against the basis functions */
696 
697  t_doubleCtrlPt *cpoint;
698  Point4 cp;
699  G4double tmp;
700 
701  for (i=0; i<orderV; i++)
702  {
703  for (j=0; j<orderU; j++)
704  {
705  ri = orderV - 1 - i;
706  rj = orderU - 1 - j;
707 
708  tmp = bu[rj] * bv[ri];
709 
710  cpoint = GetdoubleCtrlPt(j+ufirst, i+vfirst);
711  cp.x = *cpoint[G4NURBS::X];
712  cp.y = *cpoint[G4NURBS::Y];
713  cp.z = *cpoint[G4NURBS::Z];
714  cp.w = *cpoint[G4NURBS::W];
715  delete [] cpoint;
716 
717  r.x += cp.x * tmp;
718  r.y += cp.y * tmp;
719  r.z += cp.z * tmp;
720  r.w += cp.w * tmp;
721 
722  tmp = buprime[rj] * bv[ri];
723  rutan.x += cp.x * tmp;
724  rutan.y += cp.y * tmp;
725  rutan.z += cp.z * tmp;
726  rutan.w += cp.w * tmp;
727 
728  tmp = bu[rj] * bvprime[ri];
729  rvtan.x += cp.x * tmp;
730  rvtan.y += cp.y * tmp;
731  rvtan.z += cp.z * tmp;
732  rvtan.w += cp.w * tmp;
733  }
734  }
735 
736  /* Project tangents, using the quotient rule for differentiation */
737 
738  G4double wsqrdiv = 1.0 / (r.w * r.w);
739 
740  utan.setX((r.w * rutan.x - rutan.w * r.x) * wsqrdiv);
741  utan.setY((r.w * rutan.y - rutan.w * r.y) * wsqrdiv);
742  utan.setZ((r.w * rutan.z - rutan.w * r.z) * wsqrdiv);
743 
744  vtan.setX((r.w * rvtan.x - rvtan.w * r.x) * wsqrdiv);
745  vtan.setY((r.w * rvtan.y - rvtan.w * r.y) * wsqrdiv);
746  vtan.setZ((r.w * rvtan.z - rvtan.w * r.z) * wsqrdiv);
747 
748  p.setX(r.x / r.w);
749  p.setY(r.y / r.w);
750  p.setZ(r.z / r.w);
751 }