Main Page   Class Hierarchy   Compound List   File List   Compound Members  

nurbsS.cpp

00001 /*=============================================================================
00002         File: nurbsS.cpp
00003      Purpose:       
00004     Revision: $Id: nurbsS.cpp,v 1.4 2003/01/13 19:42:01 philosophil Exp $
00005   Created by: Philippe Lavoie          (3 Oct, 1996)
00006  Modified by: 
00007 
00008  Copyright notice:
00009           Copyright (C) 1996-1997 Philippe Lavoie
00010  
00011           This library is free software; you can redistribute it and/or
00012           modify it under the terms of the GNU Library General Public
00013           License as published by the Free Software Foundation; either
00014           version 2 of the License, or (at your option) any later version.
00015  
00016           This library is distributed in the hope that it will be useful,
00017           but WITHOUT ANY WARRANTY; without even the implied warranty of
00018           MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019           Library General Public License for more details.
00020  
00021           You should have received a copy of the GNU Library General Public
00022           License along with this library; if not, write to the Free
00023           Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024 =============================================================================*/
00025 
00026 #ifndef PLIB_NURBS_NURBSS_SOURCE
00027 #define PLIB_NURBS_NURBSS_SOURCE
00028 
00029 
00030 #include <nurbs.h>
00031 #include <string.h>
00032 #include <matrixRT.h>
00033 #include <math.h>
00034 #include <nurbsS.h>
00035 #include "integrate.h"
00036 
00037 #ifdef USING_VCC
00038 #include <malloc.h>
00039 #endif
00040 
00043 namespace PLib {
00044 
00053 template <class T, int N>
00054 NurbsSurface<T,N>::NurbsSurface(): 
00055   ParaSurface<T,N>(), U(1),V(1),P(1,1),degU(0),degV(0)
00056 {
00057 }
00058 
00067 template <class T, int N>
00068 NurbsSurface<T,N>::NurbsSurface(const NurbsSurface<T,N>& s): 
00069   ParaSurface<T,N>(), U(s.U), V(s.V), P(s.P), degU(s.degU), degV(s.degV)
00070 {
00071 }
00072 
00073 
00086 template <class T, int N>
00087 NurbsSurface<T,N>::NurbsSurface(int DegU, int DegV, const Vector<T>& Uk, const Vector<T>& Vk, const Matrix< HPoint_nD<T,N> >& Cp) : 
00088   ParaSurface<T,N>(), U(Uk),V(Vk),P(Cp),degU(DegU),degV(DegV)
00089 {
00090   int bad = 0 ;
00091 
00092   if(U.n() != P.rows()+degU+1){
00093 #ifdef USE_EXCEPTION
00094     throw NurbsSizeError(P.rows(),U.n(),degU) ;
00095 #else
00096     Error err("NurbsSurface<T,N> constructor") ;
00097     err << "The U knot vector and the number of rows of the control points are incompatible\n" ;
00098     err << "P.rows() = " << P.rows() << ", U.n() = " << U.n() << endl ;
00099     bad = 1 ;
00100     err.fatal() ;
00101 #endif
00102   }
00103   if(V.n() != P.cols()+degV+1){
00104 #ifdef USE_EXCEPTION
00105     throw NurbsSizeError(P.cols(),V.n(),degV);
00106 #else
00107     Error err("NurbsSurface<T,N> constructor") ;    
00108     err << "The V knot vector and the number of columns of the control points are incompatible\n" ;
00109     err << "P.cols() = " << P.cols() << ", V.n() = " << V.n() << endl ;
00110     bad = 1 ;
00111     err.fatal() ;
00112 #endif
00113   }
00114   if(bad)
00115     exit(-1) ;
00116 }
00117 
00131 template <class T, int N>
00132 NurbsSurface<T,N>::NurbsSurface(int DegU, int DegV, Vector<T>& Uk, Vector<T>& Vk, Matrix< Point_nD<T,N> >& Cp, Matrix<T>& W) : 
00133   ParaSurface<T,N>(), U(Uk),V(Vk),P(Cp.rows(),Cp.cols()),degU(DegU),degV(DegV)
00134 {
00135   int bad = 0 ;
00136 
00137   if(U.n() != Cp.rows()+degU+1){
00138 #ifdef USE_EXCEPTION
00139     throw NurbsSizeError(P.rows(),U.n(),degU);
00140 #else
00141     Error err("NurbsSurface<T,N> constructor") ;
00142     err << "The U knot vector and the number of rows of the control points are incompatible\n" ;
00143     err << "P.rows() = " << P.rows() << ", U.n() = " << U.n() << endl ;
00144     bad = 1 ;
00145     err.fatal() ;
00146 #endif
00147   }
00148   if(V.n() != Cp.cols()+degV+1){
00149 #ifdef USE_EXCEPTION
00150     throw NurbsSizeError(P.cols(),V.n(),degV);
00151 #else
00152     Error err("NurbsSurface<T,N> constructor") ;
00153     err << "The V knot vector and the number of columns of the control points are incompatible\n" ;
00154     err << "P.cols() = " << P.cols() << ", V.n() = " << V.n() << endl ;
00155     bad = 1 ;
00156     err.fatal() ;
00157 #endif
00158   }
00159   if(W.rows() != Cp.rows()){
00160 #ifdef USE_EXCEPTION
00161     throw NurbsInputError(W.rows(),Cp.rows()) ;
00162 #else
00163     Error err("NurbsSurface<T,N> constructor") ;
00164     err << "The dimension of the weights are incompatible with the dimension of the control points\n" ;
00165     err << "W( " << W.rows() << ", " << W.cols() << ") and P( " << P.rows() << ", " << P.cols() << ") \n" ;
00166     bad = 1 ;
00167     err.fatal() ;
00168 #endif
00169   }
00170   if(W.cols() != Cp.cols()){
00171 #ifdef USE_EXCEPTION
00172     throw NurbsInputError(W.cols(),Cp.cols()) ;
00173 #else
00174     Error err("NurbsSurface<T,N> constructor") ;
00175     err << "The dimension of the weights are incompatible with the dimension of the control poitns\n" ;
00176     err << "W( " << W.rows() << ", " << W.cols() << ") and P( " << P.rows() << ", " << P.cols() << ") \n" ;
00177     bad = 1 ;
00178     err.fatal() ;
00179 #endif
00180   }
00181 
00182   for(int i=0;i<Cp.rows();i++)
00183     if(bad)
00184       break ;
00185     else{
00186       for(int j=0;j<Cp.cols();j++)
00187         if(W(i,j)==0.0){
00188 #ifdef USE_EXCEPTION
00189           throw NurbsInputError();
00190 #else
00191           Error err("NurbsSurface<T,N> constructor") ;
00192           err << "Error initializing a NurbsSurface.\n" ;
00193           err << "The weight W(" << i << ", " << j << ") is equal to 0.\n" ;
00194           bad = 1 ;
00195           err.fatal() ;
00196           break ;
00197 #endif
00198         }
00199         else {
00200           P(i,j) = Cp(i,j) ;
00201           P(i,j) *= W(i,j) ;
00202         }
00203     }
00204 
00205   if(bad)
00206     exit(-1) ;
00207 }
00208 
00216 template <class T, int N>
00217 NurbsSurface<T,N>& NurbsSurface<T,N>::operator=(const NurbsSurface<T,N>& nS){
00218   P = nS.P ;
00219   U = nS.U ;
00220   V = nS.V ;
00221   degU = nS.degU ;
00222   degV = nS.degV ;
00223   return *this ;
00224 }
00225 
00226 template <class T, int N>
00227 struct AreaData {
00228   T v;
00229   T eps;
00230   T knotUi;
00231   T knotUii;
00232   T knotVj;
00233   T knotVjj;
00234   const NurbsSurface<T,N>& s ; 
00235   const BasicArray<T>  w ; 
00236   AreaData(const NurbsSurface<T,N>& surf,T e,
00237            const BasicArray<T>& ww): 
00238     s(surf),v(T(0)),eps(e),w(ww),
00239     knotUi(T(0)), knotUii(T(1)) {}
00240 };
00241 
00242 template <class T, int N> 
00243 struct OpAreaAuxFcn : public ClassPOvoid<T> {
00244   T operator()(T u, void* data){
00245     AreaData<T,N>* p = (AreaData<T,N>*)data ;
00246     return (p->s).areaF(u,p->v) ; 
00247   }
00248 };
00249 
00250 template <class T, int N>
00251 struct OpAreaFcn : public ClassPOvoid<T> {
00252   T operator()(T v, void* data){
00253     static Vector<T> w;
00254     T err;
00255     OpAreaAuxFcn<T,N>  f;
00256     AreaData<T,N>* Data = (AreaData<T,N>*)data ;
00257     Data->v = v ;            
00258     return intcc2((ClassPOvoid<T>*)&f,Data,
00259                   Data->knotUi,Data->knotUii,
00260                   Data->eps,Data->w,err);  
00261   }
00262 };
00263 
00288 template <class T, int N>
00289 T NurbsSurface<T,N>::area(T eps,int n) const {
00290   T a = T(0.0) ;
00291   T err ; 
00292   static Vector<T> bufFcn(0) ;
00293 
00294   if(bufFcn.n() != n){
00295     bufFcn.resize(n) ;
00296     intccini(bufFcn) ;
00297   }
00298 
00299   AreaData<T,N> data(*this,eps,bufFcn) ; 
00300   OpAreaFcn<T,N> op;
00301   
00302 
00303   for(int i=degU;i<P.rows();++i){
00304     if(U[i] >= U[i+1] || U[i]>=T(1.0))
00305       continue ;
00306     data.knotUi  = U[i] ; 
00307     data.knotUii = U[i+1] ; 
00308     for(int j=degV;j<P.cols();++j){
00309       if(V[j] >= V[j+1] || V[j]>=T(1.0))
00310         continue ;
00311       data.knotVj  = V[j] ; 
00312       data.knotVjj = V[j+1] ; 
00313       a += intcc2((ClassPOvoid<T>*)&op,(void*)&data,
00314                   data.knotVj,data.knotVjj,
00315                   eps,bufFcn,err) ;
00316     }
00317   }
00318   return a ; 
00319 }
00320 
00350 template <class T, int N>
00351 T NurbsSurface<T,N>::areaIn(T us, T ue, T vs, T ve, T eps, int n) const {
00352   T l = T() ;
00353   T err ; 
00354   T a ;
00355   bool bLastU = false;
00356   bool bLastV = false;
00357   static Vector<T> bufFcn ;
00358 
00359   if(bufFcn.n() != n){
00360     bufFcn.resize(n) ;
00361     intccini(bufFcn) ;
00362   }
00363   
00364   AreaData<T,N> data(*this,eps,bufFcn) ; 
00365   OpAreaFcn<T,N> op;
00366   for(int i=degU;i<P.rows();++i){
00367     if(U[i] >= U[i+1] || U[i] >= T(1))
00368       continue;
00369     if(i<findSpanU(us))
00370       continue ; 
00371     if(us>=U[i] && ue<=U[i+findMultU(i)]){
00372       data.knotUi  = us;
00373       data.knotUii = ue;
00374       bLastU = true;
00375       goto Integrate_I;
00376     }
00377     if(us>=U[i]){
00378       data.knotUi  = us;
00379       data.knotUii = U[i+findMultU(i)];
00380       bLastU = false;
00381       goto Integrate_I;
00382     }
00383     if(ue<=U[i+1]){
00384       data.knotUi  = U[i];
00385       data.knotUii = ue;
00386       bLastU = true;
00387       goto Integrate_I;
00388     }
00389     data.knotUi  = U[i] ; 
00390     data.knotUii = U[i+findMultU(i)] ; 
00391   Integrate_I:
00392     for(int j=degV;j<P.cols();++j){
00393       if(V[j] >= V[j+1] || V[j]>=T(1))
00394         continue ;
00395       if(j<findSpanV(vs))
00396         continue ; 
00397       if(vs>=V[j] && ve<=V[j+findMultV(j)]){
00398         data.knotVj  = vs;
00399         data.knotVjj = ve;
00400         bLastV = true;
00401         goto Integrate_II;
00402       }
00403       if(vs>=V[j]){
00404         data.knotVj  = vs;
00405         data.knotVjj = V[j+findMultV(j)];
00406         bLastV = false;
00407         goto Integrate_II;
00408       }
00409       if(ve<=V[j+1]){
00410         data.knotVj  = V[j];
00411         data.knotVjj = ve;
00412         bLastV = true;
00413         goto Integrate_II;
00414       }
00415       data.knotVj  = V[j] ; 
00416       data.knotVjj = V[j+findMultV(j)] ; 
00417     Integrate_II:
00418       a += intcc2((ClassPOvoid<T>*)&op,(void*)&data,data.knotVj,data.knotVjj,eps,bufFcn,err) ;
00419       if (bLastU && bLastV)
00420         return a;
00421       if (bLastV)
00422         break;
00423     }
00424   }
00425   return a ; 
00426 }
00427 
00428 // the definitions are in f_nurbs.cpp and d_nurbs.cpp
00429 
00430 
00445 template <class T, int N>
00446   T NurbsSurface<T,N>::areaF(T u, T v) const {
00447   
00448   Matrix<Point_nD<T,N> > Skl(2,2) ; 
00449   deriveAt(u,v,1,Skl);
00450   T tmp = norm(crossProduct(Skl(1,0),Skl(0,1)));
00451   return tmp ; 
00452 }
00453  
00466 template <class T, int N>
00467 int NurbsSurface<T,N>::ok() {
00468   if(P.rows() <= degU)
00469     return 0 ;
00470   if(P.cols() <= degV)
00471     return 0 ;
00472   if(P.rows() != U.n()+degU+1)
00473     return 0 ;
00474   if(P.cols() != V.n()+degV+1)
00475     return 0 ;
00476   return 1 ;
00477 }
00498 template <class T, int N>
00499 void NurbsSurface<T,N>::reset(const Matrix< HPoint_nD<T,N> >& Pts, const Vector<T> &U1, const Vector<T> &V1){
00500   P = Pts;
00501   U = U1;
00502   V = V1;
00503   degU = U.size()-P.rows()-1;
00504   degV = V.size()-P.cols()-1;
00505 }
00506 
00522 template <class T, int N>
00523 void NurbsSurface<T,N>::resize(int Pu, int Pv, int DegU, int DegV){
00524   P.resize(Pu,Pv) ;
00525   degU = DegU ;
00526   degV = DegV ;
00527   U.resize(Pu+DegU+1) ;
00528   V.resize(Pv+DegV+1) ;
00529 }
00530 
00542 template <class T, int N>
00543 void NurbsSurface<T,N>::resizeKeep(int Pu, int Pv, int DegU, int DegV){
00544   P.resizeKeep(Pu,Pv) ;
00545   degU = DegU ;
00546   degV = DegV ;
00547   U.resize(Pu+DegU+1) ;
00548   V.resize(Pv+DegV+1) ;
00549 }
00550 
00568 template <class T, int D>
00569 int NurbsSurface<T,D>::skinV(NurbsCurveArray<T,D>& ca, int dV) {
00570   Vector<T> vk(ca.n()) ;
00571   //Vector<T> d(ca.n()) ;
00572   T* d ;
00573   int i,k,N,K ;
00574 
00575   if(ca.n()<dV){
00576 #ifdef USE_EXCEPTION
00577     throw NurbsInputError();
00578 #else
00579     Error err("NurbsSurface<T,D> skinV") ;
00580     err << "The number of curves are insufficient for the degree of interpolation specified.\n" ;
00581     err << "n of curves = " << ca.n() << ", degree of interpolation = " << dV << endl ;
00582     err.warning() ;
00583     return 0 ;
00584 #endif
00585   }
00586 
00587   generateCompatibleCurves(ca) ;
00588 
00589   K = ca.n() ;
00590   N = ca[0].ctrlPnts().n() ;
00591 
00592   resize(N,K,ca[0].degree(),dV) ;
00593 
00594   //d.resize(ca[0].ctrlPnts().n()) ;
00595   d = new T[ca[0].ctrlPnts().n()] ; 
00596   for(i=0;i<N;i++){
00597     d[i] = 0 ;
00598     for(k=1;k<K;k++){
00599       d[i] += norm(ca[k].ctrlPnts(i)-ca[k-1].ctrlPnts(i)) ;
00600     }
00601   }
00602 
00603   vk[0] = 0 ;
00604   for(k=1;k<K;k++){
00605     vk[k] = 0 ;
00606     for(i=0;i<N;i++)
00607       vk[k] += norm(ca[k].ctrlPnts(i)-ca[k-1].ctrlPnts(i))/d[i] ;
00608     vk[k] /= (T)N ;//+ 1.0 ;
00609     vk[k] += vk[k-1] ;
00610   }
00611   vk[vk.n()-1] = 1.0 ;
00612 
00613   for(i=1;i<K-degV;i++){
00614     V[i+degV] = 0 ;
00615     for(k=i;k<i+degV;k++)
00616       V[i+degV] += vk[k] ;
00617     V[i+degV] /= (T)degV ;
00618   }
00619   for(i=0;i<=degV;i++) V[i] = 0.0 ;
00620   for(i=V.n()-degV-1;i<V.n();i++) V[i] = 1.0 ;
00621 
00622 
00623   Vector< HPoint_nD<T,D> > Q(K) ;
00624   NurbsCurve<T,D> i_curve ;
00625 
00626 
00627   for(i=0;i<N;i++){
00628     for(k=0;k<K;k++)
00629       Q[k] = ca[k].ctrlPnts(i) ;
00630     i_curve.globalInterpH(Q,vk,V,degV);
00631     for(k=0;k<K;k++)
00632       P(i,k) = i_curve.ctrlPnts(k) ;
00633   }
00634 
00635   U = ca[0].knot() ;
00636 
00637   delete []d ; 
00638   return 1 ;
00639 }
00640 
00657 template <class T, int nD>
00658 int NurbsSurface<T,nD>::skinU(NurbsCurveArray<T,nD>& ca, int dU) {
00659   Vector<T> uk(ca.n());
00660   //Vector<T> d(ca.n()) ;
00661   T* d; 
00662   int i,k,N,K ;
00663 
00664   if(ca.n()<dU){
00665 #ifdef USE_EXCEPTION
00666     throw NurbsInputError();
00667 #else
00668     Error err("NurbsSurface<T,N> skinU") ;
00669     err << "The number of curves are insufficient for the degree of interpolation specified.\n" ;
00670     err << "n of curves = " << ca.n() << ", degree of interpolation = " << dU << endl ;
00671     err.warning() ;
00672     return 0 ;
00673 #endif
00674   }
00675 
00676   generateCompatibleCurves(ca) ;
00677 
00678   K = ca.n() ;
00679   N = ca[0].ctrlPnts().n() ;
00680 
00681   resize(K,N,dU,ca[0].degree()) ;
00682 
00683   //d.resize(ca[0].ctrlPnts().n()) ;
00684   d = new T[ca[0].ctrlPnts().n()] ; 
00685   for(i=0;i<N;i++){
00686     d[i] = 0 ;
00687     for(k=1;k<K;k++){
00688       d[i] += norm(ca[k].ctrlPnts(i)-ca[k-1].ctrlPnts(i)) ;
00689     }
00690   }
00691 
00692   uk[0] = 0 ;
00693   for(k=1;k<K;k++){
00694     uk[k] = 0 ;
00695     for(i=0;i<N;i++)
00696       uk[k] += norm(ca[k].ctrlPnts(i)-ca[k-1].ctrlPnts(i))/d[i] ;
00697     uk[k] /= (T)N ;//+ 1.0 ;
00698     uk[k] += uk[k-1] ;
00699   }
00700   uk[uk.n()-1] = 1.0 ;
00701 
00702   for(i=1;i<K-degU;i++){
00703     U[i+degU] = 0 ;
00704     for(k=i;k<i+degU;k++)
00705       U[i+degU] += uk[k] ;
00706     U[i+degU] /= (T)degU ;
00707   }
00708   for(i=0;i<=degU;i++) U[i] = 0.0 ;
00709   for(i=U.n()-degU-1;i<U.n();i++) U[i] = 1.0 ;
00710 
00711 
00712   Vector< HPoint_nD<T,nD> > Q(K) ;
00713   NurbsCurve<T,nD> i_curve ;
00714 
00715 
00716   for(i=0;i<N;i++){
00717     for(k=0;k<K;k++)
00718       Q[k] = ca[k].ctrlPnts(i) ;
00719     i_curve.globalInterpH(Q,uk,U,degU) ;
00720     for(k=0;k<K;k++)
00721       P(k,i) = i_curve.ctrlPnts(k) ;
00722   }
00723 
00724   V = ca[0].knot() ;
00725 
00726   delete []d ; 
00727 
00728   return 1 ;
00729 }
00730 
00749 template <class T, int N>
00750 int surfMeshParams(const Matrix< Point_nD<T,N> >& Q, Vector<T>& uk, Vector<T>& vl){
00751   int n,m,k,l,num ;
00752   double d,total ;
00753   //Vector<T> cds(Q.rows()) ;
00754   T* cds = new T[maximum(Q.rows(),Q.cols())] ; // alloca might not have enough space 
00755 
00756   n = Q.rows() ;
00757   m = Q.cols() ;
00758   uk.resize(n) ;
00759   vl.resize(m) ;
00760   num = m ;
00761   
00762 
00763   // Compute the uk
00764   uk.reset(0) ;
00765 
00766   for(l=0;l<m;l++){
00767     total = 0.0 ;
00768     for(k=1;k<n;k++){
00769       cds[k] = norm(Q(k,l)-Q(k-1,l)) ;
00770       total += cds[k] ;
00771     }
00772     if(total==0.0) 
00773       num-- ;
00774     else {
00775       d = 0.0 ;
00776       for(k=1;k<n;k++){
00777         d += cds[k] ;
00778         uk[k] += d/total ;
00779       }
00780     }
00781   }
00782 
00783   if(num==0) {
00784     delete []cds ; 
00785     return 0 ;
00786   }
00787   for(k=1;k<n-1;k++)
00788     uk[k] /= num ;
00789   uk[n-1] = 1.0 ;
00790 
00791   // Compute the vl
00792   vl.reset(0) ;
00793 
00794   //cds.resize(m) ; // this line removed since the maximum is allocated at the beginning
00795 
00796   num = n ;
00797 
00798   for(k=0;k<n;k++){
00799     total = 0.0 ;
00800     for(l=1;l<m;l++){
00801       cds[l] = norm(Q(k,l)-Q(k,l-1)) ;
00802       total += cds[l] ;
00803     }
00804     if(total==0.0) 
00805       num-- ;
00806     else {
00807       d = 0.0 ;
00808       for(l=1;l<m;l++){
00809         d += cds[l] ;
00810         vl[l] += d/total ;
00811       }
00812     }
00813   }
00814 
00815   delete []cds ; 
00816 
00817   if(num==0) 
00818     return 0 ;
00819   for(l=1;l<m-1;l++)
00820     vl[l] /= num ;
00821   vl[m-1] = 1.0 ;
00822 
00823 
00824   return 1 ;
00825 }
00826 
00843 template <class T, int N>
00844 int surfMeshParamsH(const Matrix< HPoint_nD<T,N> >& Q, Vector<T>& uk, Vector<T>& vl){
00845   int n,m,k,l,num ;
00846   double d,total ;
00847   //Vector<T> cds(Q.rows()) ;
00848   T* cds = new T[maximum(Q.rows(),Q.cols())] ;
00849 
00850   n = Q.rows() ;
00851   m = Q.cols() ;
00852   uk.resize(n) ;
00853   vl.resize(m) ;
00854   num = m ;
00855   
00856 
00857   // Compute the uk
00858   uk.reset(0) ;
00859 
00860   for(l=0;l<m;l++){
00861     total = 0.0 ;
00862     for(k=1;k<n;k++){
00863       cds[k] = norm(Q(k,l)-Q(k-1,l)) ;
00864       total += cds[k] ;
00865     }
00866     if(total==0.0) 
00867       num-- ;
00868     else {
00869       d = 0.0 ;
00870       for(k=1;k<n;k++){
00871         d += cds[k] ;
00872         uk[k] += d/total ;
00873       }
00874     }
00875   }
00876 
00877   if(num==0) {
00878     delete []cds ; 
00879     return 0 ;
00880   }
00881   for(k=1;k<n-1;k++)
00882     uk[k] /= num ;
00883   uk[n-1] = 1.0 ;
00884 
00885   // Compute the vl
00886   vl.reset(0) ;
00887   //cds.resize(m) ; // taking the maximum so this is not needed
00888 
00889   num = n ;
00890 
00891   for(k=0;k<n;k++){
00892     total = 0.0 ;
00893     for(l=1;l<m;l++){
00894       cds[l] = norm(Q(k,l)-Q(k,l-1)) ;
00895       total += cds[l] ;
00896     }
00897     if(total==0.0) 
00898       num-- ;
00899     else {
00900       d = 0.0 ;
00901       for(l=1;l<m;l++){
00902         d += cds[l] ;
00903         vl[l] += d/total ;
00904       }
00905     }
00906   }
00907 
00908   delete []cds ; 
00909 
00910   if(num==0) 
00911     return 0 ;
00912   for(l=1;l<m-1;l++)
00913     vl[l] /= num ;
00914   vl[m-1] = 1.0 ;
00915   return 1 ;
00916 }
00917 
00928 template <class T, int N>
00929 void NurbsSurface<T,N>::globalInterp(const Matrix< Point_nD<T,N> >& Q, int pU, int pV){
00930   Vector<T> vk,uk ;
00931 
00932   resize(Q.rows(),Q.cols(),pU,pV) ;
00933 
00934   surfMeshParams(Q,uk,vk) ;
00935   knotAveraging(uk,pU,U) ;
00936   knotAveraging(vk,pV,V) ;
00937   
00938 
00939   Vector< HPoint_nD<T,N> > Pts(Q.rows()) ;
00940   NurbsCurve<T,N> R ;
00941   
00942   int i,j ;
00943 
00944   for(j=0;j<Q.cols();j++){
00945     for(i=0;i<Q.rows();i++)
00946       Pts[i] = Q(i,j) ;
00947     R.globalInterpH(Pts,uk,U,pU);
00948     for(i=0;i<Q.rows();i++)
00949       P(i,j) = R.ctrlPnts(i) ;
00950   }
00951 
00952   Pts.resize(Q.cols()) ;
00953   for(i=0;i<Q.rows();i++){
00954     for(j=0;j<Q.cols();j++)
00955       Pts[j] = P(i,j) ;
00956     R.globalInterpH(Pts,vk,V,pV) ;
00957     for(j=0;j<Q.cols();j++)
00958       P(i,j) = R.ctrlPnts(j) ;
00959   }
00960 }
00961 
00972 template <class T, int N>
00973 void NurbsSurface<T,N>::globalInterpH(const Matrix< HPoint_nD<T,N> >& Q, int pU, int pV){
00974   Vector<T> vk,uk ;
00975 
00976   resize(Q.rows(),Q.cols(),pU,pV) ;
00977 
00978   surfMeshParamsH(Q,uk,vk) ;
00979   knotAveraging(uk,pU,U) ;
00980   knotAveraging(vk,pV,V) ;
00981   
00982 
00983   Vector< HPoint_nD<T,N> > Pts(Q.rows()) ;
00984   NurbsCurve<T,N> R ;
00985   
00986   int i,j ;
00987 
00988   for(j=0;j<Q.cols();j++){
00989     for(i=0;i<Q.rows();i++)
00990       Pts[i] = Q(i,j) ;
00991     R.globalInterpH(Pts,uk,U,pU);
00992     for(i=0;i<Q.rows();i++)
00993       P(i,j) = R.ctrlPnts(i) ;
00994   }
00995 
00996   Pts.resize(Q.cols()) ;
00997   for(i=0;i<Q.rows();i++){
00998     for(j=0;j<Q.cols();j++)
00999       Pts[j] = P(i,j) ;
01000     R.globalInterpH(Pts,vk,V,pV) ;
01001     for(j=0;j<Q.cols();j++)
01002       P(i,j) = R.ctrlPnts(j) ;
01003   }
01004 }
01005 
01018 template <class T, int N>
01019 void NurbsSurface<T,N>::leastSquares(const Matrix< Point_nD<T,N> >& Q, int pU, int pV, int nU, int nV){
01020   Vector<T> vk,uk ;
01021 
01022   resize(nU,nV,pU,pV) ;
01023 
01024   surfMeshParams(Q,uk,vk) ;
01025 
01026   Vector< HPoint_nD<T,N> > Pts(Q.rows()) ;
01027   NurbsCurve<T,N> R ;
01028   
01029   int i,j ;
01030 
01031   Matrix< HPoint_nD<T,N> > P2 ;
01032 
01033   P2.resize(nU,Q.cols()) ;
01034 
01035   for(j=0;j<Q.cols();j++){
01036     for(i=0;i<Q.rows();i++)
01037       Pts[i] = Q(i,j) ;
01038     R.leastSquaresH(Pts,pU,nU,uk);
01039     for(i=0;i<P.rows();i++)
01040       P2(i,j) = R.ctrlPnts(i) ;
01041     if(j==0)
01042       U = R.knot() ;
01043   }
01044 
01045   Pts.resize(Q.cols()) ;
01046   for(i=0;i<P.rows();i++){
01047     for(j=0;j<Q.cols();j++)
01048       Pts[j] = P2(i,j) ;
01049     R.leastSquaresH(Pts,pV,nV,vk) ;
01050     for(j=0;j<P.cols();j++)
01051       P(i,j) = R.ctrlPnts(j) ;
01052     if(i==0)
01053       V = R.knot() ;
01054   }
01055 }
01056 
01079 template <class T, int N>
01080 void globalSurfInterpXY(const Matrix< Point_nD<T,N> >& Q, int pU, int pV, NurbsSurface<T,N>& S) {
01081   Vector<T> uk,vk ;
01082   T um,uM ;
01083   T vm,vM ;
01084 
01085   um = Q(0,0).y() ;
01086   vm = Q(0,0).x() ;
01087   uM = Q(Q.rows()-1,0).y() ;
01088   vM = Q(0,Q.cols()-1).x() ;
01089 
01090   uk.resize(Q.rows()) ;
01091   vk.resize(Q.cols()) ;
01092 
01093   uk[0] = 0.0 ;
01094   vk[0] = 0.0 ;
01095   uk[uk.n()-1] = 1.0 ;
01096   vk[vk.n()-1] = 1.0 ;
01097 
01098   T dU = uM-um ;
01099   T dV = vM-vm ;
01100 
01101   int i ;
01102   for(i=1;i<uk.n()-1;++i){
01103     uk[i] = Q(i,0).y()/dU ;
01104   }
01105   
01106   for(i=1;i<vk.n()-1;++i){
01107     vk[i] = Q(0,i).x()/dV ;
01108   }
01109   
01110   globalSurfInterpXY(Q,pU,pV,S,uk,vk) ;
01111 }
01112 
01134 template <class T, int N>
01135 void globalSurfInterpXY(const Matrix< Point_nD<T,N> >& Q, int pU, int pV, NurbsSurface<T,N>& S, const Vector<T>& uk, const Vector<T>& vk){
01136   Vector<T> V,U ;
01137   int i,j ;
01138 
01139 
01140   knotAveraging(uk,pU,U) ;
01141   knotAveraging(vk,pV,V) ;
01142   
01143   Vector< HPoint_nD<T,N> > P(Q.rows()) ;
01144   NurbsCurve<T,N> R ;
01145   
01146   S.resize(Q.rows(),Q.cols(),pU,pV) ;
01147   S.U = U ;
01148   S.V = V ;
01149 
01150   for(j=0;j<Q.cols();j++){
01151     for(i=0;i<Q.rows();i++)
01152       P[i] = Q(i,j) ;
01153     R.globalInterpH(P,uk,U,pU) ;
01154     for(i=0;i<Q.rows();i++)
01155       S.P(i,j) = R.ctrlPnts(i) ;
01156   }
01157 
01158   P.resize(Q.cols()) ;
01159   for(i=0;i<Q.rows();i++){
01160     for(j=0;j<Q.cols();j++)
01161       P[j] = S.P(i,j) ;
01162     R.globalInterpH(P,vk,V,pV) ;
01163     for(j=0;j<Q.cols();j++)
01164       S.P(i,j) = R.ctrlPnts(j) ;
01165   }
01166 }
01167 
01168 
01183 template <class T, int N>
01184 void globalSurfApprox(const Matrix< Point_nD<T,N> >& Q, int pU, int pV, NurbsSurface<T,N>& S, double error){
01185 
01186   NurbsCurveArray<T,N> R ; 
01187   Vector< Point_nD<T,N> > P ;
01188 
01189   Matrix< HPoint_nD<T,N> > St ;
01190   Vector<T> Ut,Vt ;
01191 
01192   Vector<T> vk,uk ;
01193 
01194   surfMeshParams(Q,uk,vk) ;
01195   
01196   R.resize(Q.cols()) ;
01197   P.resize(Q.rows()) ;
01198 
01199   int i,j ;
01200 
01201   for(j=0;j<Q.cols();j++){
01202     for(i=0;i<Q.rows();i++)
01203       P[i] = Q(i,j) ;
01204     R[j].globalApproxErrBnd(P,uk,pU,error) ;
01205   }
01206 
01207 
01208   generateCompatibleCurves(R) ;
01209 
01210   Ut.resize(R[0].knot().n()) ;
01211   Ut = R[0].knot() ;
01212 
01213   St.resize(R[0].ctrlPnts().n(),R.n()) ;
01214 
01215   for(i=0;i<R[0].ctrlPnts().n();i++){
01216     for(j=0;j<R.n();j++)
01217       St(i,j) = R[j].ctrlPnts(i) ;
01218   }
01219 
01220   P.resize(St.cols()) ;
01221   R.resize(St.rows()) ;
01222   for(i=0;i<St.rows();i++){
01223     for(j=0;j<St.cols();j++)
01224       P[j] = project(St(i,j)) ;
01225     R[i].globalApproxErrBnd(P,vk,pV,error) ;
01226   }
01227 
01228   generateCompatibleCurves(R) ;
01229 
01230   Vt.resize(R[0].knot().n()) ;
01231   Vt = R[0].knot() ;
01232   
01233   S.resize(St.rows(),R[0].ctrlPnts().n(),pU,pV) ;
01234   for(i=0;i<S.ctrlPnts().rows();i++)
01235     for(j=0;j<S.ctrlPnts().cols();j++){
01236       S.P(i,j) = R[i].ctrlPnts(j) ;
01237     }
01238   S.U = Ut ;
01239   S.V = Vt ;
01240 }
01241 
01242 
01254 template <class T, int N>
01255 void NurbsSurface<T,N>::degreeElevate(int tU, int tV) {
01256   degreeElevateU(tU) ;
01257   degreeElevateV(tV) ;
01258 }
01259 
01268 template <class T, int N>
01269 void NurbsSurface<T,N>::degreeElevateU(int t) {
01270   if(t<=0){
01271     return ;
01272   }
01273 
01274   NurbsSurface<T,N> S(*this) ;
01275   
01276   int i,j,k ;
01277   int n = S.ctrlPnts().rows()-1;
01278   int p = S.degU ;
01279   int m = n+p+1;
01280   int ph = p+t ;
01281   int ph2 = ph/2 ;
01282   Matrix<T> bezalfs(p+t+1,p+1) ; // coefficients for degree elevating the Bezier segment
01283   Matrix< HPoint_nD<T,N> > bpts(p+1,S.P.cols()) ; // pth-degree Bezier control points of the current segment
01284   Matrix< HPoint_nD<T,N> > ebpts(p+t+1,S.P.cols()) ; // (p+t)th-degree Bezier control points of the  current segment
01285   Matrix< HPoint_nD<T,N> > Nextbpts(p-1,S.P.cols()) ; // leftmost control points of the next Bezier segment
01286   Vector<T> alphas(p-1) ; // knot instertion alphas.
01287   
01288   // Compute the Binomial coefficients
01289   Matrix<T> Bin(ph+1,ph2+1) ;
01290   binomialCoef(Bin) ;
01291   
01292   // Compute Bezier degree elevation coefficients
01293   T inv,mpi ;
01294   bezalfs(0,0) = bezalfs(ph,p) = 1.0 ;
01295   for(i=1;i<=ph2;i++){
01296     inv= 1.0/Bin(ph,i) ;
01297     mpi = minimum(p,i) ;
01298     for(j=maximum(0,i-t); j<=mpi; j++){
01299       bezalfs(i,j) = inv*Bin(p,j)*Bin(t,i-j) ;
01300     }
01301   }
01302   
01303   for(i=ph2+1;i<ph ; i++){
01304     mpi = minimum(p,i) ;
01305     for(j=maximum(0,i-t); j<=mpi ; j++)
01306       bezalfs(i,j) = bezalfs(ph-i,p-j) ;
01307   }
01308   
01309   // Allocate more control points than necessary
01310   resize(S.P.rows()+S.P.rows()*t,S.P.cols(),ph,S.degV) ; 
01311   
01312   int colJ ;
01313   int mh = ph ;
01314   int kind = ph+1 ;
01315   T ua = S.U[0] ;
01316   T ub = 0.0 ;
01317   int r=-1 ; 
01318   int oldr ;
01319   int a = p ;
01320   int b = p+1 ; 
01321   int cind = 1 ;
01322   int rbz,lbz = 1 ; 
01323   int mul,save,s;
01324   T alf ;
01325   int first, last, kj ;
01326   T den,bet,gam,numer ;
01327   
01328   for(i=0;i<S.P.cols();i++)
01329     P(0,i) = S.P(0,i) ;
01330   for(i=0; i <= ph ; i++){
01331     U[i] = ua ;
01332   }
01333   
01334   // Initialize the first Bezier segment
01335   
01336   for(i=0;i<=p ;i++) 
01337     for(j=0;j<S.P.cols();j++)
01338       bpts(i,j) = S.P(i,j);
01339   
01340   while(b<m){ // Big loop thru knot vector
01341     i=b ;
01342     while(b<m && S.U[b] >= S.U[b+1]) // for some odd reasons... == doesn't work
01343       b++ ;
01344     mul = b-i+1 ; 
01345     mh += mul+t ;
01346     ub = S.U[b] ;
01347     oldr = r ;
01348     r = p-mul ;
01349     if(oldr>0)
01350       lbz = (oldr+2)/2 ;
01351     else
01352       lbz = 1 ;
01353     if(r>0) 
01354       rbz = ph-(r+1)/2 ;
01355     else
01356       rbz = ph ;
01357     if(r>0){ // Insert knot to get Bezier segment
01358       numer = ub-ua ;
01359       for(k=p;k>mul;k--){
01360         alphas[k-mul-1] = numer/(S.U[a+k]-ua) ;
01361       }
01362       for(j=1;j<=r;j++){
01363         save = r-j ; s = mul+j ;
01364         for(k=p;k>=s;k--){
01365           for(colJ=0;colJ<S.P.cols();colJ++){
01366             bpts(k,colJ) = alphas[k-s]*bpts(k,colJ)+(1.0-alphas[k-s])*bpts(k-1,colJ) ;}
01367         }
01368         if(Nextbpts.rows()>0)
01369           for(colJ=0;colJ<S.P.cols();colJ++){
01370             Nextbpts(save,colJ) = bpts(p,colJ) ;}
01371       }
01372     }
01373     
01374     for(i=lbz;i<=ph;i++){ // Degree elevate Bezier,  only the points lbz,...,ph are used
01375       for(colJ=0;colJ<S.P.cols();colJ++){
01376         ebpts(i,colJ) = 0.0 ;}
01377       mpi = minimum(p,i) ;
01378       for(j=maximum(0,i-t); j<=mpi ; j++)
01379         for(colJ=0;colJ<S.P.cols();colJ++){
01380           ebpts(i,colJ) += bezalfs(i,j)*bpts(j,colJ) ;}
01381     }
01382     
01383     if(oldr>1){ // Must remove knot u=c.U[a] oldr times
01384       // if(oldr>2) // Alphas on the right do not change
01385       //        alfj = (ua-nc.U[kind-1])/(ub-nc.U[kind-1]) ;
01386       first = kind-2 ; last = kind ;
01387       den = ub-ua ;
01388       bet = (ub-U[kind-1])/den ;
01389       for(int tr=1; tr<oldr; tr++){ // Knot removal loop
01390         i = first ; j = last ;
01391         kj = j-kind+1 ;
01392         while(j-i>tr){ // Loop and compute the new control points for one removal step
01393           if(i<cind){
01394             alf=(ub-U[i])/(ua-U[i]) ;
01395             for(colJ=0;colJ<S.P.cols();colJ++){
01396               P(i,colJ) = alf*P(i,colJ) + (1.0-alf)*P(i-1,colJ) ;}
01397           }
01398           if( j>= lbz){
01399             if(j-tr <= kind-ph+oldr){
01400               gam = (ub-U[j-tr])/den ;
01401               for(colJ=0;colJ<S.P.cols();colJ++){
01402                 ebpts(kj,colJ) = gam*ebpts(kj,colJ) + (1.0-gam)*ebpts(kj+1,colJ) ;}
01403             }
01404             else{
01405               for(colJ=0;colJ<S.P.cols();colJ++){
01406                 ebpts(kj,colJ) = bet*ebpts(kj,colJ)+(1.0-bet)*ebpts(kj+1,colJ) ;}
01407             }
01408           }
01409           ++i ; --j; --kj ;
01410         }
01411         --first ; ++last ;
01412       }
01413     }
01414   
01415     if(a!=p) // load the knot u=c.U[a]
01416       for(i=0;i<ph-oldr; i++){
01417         U[kind++] = ua ; 
01418       }
01419     
01420     for(j=lbz; j<=rbz ; j++) { // load control points onto nc
01421       for(colJ=0;colJ<S.P.cols();colJ++)
01422         P(cind,colJ) = ebpts(j,colJ) ; 
01423       ++cind ;
01424     }
01425     
01426     if(b<m){ // Set up for next pass thru loop
01427       for(colJ=0;colJ<S.P.cols();colJ++){
01428         for(j=0;j<r;j++)
01429           bpts(j,colJ) = Nextbpts(j,colJ) ;
01430         for(j=r;j<=p;j++)
01431           bpts(j,colJ) = S.P(b-p+j,colJ) ;
01432       }
01433       a=b ; 
01434       b++ ;
01435       ua = ub ;
01436     }
01437     else{
01438       for(i=0;i<=ph;i++)
01439         U[kind+i] = ub ;
01440     }
01441   }
01442   // Resize to the proper number of control points  
01443   resizeKeep(mh-ph,S.P.cols(),ph,S.degV) ;
01444 }
01445 
01454 template <class T, int N>
01455 void NurbsSurface<T,N>::degreeElevateV(int t) {
01456   if(t<=0){
01457     return ;
01458   }
01459 
01460   NurbsSurface<T,N> S(*this) ;
01461 
01462   int i,j,k ;
01463   int n = S.ctrlPnts().cols()-1;
01464   int p = S.degV ;
01465   int m = n+p+1;
01466   int ph = p+t ;
01467   int ph2 = ph/2 ;
01468   Matrix<T> bezalfs(p+t+1,p+1) ; // coefficients for degree elevating the Bezier segment
01469   Matrix< HPoint_nD<T,N> > bpts(p+1,S.P.rows()) ; // pth-degree Bezier control points of the current segment
01470   Matrix< HPoint_nD<T,N> > ebpts(p+t+1,S.P.rows()) ; // (p+t)th-degree Bezier control points of the  current segment
01471   Matrix< HPoint_nD<T,N> > Nextbpts(p-1,S.P.rows()) ; // leftmost control points of the next Bezier segment
01472   //Vector<T> alphas(p-1) ; // knot instertion alphas.
01473   T* alphas = (T*) alloca((p-1)*sizeof(T)) ;
01474   
01475   // Compute the Binomial coefficients
01476   Matrix<T> Bin(ph+1,ph2+1) ;
01477   binomialCoef(Bin) ;
01478   
01479   // Compute Bezier degree elevation coefficients
01480   T inv,mpi ;
01481   bezalfs(0,0) = bezalfs(ph,p) = 1.0 ;
01482   for(i=1;i<=ph2;i++){
01483     inv= 1.0/Bin(ph,i) ;
01484     mpi = minimum(p,i) ;
01485     for(j=maximum(0,i-t); j<=mpi; j++){
01486       bezalfs(i,j) = inv*Bin(p,j)*Bin(t,i-j) ;
01487     }
01488   }
01489   
01490   for(i=ph2+1;i<ph ; i++){
01491     mpi = minimum(p,i) ;
01492     for(j=maximum(0,i-t); j<=mpi ; j++)
01493       bezalfs(i,j) = bezalfs(ph-i,p-j) ;
01494   }
01495   
01496   resize(S.P.rows(),S.P.cols()+S.P.cols()*t,S.degU,ph) ; // Allocate more control points than necessary
01497   
01498   int rowJ ;
01499   int mh = ph ;
01500   int kind = ph+1 ;
01501   T va = S.V[0] ;
01502   T vb = 0.0 ;
01503   int r=-1 ; 
01504   int oldr ;
01505   int a = p ;
01506   int b = p+1 ; 
01507   int cind = 1 ;
01508   int rbz,lbz = 1 ; 
01509   int mul,save,s;
01510   T alf ;
01511   int first, last, kj ;
01512   T den,bet,gam,numer ;
01513   
01514   for(i=0;i<S.P.rows();i++)
01515     P(i,0) = S.P(i,0) ;
01516   for(i=0; i <= ph ; i++){
01517     V[i] = va ;
01518   }
01519   
01520   // Initialize the first Bezier segment
01521   
01522   for(i=0;i<=p ;i++) 
01523     for(j=0;j<S.P.rows();j++)
01524       bpts(i,j) = S.P(j,i);
01525   
01526   while(b<m){ // Big loop thru knot vector
01527     i=b ;
01528     while(b<m && S.V[b] >= S.V[b+1]) // for some odd reasons... == doesn't work
01529       b++ ;
01530     mul = b-i+1 ; 
01531     mh += mul+t ;
01532     vb = S.V[b] ;
01533     oldr = r ;
01534     r = p-mul ;
01535     if(oldr>0)
01536       lbz = (oldr+2)/2 ;
01537     else
01538       lbz = 1 ;
01539     if(r>0) 
01540       rbz = ph-(r+1)/2 ;
01541     else
01542       rbz = ph ;
01543     if(r>0){ // Insert knot to get Bezier segment
01544       numer = vb-va ;
01545       for(k=p;k>mul;k--){
01546         alphas[k-mul-1] = numer/(S.V[a+k]-va) ;
01547       }
01548       for(j=1;j<=r;j++){
01549         save = r-j ; s = mul+j ;
01550         for(k=p;k>=s;k--){
01551           for(rowJ=0;rowJ<S.P.rows();rowJ++){
01552             bpts(k,rowJ) = alphas[k-s]*bpts(k,rowJ)+(1.0-alphas[k-s])*bpts(k-1,rowJ) ;}
01553         }
01554         if(Nextbpts.rows()>0)
01555           for(rowJ=0;rowJ<S.P.rows();rowJ++){
01556             Nextbpts(save,rowJ) = bpts(p,rowJ) ;}
01557       }
01558     }
01559     
01560     for(i=lbz;i<=ph;i++){ // Degree elevate Bezier,  only the points lbz,...,ph are used
01561       for(rowJ=0;rowJ<S.P.rows();rowJ++){
01562         ebpts(i,rowJ) = 0.0 ;}
01563       mpi = minimum(p,i) ;
01564       for(j=maximum(0,i-t); j<=mpi ; j++)
01565         for(rowJ=0;rowJ<S.P.rows();rowJ++){
01566           ebpts(i,rowJ) += bezalfs(i,j)*bpts(j,rowJ) ;}
01567     }
01568     
01569     if(oldr>1){ // Must remove knot V=S.V[a] oldr times
01570       // if(oldr>2) // Alphas on the right do not change
01571       //        alfj = (va-nc.U[kind-1])/(vb-V[kind-1]) ;
01572       first = kind-2 ; last = kind ;
01573       den = vb-va ;
01574       bet = (vb-V[kind-1])/den ;
01575       for(int tr=1; tr<oldr; tr++){ // Knot removal loop
01576         i = first ; j = last ;
01577         kj = j-kind+1 ;
01578         while(j-i>tr){ // Loop and compute the new control points for one removal step
01579           if(i<cind){
01580             alf=(vb-V[i])/(va-V[i]) ;
01581             for(rowJ=0;rowJ<S.P.rows();rowJ++){
01582               P(rowJ,i) = alf*P(rowJ,i) + (1.0-alf)*P(rowJ,i-1) ;}
01583           }
01584           if( j>= lbz){
01585             if(j-tr <= kind-ph+oldr){
01586               gam = (vb-V[j-tr])/den ;
01587               for(rowJ=0;rowJ<S.P.rows();rowJ++){
01588                 ebpts(kj,rowJ) = gam*ebpts(kj,rowJ) + (1.0-gam)*ebpts(kj+1,rowJ) ;}
01589             }
01590             else{
01591               for(rowJ=0;rowJ<S.P.rows();rowJ++){
01592                 ebpts(kj,rowJ) = bet*ebpts(kj,rowJ)+(1.0-bet)*ebpts(kj+1,rowJ) ;}
01593             }
01594           }
01595           ++i ; --j; --kj ;
01596         }
01597         --first ; ++last ;
01598       }
01599     }
01600   
01601     if(a!=p) // load the knot v=S.V[a]
01602       for(i=0;i<ph-oldr; i++){
01603         V[kind++] = va ; 
01604       }
01605     
01606     for(j=lbz; j<=rbz ; j++) { // load control points onto nc
01607       for(rowJ=0;rowJ<S.P.rows();rowJ++)
01608         P(rowJ,cind) = ebpts(j,rowJ) ; 
01609       ++cind ;
01610     }
01611     
01612     if(b<m){ // Set up for next pass thru loop
01613       for(rowJ=0;rowJ<S.P.rows();rowJ++){
01614         for(j=0;j<r;j++)
01615           bpts(j,rowJ) = Nextbpts(j,rowJ) ;
01616         for(j=r;j<=p;j++)
01617           bpts(j,rowJ) = S.P(rowJ,b-p+j) ;
01618       }
01619       a=b ; 
01620       b++ ;
01621       va = vb ;
01622     }
01623     else{
01624       for(i=0;i<=ph;i++)
01625         V[kind+i] = vb ;
01626     }
01627   }
01628   // Resize to the proper number of control points  
01629   resizeKeep(S.P.rows(),mh-ph,S.degU,ph) ; 
01630 }
01642 template <class T, int N>
01643 int NurbsSurface<T,N>::findMultU(int r) const {
01644   int s=1 ;
01645   for(int i=r;i>degU+1;i--)
01646     if(U[i]<=U[i-1])
01647       s++ ;
01648     else
01649       return s ;
01650   return s ;
01651 }
01652 
01665 template <class T, int N>
01666 int NurbsSurface<T,N>::findMultV(int r) const {
01667   int s=1 ;
01668   for(int i=r;i>degV+1;i--)
01669     if(V[i]<=V[i-1])
01670       s++ ;
01671     else
01672       return s ;
01673   return s ;
01674 }
01675 
01676 
01677 
01678 
01695 template <class T, int N>
01696 void NurbsSurface<T,N>::findSpan(T u, T v, int& spanU, int& spanV) const{
01697   spanU = findSpanU(u) ;
01698   spanV = findSpanV(v) ;
01699 }
01700 
01717 template <class T, int N>
01718 int NurbsSurface<T,N>::findSpanU(T u) const{
01719   if(u>=U[P.rows()]) 
01720     return P.rows()-1 ;
01721   if(u<=U[degU])
01722     return degU ;
01723 
01724   //AF
01725   int low = 0 ;
01726   int high = P.rows()+1 ; 
01727   int mid = (low+high)/2 ;
01728 
01729   while(u<U[mid] || u>= U[mid+1]){
01730     if(u<U[mid])
01731       high = mid ;
01732     else
01733       low = mid ;
01734     mid = (low+high)/2 ;
01735   }
01736   return mid ;  
01737 }
01738 
01755 template <class T, int N>
01756 int NurbsSurface<T,N>::findSpanV(T v) const{
01757   if(v>=V[P.cols()]) 
01758     return P.cols()-1 ;
01759   if(v<=V[degV])
01760     return degV ;
01761 
01762   //AF
01763   int low  = 0 ;
01764   int high = P.cols()+1 ; 
01765   int mid = (low+high)/2 ;
01766 
01767   while(v<V[mid] || v>= V[mid+1]){
01768     if(v<V[mid])
01769       high = mid ;
01770     else
01771       low = mid ;
01772     mid = (low+high)/2 ;
01773   }
01774   return mid ;
01775 }
01776 
01790 template <class T, int N>
01791 void NurbsSurface<T,N>::basisFuns(T u, T v, int spanU, int spanV, Vector<T>& Nu, Vector<T> &Nv) const{
01792   basisFunsU(u,spanU,Nu) ;
01793   basisFunsV(v,spanV,Nv) ;
01794 }
01795 
01806 template <class T, int nD>
01807 void NurbsSurface<T,nD>::basisFunsU(T u, int span, Vector<T>& N) const {
01808   //Vector<T> left(degU+1), right(degU+1) ;
01809   T* left = (T*) alloca((degU+1)*sizeof(T)) ;
01810   T* right = (T*) alloca((degU+1)*sizeof(T)) ;
01811   T temp,saved ;
01812    
01813 
01814   N.resize(degU+1) ;
01815 
01816   N[0] = 1.0 ;
01817   for(int j=1; j<= degU ; j++){
01818     left[j] = u-U[span+1-j] ;
01819     right[j] = U[span+j]-u ;
01820     saved = 0.0 ;
01821     for(int r=0 ; r<j; r++){
01822       temp = N[r]/(right[r+1]+left[j-r]) ;
01823       N[r] = saved+right[r+1]*temp ;
01824       saved = left[j-r]*temp ;
01825     }
01826     N[j] = saved ;
01827   }  
01828 
01829 }
01830 
01841 template <class T, int nD>
01842 void NurbsSurface<T,nD>::basisFunsV(T v, int span, Vector<T>& N) const {
01843   //Vector<T> left(degV+1), right(degV+1) ;
01844   T* left = (T*) alloca((degV+1)*sizeof(T)) ;
01845   T* right = (T*) alloca((degV+1)*sizeof(T)) ;
01846   T temp,saved ;
01847    
01848 
01849   N.resize(degV+1) ;
01850 
01851   N[0] = 1.0 ;
01852   for(int j=1; j<= degV ; j++){
01853     left[j] = v-V[span+1-j] ;
01854     right[j] = V[span+j]-v ;
01855     saved = 0.0 ;
01856     for(int r=0 ; r<j; r++){
01857       temp = N[r]/(right[r+1]+left[j-r]) ;
01858       N[r] = saved+right[r+1]*temp ;
01859       saved = left[j-r]*temp ;
01860     }
01861     N[j] = saved ;
01862   }  
01863 
01864 }
01865 
01883 template <class T, int nD>
01884 void NurbsSurface<T,nD>::deriveAtH(T u, T v, int d, Matrix< HPoint_nD<T,nD> > &skl) const {
01885   int k,l,du,dv;
01886   skl.resize(d+1,d+1) ;
01887 
01888   du = minimum(d,degU) ;
01889   for(k=degU+1;k<=d;++k)
01890     for(l=0;l<=d-k;++l)
01891       skl(k,l) = 0.0 ;
01892   dv=minimum(d,degV) ;
01893   for(l=degV+1;l<=d;++l)
01894     for(k=0;k<=d-l;++k)
01895       skl(k,l) = 0.0 ;
01896   int uspan = findSpanU(u) ;
01897   int vspan = findSpanV(v) ;
01898   Matrix<T> Nu,Nv ;
01899   nurbsDersBasisFuns(du,u,uspan,degU,U,Nu) ;
01900   nurbsDersBasisFuns(dv,v,vspan,degV,V,Nv) ;
01901 
01902   Vector< HPoint_nD<T,nD> > temp(degV+1) ;
01903   int dd,r,s ;
01904   for(k=0;k<=du;++k){
01905     for(s=0;s<=degV;++s){
01906       temp[s] = 0.0 ;
01907       for(r=0;r<=degU;++r)
01908         temp[s] += Nu(k,r)*P(uspan-degU+r,vspan-degV+s) ;
01909     }
01910     dd = minimum(d-k,dv) ;
01911     for(l=0;l<=dd;++l){
01912       skl(k,l) = 0.0 ;
01913       for(s=0;s<=degV;++s)
01914         skl(k,l) += Nv(l,s)*temp[s] ;
01915     }
01916   }
01917 }
01918 
01936 template <class T, int N>
01937 void NurbsSurface<T,N>::deriveAt(T u, T v, int d, Matrix< Point_nD<T,N> > &skl) const {
01938   int k,l ;
01939   Matrix< HPoint_nD<T,N> > ders ;
01940   Point_nD<T,N> pv,pv2 ;
01941   
01942   skl.resize(d+1,d+1) ;
01943 
01944   deriveAtH(u,v,d,ders) ;
01945   
01946   Matrix<T> Bin(d+1,d+1) ;
01947   binomialCoef(Bin) ;
01948   int i,j ; 
01949 
01950   for(k=0;k<=d;++k){
01951     for(l=0;l<=d-k;++l){
01952       pv.x() = ders(k,l).x() ;
01953       pv.y() = ders(k,l).y() ;
01954       pv.z() = ders(k,l).z() ;
01955       for(j=1;j<=l;j++)
01956         pv -= Bin(l,j)*ders(0,j).w()*skl(k,l-j) ;
01957       for(i=1;i<=k;i++){
01958         pv -= Bin(k,i)*ders(i,0).w()*skl(k-i,l) ;
01959         pv2 = 0.0 ;
01960         for(j=1;j<=l;j++)
01961           pv2 += Bin(l,j)*ders(i,j).w()*skl(k-i,l-j) ;
01962         pv -= Bin(k,i)*pv2 ;
01963       }
01964       skl(k,l) = pv/ders(0,0).w() ;
01965     }
01966   }
01967 }
01968 
01980 template <class T, int N>
01981 Point_nD<T,N> NurbsSurface<T,N>::normal(T u, T v) const {
01982   Matrix< Point_nD<T,N> > ders ;
01983 
01984   deriveAt(u,v,1,ders) ;
01985 
01986   return crossProduct(ders(1,0),ders(0,1)) ;
01987 }
01988 
02002 template <class T, int N>
02003 HPoint_nD<T,N> NurbsSurface<T,N>::operator()(T u, T v) const{
02004   int uspan = findSpanU(u) ;
02005   int vspan = findSpanV(v) ;
02006   Vector<T> Nu,Nv ;
02007   Vector< HPoint_nD<T,N> > temp(degV+1)  ;
02008 
02009   basisFuns(u,v,uspan,vspan,Nu,Nv) ;
02010 
02011   int l;
02012   for(l=0;l<=degV;l++){
02013     temp[l] =0.0 ;
02014     for(int k=0;k<=degU;k++){
02015       temp[l] += Nu[k]*P(uspan-degU+k,vspan-degV+l) ;
02016     }
02017   }
02018   HPoint_nD<T,N> sp(0,0,0,0) ;
02019   for(l=0;l<=degV;l++){
02020     sp += Nv[l]*temp[l] ;
02021   }
02022   return sp ; 
02023 }
02024 
02025 inline
02026 int max3(int a,int b, int c){
02027   int m = a ;
02028   if(m <b)
02029     m = b ;
02030   if(m <c)
02031     m = c ;
02032   return m ;
02033 }
02034 
02052 template <class T, int N>
02053 void gordonSurface(NurbsCurveArray<T,N>& lU, NurbsCurveArray<T,N>& lV, const Matrix< Point_nD<T,N> >& intersections, NurbsSurface<T,N>& gS){
02054   NurbsSurface<T,N> sU,sV,sI ;
02055   sU.skinU(lU,3) ;
02056   sV.skinV(lV,3) ;
02057   sI.globalInterp(intersections,3,3) ;
02058 
02059   int du = max3(sU.degU,sV.degU,sI.degU) ;
02060   int dv = max3(sU.degV,sV.degV,sI.degV) ;
02061   
02062 
02063   NurbsSurface<T,N> SU,SV,SI ;
02064   degreeElevate(sU,du-sU.degU,dv-sU.degV,SU) ;
02065   degreeElevate(sV,du-sV.degU,dv-sV.degV,SV) ;
02066   degreeElevate(sI,du-sI.degU,dv-sI.degV,SI) ;
02067 
02068 
02069   Vector<T> U,V ;
02070   U = knotUnion(SU.knotU(),SV.knotU()) ;
02071   U = knotUnion(U,SI.knotU()) ;
02072   V = knotUnion(SU.knotV(),SV.knotV()) ;
02073   V = knotUnion(V,SI.knotV()) ;
02074 
02075   SU.mergeKnots(U,V) ;
02076   SV.mergeKnots(U,V) ;
02077   SI.mergeKnots(U,V) ;
02078   
02079   gS = SU ;
02080 
02081   for(int i=0;i<gS.P.rows();i++)
02082     for(int j=0;j<gS.P.cols();j++){
02083       gS.P(i,j) += SV.P(i,j) ;
02084       gS.P(i,j) -= SI.P(i,j) ;
02085     }
02086 }
02087 
02088 template <class T>
02089 inline void insert(T u, Vector<T>& v){
02090   int i ;
02091   if(u<v[0] || u>v[v.n()-1])
02092     return ;
02093   v.resize(v.n()+1) ;
02094   i = v.n()-1 ;
02095   while(v[i-1]>u){
02096     v[i] = v[i-1] ;
02097     --i ;
02098   }
02099   v[i] = u ;
02100 }
02101 
02102 
02144 template <class T, int N>
02145 void NurbsSurface<T,N>::sweep(const NurbsCurve<T,N>& Trj, const NurbsCurve<T,N>& C, const NurbsCurve<T,N>& Sv, int K, int useAy, int invAz) {
02146   int i,j,k,m,q,ktv,nsect ;
02147   q = Trj.degree() ;
02148   ktv = Trj.knot().n() ;
02149   nsect = K  ;
02150   
02151   V.resize(Trj.knot().n()) ;
02152   V = Trj.knot() ;
02153 
02154   if(ktv <= nsect+q){
02155     m = nsect+q-ktv+1 ;
02156     // insert m knots into T(v)
02157     // locations are not critical so inserting in the middle of the 
02158     // biggest span is used.
02159     for(i=0;i<m;++i){
02160       T md,mt ;
02161       T mu = -1;
02162       md = 0 ;
02163       for(j=1;j<V.n();++j){
02164         mt = V[j]-V[j-1] ;
02165         if(mt>md){
02166           md = mt ;
02167           mu = (V[j]+V[j-1])/2.0 ;
02168         }
02169       }
02170       insert(mu,V) ;
02171     }
02172   }
02173   else{
02174     if(ktv>nsect){ // must increase the number of instances of C(u)
02175       nsect = ktv-q-1 ; 
02176     }
02177   }
02178 
02179   Vector<T> v; 
02180 
02181   // Compute the parameters by averaging the knots
02182   v.resize(nsect) ;
02183   v[0] = Trj.knot(Trj.degree()) ;
02184   v[nsect-1] = Trj.knot(Trj.knot().n()-Trj.degree()-1) ;
02185   for(k=1;k<nsect-1;++k){ 
02186     v[k] = 0.0 ;
02187     for(i=k+1;i<k+q+1;++i) 
02188       v[k] += V[i] ;
02189     v[k] /= q ;
02190   }
02191 
02192   resize(C.ctrlPnts().n(),nsect,C.degree(),Trj.degree()) ;
02193 
02194   U = C.knot() ;
02195 
02196   // setup Bv ;
02197   Vector< Point_nD<T,N> > B ;
02198   NurbsCurve<T,N> Bv ;
02199   Vector< Point_nD<T,N> > Td ;
02200 
02201   B.resize(v.n()) ;
02202   Trj.deriveAt(v[0],1,Td) ;
02203 
02204   B[0] = Td[1] ;
02205   if(Td[1].y() ==0)
02206     B[0] = crossProduct(Point_nD<T,N>(0,1,0),B[0]) ;
02207   else
02208     B[0] = crossProduct(Point_nD<T,N>(1,0,0),B[0]) ;
02209   B[0] /= norm(B[0]) ;
02210 
02211 
02212   for(i=1;i<v.n();++i){
02213     Trj.deriveAt(v[i],1,Td);
02214     Point_nD<T,N> Ti(Td[1]) ;
02215     Ti = Ti/norm(Ti) ;
02216     Point_nD<T,N> bi ;
02217     bi = B[i-1]-(B[i-1]*Ti)*Ti ;
02218     B[i] = bi/norm(bi) ;
02219   }
02220 
02221   Bv.globalInterp(B,v,minimum(3,B.n()-1)) ;
02222 
02223   Vector< HPoint_nD<T,N> > Q(C.ctrlPnts().n()) ; 
02224   for(k=0;k<nsect;++k){
02225     // scale the control points by Sv(v[k])
02226     for(i=0;i<Q.n();++i){
02227       HPoint_nD<T,N> sk(Sv(v[k])) ;
02228       Q[i].x() = sk.x()*C.ctrlPnts(i).x() ;
02229       Q[i].y() = sk.y()*C.ctrlPnts(i).y() ;
02230       Q[i].z() = sk.z()*C.ctrlPnts(i).z() ;
02231       Q[i].w() = sk.w()*C.ctrlPnts(i).w() ;
02232     }
02233     // compute o(v[k])
02234     Point_nD<T,N> o = Trj.pointAt(v[k]) ;
02235     //T w = T(v[k]).w() ;
02236 
02237     // compute x(v[k])
02238     Trj.deriveAt(v[k],1,Td) ;
02239 
02240     Point_nD<T,N> x = Td[1]/norm(Td[1]) ;
02241 
02242     // compute z(v[k])
02243     Point_nD<T,N> z = Bv.pointAt(v[k]) ; 
02244     z /= norm(z) ;
02245 
02246     // compute y(v[k]) 
02247     Point_nD<T,N> y = crossProduct(z,x) ;
02248 
02249     /*
02250     // compute the transform matrix
02251     double az = M_PI+atan2(y.y(),y.x()) ;
02252     double ax = -atan2(z.y(),z.z()) ;
02253     double ay = 0 ;
02254     if(useAy){
02255       ay = atan2(x.z(),x.x()) ;
02256     }
02257     if(invAz){
02258       az = -1.0*az ;
02259     }
02260     MatrixRT_DOUBLE A(ax,ay,az,o.x(),o.y(),o.z()) ;
02261     */
02262 
02263     MatrixRT_DOUBLE R ; // M(4,4)
02264     R(0,0) = y.x();
02265     R(1,0) = y.y();
02266     R(2,0) = y.z();
02267     R(0,1) = x.x();
02268     R(1,1) = x.y();
02269     R(2,1) = x.z();
02270     R(0,2) = z.x();
02271     R(1,2) = z.y();
02272     R(2,2) = z.z();
02273     //R(3,3) = 1.0; 
02274 
02275     MatrixRT_DOUBLE Tx ;
02276     Tx.translate(o.x(),o.y(),o.z());
02277     //MatrixRT_DOUBLE R(M) ;
02278     MatrixRT_DOUBLE A ;
02279     A = Tx * R ;
02280 
02281     for(i=0;i<Q.n();++i){
02282       P(i,k) = A*(Q[i]) ;
02283     }
02284   }
02285 
02286   // interpolate along V
02287   Q.resize(P.cols()) ;
02288   NurbsCurve<T,N> R;
02289   for(i=0;i<P.rows();++i){
02290     for(k=0;k<P.cols();++k)
02291       Q[k] = P(i,k) ;
02292     R.globalInterpH(Q,v,V,degV) ;
02293     for(k=0;k<P.cols();++k)
02294       P(i,k) = R.ctrlPnts(k) ;
02295   }
02296   
02297 }
02298 
02331 template <class T, int N>
02332 void NurbsSurface<T,N>::sweep(const NurbsCurve<T,N>& Trj, const NurbsCurve<T,N>& C, int K, int useAy,int invAz) {
02333   // setup Sv 
02334   Vector< HPoint_nD<T,N> > p(2) ;
02335   p[0] = HPoint_nD<T,N>(1,1,1,1) ;
02336   p[1] = HPoint_nD<T,N>(1,1,1,1) ;
02337   Vector<T> u(4) ;
02338   u[0] = u[1] = 0.0 ; u[2] = u[3] = 1.0 ;
02339 
02340   NurbsCurve<T,N> Sv(p,u,1) ;
02341   
02342   sweep(Trj,C,Sv,K,useAy,invAz) ;
02343 }
02344 
02356 template <class T, int N>
02357 void NurbsSurface<T,N>::transform(const MatrixRT<T>& A){
02358   for(int i=0;i<P.rows();++i)
02359     for(int j=0;j<P.cols();++j)
02360       P(i,j) = A*P(i,j) ;
02361 }
02362 
02372 template <class T, int N>
02373 void NurbsSurface<T,N>::refineKnots(const Vector<T>& nU, const Vector<T>& nV){
02374   refineKnotU(nU) ;
02375   refineKnotV(nV) ;
02376 }
02377 
02386 template <class T, int N>
02387 void NurbsSurface<T,N>::refineKnotU(const Vector<T>& X) {
02388   if(X.n()<=0)
02389     return ;
02390   int n = P.rows()-1 ;
02391   int p = degU;
02392   int m = n+p+1 ;
02393   int a,b ;
02394   int r = X.n()-1 ;
02395   NurbsSurface<T,N> nS ;
02396   
02397   nS = *this ;
02398   nS.resize(r+1+n+1,P.cols(),degU,degV) ;
02399 
02400   a = findSpanU(X[0]) ;
02401   b = findSpanU(X[r]) ;
02402   ++b ;
02403 
02404   int j,col ;
02405   for(col=0;col<P.cols();col++){
02406     for(j=0; j<=a-p ; j++)
02407       nS.P(j,col) = P(j,col);
02408     for(j = b-1 ; j<=n ; j++)
02409       nS.P(j+r+1,col) = P(j,col) ;
02410   }
02411   for(j=0; j<=a ; j++)
02412     nS.U[j] = U[j] ;
02413   for(j=b+p ; j<=m ; j++)
02414     nS.U[j+r+1] = U[j] ;
02415   int i = b+p-1 ; 
02416   int k = b+p+r ;
02417   for(j=r; j>=0 ; j--){
02418     while(X[j] <= U[i] && i>a){
02419       for(col=0;col<P.cols();col++)
02420         nS.P(k-p-1,col) = P(i-p-1,col) ;
02421       nS.U[k] = U[i] ;
02422       --k ;
02423       --i ;
02424     }
02425     for(col=0;col<P.cols();col++)
02426         nS.P(k-p-1,col) = nS.P(k-p,col) ;
02427     for(int l=1; l<=p ; l++){
02428       int ind = k-p+l ;
02429       T alpha = nS.U[k+l] - X[j] ;
02430       if(alpha==0.0)
02431         for(col=0;col<P.cols();col++)
02432           nS.P(ind-1,col) = nS.P(ind,col) ;
02433       else
02434         alpha /= nS.U[k+l]-U[i-p+l] ;
02435       for(col=0;col<P.cols();col++)
02436         nS.P(ind-1,col) = alpha*nS.P(ind-1,col) + (1.0-alpha)*nS.P(ind,col) ;
02437     }
02438     nS.U[k] = X[j] ;
02439     --k ;
02440   }
02441   *this = nS ;
02442 }
02443 
02452 template <class T, int N>
02453 void NurbsSurface<T,N>::refineKnotV(const Vector<T>& X) {
02454   if(X.n()<=0)
02455     return ;
02456   int n = P.cols()-1 ;
02457   int p = degV;
02458   int m = n+p+1 ;
02459   int a,b ;
02460   int r = X.n()-1 ;
02461   NurbsSurface<T,N> nS ;
02462   
02463   try {
02464     nS = *this ;
02465     nS.resize(P.rows(),r+1+n+1,degU,degV) ;
02466   }
02467   catch(...){
02468     cerr << "Out of memory\n" ; 
02469   }
02470 
02471   a = findSpanV(X[0]) ;
02472   b = findSpanV(X[r]) ;
02473   ++b ;
02474 
02475   int j,row ;
02476   for(row=0;row<P.rows();row++){
02477     for(j=0; j<=a-p ; j++)
02478       nS.P(row,j) = P(row,j);
02479     for(j = b-1 ; j<=n ; j++)
02480       nS.P(row,j+r+1) = P(row,j) ;
02481   }
02482   for(j=0; j<=a ; j++)
02483     nS.V[j] = V[j] ;
02484   for(j=b+p ; j<=m ; j++)
02485     nS.V[j+r+1] = V[j] ;
02486   int i = b+p-1 ; 
02487   int k = b+p+r ;
02488   for(j=r; j>=0 ; j--){
02489     while(X[j] <= V[i] && i>a){
02490       for(row=0;row<P.rows();row++)
02491         nS.P(row,k-p-1) = P(row,i-p-1) ;
02492       nS.V[k] = V[i] ;
02493       --k ;
02494       --i ;
02495     }
02496     for(row=0;row<P.rows();row++)
02497         nS.P(row,k-p-1) = nS.P(row,k-p) ;
02498     for(int l=1; l<=p ; l++){
02499       int ind = k-p+l ;
02500       T alpha = nS.V[k+l] - X[j] ;
02501       if(alpha==0.0)
02502         for(row=0;row<P.rows();row++)
02503           nS.P(row,ind-1) = nS.P(row,ind) ;
02504       else
02505         alpha /= nS.V[k+l]-V[i-p+l] ;
02506       for(row=0;row<P.rows();row++)
02507         nS.P(row,ind-1) = alpha*nS.P(row,ind-1) + (1.0-alpha)*nS.P(row,ind) ;
02508     }
02509     nS.V[k] = X[j] ;
02510     --k ;
02511   }
02512   *this = nS ;
02513 }
02514 
02515 
02528 template <class T, int N>
02529 void NurbsSurface<T,N>::mergeKnots(const Vector<T>& nU, const Vector<T>& nV) {
02530   mergeKnotU(nU) ;
02531   mergeKnotV(nV) ;
02532 }
02533 
02544 template <class T, int N>
02545 void NurbsSurface<T,N>::mergeKnotU(const Vector<T>& X){
02546   int i,ia,ib ;
02547   // Find the knots to insert
02548   Vector<T> I(U.n()) ;
02549   int done = 0 ;
02550   i = ia = ib = 0 ;
02551   while(!done) {
02552     if(X[ib] == U[ia]){
02553       ++ib ; ++ia ;
02554     }
02555     else{
02556       I[i++] = X[ib] ;
02557       ib++ ;
02558     }
02559     done = (ia>=U.n() || ib >= X.n()) ;
02560   }
02561   I.resize(i) ;
02562 
02563   if(I.n()>0)
02564     refineKnotU(I) ;
02565 }
02566 
02577 template <class T, int N>
02578 void NurbsSurface<T,N>::mergeKnotV(const Vector<T>& X){
02579   int i,ia,ib ;
02580   // Find the knots to insert
02581   Vector<T> I(V.n()) ;
02582   int done = 0 ;
02583   i = ia = ib = 0 ;
02584   while(!done) {
02585     if(X[ib] == V[ia]){
02586       ++ib ; ++ia ;
02587     }
02588     else{
02589       I[i++] = X[ib] ;
02590       ib++ ;
02591     }
02592     done = (ia>=V.n() || ib >= X.n()) ;
02593   }
02594   I.resize(i) ;
02595 
02596   if(I.n()>0)
02597     refineKnotV(I) ;
02598 }
02599 
02610 template <class T, int N>
02611 int NurbsSurface<T,N>::read(ifstream &fin){
02612   if(!fin) {
02613     return 0 ;
02614   }
02615   int nu,nv,du,dv;
02616   char *type ;
02617   type = new char[3] ;
02618   if(!fin.read(type,sizeof(char)*3)) { delete []type ; return 0 ;}
02619   int r1 = strncmp(type,"ns3",3) ;
02620   int r2 = strncmp(type,"ns4",3) ;
02621   if(!(r1 || r2)) 
02622     return 0 ;
02623   int st ;
02624   char stc ;
02625   if(!fin.read((char*)&stc,sizeof(char))) { delete []type ; return 0 ;}
02626   if(!fin.read((char*)&nu,sizeof(int))) { delete []type ; return 0 ;}
02627   if(!fin.read((char*)&nv,sizeof(int))) { delete []type ; return 0 ;}
02628   if(!fin.read((char*)&du,sizeof(int))) { delete []type ; return 0 ;}
02629   if(!fin.read((char*)&dv,sizeof(int))) { delete []type ; return 0 ;}
02630 
02631   st = stc - '0' ; 
02632   if(st != sizeof(T)){ // not of the same type size
02633     delete []type ;
02634     return 0 ; 
02635   }
02636 
02637   resize(nu,nv,du,dv) ;
02638   
02639   if(!fin.read((char*)U.memory(),sizeof(T)*U.n())) { delete []type ; return 0 ;}
02640   if(!fin.read((char*)V.memory(),sizeof(T)*V.n())) { delete []type ; return 0 ;}
02641      
02642 
02643   T *p,*p2 ;
02644   if(!r1){
02645     p = new T[3*nu*nv] ;
02646     if(!fin.read((char*)p,sizeof(T)*3*nu*nv)) { delete []type ; return 0 ;}
02647     p2 = p ;
02648     for(int i=0;i<nu;i++)
02649       for(int j=0;j<nv;j++){
02650         P(i,j).x() = *(p++) ;
02651         P(i,j).y() = *(p++) ;
02652         P(i,j).z() = *(p++) ;
02653         P(i,j).w() = 1.0 ;
02654       }
02655     delete []p2 ;
02656   }
02657   else{
02658     p = new T[4*nu*nv] ;
02659     if(!fin.read((char*)p,sizeof(T)*4*nu*nv)) { delete []type ; return 0 ;}
02660     p2 = p ;
02661     for(int i=0;i<nu;i++)
02662       for(int j=0;j<nv;j++){
02663         P(i,j).x() = *(p++) ;
02664         P(i,j).y() = *(p++) ;
02665         P(i,j).z() = *(p++) ;
02666         P(i,j).w() = *(p++) ;
02667       }
02668     delete []p2 ;
02669   }
02670 
02671   delete []type ;
02672   return 1 ;
02673 }
02674 
02685 template <class T, int N>
02686 int NurbsSurface<T,N>::read(const char* filename){
02687   ifstream fin(filename) ;
02688   if(!fin) {
02689     return 0 ;
02690   }
02691 
02692   return read(fin) ;
02693 }
02694 
02705 template <class T, int N>
02706 int NurbsSurface<T,N>::write(ofstream &fout) const {
02707   if(!fout)
02708     return 0 ;
02709   int prows = P.rows();
02710   int pcols = P.cols();
02711   char st = '0' + sizeof(T) ;
02712   if(!fout.write((char*)&"ns4",sizeof(char)*3)) return 0 ;
02713   if(!fout.write((char*)&st,sizeof(char))) return 0 ; 
02714   if(!fout.write((char*)&prows,sizeof(int))) return 0 ;
02715   if(!fout.write((char*)&pcols,sizeof(int))) return 0 ;
02716   if(!fout.write((char*)&degU,sizeof(int))) return 0 ;
02717   if(!fout.write((char*)&degV,sizeof(int))) return 0 ;
02718   if(!fout.write((char*)U.memory(),sizeof(T)*U.n())) return 0 ;
02719   if(!fout.write((char*)V.memory(),sizeof(T)*V.n())) return 0 ;
02720   
02721   T *p,*p2 ;
02722   p = new T[P.rows()*P.cols()*4] ;
02723   p2 = p ;
02724   for(int i=0;i<P.rows();i++) 
02725     for(int j=0;j<P.cols();j++){
02726       *p = P(i,j).x() ; p++ ;
02727       *p = P(i,j).y() ; p++ ;
02728       *p = P(i,j).z() ; p++ ;
02729       *p = P(i,j).w() ; p++ ;
02730     }
02731   if(!fout.write((char*)p2,sizeof(T)*P.rows()*P.cols()*4)) return 0 ;
02732   delete []p2 ;
02733   return 1 ;
02734 }
02735 
02746 template <class T, int N>
02747 int NurbsSurface<T,N>::write(const char* filename) const {
02748   ofstream fout(filename) ;    
02749   if(!fout)
02750     return 0 ;
02751   return write(fout);
02752 }
02753 
02766 template <class T, int N>
02767 NurbsSurface<T,N>& NurbsSurface<T,N>::transpose(void){
02768   Vector<T> t(U) ;
02769   int d ;
02770   U = V ;
02771   V = t ;
02772   d = degU ;
02773   degU = degV ;
02774   degV = d ;
02775   P = ::transpose(P) ;
02776   return *this ;
02777 }
02778 
02796 template <class T, int N>
02797 int NurbsSurface<T,N>::movePoint(T u, T v, const Point_nD<T,N>& delta){
02798   // setup B
02799   Matrix_DOUBLE B(1,(degU+1)*(degV+1)) ;
02800   int i,j,k ;
02801   
02802   int spanU,spanV ;
02803 
02804   Vector<T> Ru,Rv ;
02805 
02806   B.reset(0.0) ;
02807   
02808   findSpan(u,v,spanU,spanV) ;
02809   nurbsBasisFuns(u,spanU,degU,U,Ru) ;
02810   nurbsBasisFuns(v,spanV,degV,V,Rv) ;
02811   for(j=0;j<=degU;++j){
02812     for(k=0;k<=degV;++k){
02813       B(0,j*(degV+1)+k) 
02814         = (double)Ru[j]*(double)Rv[k] ;
02815     }
02816   }
02817   
02818   Matrix_DOUBLE A  ;
02819   Matrix_DOUBLE Bt(::transpose(B)) ;
02820   Matrix_DOUBLE BBt ;
02821 
02822   BBt = inverse(B*Bt) ;
02823   A = Bt*BBt ;
02824 
02825   Matrix_DOUBLE dD(1,3) ;
02826 
02827   for(j=0;j<3;++j)
02828     dD(0,j) = (double)delta.data[j] ;
02829 
02830   Matrix_DOUBLE dP ;
02831 
02832   dP = A*dD ;
02833 
02834   i= 0 ;
02835 
02836   for(j=0;j<=degU;++j){
02837     for(k=0;k<=degV;++k){
02838       T w = P(spanU-degU+j,spanV-degV+k).w() ;
02839       P(spanU-degU+j,spanV-degV+k).x() += dP(i,0)*w ;
02840       P(spanU-degU+j,spanV-degV+k).y() += dP(i,1)*w ;
02841       P(spanU-degU+j,spanV-degV+k).z() += dP(i,2)*w ;
02842       ++i ;
02843     }
02844   }
02845 
02846   return 1 ;
02847 }
02848 
02879 template <class T, int N>
02880 int NurbsSurface<T,N>::movePoint(const Vector<T>& ur, const Vector<T>& vr, const Vector< Point_nD<T,N> >& D, const Vector_INT& Du, const Vector_INT& Dv) {
02881   Vector_INT Dk(Du.n()),Dl(Dv.n()) ;
02882   BasicArray<Coordinate> fixCP(0) ;
02883   Dk.reset(0) ;
02884   Dl.reset(0) ;
02885   return movePoint(ur,vr,D,Du,Dv,Dk,Dl,fixCP) ;
02886 }
02887 
02922 template <class T, int N>
02923 int NurbsSurface<T,N>::movePoint(const Vector<T>& ur, const Vector<T>& vr, const Vector< Point_nD<T,N> >& D, const Vector_INT& Du, const Vector_INT& Dv, const Vector_INT& Dk, const Vector_INT& Dl) {
02924   BasicArray<Coordinate> fixCP(0) ;
02925   return movePoint(ur,vr,D,Du,Dv,Dk,Dl,fixCP) ;
02926 }
02927 
02928 
02929 
02969 template <class T, int N>
02970 int NurbsSurface<T,N>::movePoint(const Vector<T>& ur, const Vector<T>& vr, const Vector< Point_nD<T,N> >& D, const Vector_INT& Du, const Vector_INT& Dv, const Vector_INT& Dk, const Vector_INT& Dl, const BasicArray<Coordinate>& fixCP) {
02971   int i,j,k,n ;
02972 
02973   if(D.n() != Du.n() || D.n() !=Du.n() || D.n() != Dv.n() || D.n() != Dv.n()){
02974 #ifdef USE_EXCEPTION
02975     throw NurbsInputError();
02976 #else
02977     Error err("movePoint(ur,D,Dr,Dk,fixCP)");
02978     err << "The D,Dr,Dk vectors are not of the same size\n" ;
02979     err << "D.n()= " << D.n() << ", Du.n() = " << Du.n() 
02980         << ", Dk.n() = " << Dk.n() << ", Dv.n() = " << Dv.n() 
02981         << ", Dl.n() = " << Dl.n() << endl ;
02982     err.fatal() ;
02983 #endif
02984   }  
02985   
02986   // setup B
02987   Matrix_DOUBLE B ;
02988   
02989   B.resize(D.n(),P.rows()*P.cols()) ;
02990   
02991   int spanU,spanV ;
02992 
02993   Matrix<T> Ru,Rv ;
02994 
02995   B.reset(0.0) ;
02996   
02997   for(i=0;i<D.rows();++i){
02998     findSpan(ur[Du[i]],vr[Dv[i]],spanU,spanV) ;
02999     nurbsDersBasisFuns(Dk[i],ur[Du[i]],spanU,degU,U,Ru) ;
03000     nurbsDersBasisFuns(Dl[i],vr[Dv[i]],spanV,degV,V,Rv) ;
03001     for(j=0;j<=degU;++j){
03002       for(k=0;k<=degV;++k){
03003         B(i,(spanU-degU+j)*P.cols()+spanV-degV+k) 
03004           = (double)Ru(Dk[i],j)*(double)Rv(Dl[i],k) ;
03005       }
03006     }
03007   }
03008   
03009   // optimize B
03010   Vector_INT remove(B.cols()) ;
03011   BasicArray<Coordinate> map(B.cols()) ;
03012   remove.reset((int)1.0) ;
03013 
03014   for(j=0;j<B.cols();++j){
03015     for(i=0;i<B.rows();++i)
03016       if((B(i,j)*B(i,j))>1e-10){
03017         remove[j] = 0 ;
03018         break ;
03019       }
03020   }
03021 
03022   for(i=0;i<fixCP.n();++i){
03023     remove[fixCP[i].i*P.cols()+fixCP[i].j] = 1 ;
03024   }
03025   
03026   n = 0 ;
03027   for(i=0;i<B.cols();++i){
03028     if(!remove[i]){
03029       map[n].i = i/P.cols() ;
03030       map[n].j = i%P.cols() ;
03031       ++n ;
03032     }
03033   }
03034 
03035   map.resize(n) ;
03036 
03037   Matrix_DOUBLE Bopt(B.rows(),n) ;
03038   for(j=0;j<n;++j){
03039     for(i=0;i<B.rows();++i)
03040       Bopt(i,j) = B(i,map[j].i*P.cols()+map[j].j) ;
03041   }
03042 
03043   Matrix_DOUBLE A  ;
03044   Matrix_DOUBLE Bt(::transpose(Bopt)) ;
03045   Matrix_DOUBLE BBt ;
03046 
03047   BBt = inverse(Bopt*Bt) ;
03048 
03049   A = Bt*BBt ;
03050 
03051   Matrix_DOUBLE dD(D.rows(),3) ;
03052 
03053   for(i=0;i<D.rows();++i){
03054     const Point_nD<T,N>& d = D[i] ; // this makes the SGI compiler happy
03055     for(j=0;j<3;++j)
03056       dD(i,j) = (double)d.data[j] ;
03057   }
03058 
03059   Matrix_DOUBLE dP ;
03060 
03061   dP = A*dD ;
03062 
03063   for(i=0;i<map.n();++i){
03064     P(map[i].i,map[i].j).x() += dP(i,0)*P(map[i].i,map[i].j).w() ;
03065     P(map[i].i,map[i].j).y() += dP(i,1)*P(map[i].i,map[i].j).w() ;
03066     P(map[i].i,map[i].j).z() += dP(i,2)*P(map[i].i,map[i].j).w() ;
03067   }
03068 
03069   return 1 ;
03070 }
03071 
03072 
03084 template <class T, int N>
03085 void projectToLine(const Point_nD<T,N>& S, const Point_nD<T,N>& Trj, const Point_nD<T,N>& pnt, Point_nD<T,N>& p) {
03086 
03087   Point_nD<T,N> a = pnt-S ;  
03088   //p = S+ norm(a)*cos(angle(a,Trj))*Trj.unitLength() ;
03089   T fraction, denom ;
03090   denom = norm2(Trj) ; 
03091   fraction = (denom == 0.0) ? 0.0 : (Trj*a) / denom ; 
03092   p =  fraction * Trj ; 
03093   p += S ; 
03094 }
03095 
03117 template <class T, int N>
03118 void NurbsSurface<T,N>::makeFromRevolution(const NurbsCurve<T,N>& profile, const Point_nD<T,N>& S, const Point_nD<T,N>& Tvec, double theta){
03119   double angle,dtheta ;
03120   int narcs ;
03121   int i,j ;
03122 
03123   //while(theta>2.0*M_PI)
03124   //  theta -= 2.0*M_PI ;
03125 
03126   if(theta>2.0*M_PI)
03127     theta = 2.0*M_PI ;
03128 
03129   if(theta <= 0)
03130     theta = 0 ;
03131 
03132   if(theta<M_PI/2.0)    
03133     narcs = 1 ;
03134   else{
03135     if(theta<M_PI)
03136       narcs = 2 ;
03137     else{
03138       if(theta<1.5*M_PI)
03139         narcs = 3 ;
03140       else
03141         narcs = 4 ;
03142     }
03143   }
03144   dtheta = theta/(double)narcs ;
03145 
03146   int n = 2*narcs+1 ; // n control points ;
03147   resize(n,profile.ctrlPnts().n(),2,profile.degree()) ;
03148 
03149   switch(narcs){
03150   case 1: break ;
03151   case 2: 
03152     U[3] = U[4] = 0.5 ;
03153     break ;
03154   case 3:
03155     U[3] = U[4] = 1.0/3.0 ;
03156     U[5] = U[6] = 2.0/3.0 ;
03157     break ;
03158   case 4:
03159     U[3] = U[4] = 0.25 ;
03160     U[5] = U[6] = 0.50 ;  
03161     U[7] = U[8] = 0.75 ;
03162     break ;    
03163   }
03164 
03165   j = 3 + 2*(narcs-1) ;  // loading the end knots
03166   for(i=0;i<3;++j,++i){
03167     U[i] = 0.0 ;
03168     U[j] = 1.0 ;
03169   }
03170 
03171   V = profile.knot() ;
03172 
03173   double wm = cos(dtheta/2.0) ; // dtheta/2.0 is base angle
03174 
03175   Vector_DOUBLE cosines(narcs+1),sines(narcs+1) ;
03176   angle = 0 ;
03177   for(i=1;i<=narcs;++i){
03178     angle = dtheta*(double)i ;
03179     cosines[i] = cos(angle) ;
03180     sines[i] = sin(angle) ;
03181   }
03182 
03183   Point_nD<T,N> P0,T0,P2,T2,P1 ;
03184 
03185   for(j=0;j<P.cols();++j){
03186     Point_nD<T,N> O ;
03187     T wj = profile.ctrlPnts(j).w() ;
03188 
03189     projectToLine(S,Tvec,project(profile.ctrlPnts(j)),O) ;
03190     //projectToLine(S,Tvec,profile.ctrlPnts(j).projectW(),O) ;
03191     Point_nD<T,N> X,Y ;
03192     X = project(profile.ctrlPnts(j))-O ;
03193     //X = profile.ctrlPnts(j).projectW() - O ; 
03194 
03195     double r = norm(X) ;
03196 
03197     if(r < 1e-7){
03198       for(i=0;i<P.rows();++i){
03199         P(i,j) = O ;
03200         P(i,j) *= wj ;
03201       }
03202       continue ;
03203     }
03204 
03205     T b1 = X.norm2() ;
03206     T b2 = X.norm() ;
03207     T b3 = sqrt(b1) ;
03208     T b4 = norm(X) ;
03209    
03210     X = X.unitLength() ;
03211     Y = crossProduct(Tvec,X) ;
03212     Y = Y.unitLength() ;
03213 
03214     P0 = project(profile.ctrlPnts(j)) ;
03215     //P0 = profile.ctrlPnts(j).projectW() ;
03216     P(0,j) = profile.ctrlPnts(j) ;
03217 
03218     T0 = Y ;
03219     int index = 0 ;
03220 
03221     for(i=1;i<=narcs;++i){
03222       angle = dtheta*(double)i ;
03223       P2 = O+ r*cosines[i]*X + r*sines[i]*Y ;  
03224       //P2 = O+ r*cos(angle)*X + r*sin(angle)*Y ;  
03225       P(index+2,j) = P2 ;
03226       P(index+2,j) *= wj ;
03227       T2 = -sines[i]*X + cosines[i]*Y ;
03228       //T2 = -sin(angle)*X + cos(angle)*Y ;
03229       intersectLine(P0,T0,P2,T2,P1) ;
03230       P(index+1,j) = P1 ;
03231       P(index+1,j) *= wm*wj ;
03232       index += 2 ;
03233       P0 = P2 ;
03234       T0 = T2 ;
03235     }
03236   }
03237 }
03238 
03256 template <class T, int N>
03257 void NurbsSurface<T,N>::makeFromRevolution(const NurbsCurve<T,N>& profile, const Point_nD<T,N>& S, const Point_nD<T,N>& Tvec){
03258   double angle,dtheta ;
03259   int narcs ;
03260   int i,j ;
03261 
03262   int n = 9 ; // n control points ;
03263   resize(n,profile.ctrlPnts().n(),2,profile.degree()) ;
03264 
03265   U[0] = U[1] = U[2] = 0 ;
03266   U[3] = U[4] = 0.25 ;
03267   U[5] = U[6] = 0.50 ;  
03268   U[7] = U[8] = 0.75 ;
03269   U[9] = U[10] = U[11] = 1 ;
03270 
03271   V = profile.knot() ;
03272 
03273 
03274   const T wm = T(0.707106781185) ; // sqrt(2)/2
03275 
03276   for(j=0;j<P.cols();++j){
03277     Point_nD<T,N> O ;
03278     T wj = profile.ctrlPnts(j).w() ;
03279 
03280     projectToLine(S,Tvec,project(profile.ctrlPnts(j)),O) ;
03281     //projectToLine(S,Tvec,profile.ctrlPnts(j).projectW(),O) ;
03282     Point_nD<T,N> X,Y ;
03283     X = project(profile.ctrlPnts(j))-O ;
03284     //X = profile.ctrlPnts(j).projectW() - O ; 
03285 
03286     double r = norm(X) ;
03287 
03288     if(r < 1e-7){
03289       for(i=0;i<P.rows();++i){
03290         P(i,j) = O ;
03291         P(i,j) *= wj ;
03292       }
03293       continue ;
03294     }
03295 
03296     X = X.unitLength() ;
03297     Y = crossProduct(Tvec,X) ;
03298     Y = Y.unitLength() ;
03299 
03300     P(0,j) = O + r*X ;
03301     P(1,j) = O + r*X + r*Y ; 
03302     P(2,j) = O + r*Y ; 
03303     P(3,j) = O - r*X + r*Y ; 
03304     P(4,j) = O - r*X ;
03305     P(5,j) = O - r*X - r*Y ; 
03306     P(6,j) = O - r*Y ; 
03307     P(7,j) = O + r*X - r*Y ; 
03308     P(8,j) = P(0,j) ; 
03309     P(0,j) *= wj ;
03310     P(1,j) *= wj*wm ;
03311     P(2,j) *= wj ;
03312     P(3,j) *= wj*wm ;
03313     P(4,j) *= wj ;
03314     P(5,j) *= wj*wm ;
03315     P(6,j) *= wj ;
03316     P(7,j) *= wj*wm ;
03317     P(8,j) *= wj ;
03318   }
03319 }
03320 
03331 template <class T, int N>
03332 void NurbsSurface<T,N>::makeFromRevolution(const NurbsCurve<T,N>& profile){
03333   int j ; 
03334   int n = 9 ; // n control points ;
03335   resize(n,profile.ctrlPnts().n(),2,profile.degree()) ;
03336 
03337   U[0] = U[1] = U[2] = 0 ;
03338   U[3] = U[4] = 0.25 ;
03339   U[5] = U[6] = 0.50 ;  
03340   U[7] = U[8] = 0.75 ;
03341   U[9] = U[10] = U[11] = 1 ;
03342 
03343   V = profile.knot() ;
03344 
03345 
03346   const T wm = T(0.707106781185) ; // sqrt(2)/2
03347 
03348   for(j=0;j<P.cols();++j){
03349     T wj = profile.ctrlPnts(j).w() ;
03350 
03351     Point_nD<T,N> p = project(profile.ctrlPnts(j)) ;
03352     T r = T(sqrt(p.x()*p.x()+p.y()*p.y()));
03353 
03354     T wjm = wj*wm ; 
03355     T rwjm = r*wj*wm ;
03356     T rwj = r*wj ; 
03357     p.z() *= wj ; 
03358     
03359     P(0,j) = HPoint_nD<T,N>(rwj,0,p.z(),wj) ;          
03360     P(1,j) = HPoint_nD<T,N>(rwjm,rwjm,p.z()*wm,wjm) ;   
03361     P(2,j) = HPoint_nD<T,N>(0,rwj,p.z(),wj) ;          
03362     P(3,j) = HPoint_nD<T,N>(-rwjm,rwjm,p.z()*wm,wjm) ;  
03363     P(4,j) = HPoint_nD<T,N>(-rwj,0,p.z(),wj) ;         
03364     P(5,j) = HPoint_nD<T,N>(-rwjm,-rwjm,p.z()*wm,wjm) ; 
03365     P(6,j) = HPoint_nD<T,N>(0,-rwj,p.z(),wj) ;         
03366     P(7,j) = HPoint_nD<T,N>(rwjm,-rwjm,p.z()*wm,wjm) ;  
03367     P(8,j) = HPoint_nD<T,N>(rwj,0,p.z(),wj) ;          
03368   }
03369 }
03370 
03385 template <class T, int D>
03386 void NurbsSurface<T,D>::isoCurveU(T u, NurbsCurve<T,D>& c) const {
03387   c.resize(P.cols(),degV) ;
03388 
03389   c.modKnot(V) ;
03390 
03391   if(u>U[U.n()-1])
03392     u = U[U.n()-1] ;
03393   if(u<U[0])
03394     u = U[0] ;
03395 
03396 
03397 
03398   int span = findSpanU(u) ;
03399   
03400   Vector<T> N ;
03401   basisFunsU(u,span,N) ;
03402 
03403   HPoint_nD<T,D> p ;
03404   for(int i=0;i<P.cols();++i){
03405     p = 0 ;
03406     for(int j=0;j<=degU;++j)
03407       p += N[j]*P(span-degU+j,i) ;
03408     c.modCP(i,p) ;
03409   }
03410   
03411 }
03412 
03427 template <class T, int D>
03428 void NurbsSurface<T,D>::isoCurveV(T v, NurbsCurve<T,D>& c) const {
03429   c.resize(P.rows(),degU) ;
03430 
03431   c.modKnot(U) ;
03432 
03433   if(v>V[V.n()-1])
03434     v = V[V.n()-1] ;
03435   if(v<V[0])
03436     v = V[0] ;
03437 
03438   int span = findSpanV(v) ;
03439   
03440   Vector<T> N ;
03441   basisFunsV(v,span,N) ;
03442   
03443   HPoint_nD<T,D> p ;
03444   for(int i=0;i<P.rows();++i){
03445     p = 0  ;
03446     for(int j=0;j<=degV;++j)
03447       p += N[j]*P(i,span-degV+j) ;
03448     c.modCP(i,p) ;
03449   }
03450 }
03451 
03464 template <class T, int N>
03465 int NurbsSurface<T,N>::decompose(NurbsSurfaceArray<T,N>& S) const {
03466   int i,m,a,b,nb,mult,j,r,save,s,k,row,col ;
03467   T numer,alpha ;
03468 
03469 
03470   //Vector<T> alphas(degU+1) ;
03471   T* alphas = (T*) alloca((maximum(degU,degV)+1)*sizeof(T)) ;
03472   // all the surfaces will have the same knot vector in both the U and V
03473   // direction
03474   Vector<T> nU ;
03475   nU.resize(2*(degU+1)) ;
03476   for(i=0;i<nU.n()/2;++i)
03477     nU[i] = 0 ;
03478   for(i=nU.n()/2;i<nU.n();++i)
03479     nU[i] = 1 ;
03480   
03481   Vector<T> nV ;
03482   nV.resize(2*(degV+1)) ;
03483   for(i=0;i<nV.n()/2;++i)
03484     nV[i] = 0 ;
03485   for(i=nV.n()/2;i<nV.n();++i)
03486     nV[i] = 1 ;
03487 
03488   NurbsSurfaceArray<T,N> Su ;
03489   Su.resize(P.rows()-degU) ; // )*(P.cols()-degV)) ;
03490   for(i=0;i<Su.n();i++){
03491     Su[i].resize(degU+1,P.cols(),degU,degV) ;
03492     Su[i].U = nU ;
03493     Su[i].V = V ;
03494   }
03495   
03496   m = P.rows()+degU ;
03497   a = degU ;
03498   b = degU+1 ;
03499   nb = 0 ;
03500 
03501   for(i=0;i<=degU;i++)
03502     for(col=0;col<P.cols();col++)
03503       Su[nb].P(i,col) = P(i,col) ;
03504   while(b<m){
03505     i = b ;
03506     while(b<m && U[b+1] <= U[b]) b++ ;
03507     mult = b-i+1 ;
03508     if(mult<degU){
03509       numer = U[b]-U[a] ; // the enumerator of the alphas
03510       for(j=degU;j>mult;j--) // compute and store the alphas
03511         alphas[j-mult-1] = numer/(U[a+j]-U[a]) ;
03512       r = degU-mult ; // insert knot r times
03513       for(j=1;j<=r;j++){
03514         save=r-j;
03515         s=mult+j; // this many new points
03516         for(k=degU;k>=s;k--){
03517           alpha = alphas[k-s] ;
03518           for(col=0;col<P.cols();++col)
03519             Su[nb].P(k,col) = alpha*Su[nb].P(k,col)+(1.0-alpha)*Su[nb].P(k-1,col);
03520         }
03521         if(b<m) // control point of next patch
03522           for(col=0;col<P.cols();++col)
03523             Su[nb+1].P(save,col) = Su[nb].P(degU,col) ;
03524       }
03525     }
03526     ++nb ;
03527     if(b<m){ // initialize for next segment
03528       for(i=degU-mult; i<= degU ; ++i)
03529         for(col=0;col<P.cols();++col)
03530           Su[nb].P(i,col) = P(b-degU+i,col) ;
03531       a=b ;
03532       ++b ;
03533     }
03534   }
03535   Su.resize(nb) ;
03536   
03537   S.resize(Su.n()*(P.cols()-degV)) ;
03538 
03539   for(i=0;i<S.n();i++){
03540     S[i].resize(degU+1,degV+1,degU,degV) ;
03541     S[i].U = nU ;
03542     S[i].V = nV ;
03543   }
03544   
03545   nb = 0 ;
03546 
03547   for(int np=0;np<Su.n();++np){
03548     for(i=0;i<=degU;i++)
03549       for(j=0;j<=degV;++j)
03550         S[nb].P(i,j) = Su[np].P(i,j) ;
03551     m = P.cols()+degV ;
03552     a = degV ;
03553     b = degV+1 ;
03554     while(b<m){
03555       i = b ;
03556       while(b<m && V[b+1] <= V[b]) b++ ;
03557       mult = b-i+1 ;
03558       if(mult<degV){
03559         numer = V[b]-V[a] ; // the enumerator of the alphas
03560         for(j=degV;j>mult;j--) // compute and store the alphas
03561           alphas[j-mult-1] = numer/(V[a+j]-V[a]) ;
03562         r = degV-mult ; // insert knot r times
03563         for(j=1;j<=r;j++){
03564           save=r-j;
03565           s=mult+j; // this many new points
03566           for(k=degV;k>=s;k--){
03567             alpha = alphas[k-s] ;
03568             for(row=0;row<=degU;++row)
03569               S[nb].P(row,k) = alpha*S[nb].P(row,k)+(1.0-alpha)*S[nb].P(row,k-1);
03570           }
03571           if(b<m) // control point of next patch
03572             for(row=0;row<=degU;++row)
03573               S[nb+1].P(row,save) = S[nb].P(row,degV) ;
03574         }
03575       }
03576       ++nb ;
03577       if(b<m){ // initialize for next patch
03578         for(i=degV-mult; i<= degV ; ++i)
03579           for(row=0;row<=degU;++row)
03580             S[nb].P(row,i) = Su[np].P(row,b-degV+i) ;
03581         a=b ;
03582         ++b ;
03583       }
03584     }
03585   }
03586 
03587   S.resize(nb) ;
03588 
03589   return Su.n() ;
03590 }
03591 
03617 template <class T, int N>
03618 int NurbsSurface<T,N>::writePOVRAY(ostream& povray, int patch_type, double flatness, int num_u_steps, int num_v_steps) const {
03619   if(degU>3 || degV>3){
03620 #ifdef USE_EXCEPTION
03621     throw NurbsInputError();
03622 #else
03623     Error err("NurbsSurface<T,N> writePOVRAY") ;
03624     err << "The degree of the surface is higher than 3!\n"
03625         << "A povrary file can not be generated.\n" ;
03626     err.warning() ;
03627     return 0;
03628 #endif
03629   }
03630 
03631   NurbsSurface<T,N> S(*this) ;
03632 
03633   S.degreeElevate(3-degU,3-degV) ;
03634 
03635   NurbsSurfaceArray<T,N> Sa ;
03636   S.decompose(Sa) ;
03637   int bad = 0 ; 
03638 
03639   povray << "//\n//Generated for POV-Ray(tm) 3.0 by Phil's NURBS library\n" ;
03640   povray << "//   http://yukon.genie.uottawa.ca/info/soft/nurbs\n//\n" ;
03641 
03642   for(int i=0;i<Sa.n();++i){
03643     povray << "bicubic_patch {\n\ttype " << patch_type << endl ;
03644     povray << "\tflatness " << flatness << endl ;
03645     povray << "\tu_steps " << num_u_steps << endl ;
03646     povray << "\tv_steps " << num_v_steps << endl ;
03647     for(int j=0;j<4;++j){
03648       for(int k=0;k<4;++k){
03649         Point_nD<T,N> p = project(Sa[i].ctrlPnts(j,k)) ;
03650         if(Sa[i].ctrlPnts(j,k).w()>1.0001 || Sa[i].ctrlPnts(j,k).w()<0.9999)
03651           bad = 1 ;
03652         povray << "\t<" << p.x() << ", " << p.y() << ", " << p.z() << ">" ;
03653         if(j==3 && k==3)
03654           povray << "\n}\n\n" ;
03655         else
03656           povray << ",\n " ;
03657       }
03658       povray << endl ;
03659     }
03660   }
03661   if(bad){
03662 #ifdef USE_EXCEPTION
03663     throw NurbsWarning();
03664 #else
03665     Error err("NurbsSurface<T,N> writePOVRAY") ;
03666     err << "Warning: at least one of the control point was not rational\n" ;
03667     err << "The resulting surface will NOT be the same as the one which\n" ;
03668     err << "generated it.\n" ;
03669     err.warning() ;
03670 #endif
03671   }
03672   return bad ;
03673 }
03674 
03675 
03697 template <class T, int N>
03698 int NurbsSurface<T,N>::writePOVRAY(T tolerance, ostream& povray,const Color& color, int smooth, T ambient, T diffuse) const {
03699   BasicList<Point_nD<T,N> > points ;
03700   BasicList<int> connect ;
03701   BasicList<Point_nD<T,N> > norm ;
03702 
03703   if(smooth)
03704     tesselate(tolerance,points,connect,&norm) ;
03705   else
03706     tesselate(tolerance,points,connect) ;
03707     
03708   povray << "mesh {\n" ;
03709   
03710   BasicNode<int> *node ;
03711 
03712   BasicNode<Point_nD<T,N> > *nodeP ;
03713   BasicNode<Point_nD<T,N> > *nodeN ;
03714   nodeP = points.goToFirst() ;
03715   nodeN = 0 ;
03716 
03717   if(smooth)
03718     nodeN = norm.goToFirst() ;
03719 
03720   Vector< Point_nD<T,N> > Pts(points.size()) ;
03721   Vector< Point_nD<T,N> > Norm(norm.size()) ;
03722   for(int i=0;i<Pts.n();++i){
03723     Pts[i] = *nodeP->data ;
03724     nodeP = points.goToNext() ;
03725     if(smooth){
03726       Norm[i] = *nodeN->data ;
03727       nodeN = norm.goToNext() ;
03728     }
03729   }
03730 
03731   node = connect.goToFirst() ;
03732   while(node){
03733     if(smooth)
03734       povray << "\tsmooth_triangle { " ;
03735     else
03736       povray << "\ttriangle { " ;
03737     povray << "< " << Pts[*node->data].x() << ", " << Pts[*node->data].y() << ", " << Pts[*node->data].z() << "> , " ;
03738     if(smooth)
03739       povray << "< " << Norm[*node->data].x() << ", " << Norm[*node->data].y() << ", " << Norm[*node->data].z() << "> , " ;
03740     node = connect.goToNext() ; 
03741     povray << "< " << Pts[*node->data].x() << ", " << Pts[*node->data].y() << ", " << Pts[*node->data].z() << "> , " ;
03742     if(smooth)
03743       povray << "< " << Norm[*node->data].x() << ", " << Norm[*node->data].y() << ", " << Norm[*node->data].z() << "> , " ;
03744     node = connect.goToNext() ;
03745     povray << "< " << Pts[*node->data].x() << ", " << Pts[*node->data].y() << ", " << Pts[*node->data].z() << "> " ;
03746     if(smooth)
03747       povray << ", < " << Norm[*node->data].x() << ", " << Norm[*node->data].y() << ", " << Norm[*node->data].z() << "> " ;
03748     node = connect.goToNext() ; // skip the -1 value
03749     node = connect.goToNext() ;
03750     povray << "}\n" ;
03751   }
03752   
03753   povray << "\ttexture{ pigment { rgb < " << (double)color.r/255.0 << ", " << (double)color.g/255.0 << ", " << (double)color.b/255.0 << " >}\n" ;
03754   povray << "\t\tfinish { ambient " << ambient << " diffuse " << diffuse << " }\n\t}\n" ;
03755   
03756   povray << "}\n\n" ;
03757   return povray.good() ;
03758 }
03759 
03782 template <class T, int N>
03783 int NurbsSurface<T,N>::writePOVRAY(const char *filename, const Color& col, const Point_nD<T,N>& cView, const Point_nD<T,N>& up, int patch_type, double flatness, int num_u_steps, int num_v_steps) const {
03784   ofstream fout(filename) ;
03785   if(!fout)
03786     return 0 ;
03787   
03788   Point_nD<T,N> view(T(-1.0)*cView) ;
03789 
03790   fout << "//\n//Generated for POV-Ray(tm) 3.0 by Phil's NURBS library\n//\n" ;
03791   fout << "\n#include \"colors.inc\"\n" ;
03792 
03793   // we want the camera to look at the center of the object
03794   // and be able to view the whole object
03795   // we use and angle of 36 to view the object
03796   // and position the rest according to this.
03797   Point_nD<T,N> minP, maxP ;
03798   minP.x() = extremum(1,coordX) ;
03799   minP.y() = extremum(1,coordY) ;
03800   minP.z() = extremum(1,coordZ) ;
03801   maxP.x() = extremum(0,coordX) ;
03802   maxP.y() = extremum(0,coordY) ;
03803   maxP.z() = extremum(0,coordZ) ;
03804 
03805   Point_nD<T,N> lookAt  ;
03806   lookAt.x() = (minP.x()+maxP.x())/2.0 ;
03807   lookAt.y() = (minP.y()+maxP.y())/2.0 ;
03808   lookAt.z() = (minP.z()+maxP.z())/2.0 ;
03809 
03810   Point_nD<T,N> camera1, camera2 ;
03811 
03812   Point_nD<T,N> q1 = minP-lookAt ;
03813   Point_nD<T,N> q2 = maxP-lookAt ;
03814   T D1 = absolute(dot(q1,view))/norm(view) ;
03815   T D2 = absolute(dot(q2,view))/norm(view) ;
03816 
03817   T a1 = norm(q1)*cos(angle(view,q1)) ;
03818   T a2 = norm(q2)*cos(angle(view,q2)) ;
03819 
03820   T b1 = D1/tan(18.0*M_PI/180.0) ;
03821   T b2 = D2/tan(18.0*M_PI/180.0) ; // this gives the 36 degree angle
03822 
03823   camera1 = lookAt+(a1+b1)*view.unitLength() ;
03824   camera2 = lookAt+(a2+b2)*view.unitLength() ;
03825 
03826   Point_nD<T,N> right ;
03827 
03828   right = crossProduct(view,up) ; // inversed because pov-ray uses a left-handed system
03829 
03830   fout << "camera {\n\tlocation <" ;
03831   if(norm2(camera1-lookAt)>norm2(camera2-lookAt))
03832     fout << camera1.x() << ", " << camera1.y() << ", " << camera1.z() << ">\n" ;
03833   else
03834     fout << camera2.x() << ", " << camera2.y() << ", " << camera2.z() << ">\n" ;
03835   fout << "\tup < " << up.x() << ", " << up.y() << ", " << up.z() << ">\n" ;
03836   fout << "\tright < " << right.x() << ", " << right.y() << ", " << right.z() << ">\n" ;
03837   fout << "\tlook_at < " << lookAt.x() << ", " << lookAt.y() << ", " << lookAt.z() << ">\n\tangle 36\n}\n\n" ;
03838 
03839   fout << "union {\n" ;
03840   writePOVRAY(fout,patch_type,flatness,num_u_steps,num_v_steps) ;
03841   fout << " texture {\n\tpigment {\n\t\tcolor rgb < " << (double)col.r/255.0 << 
03842     ", " << (double)col.g/255.0 << ", " << (double)col.b/255.0 << "> \n" <<
03843     "\t}\n\tfinish { \n\t\tambient .2\n\t\tdiffuse .6\n\t}\n }\n" ;
03844   fout << "\n}\n" ;
03845 
03846   fout << "light_source { < " ;
03847   if(norm2(camera1-lookAt)>norm2(camera2-lookAt))
03848     fout << camera1.x()+view.x() << ", " << camera1.y()+view.y() << ", " << camera1.z()+view.z() << "> color White}\n\n" ;
03849   else
03850     fout << camera2.x()+view.x() << ", " << camera2.y()+view.y() << ", " << camera2.z()+view.z() << "> color White}\n\n" ;
03851   
03852   return fout.good() ;
03853 }
03854 
03855 
03880 template <class T, int N>
03881 int NurbsSurface<T,N>::writePOVRAY(T tolerance, const char *filename, const Color& col, const Point_nD<T,N>& cView, const Point_nD<T,N>& up, int smooth, T ambient, T diffuse) const {
03882   ofstream fout(filename) ;
03883   if(!fout)
03884     return 0 ;
03885   
03886   Point_nD<T,N> view(T(-1)*cView) ;
03887 
03888   fout << "//\n//Generated for POV-Ray(tm) 3.0 by Phil's NURBS library\n//\n" ;
03889   fout << "\n#include \"colors.inc\"\n" ;
03890 
03891   // we want the camera to look at the center of the object
03892   // and be able to view the whole object
03893   // we use and angle of 36 to view the object
03894   // and position the rest according to this.
03895   Point_nD<T,N> minP, maxP ;
03896   minP.x() = extremum(1,coordX) ;
03897   minP.y() = extremum(1,coordY) ;
03898   minP.z() = extremum(1,coordZ) ;
03899   maxP.x() = extremum(0,coordX) ;
03900   maxP.y() = extremum(0,coordY) ;
03901   maxP.z() = extremum(0,coordZ) ;
03902 
03903   Point_nD<T,N> lookAt  ;
03904   lookAt.x() = (minP.x()+maxP.x())/2.0 ;
03905   lookAt.y() = (minP.y()+maxP.y())/2.0 ;
03906   lookAt.z() = (minP.z()+maxP.z())/2.0 ;
03907 
03908   Point_nD<T,N> camera1, camera2 ;
03909 
03910   Point_nD<T,N> q1 = minP-lookAt ;
03911   Point_nD<T,N> q2 = maxP-lookAt ;
03912   T D1 = absolute(dot(q1,view))/norm(view) ;
03913   T D2 = absolute(dot(q2,view))/norm(view) ;
03914 
03915   T a1 = norm(q1)*cos(angle(view,q1)) ;
03916   T a2 = norm(q2)*cos(angle(view,q2)) ;
03917 
03918   T b1 = D1/tan(18.0*M_PI/180.0) ;
03919   T b2 = D2/tan(18.0*M_PI/180.0) ; // this gives the 36 degree angle
03920 
03921   camera1 = lookAt+(a1+b1)*view.unitLength() ;
03922   camera2 = lookAt+(a2+b2)*view.unitLength() ;
03923 
03924   Point_nD<T,N> right ;
03925 
03926   right = crossProduct(view,up) ; // inversed because pov-ray uses a left-handed system
03927 
03928   fout << "camera {\n\tlocation <" ;
03929   if(norm2(camera1-lookAt)>norm2(camera2-lookAt))
03930     fout << camera1.x() << ", " << camera1.y() << ", " << camera1.z() << ">\n" ;
03931   else
03932     fout << camera2.x() << ", " << camera2.y() << ", " << camera2.z() << ">\n" ;
03933   fout << "\tup < " << up.x() << ", " << up.y() << ", " << up.z() << ">\n" ;
03934   fout << "\tright < " << right.x() << ", " << right.y() << ", " << right.z() << ">\n" ;
03935   fout << "\tlook_at < " << lookAt.x() << ", " << lookAt.y() << ", " << lookAt.z() << ">\n\tangle 36\n}\n\n" ;
03936 
03937   writePOVRAY(tolerance,fout,col,smooth,ambient,diffuse) ;
03938   
03939 
03940   fout << "light_source { < " ;
03941   if(norm2(camera1-lookAt)>norm2(camera2-lookAt))
03942     fout << camera1.x()+view.x() << ", " << camera1.y()+view.y() << ", " << camera1.z()+view.z() << "> color White}\n\n" ;
03943   else
03944     fout << camera2.x()+view.x() << ", " << camera2.y()+view.y() << ", " << camera2.z()+view.z() << "> color White}\n\n" ;
03945   
03946   return fout.good() ;
03947 }
03948 
03949 
03950 
03951 
03971 template <class T, int N>
03972 int NurbsSurface<T,N>::writeRIB(ostream& rib) const {
03973   rib << "NuPatch " << P.rows() << ' ' << degU+1 << " [ " ; 
03974   int k;
03975   // I have to loop since RIB is new line sensitive and 
03976   // by default a vector adds a new line at the end when using cout
03977   for(k=0;k<U.n();++k) 
03978     rib << U[k] << ' ' ;
03979   rib << " ] " << U[0] << ' ' << U[U.n()-1] << ' ' << P.cols() << ' ' << degV+1 << " [ " ;
03980   for(k=0;k<V.n();++k)
03981     rib << V[k] << ' ' ;
03982   rib << " ] " << V[0] << ' ' << V[V.n()-1] << " \"Pw\" [ " ;
03983   for(int j=0;j<P.cols();++j)
03984     for(int i=0;i<P.rows();++i)
03985       rib << P(i,j) ;
03986   rib << " ]\n" ;
03987   return rib.good() ;
03988 }
03989 
04012 template <class T, int N>
04013 int NurbsSurface<T,N>::writeRIB(const char* filename, const Color& col, const Point_nD<T,N>& view) const {
04014   ofstream fout(filename) ;
04015   if(!fout)
04016     return 0;
04017   
04018   // The following code is based on Listing 8.2 from the RenderMan Companion
04019   // http://pete.cs.caltech.edu/RMR/Pixar/ch8/listing8_2.c
04020   int i,j ;
04021 
04022   // aimZ
04023   MatrixRT<double> Rx ;
04024   double xzlen, yzlen, yrot, xrot;
04025 
04026   //
04027   // The initial rotation about the y axis is given by the projection of
04028   // the direction vector onto the x,z plane: the x and z components
04029   // of the direction. 
04030   xzlen = sqrt(view.x()*view.x()+view.z()*view.z()) ;
04031   if(xzlen == 0)    
04032     yrot = (view.y() < 0) ? M_PI : 0;
04033   else
04034     yrot = acos(view.y()/xzlen);
04035   
04036   //
04037   // The second rotation, about the x axis, is given by the projection on
04038   // the y,z plane of the y-rotated direction vector: the original y
04039   // component, and the rotated x,z vector from above. 
04040   //
04041   yzlen = sqrt(view.y()*view.y()+xzlen*xzlen);
04042   xrot = acos(xzlen/yzlen);       /* yzlen should never be 0 */
04043 
04044   // A rotation around y first 
04045   if (view.y() > 0){
04046     if(view.x()>0)
04047       Rx.rotate(xrot,yrot,0.0) ;
04048     else
04049       Rx.rotate(xrot,-yrot,0.0) ;
04050   }
04051   else{
04052     if(view.x()>0)
04053       Rx.rotate(-xrot,yrot,0.0) ;
04054     else
04055       Rx.rotate(-xrot,-yrot,0.0) ;
04056   }
04057 
04058   Point_nD<T,N> minP, maxP ;
04059   minP.x() = extremum(1,coordX) ;
04060   minP.y() = extremum(1,coordY) ;
04061   minP.z() = extremum(1,coordZ) ;
04062   maxP.x() = extremum(0,coordX) ;
04063   maxP.y() = extremum(0,coordY) ;
04064   maxP.z() = extremum(0,coordZ) ;
04065 
04066   Point_nD<T,N> lookAt  ;
04067   lookAt.x() = (minP.x()+maxP.x())/2.0 ;
04068   lookAt.y() = (minP.y()+maxP.y())/2.0 ;
04069   lookAt.z() = (minP.z()+maxP.z())/2.0 ;
04070 
04071   Point_nD<T,N> camera1, camera2 ;
04072 
04073   Point_nD<T,N> q1 = minP-lookAt ;
04074   Point_nD<T,N> q2 = maxP-lookAt ;
04075   T D1 = absolute(dot(q1,view))/norm(view) ;
04076   T D2 = absolute(dot(q2,view))/norm(view) ;
04077 
04078   T a1 = norm(q1)*cos(angle(view,q1)) ;
04079   T a2 = norm(q2)*cos(angle(view,q2)) ;
04080 
04081   T b1 = D1/tan(18.0*M_PI/180.0) ;
04082   T b2 = D2/tan(18.0*M_PI/180.0) ; // this gives the 36 degree angle
04083 
04084   camera1 = lookAt+(a1+b1)*view.unitLength() ;
04085   camera2 = lookAt+(a2+b2)*view.unitLength() ;
04086 
04087   Point_nD<T,N> camera ;
04088 
04089   if(norm(camera1-lookAt)>norm(camera2-lookAt))
04090     camera = camera1 ;
04091   else
04092     camera = camera2 ;
04093 
04094   char front[1024] ;
04095 
04096   char *ext ;
04097   ext = strstr(filename,".rib") ;
04098   if(ext){
04099     for(i=0;i<1024;++i){
04100       if(&filename[i] == ext)
04101         break ;
04102       else
04103         front[i] = filename[i] ;
04104       if(!front[i])
04105         break ;
04106     }
04107   }
04108   else{
04109     strcpy(front,filename) ;
04110   }
04111   
04112 
04113   fout << "##RenderMan RIB-Structure 1.0\n" ;
04114   fout << "#" << filename << endl;
04115   fout << "Format 400 400 1\n";
04116   fout << "Display \"" << front << ".tif\" \"file\" \"rgba\"\n" ;
04117   fout << "Projection \"perspective\" \"fov\" [36]\n" ;
04118   fout << "Translate 0 0 " << norm(camera-lookAt) << endl ;
04119   fout << "Option \"render\" \"prmanspecular\" [1]\n" ;
04120 
04121   fout << "\nWorldBegin\n" ;
04122   fout << "LightSource \"ambientlight\" 0 \"intensity\" [0.3]\n" ;
04123   fout << "LightSource \"distantlight\" 1 \"to\" [ " << view.x() << ' ' << view.y() << ' ' << view.z()  << "]\n" ;
04124   //fout << "LightSource \"spotlight\" 1 \"intensity\" [300] \"from\" [ " ;
04125   //fout << camera.x()+view.x() << ' ' << camera.y()+view.y() << ' ' << camera.z()+view.z() << " ]\n\n" ;
04126   fout << "AttributeBegin\nSurface \"plastic\"\n" ;
04127   fout << "Color [ " << (double)col.r/255.0 << ' ' << (double)col.g/255.0 << ' ' << double(col.b)/255.0 << "]\n" ;
04128 
04129   fout << "Transform [ " ;
04130 
04131   for(j=0;j<4;++j)
04132     for(i=0;i<4;++i)
04133       fout << Rx(i,j) << ' ' ;
04134   fout << "]\n" ;
04135   fout << "Translate " << -lookAt.x() << ' ' << -lookAt.y() << ' ' << -lookAt.z() << endl ;
04136 
04137 
04138   writeRIB(fout) ;
04139 
04140   fout << "AttributeEnd\nWorldEnd\n\n" ;
04141 
04142   return fout.good() ;
04143 }
04144 
04145 
04159 template <class T, int N>
04160 void NurbsSurface<T,N>::tesselate(T tolerance, BasicList<Point_nD<T,N> > &points, BasicList<int> &connect, BasicList<Point_nD<T,N> > *Norm) const {
04161 
04162 #ifdef USE_EXCEPTION
04163   throw NurbsError() ;
04164 #else
04165   Error err("NurbsSurface<T,N>::tesselate");
04166   err << "The tesselate member function is deprecated. Please use\n"
04167     "the NurbsSubSurface class member functions instead.\n" ; 
04168   err.fatal();
04169 #endif
04170 }
04171 
04172 
04185 template <class T, int N>
04186 void NurbsSurface<T,N>::makeSphere(const Point_nD<T,N>& O, T r) {
04187   NurbsCurve<T,N> c ;
04188 
04189   const T wm = T(0.707106781185) ;  // sqrt(2)/2
04190 
04191   c.resize(5,2) ; 
04192 
04193   c.modCP(0,HPoint_nD<T,N>(0,0,r,1)) ; 
04194   c.modCP(1,HPoint_nD<T,N>(-r*wm,0,r*wm,wm)) ; 
04195   c.modCP(2,HPoint_nD<T,N>(-r,0,0,1)) ; 
04196   c.modCP(3,HPoint_nD<T,N>(-r*wm,0,-r*wm,wm)) ; 
04197   c.modCP(4,HPoint_nD<T,N>(0,0,-r,1)) ; 
04198   
04199   Vector<T> k(5+2+1) ;
04200   k[0] = k[1] = k[2] = 0 ;
04201   k[3] = k[4] = 0.5 ;
04202   k[5] = k[6] = k[7] = 1 ; 
04203   
04204   c.modKnot(k) ; 
04205 
04206   makeFromRevolution(c) ; 
04207   MatrixRT<T> Tx ;
04208   Tx.translate(O.x(),O.y(),O.z()) ;
04209   transform(Tx) ;
04210 }
04211 
04242 template <class T, int N>
04243 int NurbsSurface<T,N>::writePS(const char* filename, int nu, int nv, const Point_nD<T,N>& camera, const Point_nD<T,N>& lookAt, int cp,T magFact,T dash) const {
04244   NurbsCurveArray<T,N> Ca ;
04245   if(nu<=0 || nv<=0)
04246     return 0 ;
04247 
04248 
04249   // We need to find the rotation matrix to have z axis along nv
04250   Point_nD<T,N> np  = lookAt-camera ; 
04251   np = np.unitLength() ; 
04252   np *= -1 ;
04253   
04254   T rx = atan2(np.z(),np.y()) ;
04255   T ry = atan2(np.z(),np.x()) ;
04256   
04257   MatrixRT<T> Tx(rx,ry,0,camera.x(),camera.y(),camera.z()) ;
04258   //MatrixRT<T,N> Sc ; Sc.scale(1,1,T(norm(lookAt-camera))/plane) ;
04259   //MatrixRT<T,N> Tg(Sc*Tx) ; 
04260 
04261   Ca.resize(nu+nv+2) ; 
04262   int i ; 
04263   for(i=0;i<=nu;++i){
04264     T u = U[0]+T(i)*(U[U.n()-1]-U[0])/T(nu) ;
04265     isoCurveU(u , Ca[i]) ;
04266     Ca[i].transform(Tx) ; 
04267   }
04268   for(;i<=nv+nu+1;++i){
04269     T v = V[0]+T(i-nu-1)*(V[V.n()-1]-V[0])/T(nv) ;
04270     isoCurveV(v , Ca[i]) ;
04271     Ca[i].transform(Tx) ; 
04272   }
04273 
04274 
04275   return Ca.writePS(filename,cp,magFact,dash) ;
04276 }
04277 
04317 template <class T, int N>
04318 int NurbsSurface<T,N>::writePSp(const char*, int nu, int nv, const Point_nD<T,N>& camera, const Point_nD<T,N>& lookAt, const Vector< Point_nD<T,N> >&,const Vector< Point_nD<T,N> >&, int cp,T magFact,T dash) const {
04319   cerr << "Not implemented. Not sure what is different between this and writePS\n";
04320   return 0;
04321 }
04322 
04331 template <class T, int N>
04332 ostream& NurbsSurface<T,N>::print(ostream& o) const {
04333   o << "Degree: " << degU << ' ' << degV << endl;
04334   o << "U : " << U << endl;
04335   o << "V: " << V << endl ;
04336   o << "matrix size: " << P.rows() << ' ' << P.cols() << endl ;
04337   o << P << endl;
04338   return o;
04339 }
04340 
04357 template <class T, int N>
04358 int surfMeshParamsClosedU(const Matrix< Point_nD<T,N> >& Q, Vector<T>& uk, Vector<T>& vl, int degU){
04359 
04360   int n,m,k,l,num ;
04361   double d,total ;
04362   Vector<T> cds(Q.rows()) ;
04363 
04364   n = Q.rows() ;
04365   m = Q.cols() ;
04366   uk.resize(n) ;
04367   vl.resize(m) ;
04368   num = m ;
04369   
04370   // Compute the uk
04371   uk.reset(0) ;
04372 
04373   for(l=0;l<m;l++){
04374     total = 0.0 ;
04375     for(k=1;k<=n-degU;k++){
04376       cds[k] = norm(Q(k,l)-Q(k-1,l)) ;
04377       total += cds[k] ;
04378     }
04379     for(k=n-degU+1; k<n ;k++)
04380       cds[k] = norm(Q(k,l)-Q(k-1,l)) ;
04381 
04382     if(total==0.0) 
04383       num-- ;
04384     else {
04385       d = 0.0 ;
04386       for(k=1;k<n;k++){
04387         d += cds[k] ;
04388         uk[k] += d/total ;
04389       }
04390     }
04391   }
04392   if(num==0) 
04393     return 0 ;
04394   for(k=1;k<n;k++)
04395     uk[k] /= num ;
04396 
04397   // Compute the vl
04398   vl.reset(0) ;
04399   cds.resize(m) ;
04400 
04401   num = n ;
04402 
04403   for(k=0;k<n;k++){
04404     total = 0.0 ;
04405     for(l=1;l<m;l++){
04406       cds[l] = norm(Q(k,l)-Q(k,l-1)) ;
04407       total += cds[l] ;
04408     }
04409     if(total==0.0) 
04410       num-- ;
04411     else {
04412       d = 0.0 ;
04413       for(l=1;l<m;l++){
04414         d += cds[l] ;
04415         vl[l] += d/total ;
04416       }
04417     }
04418   }
04419   if(num==0) 
04420     return 0 ;
04421   for(l=1;l<m-1;l++)
04422     vl[l] /= num ;
04423   vl[m-1] = 1.0 ;
04424 
04425 
04426   return 1 ;
04427 }
04428 
04445 template <class T, int N>
04446 int surfMeshParamsClosedUH(const Matrix< HPoint_nD<T,N> >& Q, Vector<T>& uk, Vector<T>& vl, int degU){
04447 
04448   int n,m,k,l,num ;
04449   double d,total ;
04450   Vector<T> cds(Q.rows()) ;
04451 
04452   n = Q.rows() ;
04453   m = Q.cols() ;
04454   uk.resize(n) ;
04455   vl.resize(m) ;
04456   num = m ;
04457   
04458   // Compute the uk
04459   uk.reset(0) ;
04460 
04461   for(l=0;l<m;l++){
04462     total = 0.0 ;
04463     // Normalization factor
04464     for(k=1;k<=n-degU;k++){
04465       cds[k] = norm(Q(k,l)-Q(k-1,l)) ;
04466       total += cds[k] ;
04467     }
04468     for(k=n-degU+1; k<n ;k++)
04469       cds[k] = norm(Q(k,l)-Q(k-1,l)) ;
04470     if(total==0.0) 
04471       num-- ;
04472     else {
04473       d = 0.0 ;
04474       for(k=1;k<n;k++){
04475         d += cds[k] ;
04476         uk[k] += d/total ;
04477       }
04478     }
04479   }
04480   if(num==0) 
04481     return 0 ;
04482   for(k=1;k<n;k++)
04483     uk[k] /= num ;
04484 
04485   // Compute the vl
04486   vl.reset(0) ;
04487   cds.resize(m) ;
04488 
04489   num = n ;
04490 
04491   for(k=0;k<n;k++){
04492     total = 0.0 ;
04493     for(l=1;l<m;l++){
04494       cds[l] = norm(Q(k,l)-Q(k,l-1)) ;
04495       total += cds[l] ;
04496     }
04497     if(total==0.0) 
04498       num-- ;
04499     else {
04500       d = 0.0 ;
04501       for(l=1;l<m;l++){
04502         d += cds[l] ;
04503         vl[l] += d/total ;
04504       }
04505     }
04506   }
04507   if(num==0) 
04508     return 0 ;
04509   for(l=1;l<m-1;l++)
04510     vl[l] /= num ;
04511   vl[m-1] = 1.0 ;
04512 
04513   return 1 ;
04514 }
04515 
04516 
04533 template <class T, int N>
04534 void NurbsSurface<T,N>::globalInterpClosedU(const Matrix< Point_nD<T,N> >& Q, int pU, int pV){
04535   Vector<T> vk,uk ;
04536 
04537   resize(Q.rows(),Q.cols(),pU,pV) ;
04538 
04539   surfMeshParamsClosedU(Q,uk,vk,pU) ;
04540   knotAveragingClosed(uk,pU,U) ;
04541   knotAveraging(vk,pV,V) ;
04542 
04543 
04544   Vector< HPoint_nD<T,N> > Pts(Q.cols()) ;
04545   NurbsCurve<T,N> R ;
04546   
04547   int i,j ;
04548   for(i=0;i<Q.rows();i++){
04549     for(j=0;j<Q.cols();j++)
04550       Pts[j] = Q(i,j) ;
04551     R.globalInterpH(Pts,vk,V,pV) ;
04552     for(j=0;j<Q.cols();j++)
04553       P(i,j) = R.ctrlPnts(j) ;
04554   }
04555   
04556   Pts.resize(Q.rows()) ;
04557   for(j=0;j<Q.cols();j++){
04558     for(i=0;i<Q.rows();i++)
04559       Pts[i] = P(i,j) ;
04560     
04561     R.globalInterpClosedH(Pts,uk,U,pU);
04562     for(i=0;i<Q.rows();i++)
04563       P(i,j) = R.ctrlPnts(i) ;
04564   }
04565 
04566 }
04567 
04583 template <class T, int N>
04584 void NurbsSurface<T,N>::globalInterpClosedUH(const Matrix< HPoint_nD<T,N> >& Q, int pU, int pV){
04585   Vector<T> vk,uk ;
04586 
04587   resize(Q.rows(),Q.cols(),pU,pV) ;
04588 
04589   surfMeshParamsClosedUH(Q,uk,vk,pU) ;
04590   knotAveragingClosed(uk,pU,U) ;
04591   knotAveraging(vk,pV,V) ;
04592   
04593   Vector< HPoint_nD<T,N> > Pts(Q.rows()) ;
04594   NurbsCurve<T,N> R ;
04595   
04596   int i,j ;
04597 
04598   for(j=0;j<Q.cols();j++){
04599     for(i=0;i<Q.rows();i++)
04600       Pts[i] = Q(i,j) ;
04601     R.globalInterpH(Pts,uk,U,pU);
04602     for(i=0;i<Q.rows();i++)
04603       P(i,j) = R.ctrlPnts(i) ;
04604   }
04605 
04606   Pts.resize(Q.cols()) ;
04607   for(i=0;i<Q.rows();i++){
04608     for(j=0;j<Q.cols();j++)
04609       Pts[j] = P(i,j) ;
04610     R.globalInterpClosedH(Pts,vk,V,pV) ;
04611     for(j=0;j<Q.cols();j++)
04612       P(i,j) = R.ctrlPnts(j) ;
04613   }
04614 }
04615 
04616 
04635 template <class T, int N>
04636 void NurbsSurface<T,N>::leastSquaresClosedU(const Matrix< Point_nD<T,N> >& Q, int pU, int pV, int nU, int nV){
04637   Vector<T> vk,uk ;
04638 
04639   resize(nU+pU,nV,pU,pV) ;
04640 
04641   surfMeshParamsClosedU(Q,uk,vk,pU) ;
04642 
04643 
04644   Vector< HPoint_nD<T,N> > Pts(Q.rows()) ;
04645   NurbsCurve<T,N> R ;
04646   
04647   int i,j ;
04648 
04649   Matrix< HPoint_nD<T,N> > P2 ;
04650 
04651   P2.resize(nU+pU,Q.cols()) ;
04652 
04653   for(j=0;j<Q.cols();j++){
04654     for(i=0;i<Q.rows();i++)
04655       Pts[i] = Q(i,j) ;
04656     R.leastSquaresClosedH(Pts,pU,nU,uk);
04657     for(i=0;i<P.rows();i++)
04658       P2(i,j) = R.ctrlPnts(i) ;
04659     if(j==0)
04660       U = R.knot() ;
04661   }
04662 
04663   Pts.resize(Q.cols()) ;
04664   for(i=0;i<P.rows();i++){
04665     for(j=0;j<Q.cols();j++)
04666       Pts[j] = P2(i,j) ;
04667     R.leastSquaresH(Pts,pV,nV,vk) ;
04668     for(j=0;j<P.cols();j++)
04669       P(i,j) = R.ctrlPnts(j) ;
04670     if(i==0)
04671       V = R.knot() ;
04672   }  
04673 
04674 }
04675 
04705 template <class T, int N>
04706 int NurbsSurface<T,N>::writeOOGL(const char* filename,
04707                                  T fDu,
04708                                  T fDv,
04709                                  T fBu, T fBv,
04710                                  T fEu, T fEv,
04711                                  bool  bDrawCP) const {
04712   ofstream fout(filename) ;
04713   if(!fout)
04714     return 0 ;
04715   
04716   // Write file header
04717   fout << "{ LIST \n";
04718   fout << "\t{ appearance { shading smooth } \n " ;
04719   fout << "\tNMESH" << endl;
04720   T Nu = (fEu-fBu)/fDu + 1;
04721   T Nv = (fEv-fBv)/fDv + 1;
04722   fout << "\t"<< Nu << ' ' << Nv << endl;
04723 
04724   // Write mesh vertexes
04725   Point_nD<T,N> Sp, Np;
04726   T u,v;
04727   for (u = fBu; u<fEu+fDu/2; u+=fDu)
04728     for (v = fBv; v<fEv+fDv/2; v+=fDv){
04729       Sp = pointAt(u,v);
04730       Np = normal(u,v);
04731       Np = (norm(Np)!=0)?Np.unitLength():Point_nD<T,N>(0.0);
04732       fout << "\t" << Sp << "\t " << Np << endl;
04733     }
04734   fout << "\t}" << endl << std::flush;
04735 
04736   // Write the control points 
04737   if (bDrawCP){
04738     fout << "\t{ " << endl; 
04739     fout << "\t  appearance {shading smooth linewidth 5 } " << endl;
04740 
04741     fout << "\t" << "SKEL" << endl; 
04742     fout <<  P.rows()*P.cols() << ' ' << P.rows()*P.cols() << endl;
04743     for (int i = 0; i<P.rows(); i++)
04744       for (int j = 0; j<P.cols(); j++) 
04745         fout << "\t" << project(P(i,j)) << endl;    
04746     fout << endl;
04747     for (int i = 0; i<P.rows()*P.cols(); i++)
04748       fout << "\t" << "1 " << i << " 0 0 1 0.5 " << endl;
04749       fout << "\t" << " }" << endl;
04750   }
04751   fout << "} " << endl;
04752   fout << std::flush;
04753 
04754   return 1 ;
04755 }
04756 
04774 template <class T, int N>
04775 int NurbsSurface<T,N>::writeDisplayQUADMESH(const char* filename, int iNu,int iNv,const Color& color,T fA, T fO) const 
04776 {
04777 
04778   T fDu = 1/T(iNu);
04779   T fDv = 1/T(iNv-1);
04780 
04781   ofstream fout(filename) ;
04782   if(!fout)
04783     return 0 ;
04784 
04785   // Save the object type
04786   const char QUADMESH='q'+ ('A' - 'a');
04787   fout << QUADMESH << ' ';       ;
04788 
04789   // Compute surface properties
04790   T a, d, s, se, t;
04791 
04792   // Ambient reflectance coefficient
04793   a  = 0.3;
04794   // Diffusse reflectance coefficient
04795   d  = 0.3;
04796   // Specularity reflectance coeficcient
04797   s  = 0.4;
04798   // Specularity reflectance exponent
04799   se = 10;
04800   // Opacity
04801   t  = fO;
04802 
04803   // Save surface properties
04804   fout << a << ' ' 
04805        << d << ' ' 
04806        << s << ' ' 
04807        << se << ' ' 
04808        << t  << ' ';
04809 
04810   // Save mesh dimensions  
04811   fout << iNu << ' ' 
04812        << iNv << ' ' ;
04813   
04814   // Save wrapp status in each direction (v,u)  
04815   fout << "F T ";
04816 
04817   // New line
04818   fout << endl ;
04819   
04820   // Surface color RGBA (one color for the whole surface)
04821   T fR= T(color.r)/255;
04822   T fG= T(color.g)/255;
04823   T fB= T(color.b)/255;
04824 
04825   /* Colour flag = ONE_COLOUR */
04826   fout << 0 << ' ' ;
04827   /* The colour */
04828   fout << fR << ' '
04829        << fG << ' '
04830        << fB << ' '
04831        << fA << endl;
04832   
04833   // New line
04834   fout << endl ;
04835 
04836   // Now the list of 3D points
04837   T u,v;
04838   Point_nD<T,N> Sp;
04839   for (v = 0; v<1+fDv/2; v+=fDv)
04840     for (u = 0; u<1-fDu/2; u+=fDu){
04841       // The change in sign and the swap of y and z coordinates is
04842       // for conversion to MINC format.
04843       Sp = -(T)1.0 * pointAt(u,v) ;
04844       fout << Sp.x() << ' ' << Sp.z() << ' ' << Sp.y() << endl;
04845     }
04846 
04847   // New line
04848   fout << endl ;
04849 
04850   // Now the normal vectors
04851   Point_nD<T,N> Np;
04852   for (v = 0; v<1+fDv/2; v+=fDv)
04853     for (u = 0; u<1-fDu/2; u+=fDu){
04854       Np = normal(u,v);
04855       Np = (norm(Np)!=0)?Np.unitLength():Point_nD<T,N>(0.0);
04856       fout << Np.x() << ' ' << Np.z() << ' ' << Np.y() << endl;
04857     }
04858 
04859   // New line
04860   fout << endl ;
04861 
04862 
04863   return 1;
04864 }
04865 
04880 template <class T, int N>
04881 int NurbsSurface<T,N>::writeOOGL(const char* filename) const {
04882   ofstream fout(filename) ;
04883   if(!fout)
04884     return 0 ;
04885 
04886   // Write file header
04887   int iPointDim = 4;
04888   fout << "BEZ" << degU << degV << iPointDim << endl;
04889 
04890   // Decompose surface in its Bezier Patches
04891   NurbsSurfaceArray<T,N> S;
04892   NurbsSurface<T,N>      surface(*this);
04893   surface.decompose(S);
04894 
04895   // Write patch vertexes
04896   for (int iPatch = 0; iPatch < S.n(); iPatch++){
04897     for(int iu = 0; iu < degU + 1; iu++){
04898       for(int iv = 0; iv < degV + 1; iv++)
04899         fout << S[iPatch].ctrlPnts(iu,iv).x() << ' ' 
04900              << S[iPatch].ctrlPnts(iu,iv).y() << ' '  
04901              << S[iPatch].ctrlPnts(iu,iv).z() << ' '
04902              << S[iPatch].ctrlPnts(iu,iv).w() << endl;
04903     }
04904     fout << endl;    
04905   }
04906   fout << std::flush;
04907 
04908   return 1 ;
04909 }
04910 
04911 
04926 template <class T, int N>
04927 void wrapPointMatrix(const Matrix< Point_nD<T,N> >& Q, int d, int dir,  Matrix< Point_nD<T,N> >& Qw){
04928   int i, row, col;
04929 
04930   Qw = Q;
04931 
04932   if (dir==0){
04933     //    cout << " Wrapping in U dir " << endl << std::flush ;
04934     Qw.resizeKeep(Q.rows()+d,Q.cols());
04935     for (col=0; col < Q.cols(); col++)
04936       for (i=0; i<d; i++)
04937         Qw(i+Q.rows(),col) = Q(i,col);
04938   }
04939   else{
04940     //    cout << " Wrapping in V dir " << endl << std::flush ;
04941     Qw.resizeKeep(Q.rows(),Q.cols()+d);
04942     for (row=0; row < Q.rows(); row++)
04943       for (i=0; i<d; i++)
04944         Qw(row,i+Q.cols()) = Q(row,i);
04945   }
04946   
04947 } 
04948 
04966 template <class T, int N>
04967 void NurbsSurface<T,N>::dersBasisFuns(T u, T v, int dU, int dV, int uspan, int vspan, Matrix<T> & Niku, Matrix<T> & Njkv ) const {
04968   // Get derivatives
04969   nurbsDersBasisFuns(dU,u,uspan,degU,U,Niku) ;
04970   nurbsDersBasisFuns(dV,v,vspan,degV,V,Njkv) ;
04971 }
04972 
04987 template <class T, int N>
04988 void NurbsSurface<T,N>::makeTorus(const Point_nD<T,N>& O, T R, T r) {
04989   // These define the shape of a unit torus centered about the origin. 
04990   T xvalues[] = { 0.0, -1.0, -1.0, -1.0, 0.0, 1.0, 1.0, 1.0, 0.0 };
04991   T yvalues[] = { 1.0, 1.0, 0.0, -1.0, -1.0, -1.0, 0.0, 1.0, 1.0 };
04992   T zvalues[] = { 0.0, 1.0, 1.0, 1.0, 0.0, -1.0, -1.0, -1.0, 0.0 };
04993   T offsets[] = { -1.0, -1.0, 0.0, 1.0, 1.0, 1.0, 0.0, -1.0, -1.0 };
04994 
04995   // Piecewise Bezier knot vector for a quadratic curve with four segments 
04996   T knotsMem[] = { 0, 0, 0, 0.25, 0.25, 0.5, 0.5, 0.75, 0.75 , 1, 1, 1 };
04997   Vector<T> knots(knotsMem,12) ;
04998 
04999   resize(9,9,2,2);
05000 
05001   int i, j;
05002 
05003   double r2over2 = sqrt( 2.0 ) / 2.0;
05004   double weight;
05005 
05006   for (i = 0; i < 9; i++){
05007     for (j = 0; j < 9; j++) {
05008       HPoint_nD<T,N> hp ;
05009       weight = ((j & 1) ? r2over2 : 1.0) * ((i & 1) ? r2over2 : 1.0);
05010       // Notice how the weights are pre-multiplied with the x, y and z values
05011       P(i,j).x() = xvalues[j]* (R + offsets[i] * r) * weight;
05012       P(i,j).y() = yvalues[j]* (R + offsets[i] * r) * weight;
05013       P(i,j).z() = (zvalues[i] * r) * weight;
05014       P(i,j).w() = weight;
05015     }
05016   }
05017 
05018   // The knot vectors define piecewise Bezier segments 
05019   // (the same in both U and V).
05020   
05021   U = knots ;
05022   V = knots ; 
05023 
05024   MatrixRT<T> Tx ;
05025   Tx.translate(O.x(),O.y(),O.z()) ;
05026   transform(Tx) ;  
05027 }
05028 
05029 
05030 } // end namespace
05031 
05032 #endif // #define PLIB_NURBS_NURBSS_SOURCE

Generated on Tue Jun 24 13:26:58 2003 for NURBS++ by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002