Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

gunu_project.cpp

Go to the documentation of this file.
00001 /* LIBGUL - Geometry Utility Library
00002  * Copyright (C) 1998-1999 Norbert Irmer
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 
00021 #include "stdafx.h"
00022 
00023 #include "gul_types.h"
00024 #include "gul_float.h"
00025 #include "gul_vector.h"
00026 #include "guma_newton.h"
00027 #include "gunu_basics.h"
00028 #include "gunu_refine.h"
00029 #include "gunu_sample.h"
00030 #include "gunu_bezier_derivatives.h"
00031 #include "guma_random.h"
00032 #include "guma_rkdtree.h"
00033 #include "gunu_project.h"
00034 
00035 #include <iostream>
00036 #include "gul_io.h"
00037 
00038 namespace gunu {
00039 
00040 using gul::rtr;
00041 using gul::Ptr;
00042 using gul::point;
00043 using gul::hpoint;
00044 using gul::kdpoint;
00045 using gul::List;
00046 using gul::ListNode;
00047 using gul::rel_equal;
00048 using guma::rkdtree;
00049 using guma::kdnnrec;
00050 using guma::kdrec;
00051 using guma::newton_info;
00052 using guma::random_des;
00053 using guma::Newton;
00054 using gul::distance;
00055 
00056 /*---------------------------------------------------------------------
00057   help classes, used by Newton iteration code
00058 ---------------------------------------------------------------------*/
00059 
00060 template< class T, class HP >
00061 struct patch_ninfo : public gul::pool_object
00062 {
00063   int pu;
00064   int pv;
00065   Ptr<T> U;
00066   Ptr<T> V;
00067   Ptr< Ptr<HP> > Pw;
00068 
00069   int row;  /* position of bezier segment in nurbs surface */
00070   int col;    
00071 };
00072 
00073 template< class T, class HP, class EP >
00074 class point_ninfo : public kdpoint<T,EP>
00075 {
00076 public:
00077   Ptr< patch_ninfo<T,HP> > S;
00078 
00079   T u;
00080   T v;
00081 
00082   point_ninfo *next;
00083   point_ninfo *prev;
00084 
00085   point_ninfo( EP& inP, Ptr< patch_ninfo<T,HP> >& inS, T in_u, T in_v )
00086     : kdpoint<T,EP>( inP, 0 )
00087   {
00088     S = inS;
00089     u = in_u;
00090     v = in_v;
00091   }
00092 
00093 };
00094 
00095 template< class T, class HP, class EP >
00096 class bezier_ninfo : public newton_info<T>
00097 {
00098 public:
00099   T                           last_u;
00100   T                           last_v;
00101   bool                        last_result;
00102   const EP                   *P;
00103   const point_ninfo<T,HP,EP> *SP;
00104   Ptr< Ptr<EP> >              SKL;
00105   T                           tol1;
00106   T                           tol2;
00107   bool                        init;
00108 
00109   bezier_ninfo( T in_tol1, T in_tol2 )
00110           : newton_info<T>( 2, (T)0.0001, in_tol2 )
00111   {
00112     int i;
00113     
00114     tol1 = in_tol1;
00115     tol2 = in_tol2;
00116   
00117     init = false;
00118     P = 0;
00119     SP = 0;
00120    
00121     SKL.reserve_pool(3);
00122     for( i = 0; i < 3; i++ )
00123       SKL[i].reserve_pool(3);
00124   }
00125   
00126   virtual bool evaluate( const gul::Ptr<T>& dom );
00127 
00128   void setCurrentPoint( const EP *inP, const point_ninfo<T,HP,EP> *inSP )
00129   {
00130     init = false;
00131 
00132     P = inP;
00133     SP = inSP; 
00134   }
00135 };
00136 
00137 
00138 template< class T, class HP, class EP >
00139 bool bezier_ninfo<T,HP,EP>::evaluate( const Ptr<T>& dom )
00140 {
00141   T u = dom[0], v = dom[1], rootPS;
00142   EP S, Su, Sv, Suu, Svv, Suv, PS;
00143   T SuSu, SvSv, b1, b2;
00144 
00145   if( init && (u == last_u) && (v == last_v) )
00146     return last_result;
00147   else
00148   {
00149     init = true;
00150     last_u = u;
00151     last_v = v;
00152   }   
00153 
00154   if( u < 0.0 ) u = 0.0;
00155   else if( u > 1.0 ) u = 1.0;  
00156 
00157   if( v < 0.0 ) v = 0.0;
00158   else if( v > 1.0 ) v = 1.0;  
00159 
00160   BezierSurfaceDerivatives( 
00161               u, v,  SP->S[0].pu, SP->S[0].U, SP->S[0].pv, SP->S[0].V, 
00162               SP->S[0].Pw, 2, SKL );
00163 
00164   S = SKL[0][0];
00165   Su = SKL[1][0];
00166   Sv = SKL[0][1];
00167   Suu = SKL[2][0];
00168   Suv = SKL[1][1];
00169   Svv = SKL[0][2];
00170 
00171   PS = S - *P;
00172   SuSu = Su*Su;
00173   SvSv = Sv*Sv;
00174 
00175   fjac[0][0] = PS*Suu + SuSu;
00176   fjac[0][1] = fjac[1][0] = PS*Suv + Su*Sv;
00177   fjac[1][1] = PS*Svv + SvSv;
00178   
00179   fvec[0] = Su*PS;
00180   fvec[1] = Sv*PS;
00181 
00182   if( rel_equal(S,*P,tol1) )
00183   {
00184     last_result = true;
00185     return true;
00186   }
00187 
00188   rootPS = rtr<T>::sqrt(PS*PS);
00189   b1 = rtr<T>::sqrt(SuSu)*rootPS;
00190   b2 = rtr<T>::sqrt(SvSv)*rootPS;
00191 
00192   if( rel_equal(fvec[0]+b1,b1,tol2) &&
00193       rel_equal(fvec[1]+b2,b2,tol2) )
00194   {
00195     last_result = true;
00196     return true;
00197   }
00198 
00199   last_result = false;
00200   return false;
00201 }
00202 
00203 /*---------------------------------------------------------------------
00204   Projects a set of points onto a nurbs surface
00205 ---------------------------------------------------------------------*/
00206 
00207 template< class T, class HP, class EP >
00208 GULAPI int ProjectToSurface(
00209            int nDatPoints, const Ptr<EP>& datPoints,
00210            int ref_nu, int ref_pu, const Ptr<T>& refU,
00211            int ref_nv, int ref_pv, const Ptr<T>& refV,
00212            const Ptr< Ptr<HP> >& refPw, 
00213            Ptr< pts_point<T,EP> >& retPts )
00214 {
00215   Ptr<T> BezU,BezV;
00216   Ptr< Ptr< Ptr<HP> > > strips;
00217   Ptr< Ptr< Ptr<HP> > > segs;
00218   Ptr<T> sampU, sampV;
00219   Ptr< Ptr<EP> > sampP;
00220   int nStrips, nSegs, i, j, k, l;
00221   int nSampU, nSampV;
00222   int nKu, nKv;
00223   Ptr<int> Ku,Mu,Kv,Mv;
00224   bezier_ninfo<T,HP,EP> I((T)0.000001,(T)0.000001);
00225   Ptr< patch_ninfo<T,HP> > S;
00226   point_ninfo<T,HP,EP> *P;
00227   List< point_ninfo<T,HP,EP> > LP;
00228   rkdtree< kdpoint<T,EP>,T,random_des > KDT(3);
00229   Ptr< kdnnrec< kdpoint<T,EP>,T > > N; 
00230   ListNode< kdrec< kdpoint<T,EP>,T > > *r;
00231   Ptr<T> dom,x1,x2;  
00232   point_ninfo<T,HP,EP> *pi;
00233   int n;
00234   bool found;
00235   int index,nFound;
00236   T u,v,nurbs_u,nurbs_v,min_u,min_v,dist,min_dist;
00237   EP min_S;
00238   int nRetPts;
00239 
00240   nRetPts = 0;
00241 
00242   dom.reserve_pool(2);
00243   x1.reserve_pool(2);
00244   x2.reserve_pool(2);
00245 
00246   /* form Bezier knot vectors */
00247 
00248   BezU.reserve_pool(ref_pu+ref_pu+2);
00249   BezV.reserve_pool(ref_pv+ref_pv+2);
00250   
00251   BezierKnotVector(ref_pu,BezU);
00252   BezierKnotVector(ref_pv,BezV);
00253 
00254   /* ----- divide surface into Bezier segments ----------------------- */
00255 
00256   nSampU = ref_pu*3;
00257   nSampV = ref_pv*3;
00258 
00259   sampP.reserve_pool(nSampV);
00260   for( i = 0; i < nSampV; i++ )
00261     sampP[i].reserve_pool(nSampU);
00262   
00263   sampU.reserve_pool(nSampU);
00264   sampV.reserve_pool(nSampV);
00265   EqualSpacedParameters( nSampU, BezU[0], BezU[ref_pu+1], sampU );
00266   EqualSpacedParameters( nSampV, BezV[0], BezV[ref_pv+1], sampV );
00267 
00268   nKu = BezierPositions( ref_nu, ref_pu, refU, Ku, Mu );
00269   nKv = BezierPositions( ref_nv, ref_pv, refV, Kv, Mv );
00270   nStrips = nKv;
00271   nSegs = nKu;
00272 
00273   // form horizontal Bezier strips:
00274 
00275   BezierDecomposeSurfaceV( nKv, Kv, Mv, ref_nu, ref_pu, refU, 
00276                            ref_nv, ref_pv, refV, refPw, &strips );
00277                            
00278   // divide horizontal strips into Bezier segments:
00279 
00280   segs.reserve_pool( nStrips );
00281 
00282   for( i = 0; i < nStrips; i++ )
00283   {
00284     BezierDecomposeSurfaceU( nKu, Ku, Mu, ref_nu, ref_pu, refU, 
00285                              ref_pv, ref_pv, BezV, strips[i], &segs );
00286 
00287     strips[i].reset(); // delete memory of strips, not needed anymore
00288 
00289     for( j = 0; j < nSegs; j++ )
00290     {
00291       CalcSurfaceMesh( ref_pu, ref_pu, BezU, ref_pv, ref_pv, BezV, segs[j],
00292                        nSampU, sampU, nSampV, sampV, sampP );
00293 
00294       S.reserve_pool(1);
00295 
00296       S[0].pu = ref_pu;
00297       S[0].pv = ref_pv;
00298       S[0].U = BezU;
00299       S[0].V = BezV;
00300       S[0].Pw = segs[j];
00301       S[0].row = i;
00302       S[0].col = j;
00303       
00304       for( k = 0; k < nSampV; k++ )
00305       {
00306         for( l = 0; l < nSampU; l++ )
00307         {
00308           P = new point_ninfo<T,HP,EP>( sampP[k][l], S, sampU[l], sampV[k] );
00309           LP.Append( P ); 
00310 
00311           KDT.insert( P );
00312         }
00313       }
00314     }
00315     // control points are referenced now by the patch infos, and the 'strips'
00316     // array is still needed for the next strip, so it is neither necessary 
00317     // nor possible to free something ! 
00318   }
00319 
00320   // search for each data point a nearest neighbor, and then do the newton
00321   // iteration
00322 
00323   x1[0] = x1[1] = (T)0;
00324   x2[0] = x2[1] = (T)1;
00325   
00326   for( i = 0; i < nDatPoints; i++ )
00327   {
00328     N.reserve_pool(1); // this ensures that memory from previous runs is freed
00329                      // (though this isn't necessary since N only has 1 element)
00330 
00331     n = KDT.nearest_neighbors( kdpoint<T,EP>(datPoints[i],0), 1, N );
00332     if( !n ) continue;
00333 
00334     /*
00335     cout << "data point #" << i << ": " << datPoints[i] << "\n";
00336     cout << "nearest neighbors with rkdtree\n";
00337     for( j = 0; j < n; j++ )
00338       N[j].dump(3);
00339     */
00340 
00341     nFound = 0;
00342     for( r = N[0].m_recs.First(); r; r = r->next )
00343     {
00344       pi = (point_ninfo<T,HP,EP> *)r->el.m_base;
00345       I.setCurrentPoint( &datPoints[i], pi ); 
00346 
00347       dom[0] = pi->u;
00348       dom[1] = pi->v;
00349       found = Newton( dom, x1, x2, I, 200 );
00350       if( !found ) continue;
00351 
00352       // calculate position in nurbs surface domain
00353 
00354       u = I.last_u;
00355       v = I.last_v;
00356 
00357       index = pi->S[0].row-1;
00358       if( index < 0 )
00359         nurbs_v = ((T)1-v)*refV[ref_pu] + v*refV[Kv[index+1]];
00360       else
00361         nurbs_v = ((T)1-v)*refV[Kv[index]] + v*refV[Kv[index+1]];    
00362 
00363       index = pi->S[0].col-1;
00364       if( index < 0 )
00365         nurbs_u = ((T)1-u)*refU[ref_pu] + u*refU[Ku[index+1]];
00366       else
00367         nurbs_u = ((T)1-u)*refU[Ku[index]] + u*refU[Ku[index+1]];    
00368 
00369       // if multiple points were found, take the nearest
00370 
00371       dist = distance( I.SKL[0][0], datPoints[i] );
00372 
00373       if( !nFound || (dist < min_dist) )
00374       {
00375         min_dist = dist;
00376         min_u = nurbs_u;
00377         min_v = nurbs_v;
00378         min_S = I.SKL[0][0];
00379       }
00380       nFound++;
00381       
00382       /*
00383       cout << "point calculated by newton iteration: " << I.SKL[0][0] << "\n";
00384       */
00385     }
00386 
00387     // append a record to the result list
00388     
00389     if( nFound )
00390     {
00391       retPts[nRetPts].i = i;
00392       retPts[nRetPts].u = min_u;
00393       retPts[nRetPts].v = min_v;
00394       retPts[nRetPts].S = min_S;
00395       nRetPts++;
00396     }
00397   }
00398 
00399   return nRetPts;
00400 }
00401 // template instantiation
00402 template GULAPI int ProjectToSurface(
00403            int nDatPoints, const Ptr< point<float> >& datPoints,
00404            int ref_nu, int ref_pu, const Ptr<float>& refU,
00405            int ref_nv, int ref_pv, const Ptr<float>& refV,
00406            const Ptr< Ptr< hpoint<float> > >& Pw,
00407            Ptr< pts_point< float,point<float> > >& retPts );
00408 template GULAPI int ProjectToSurface(
00409            int nDatPoints, const Ptr< point<double> >& datPoints,
00410            int ref_nu, int ref_pu, const Ptr<double>& refU,
00411            int ref_nv, int ref_pv, const Ptr<double>& refV,
00412            const Ptr< Ptr< hpoint<double> > >& Pw,
00413            Ptr< pts_point< double,point<double> > >& retPts );
00414 template GULAPI int ProjectToSurface(
00415            int nDatPoints, const Ptr< point<float> >& datPoints,
00416            int ref_nu, int ref_pu, const Ptr<float>& refU,
00417            int ref_nv, int ref_pv, const Ptr<float>& refV,
00418            const Ptr< Ptr< point<float> > >& Pw,
00419            Ptr< pts_point< float,point<float> > >& retPts );
00420 template GULAPI int ProjectToSurface(
00421            int nDatPoints, const Ptr< point<double> >& datPoints,
00422            int ref_nu, int ref_pu, const Ptr<double>& refU,
00423            int ref_nv, int ref_pv, const Ptr<double>& refV,
00424            const Ptr< Ptr< point<double> > >& Pw,
00425            Ptr< pts_point< double,point<double> > >& retPts );
00426 
00427 }

Generated on Mon Jan 21 04:17:41 2002 for GUL 0.6 - Geometry Utility Library by doxygen1.2.13.1 written by Dimitri van Heesch, © 1997-2001