Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
HiReconstruction.cpp
Go to the documentation of this file.
00001 #include "moab/DiscreteGeometry/HiReconstruction.hpp"
00002 #include "moab/DiscreteGeometry/DGMSolver.hpp"
00003 #include "moab/HalfFacetRep.hpp"
00004 
00005 #ifdef MOAB_HAVE_MPI
00006 #include "moab/ParallelComm.hpp"
00007 #endif
00008 #include "MBTagConventions.hpp"
00009 
00010 #define HIREC_USE_AHF
00011 
00012 #include <cmath>
00013 #include <deque>
00014 #include <iostream>
00015 
00016 namespace moab
00017 {
00018 HiReconstruction::HiReconstruction( Core* impl, ParallelComm* comm, EntityHandle meshIn, int minpnts, bool recwhole )
00019     : mbImpl( impl ), pcomm( comm ), _mesh2rec( meshIn ), _MINPNTS( minpnts )
00020 {
00021     assert( NULL != impl );
00022     ErrorCode error;
00023     _MINEPS      = 1e-12;
00024     _dim         = 0;
00025     _hasfittings = false;
00026     _hasderiv    = false;
00027 #ifdef MOAB_HAVE_MPI
00028     if( !pcomm )
00029     {
00030         pcomm = moab::ParallelComm::get_pcomm( mbImpl, 0 );
00031     }
00032 #endif
00033 
00034     error = initialize( recwhole );
00035     if( MB_SUCCESS != error )
00036     {
00037         std::cout << "Error initializing HiReconstruction\n" << std::endl;
00038         exit( 1 );
00039     }
00040 }
00041 
00042 HiReconstruction::~HiReconstruction()
00043 {
00044 #ifdef MOAB_HAVE_AHF
00045     ahf = NULL;
00046 #else
00047     delete ahf;
00048 #endif
00049 }
00050 
00051 ErrorCode HiReconstruction::initialize( bool recwhole )
00052 {
00053     ErrorCode error;
00054 
00055 #ifdef HIREC_USE_AHF
00056     std::cout << "HIREC_USE_AHF: Initializing" << std::endl;
00057     ahf = new HalfFacetRep( mbImpl, pcomm, _mesh2rec, false );
00058     if( !ahf )
00059     {
00060         return MB_MEMORY_ALLOCATION_FAILED;
00061     }
00062     error = ahf->initialize();MB_CHK_ERR( error );
00063 #else
00064     ahf        = NULL;
00065 #endif
00066 
00067     // error = ahf->get_entity_ranges(_inverts,_inedges,_infaces,_incells); MB_CHK_ERR(error);
00068     error = mbImpl->get_entities_by_dimension( _mesh2rec, 0, _inverts );MB_CHK_ERR( error );
00069     error = mbImpl->get_entities_by_dimension( _mesh2rec, 1, _inedges );MB_CHK_ERR( error );
00070     error = mbImpl->get_entities_by_dimension( _mesh2rec, 2, _infaces );MB_CHK_ERR( error );
00071     error = mbImpl->get_entities_by_dimension( _mesh2rec, 3, _incells );MB_CHK_ERR( error );
00072     if( _inedges.size() && _infaces.empty() && _incells.empty() )
00073     {
00074         _dim     = 1;
00075         _MAXPNTS = 13;
00076     }
00077     else if( _infaces.size() && _incells.empty() )
00078     {
00079         _dim     = 2;
00080         _MAXPNTS = 128;
00081     }
00082     else
00083     {
00084         MB_SET_ERR( MB_FAILURE, "Encountered a non-manifold mesh or a mesh with volume elements" );
00085     }
00086 
00087     // get locally hosted vertices by filtering pstatus
00088 #ifdef MOAB_HAVE_MPI
00089     if( pcomm )
00090     {
00091         error = pcomm->filter_pstatus( _inverts, PSTATUS_GHOST, PSTATUS_NOT, -1, &_verts2rec );MB_CHK_ERR( error );
00092     }
00093     else
00094     {
00095         _verts2rec = _inverts;
00096     }
00097 #else
00098     _verts2rec = _inverts;
00099 #endif
00100     _nv2rec = _verts2rec.size();
00101 
00102     if( recwhole )
00103     {
00104         // compute normals(surface) or tangent vector(curve) for all locally hosted vertices
00105         if( 2 == _dim )
00106         {
00107             compute_average_vertex_normals_surf();
00108         }
00109         else if( 1 == _dim )
00110         {
00111             compute_average_vertex_tangents_curve();
00112         }
00113         else
00114         {
00115             MB_SET_ERR( MB_FAILURE, "Unknow space dimension" );
00116         }
00117         _hasderiv = true;
00118     }
00119     return error;
00120 }
00121 
00122 /***************************************************
00123  *  User Interface for Reconstruction of Geometry  *
00124  ***************************************************/
00125 
00126 ErrorCode HiReconstruction::reconstruct3D_surf_geom( int degree, bool interp, bool safeguard, bool reset )
00127 {
00128     assert( 2 == _dim );
00129     if( _hasfittings && !reset )
00130     {
00131         // This object has precomputed fitting results and user don't want to reset
00132         return MB_SUCCESS;
00133     }
00134     else
00135     {
00136         _initfittings = _hasfittings = false;
00137     }
00138     // initialize for geometric information
00139     initialize_surf_geom( degree );
00140     ErrorCode error;
00141     double *coeffs, *coords;
00142     int* degree_out;
00143     int ncoeffs = ( degree + 2 ) * ( degree + 1 ) / 2;
00144 
00145     // DBG
00146     int dcount = 0;
00147 
00148     for( Range::iterator ivert = _verts2rec.begin(); ivert != _verts2rec.end(); ++ivert )
00149     {
00150         int index = _verts2rec.index( *ivert );
00151         // for debug
00152         /*if(index==70){
00153             EntityHandle vid = *ivert;
00154             double vertcoords[3];
00155             error = mbImpl->get_coords(&vid,1,vertcoords);
00156         }*/
00157 
00158         size_t istr     = _vertID2coeffID[index];
00159         coords          = &( _local_coords[9 * index] );
00160         coeffs          = &( _local_fit_coeffs[istr] );
00161         degree_out      = &( _degrees_out[index] );
00162         _interps[index] = interp;
00163         error = polyfit3d_walf_surf_vertex( *ivert, interp, degree, _MINPNTS, safeguard, 9, coords, degree_out, ncoeffs,
00164                                             coeffs );MB_CHK_ERR( error );
00165 
00166         // DBG
00167         if( degree_out[0] < degree ) dcount += 1;
00168     }
00169 
00170     // DBG
00171     // std::cout<<"Total #points ="<<_verts2rec.size()<<", #degraded points = "<<dcount<<std::endl;
00172 
00173     _geom        = HISURFACE;
00174     _hasfittings = true;
00175     return error;
00176 }
00177 
00178 ErrorCode HiReconstruction::reconstruct3D_surf_geom( size_t npts,
00179                                                      int* degrees,
00180                                                      bool* interps,
00181                                                      bool safeguard,
00182                                                      bool reset )
00183 {
00184     assert( _dim == 2 );
00185     if( npts != _nv2rec )
00186     {
00187         MB_SET_ERR( MB_FAILURE, "Input number of degrees doesn't match number of vertices" );
00188     }
00189     if( _hasfittings && !reset )
00190     {
00191         return MB_SUCCESS;
00192     }
00193     else
00194     {
00195         _initfittings = _hasfittings = false;
00196     }
00197     ErrorCode error;
00198     // initialization for fitting
00199     initialize_surf_geom( npts, degrees );
00200     double *coeffs, *coords;
00201     int* degree_out;
00202     size_t i = 0;
00203     for( Range::iterator ivert = _verts2rec.begin(); ivert != _verts2rec.end(); ++ivert, ++i )
00204     {
00205         int index = _verts2rec.index( *ivert );
00206         assert( -1 != index );
00207         size_t istr     = _vertID2coeffID[index];
00208         coords          = &( _local_coords[9 * index] );
00209         coeffs          = &( _local_fit_coeffs[istr] );
00210         degree_out      = &( _degrees_out[index] );
00211         _interps[index] = interps[i];
00212         int ncoeffs     = ( degrees[i] + 2 ) * ( degrees[i] + 1 ) / 2;
00213         error = polyfit3d_walf_surf_vertex( *ivert, interps[i], degrees[i], _MINPNTS, safeguard, 9, coords, degree_out,
00214                                             ncoeffs, coeffs );MB_CHK_ERR( error );
00215     }
00216     _geom        = HISURFACE;
00217     _hasfittings = true;
00218     return error;
00219 }
00220 
00221 ErrorCode HiReconstruction::reconstruct3D_curve_geom( int degree, bool interp, bool safeguard, bool reset )
00222 {
00223     assert( _dim == 1 );
00224     if( _hasfittings && !reset )
00225     {
00226         return MB_SUCCESS;
00227     }
00228     else
00229     {
00230         _initfittings = _hasfittings = false;
00231     }
00232     initialize_3Dcurve_geom( degree );
00233     ErrorCode error;
00234     double *coords = 0, *coeffs;
00235     int* degree_out;
00236     int ncoeffs = 3 * ( degree + 1 );
00237     for( Range::iterator ivert = _verts2rec.begin(); ivert != _verts2rec.end(); ++ivert )
00238     {
00239         int index = _verts2rec.index( *ivert );
00240         assert( index != -1 );
00241         size_t istr     = _vertID2coeffID[index];
00242         coeffs          = &( _local_fit_coeffs[istr] );
00243         degree_out      = &( _degrees_out[index] );
00244         _interps[index] = interp;
00245         error = polyfit3d_walf_curve_vertex( *ivert, interp, degree, _MINPNTS, safeguard, 0, coords, degree_out,
00246                                              ncoeffs, coeffs );MB_CHK_ERR( error );
00247     }
00248     _geom        = HI3DCURVE;
00249     _hasfittings = true;
00250     return error;
00251 }
00252 
00253 ErrorCode HiReconstruction::reconstruct3D_curve_geom( size_t npts,
00254                                                       int* degrees,
00255                                                       bool* interps,
00256                                                       bool safeguard,
00257                                                       bool reset )
00258 {
00259     assert( _dim == 1 );
00260     ErrorCode error;
00261     if( npts != _nv2rec )
00262     {
00263         MB_SET_ERR( MB_FAILURE, "Input number of degrees doesn't match the number of vertices" );
00264     }
00265     if( _hasfittings && !reset )
00266     {
00267         return MB_SUCCESS;
00268     }
00269     else
00270     {
00271         _initfittings = _hasfittings = false;
00272     }
00273     // initialize
00274     initialize_3Dcurve_geom( npts, degrees );
00275     double *coords = 0, *coeffs;
00276     int* degree_out;
00277     size_t i = 0;
00278     for( Range::iterator ivert = _verts2rec.begin(); ivert != _verts2rec.end(); ++ivert, ++i )
00279     {
00280         int index       = _verts2rec.index( *ivert );
00281         size_t istr     = _vertID2coeffID[index];
00282         coeffs          = &( _local_fit_coeffs[istr] );
00283         degree_out      = &( _degrees_out[index] );
00284         _interps[index] = interps[i];
00285         int ncoeffs     = 3 * ( degrees[i] + 1 );
00286         error = polyfit3d_walf_curve_vertex( *ivert, interps[i], degrees[i], _MINPNTS, safeguard, 0, coords, degree_out,
00287                                              ncoeffs, coeffs );MB_CHK_ERR( error );
00288     }
00289     _geom        = HI3DCURVE;
00290     _hasfittings = true;
00291     return error;
00292 }
00293 
00294 ErrorCode HiReconstruction::polyfit3d_walf_surf_vertex( const EntityHandle vid,
00295                                                         const bool interp,
00296                                                         int degree,
00297                                                         int minpnts,
00298                                                         const bool safeguard,
00299                                                         const int ncoords,
00300                                                         double* coords,
00301                                                         int* degree_out,
00302                                                         const int ncoeffs,
00303                                                         double* coeffs )
00304 {
00305     assert( _dim == 2 );
00306     ErrorCode error;
00307     int ring = estimate_num_rings( degree, interp );
00308     // std::cout<<"ring = "<<ring<<std::endl;
00309     // get n-ring neighbors
00310     Range ngbvs;
00311     error = obtain_nring_ngbvs( vid, ring, minpnts, ngbvs );MB_CHK_ERR( error );
00312     // for debug
00313     /*if(_verts2rec.index(vid)==70){
00314         for(Range::iterator ingb=ngbvs.begin();ingb!=ngbvs.end();++ingb) std::cerr <<
00315     _verts2rec.index(*ingb) << " "; std::cout << std::endl;
00316     }*/
00317 
00318     // get coordinates;
00319     size_t nverts = ngbvs.size();
00320     assert( nverts );
00321     double* ngbcoords = new double[nverts * 3];
00322     error             = mbImpl->get_coords( ngbvs, ngbcoords );MB_CHK_ERR( error );
00323     // get normals
00324     double* ngbnrms = new double[nverts * 3];
00325     error           = get_normals_surf( ngbvs, ngbnrms );MB_CHK_ERR( error );
00326     // switch vid to first one
00327     int index = ngbvs.index( vid );
00328     assert( index != -1 );
00329     std::swap( ngbcoords[0], ngbcoords[3 * index] );
00330     std::swap( ngbcoords[1], ngbcoords[3 * index + 1] );
00331     std::swap( ngbcoords[2], ngbcoords[3 * index + 2] );
00332     std::swap( ngbnrms[0], ngbnrms[3 * index] );
00333     std::swap( ngbnrms[1], ngbnrms[3 * index + 1] );
00334     std::swap( ngbnrms[2], ngbnrms[3 * index + 2] );
00335     // local WLS fitting
00336     int degree_pnt, degree_qr;
00337     polyfit3d_surf_get_coeff( nverts, ngbcoords, ngbnrms, degree, interp, safeguard, ncoords, coords, ncoeffs, coeffs,
00338                               degree_out, &degree_pnt, &degree_qr );
00339     delete[] ngbcoords;
00340     delete[] ngbnrms;
00341     return error;
00342 }
00343 
00344 ErrorCode HiReconstruction::polyfit3d_walf_curve_vertex( const EntityHandle vid,
00345                                                          const bool interp,
00346                                                          int degree,
00347                                                          int minpnts,
00348                                                          const bool safeguard,
00349                                                          const int ncoords,
00350                                                          double* coords,
00351                                                          int* degree_out,
00352                                                          const int ncoeffs,
00353                                                          double* coeffs )
00354 {
00355     ErrorCode error;
00356     int ring = estimate_num_rings( degree, interp );
00357     // get n-ring neighbors
00358     Range ngbvs;
00359     error = obtain_nring_ngbvs( vid, ring, minpnts, ngbvs );MB_CHK_ERR( error );
00360     // get coordinates
00361     size_t nverts = ngbvs.size();
00362     assert( nverts );
00363     double* ngbcoords = new double[nverts * 3];
00364     error             = mbImpl->get_coords( ngbvs, ngbcoords );MB_CHK_ERR( error );
00365     // get tangent vectors
00366     double* ngbtangs = new double[nverts * 3];
00367     error            = get_tangents_curve( ngbvs, ngbtangs );MB_CHK_ERR( error );
00368     // switch vid to first one
00369     int index = ngbvs.index( vid );
00370     assert( index != -1 );
00371     std::swap( ngbcoords[0], ngbcoords[3 * index] );
00372     std::swap( ngbcoords[1], ngbcoords[3 * index + 1] );
00373     std::swap( ngbcoords[2], ngbcoords[3 * index + 2] );
00374     std::swap( ngbtangs[0], ngbtangs[3 * index] );
00375     std::swap( ngbtangs[1], ngbtangs[3 * index + 1] );
00376     std::swap( ngbtangs[2], ngbtangs[3 * index + 2] );
00377     // local WLS fittings
00378     polyfit3d_curve_get_coeff( nverts, ngbcoords, ngbtangs, degree, interp, safeguard, ncoords, coords, ncoeffs, coeffs,
00379                                degree_out );
00380     delete[] ngbcoords;
00381     delete[] ngbtangs;
00382     return error;
00383 }
00384 
00385 /**************************************************************
00386  *  User Interface for Evaluation via Reconstructed Geometry  *
00387  **************************************************************/
00388 
00389 ErrorCode HiReconstruction::hiproj_walf_in_element( EntityHandle elem,
00390                                                     const int nvpe,
00391                                                     const int npts2fit,
00392                                                     const double* naturalcoords2fit,
00393                                                     double* newcoords )
00394 {
00395     assert( newcoords );
00396     ErrorCode error;
00397     // get connectivity table
00398     std::vector< EntityHandle > elemconn;
00399     error = mbImpl->get_connectivity( &elem, 1, elemconn );MB_CHK_ERR( error );
00400     if( nvpe != (int)elemconn.size() )
00401     {
00402         MB_SET_ERR( MB_FAILURE, "element connectivity table size doesn't match input size" );
00403     }
00404 
00405     if( !_hasfittings )
00406     {
00407         MB_SET_ERR( MB_FAILURE, "There is no existing fitting results" );
00408     }
00409     else
00410     {
00411         std::ostringstream convert;
00412         convert << elem;
00413         std::string ID = convert.str();
00414         for( int i = 0; i < nvpe; ++i )
00415         {
00416             if( -1 == _verts2rec.index( elemconn[i] ) )
00417             {
00418                 MB_SET_ERR( MB_FAILURE, "There is no existing fitting results for element " + ID );
00419             }
00420         }
00421     }
00422     // check correctness of input
00423     for( int i = 0; i < npts2fit; ++i )
00424     {
00425         if( !check_barycentric_coords( nvpe, naturalcoords2fit + i * nvpe ) )
00426         {
00427             MB_SET_ERR( MB_FAILURE, "Wrong barycentric coordinates" );
00428         }
00429     }
00430 
00431     double* elemcoords = new double[nvpe * 3];
00432     error              = mbImpl->get_coords( &( elemconn[0] ), nvpe, elemcoords );MB_CHK_ERR( error );
00433 
00434     double* coords2fit = new double[3 * npts2fit]();
00435     for( int i = 0; i < npts2fit; ++i )
00436     {
00437         for( int j = 0; j < nvpe; ++j )
00438         {
00439             coords2fit[3 * i] += naturalcoords2fit[i * nvpe + j] * elemcoords[3 * j];
00440             coords2fit[3 * i + 1] += naturalcoords2fit[i * nvpe + j] * elemcoords[3 * j + 1];
00441             coords2fit[3 * i + 2] += naturalcoords2fit[i * nvpe + j] * elemcoords[3 * j + 2];
00442         }
00443     }
00444 
00445     double* hiproj_new = new double[3 * npts2fit];
00446     // initialize output
00447     for( int i = 0; i < npts2fit; ++i )
00448     {
00449         newcoords[3 * i] = newcoords[3 * i + 1] = newcoords[3 * i + 2] = 0;
00450     }
00451     // for each input vertex, call nvpe fittings and take average
00452     for( int j = 0; j < nvpe; ++j )
00453     {
00454         error = hiproj_walf_around_vertex( elemconn[j], npts2fit, coords2fit, hiproj_new );MB_CHK_ERR( error );
00455         for( int i = 0; i < npts2fit; ++i )
00456         {
00457             newcoords[3 * i] += naturalcoords2fit[i * nvpe + j] * hiproj_new[3 * i];
00458             newcoords[3 * i + 1] += naturalcoords2fit[i * nvpe + j] * hiproj_new[3 * i + 1];
00459             newcoords[3 * i + 2] += naturalcoords2fit[i * nvpe + j] * hiproj_new[3 * i + 2];
00460         }
00461     }
00462     delete[] elemcoords;
00463     delete[] coords2fit;
00464     delete[] hiproj_new;
00465     return error;
00466 }
00467 
00468 ErrorCode HiReconstruction::hiproj_walf_around_vertex( EntityHandle vid,
00469                                                        const int npts2fit,
00470                                                        const double* coords2fit,
00471                                                        double* hiproj_new )
00472 {
00473     if( !_hasfittings )
00474     {
00475         MB_SET_ERR( MB_FAILURE, "There is no existing fitting results" );
00476     }
00477     else if( -1 == _verts2rec.index( vid ) )
00478     {
00479         std::ostringstream convert;
00480         convert << vid;
00481         std::string VID = convert.str();
00482         MB_SET_ERR( MB_FAILURE, "There is no existing fitting results for vertex " + VID );
00483     }
00484     ErrorCode error;
00485     // get center of local coordinates system
00486     double local_origin[3];
00487     error = mbImpl->get_coords( &vid, 1, local_origin );MB_CHK_ERR( error );
00488     // get local fitting parameters
00489     int index     = _verts2rec.index( vid );
00490     bool interp   = _interps[index];
00491     int local_deg = _degrees_out[index];
00492     double *uvw_coords, *local_coeffs;
00493     if( _geom == HISURFACE )
00494     {
00495         uvw_coords = &( _local_coords[9 * index] );
00496         // int ncoeffs = (local_deg+2)*(local_deg+1)>>1;
00497         size_t istr  = _vertID2coeffID[index];
00498         local_coeffs = &( _local_fit_coeffs[istr] );
00499         walf3d_surf_vertex_eval( local_origin, uvw_coords, local_deg, local_coeffs, interp, npts2fit, coords2fit,
00500                                  hiproj_new );
00501     }
00502     else if( _geom == HI3DCURVE )
00503     {
00504         uvw_coords   = &( _local_coords[3 * index] );
00505         size_t istr  = _vertID2coeffID[index];
00506         local_coeffs = &( _local_fit_coeffs[istr] );
00507         walf3d_curve_vertex_eval( local_origin, uvw_coords, local_deg, local_coeffs, interp, npts2fit, coords2fit,
00508                                   hiproj_new );
00509     }
00510     return error;
00511 }
00512 
00513 void HiReconstruction::walf3d_surf_vertex_eval( const double* local_origin,
00514                                                 const double* local_coords,
00515                                                 const int local_deg,
00516                                                 const double* local_coeffs,
00517                                                 const bool interp,
00518                                                 const int npts2fit,
00519                                                 const double* coords2fit,
00520                                                 double* hiproj_new )
00521 {
00522     double xaxis[3], yaxis[3], zaxis[3];
00523     for( int i = 0; i < 3; ++i )
00524     {
00525         xaxis[i] = local_coords[i];
00526         yaxis[i] = local_coords[3 + i];
00527         zaxis[i] = local_coords[6 + i];
00528     }
00529     // double *basis = new double[(local_deg+2)*(local_deg+1)/2-1];
00530     std::vector< double > basis( ( local_deg + 2 ) * ( local_deg + 1 ) / 2 - 1 );
00531     for( int i = 0; i < npts2fit; ++i )
00532     {
00533         double local_pos[3];
00534         for( int j = 0; j < 3; ++j )
00535         {
00536             local_pos[j] = coords2fit[3 * i + j] - local_origin[j];
00537         }
00538         double u, v, height = 0;
00539         u        = DGMSolver::vec_innerprod( 3, local_pos, xaxis );
00540         v        = DGMSolver::vec_innerprod( 3, local_pos, yaxis );
00541         basis[0] = u;
00542         basis[1] = v;
00543         int l    = 1;
00544         for( int k = 2; k <= local_deg; ++k )
00545         {
00546             ++l;
00547             basis[l] = u * basis[l - k];
00548             for( int id = 0; id < k; ++id )
00549             {
00550                 ++l;
00551                 basis[l] = basis[l - k - 1] * v;
00552             }
00553         }
00554         if( !interp )
00555         {
00556             height = local_coeffs[0];
00557         }
00558         for( int p = 0; p <= l; ++p )
00559         {
00560             height += local_coeffs[p + 1] * basis[p];
00561         }
00562         hiproj_new[3 * i]     = local_origin[0] + u * xaxis[0] + v * yaxis[0] + height * zaxis[0];
00563         hiproj_new[3 * i + 1] = local_origin[1] + u * xaxis[1] + v * yaxis[1] + height * zaxis[1];
00564         hiproj_new[3 * i + 2] = local_origin[2] + u * xaxis[2] + v * yaxis[2] + height * zaxis[2];
00565     }
00566     // delete [] basis;
00567 }
00568 
00569 void HiReconstruction::walf3d_curve_vertex_eval( const double* local_origin,
00570                                                  const double* local_coords,
00571                                                  const int local_deg,
00572                                                  const double* local_coeffs,
00573                                                  const bool interp,
00574                                                  const int npts2fit,
00575                                                  const double* coords2fit,
00576                                                  double* hiproj_new )
00577 {
00578     assert( local_origin && local_coords && local_coeffs );
00579     int ncoeffspvpd = local_deg + 1;
00580     for( int i = 0; i < npts2fit; ++i )
00581     {
00582         // get the vector from center to current point, project to tangent line
00583         double vec[3], ans[3] = { 0, 0, 0 };
00584         DGMSolver::vec_linear_operation( 3, 1, coords2fit + 3 * i, -1, local_origin, vec );
00585         double u = DGMSolver::vec_innerprod( 3, local_coords, vec );
00586         // evaluate polynomials
00587         if( !interp )
00588         {
00589             ans[0] = local_coeffs[0];
00590             ans[1] = local_coeffs[ncoeffspvpd];
00591             ans[2] = local_coeffs[2 * ncoeffspvpd];
00592         }
00593         double uk = 1;  // degree_out and degree different, stored in columnwise contiguously
00594         for( int j = 1; j < ncoeffspvpd; ++j )
00595         {
00596             uk *= u;
00597             ans[0] += uk * local_coeffs[j];
00598             ans[1] += uk * local_coeffs[j + ncoeffspvpd];
00599             ans[2] += uk * local_coeffs[j + 2 * ncoeffspvpd];
00600         }
00601         hiproj_new[3 * i]     = ans[0] + local_origin[0];
00602         hiproj_new[3 * i + 1] = ans[1] + local_origin[1];
00603         hiproj_new[3 * i + 2] = ans[2] + local_origin[2];
00604     }
00605 }
00606 
00607 bool HiReconstruction::get_fittings_data( EntityHandle vid,
00608                                           GEOMTYPE& geomtype,
00609                                           std::vector< double >& coords,
00610                                           int& degree_out,
00611                                           std::vector< double >& coeffs,
00612                                           bool& interp )
00613 {
00614     if( !_hasfittings )
00615     {
00616         return false;
00617     }
00618     else
00619     {
00620         int index = _verts2rec.index( vid );
00621         if( -1 == index )
00622         {
00623             std::cout << "Input vertex is not locally hosted vertex in this mesh set" << std::endl;
00624             return false;
00625         }
00626         geomtype = _geom;
00627         if( HISURFACE == _geom )
00628         {
00629             coords.insert( coords.end(), _local_coords.begin() + 9 * index, _local_coords.begin() + 9 * index + 9 );
00630             degree_out  = _degrees_out[index];
00631             interp      = _interps[index];
00632             int ncoeffs = ( degree_out + 2 ) * ( degree_out + 1 ) >> 1;
00633             size_t istr = _vertID2coeffID[index];
00634             coeffs.insert( coeffs.end(), _local_fit_coeffs.begin() + istr, _local_fit_coeffs.begin() + istr + ncoeffs );
00635         }
00636         else if( HI3DCURVE == _geom )
00637         {
00638             coords.insert( coords.end(), _local_coords.begin() + 3 * index, _local_coords.begin() + 3 * index + 3 );
00639             degree_out  = _degrees_out[index];
00640             interp      = _interps[index];
00641             int ncoeffs = 3 * ( degree_out + 1 );
00642             size_t istr = _vertID2coeffID[index];
00643             coeffs.insert( coeffs.end(), _local_fit_coeffs.begin() + istr, _local_fit_coeffs.begin() + istr + ncoeffs );
00644         }
00645         return true;
00646     }
00647 }
00648 
00649 /****************************************************************
00650  *  Basic Internal Routines to initialize and set fitting data  *
00651  ****************************************************************/
00652 
00653 int HiReconstruction::estimate_num_rings( int degree, bool interp )
00654 {
00655     return interp ? ( ( degree + 1 ) >> 1 ) + ( ( degree + 1 ) & 1 ) : ( ( degree + 2 ) >> 1 ) + ( ( degree + 2 ) & 1 );
00656 }
00657 
00658 ErrorCode HiReconstruction::vertex_get_incident_elements( const EntityHandle& vid,
00659                                                           const int elemdim,
00660                                                           std::vector< EntityHandle >& adjents )
00661 {
00662     ErrorCode error;
00663     assert( elemdim == _dim );
00664 #ifdef HIREC_USE_AHF
00665     error = ahf->get_up_adjacencies( vid, elemdim, adjents );MB_CHK_ERR( error );
00666 #else
00667     error      = mbImpl->get_adjacencies( &vid, 1, elemdim, false, adjents );MB_CHK_ERR( error );
00668 #endif
00669     return error;
00670 }
00671 
00672 ErrorCode HiReconstruction::obtain_nring_ngbvs( const EntityHandle vid, int ring, const int minpnts, Range& ngbvs )
00673 {
00674     ErrorCode error;
00675     std::deque< EntityHandle > todo;
00676     todo.push_back( vid );
00677     ngbvs.insert( vid );
00678     EntityHandle pre, nxt;
00679     for( int i = 1; i <= ring; ++i )
00680     {
00681         int count = todo.size();
00682         while( count )
00683         {
00684             EntityHandle center = todo.front();
00685             todo.pop_front();
00686             --count;
00687             std::vector< EntityHandle > adjents;
00688             error = vertex_get_incident_elements( center, _dim, adjents );MB_CHK_ERR( error );
00689             for( size_t j = 0; j < adjents.size(); ++j )
00690             {
00691                 std::vector< EntityHandle > elemconn;
00692                 error = mbImpl->get_connectivity( &adjents[j], 1, elemconn );MB_CHK_ERR( error );
00693                 int nvpe = elemconn.size();
00694                 for( int k = 0; k < nvpe; ++k )
00695                 {
00696                     if( elemconn[k] == center )
00697                     {
00698                         pre = k == 0 ? elemconn[nvpe - 1] : elemconn[k - 1];
00699                         nxt = elemconn[( k + 1 ) % nvpe];
00700                         if( ngbvs.find( pre ) == ngbvs.end() )
00701                         {
00702                             ngbvs.insert( pre );
00703                             todo.push_back( pre );
00704                         }
00705                         if( ngbvs.find( nxt ) == ngbvs.end() )
00706                         {
00707                             ngbvs.insert( nxt );
00708                             todo.push_back( nxt );
00709                         }
00710                         break;
00711                     }
00712                 }
00713             }
00714         }
00715         if( _MAXPNTS <= (int)ngbvs.size() )
00716         {
00717             // obtain enough points
00718             return error;
00719         }
00720         if( !todo.size() )
00721         {
00722             // current ring cannot introduce any points, return incase deadlock
00723             return error;
00724         }
00725         if( ( i == ring ) && ( minpnts > (int)ngbvs.size() ) )
00726         {
00727             // reach maximum ring but not enough points
00728             ++ring;
00729         }
00730     }
00731     return error;
00732 }
00733 
00734 void HiReconstruction::initialize_surf_geom( const int degree )
00735 {
00736     if( !_hasderiv )
00737     {
00738         compute_average_vertex_normals_surf();
00739         _hasderiv = true;
00740     }
00741     if( !_initfittings )
00742     {
00743         int ncoeffspv = ( degree + 2 ) * ( degree + 1 ) / 2;
00744         _degrees_out.assign( _nv2rec, 0 );
00745         _interps.assign( _nv2rec, false );
00746         _vertID2coeffID.resize( _nv2rec );
00747         _local_fit_coeffs.assign( _nv2rec * ncoeffspv, 0 );
00748         for( size_t i = 0; i < _nv2rec; ++i )
00749         {
00750             _vertID2coeffID[i] = i * ncoeffspv;
00751         }
00752         _initfittings = true;
00753     }
00754 }
00755 
00756 void HiReconstruction::initialize_surf_geom( const size_t npts, const int* degrees )
00757 {
00758     if( !_hasderiv )
00759     {
00760         compute_average_vertex_normals_surf();
00761         _hasderiv = true;
00762     }
00763     if( !_initfittings )
00764     {
00765         assert( _nv2rec == npts );
00766         _degrees_out.assign( _nv2rec, 0 );
00767         _interps.assign( _nv2rec, false );
00768         _vertID2coeffID.resize( _nv2rec );
00769         size_t index = 0;
00770         for( size_t i = 0; i < _nv2rec; ++i )
00771         {
00772             _vertID2coeffID[i] = index;
00773             index += ( degrees[i] + 2 ) * ( degrees[i] + 1 ) / 2;
00774         }
00775         _local_fit_coeffs.assign( index, 0 );
00776         _initfittings = true;
00777     }
00778 }
00779 
00780 void HiReconstruction::initialize_3Dcurve_geom( const int degree )
00781 {
00782     if( !_hasderiv )
00783     {
00784         compute_average_vertex_tangents_curve();
00785         _hasderiv = true;
00786     }
00787     if( !_initfittings )
00788     {
00789         int ncoeffspvpd = degree + 1;
00790         _degrees_out.assign( _nv2rec, 0 );
00791         _interps.assign( _nv2rec, false );
00792         _vertID2coeffID.resize( _nv2rec );
00793         _local_fit_coeffs.assign( _nv2rec * ncoeffspvpd * 3, 0 );
00794         for( size_t i = 0; i < _nv2rec; ++i )
00795         {
00796             _vertID2coeffID[i] = i * ncoeffspvpd * 3;
00797         }
00798         _initfittings = true;
00799     }
00800 }
00801 
00802 void HiReconstruction::initialize_3Dcurve_geom( const size_t npts, const int* degrees )
00803 {
00804     if( !_hasderiv )
00805     {
00806         compute_average_vertex_tangents_curve();
00807         _hasderiv = true;
00808     }
00809     if( !_hasfittings )
00810     {
00811         assert( _nv2rec == npts );
00812         _degrees_out.assign( _nv2rec, 0 );
00813         _interps.assign( _nv2rec, false );
00814         _vertID2coeffID.reserve( _nv2rec );
00815         size_t index = 0;
00816         for( size_t i = 0; i < _nv2rec; ++i )
00817         {
00818             _vertID2coeffID[i] = index;
00819             index += 3 * ( degrees[i] + 1 );
00820         }
00821         _local_fit_coeffs.assign( index, 0 );
00822         _initfittings = true;
00823     }
00824 }
00825 
00826 /* ErrorCode HiReconstruction::set_geom_data_surf(const EntityHandle vid, const double* coords,
00827  const double degree_out, const double* coeffs, bool interp)
00828  {
00829    return MB_SUCCESS;
00830  }
00831 
00832  ErrorCode HiReconstruction::set_geom_data_3Dcurve(const EntityHandle vid, const double* coords,
00833  const double degree_out, const double* coeffs, bool interp)
00834  {
00835    return MB_SUCCESS;
00836  } */
00837 
00838 /*********************************************************
00839  * Routines for vertex normal/tangent vector estimation *
00840  *********************************************************/
00841 ErrorCode HiReconstruction::average_vertex_normal( const EntityHandle vid, double* nrm )
00842 {
00843     ErrorCode error;
00844     std::vector< EntityHandle > adjfaces;
00845     error = vertex_get_incident_elements( vid, 2, adjfaces );MB_CHK_ERR( error );
00846     int npolys = adjfaces.size();
00847     if( !npolys )
00848     {
00849         MB_SET_ERR( MB_FAILURE, "Vertex has no incident 2D entities" );
00850     }
00851     else
00852     {
00853         double v1[3], v2[3], v3[3], a[3], b[3], c[3];
00854         nrm[0] = nrm[1] = nrm[2] = 0;
00855         for( int i = 0; i < npolys; ++i )
00856         {
00857             // get incident "triangles"
00858             std::vector< EntityHandle > elemconn;
00859             error = mbImpl->get_connectivity( &adjfaces[i], 1, elemconn );MB_CHK_ERR( error );
00860             EntityHandle pre, nxt;
00861             int nvpe = elemconn.size();
00862             for( int j = 0; j < nvpe; ++j )
00863             {
00864                 if( vid == elemconn[j] )
00865                 {
00866                     pre = j == 0 ? elemconn[nvpe - 1] : elemconn[j - 1];
00867                     nxt = elemconn[( j + 1 ) % nvpe];
00868                     break;
00869                 }
00870             }
00871             // compute area weighted normals
00872             error = mbImpl->get_coords( &pre, 1, a );MB_CHK_ERR( error );
00873             error = mbImpl->get_coords( &vid, 1, b );MB_CHK_ERR( error );
00874             error = mbImpl->get_coords( &nxt, 1, c );MB_CHK_ERR( error );
00875             DGMSolver::vec_linear_operation( 3, 1, c, -1, b, v1 );
00876             DGMSolver::vec_linear_operation( 3, 1, a, -1, b, v2 );
00877             DGMSolver::vec_crossprod( v1, v2, v3 );
00878             DGMSolver::vec_linear_operation( 3, 1, nrm, 1, v3, nrm );
00879         }
00880 #ifndef NDEBUG
00881         assert( DGMSolver::vec_normalize( 3, nrm, nrm ) );
00882 #endif
00883     }
00884     return error;
00885 }
00886 
00887 ErrorCode HiReconstruction::compute_average_vertex_normals_surf()
00888 {
00889     if( _hasderiv )
00890     {
00891         return MB_SUCCESS;
00892     }
00893     ErrorCode error;
00894     _local_coords.assign( 9 * _nv2rec, 0 );
00895     size_t index = 0;
00896     for( Range::iterator ivert = _verts2rec.begin(); ivert != _verts2rec.end(); ++ivert, ++index )
00897     {
00898         error = average_vertex_normal( *ivert, &( _local_coords[9 * index + 6] ) );MB_CHK_ERR( error );
00899     }
00900     return error;
00901 }
00902 
00903 ErrorCode HiReconstruction::get_normals_surf( const Range& vertsh, double* nrms )
00904 {
00905     ErrorCode error = MB_SUCCESS;
00906     if( _hasderiv )
00907     {
00908         size_t id = 0;
00909         for( Range::iterator ivert = vertsh.begin(); ivert != vertsh.end(); ++ivert, ++id )
00910         {
00911             int index = _verts2rec.index( *ivert );
00912 #ifdef MOAB_HAVE_MPI
00913             if( -1 == index )
00914             {
00915                 // ghost vertex
00916                 error = average_vertex_normal( *ivert, nrms + 3 * id );MB_CHK_ERR( error );
00917             }
00918             else
00919             {
00920                 nrms[3 * id]     = _local_coords[9 * index + 6];
00921                 nrms[3 * id + 1] = _local_coords[9 * index + 7];
00922                 nrms[3 * id + 2] = _local_coords[9 * index + 8];
00923             }
00924 #else
00925             assert( -1 != index );
00926             nrms[3 * id]     = _local_coords[9 * index + 6];
00927             nrms[3 * id + 1] = _local_coords[9 * index + 7];
00928             nrms[3 * id + 2] = _local_coords[9 * index + 8];
00929 #endif
00930         }
00931     }
00932     else
00933     {
00934         size_t id = 0;
00935         for( Range::iterator ivert = vertsh.begin(); ivert != vertsh.end(); ++ivert, ++id )
00936         {
00937             error = average_vertex_normal( *ivert, nrms + 3 * id );MB_CHK_ERR( error );
00938         }
00939     }
00940     return error;
00941 }
00942 
00943 ErrorCode HiReconstruction::average_vertex_tangent( const EntityHandle vid, double* tang )
00944 {
00945     ErrorCode error;
00946     std::vector< EntityHandle > adjedges;
00947     error = vertex_get_incident_elements( vid, 1, adjedges );MB_CHK_ERR( error );
00948     int nedges = adjedges.size();
00949     if( !nedges )
00950     {
00951         MB_SET_ERR( MB_FAILURE, "Vertex has no incident edges" );
00952     }
00953     else
00954     {
00955         assert( nedges <= 2 );
00956         tang[0] = tang[1] = tang[2] = 0;
00957         for( int i = 0; i < nedges; ++i )
00958         {
00959             std::vector< EntityHandle > edgeconn;
00960             error = mbImpl->get_connectivity( &adjedges[i], 1, edgeconn );
00961             double istr[3], iend[3], t[3];
00962             error = mbImpl->get_coords( &( edgeconn[0] ), 1, istr );
00963             error = mbImpl->get_coords( &( edgeconn[1] ), 1, iend );
00964             DGMSolver::vec_linear_operation( 3, 1, iend, -1, istr, t );
00965             DGMSolver::vec_linear_operation( 3, 1, tang, 1, t, tang );
00966         }
00967 #ifndef NDEBUG
00968         assert( DGMSolver::vec_normalize( 3, tang, tang ) );
00969 #endif
00970     }
00971     return error;
00972 }
00973 
00974 ErrorCode HiReconstruction::compute_average_vertex_tangents_curve()
00975 {
00976     if( _hasderiv )
00977     {
00978         return MB_SUCCESS;
00979     }
00980     ErrorCode error;
00981     _local_coords.assign( 3 * _nv2rec, 0 );
00982     size_t index = 0;
00983     for( Range::iterator ivert = _verts2rec.begin(); ivert != _verts2rec.end(); ++ivert, ++index )
00984     {
00985         error = average_vertex_tangent( *ivert, &( _local_coords[3 * index] ) );MB_CHK_ERR( error );
00986     }
00987     return error;
00988 }
00989 
00990 ErrorCode HiReconstruction::get_tangents_curve( const Range& vertsh, double* tangs )
00991 {
00992     ErrorCode error = MB_SUCCESS;
00993     if( _hasderiv )
00994     {
00995         size_t id = 0;
00996         for( Range::iterator ivert = vertsh.begin(); ivert != vertsh.end(); ++ivert, ++id )
00997         {
00998             int index = _verts2rec.index( *ivert );
00999 #ifdef MOAB_HAVE_MPI
01000             if( -1 != index )
01001             {
01002                 tangs[3 * id]     = _local_coords[3 * index];
01003                 tangs[3 * id + 1] = _local_coords[3 * index + 1];
01004                 tangs[3 * id + 2] = _local_coords[3 * index + 2];
01005             }
01006             else
01007             {
01008                 error = average_vertex_tangent( *ivert, tangs + 3 * id );MB_CHK_ERR( error );
01009             }
01010 #else
01011             assert( -1 != index );
01012             tangs[3 * id]     = _local_coords[3 * index];
01013             tangs[3 * id + 1] = _local_coords[3 * index + 1];
01014             tangs[3 * id + 2] = _local_coords[3 * index + 2];
01015 #endif
01016         }
01017     }
01018     else
01019     {
01020         size_t id = 0;
01021         for( Range::iterator ivert = vertsh.begin(); ivert != vertsh.end(); ++ivert, ++id )
01022         {
01023             error = average_vertex_tangent( *ivert, tangs + 3 * id );MB_CHK_ERR( error );
01024         }
01025     }
01026     return error;
01027 }
01028 
01029 /************************************************
01030  *  Internal Routines for local WLS fittings    *
01031  *************************************************/
01032 
01033 void HiReconstruction::polyfit3d_surf_get_coeff( const int nverts,
01034                                                  const double* ngbcoords,
01035                                                  const double* ngbnrms,
01036                                                  int degree,
01037                                                  const bool interp,
01038                                                  const bool safeguard,
01039                                                  const int ncoords,
01040                                                  double* coords,
01041                                                  const int ncoeffs,
01042                                                  double* coeffs,
01043                                                  int* degree_out,
01044                                                  int* degree_pnt,
01045                                                  int* degree_qr )
01046 {
01047     if( nverts <= 0 )
01048     {
01049         return;
01050     }
01051 
01052     // std::cout << "npnts in initial stencil = " << nverts << std::endl;
01053     // std::cout << "centered at (" << ngbcoords[0] << "," << ngbcoords[1] << "," << ngbcoords[2] <<
01054     // ")" << std::endl;
01055 
01056     // step 1. copmute local coordinate system
01057     double nrm[3] = { ngbnrms[0], ngbnrms[1], ngbnrms[2] }, tang1[3] = { 0, 0, 0 }, tang2[3] = { 0, 0, 0 };
01058     if( fabs( nrm[0] ) > fabs( nrm[1] ) && fabs( nrm[0] ) > fabs( nrm[2] ) )
01059     {
01060         tang1[1] = 1.0;
01061     }
01062     else
01063     {
01064         tang1[0] = 1.0;
01065     }
01066 
01067     DGMSolver::vec_projoff( 3, tang1, nrm, tang1 );
01068 #ifndef NDEBUG
01069     assert( DGMSolver::vec_normalize( 3, tang1, tang1 ) );
01070 #endif
01071     DGMSolver::vec_crossprod( nrm, tang1, tang2 );
01072     if( 9 <= ncoords && coords )
01073     {
01074         coords[0] = tang1[0];
01075         coords[1] = tang1[1];
01076         coords[2] = tang1[2];
01077         coords[3] = tang2[0];
01078         coords[4] = tang2[1];
01079         coords[5] = tang2[2];
01080         coords[6] = nrm[0];
01081         coords[7] = nrm[1];
01082         coords[8] = nrm[2];
01083     }
01084     if( !ncoeffs || !coeffs )
01085     {
01086         return;
01087     }
01088     else
01089     {
01090         assert( ncoeffs >= ( degree + 2 ) * ( degree + 1 ) / 2 );
01091     }
01092 
01093     // step 2. project onto local coordinates system
01094     int npts2fit = nverts - interp;
01095     if( 0 == npts2fit )
01096     {
01097         *degree_out = *degree_pnt = *degree_qr = 0;
01098         for( int i = 0; i < ncoeffs; ++i )
01099         {
01100             coeffs[i] = 0;
01101         }
01102         // coeffs[0] = 0;
01103         return;
01104     }
01105     std::vector< double > us( npts2fit * 2 );  // double *us = new double[npts2fit*2];
01106     std::vector< double > bs( npts2fit );      // double *bs = new double[npts2fit];
01107     for( int i = interp; i < nverts; ++i )
01108     {
01109         int k = i - interp;
01110         double uu[3];
01111         DGMSolver::vec_linear_operation( 3, 1, ngbcoords + 3 * i, -1, ngbcoords, uu );
01112         us[k * 2]     = DGMSolver::vec_innerprod( 3, tang1, uu );
01113         us[k * 2 + 1] = DGMSolver::vec_innerprod( 3, tang2, uu );
01114         bs[k]         = DGMSolver::vec_innerprod( 3, nrm, uu );
01115     }
01116 
01117     // step 3. compute weights
01118     std::vector< double > ws( npts2fit );  // double *ws = new double[npts2fit];
01119     int nzeros = compute_weights( npts2fit, 2, &( us[0] ), nverts, ngbnrms, degree, _MINEPS, &( ws[0] ) );
01120 
01121     // step 4. adjust according to zero-weights
01122     if( nzeros )
01123     {
01124         if( nzeros == npts2fit )
01125         {
01126             *degree_out = *degree_pnt = *degree_qr = 0;
01127             for( int i = 0; i < ncoeffs; ++i )
01128             {
01129                 coeffs[i] = 0;
01130             }
01131             // coeffs[0] = 0;
01132             return;
01133         }
01134         int index = 0;
01135         for( int i = 0; i < npts2fit; ++i )
01136         {
01137             if( ws[i] )
01138             {
01139                 if( i > index )
01140                 {
01141                     us[index * 2]     = us[i * 2];
01142                     us[index * 2 + 1] = us[i * 2 + 1];
01143                     bs[index]         = bs[i];
01144                     ws[index]         = ws[i];
01145                 }
01146                 ++index;
01147             }
01148         }
01149         npts2fit -= nzeros;
01150         assert( index == npts2fit );
01151         us.resize( npts2fit * 2 );
01152         bs.resize( npts2fit );
01153         ws.resize( npts2fit );
01154         /*us = realloc(us,npts2fit*2*sizeof(double));
01155         bs = realloc(bs,npts2fit*sizeof(double));
01156         ws = realloc(ws,npts2fit*sizeof(double));*/
01157     }
01158 
01159     // std::cout<<"npnts after weighting = "<<npts2fit<<std::endl;
01160 
01161     // step 5. fitting
01162     eval_vander_bivar_cmf( npts2fit, &( us[0] ), 1, &( bs[0] ), degree, &( ws[0] ), interp, safeguard, degree_out,
01163                            degree_pnt, degree_qr );
01164 
01165     // step 6. organize output
01166     int ncoeffs_out = ( *degree_out + 2 ) * ( *degree_out + 1 ) / 2;
01167     assert( ncoeffs_out <= ncoeffs );
01168     coeffs[0] = 0;
01169     for( int j = 0; j < ncoeffs_out - interp; ++j )
01170     {
01171         coeffs[j + interp] = bs[j];
01172     }
01173     // delete [] us; delete [] bs; delete [] ws;
01174 }
01175 
01176 void HiReconstruction::eval_vander_bivar_cmf( const int npts2fit,
01177                                               const double* us,
01178                                               const int ndim,
01179                                               double* bs,
01180                                               int degree,
01181                                               const double* ws,
01182                                               const bool interp,
01183                                               const bool safeguard,
01184                                               int* degree_out,
01185                                               int* degree_pnt,
01186                                               int* degree_qr )
01187 {
01188     // step 1. adjust the degree according to number of points to fit
01189     int ncols = ( ( ( degree + 2 ) * ( degree + 1 ) ) >> 1 ) - interp;
01190     while( 1 < degree && npts2fit < ncols )
01191     {
01192         --degree;
01193         ncols = ( ( ( degree + 2 ) * ( degree + 1 ) ) >> 1 ) - interp;
01194     }
01195     *degree_pnt = degree;
01196 
01197     // std::cout << "degree_pnt: " << *degree_pnt << std::endl;
01198 
01199     // step 2. construct Vandermonde matrix, stored in columnwise
01200     std::vector< double > V;  // V(npts2fit*(ncols+interp)); //double *V_init = new double[npts2fit*(ncols+interp)];
01201     DGMSolver::gen_vander_multivar( npts2fit, 2, us, degree, V );
01202     // remove the first column of 1s if interpolation
01203     if( interp )
01204     {
01205         V.erase( V.begin(), V.begin() + npts2fit );
01206     }
01207     /*double* V;
01208     if(interp){
01209         V = new double[npts2fit*ncols];
01210         std::memcpy(V,V_init+npts2fit,ncols*npts2fit*sizeof(double));
01211         delete [] V_init; V_init = 0;
01212     }else{
01213         V = V_init;
01214     }*/
01215 
01216     // step 3. Scale rows to assign different weights to different points
01217     for( int i = 0; i < npts2fit; ++i )
01218     {
01219         for( int j = 0; j < ncols; ++j )
01220         {
01221             V[j * npts2fit + i] *= ws[i];
01222         }
01223         for( int k = 0; k < ndim; ++k )
01224         {
01225             bs[k * npts2fit + i] *= ws[i];
01226         }
01227     }
01228 
01229     // step 4. scale columns to reduce condition number
01230     std::vector< double > ts( ncols );  // double *ts = new double[ncols];
01231     DGMSolver::rescale_matrix( npts2fit, ncols, &( V[0] ), &( ts[0] ) );
01232 
01233     // step 5. Perform Householder QR factorization
01234     std::vector< double > D( ncols );  // double *D = new double[ncols];
01235     int rank;
01236     DGMSolver::qr_polyfit_safeguarded( npts2fit, ncols, &( V[0] ), &( D[0] ), &rank );
01237 
01238     // step 6. adjust degree of fitting according to rank of Vandermonde matrix
01239     int ncols_sub = ncols;
01240     while( rank < ncols_sub )
01241     {
01242         --degree;
01243         if( degree == 0 )
01244         {
01245             // surface is flat, return 0
01246             *degree_out = *degree_qr = degree;
01247             for( int i = 0; i < npts2fit; ++i )
01248             {
01249                 for( int k = 0; k < ndim; ++k )
01250                 {
01251                     bs[k * npts2fit + i] = 0;
01252                 }
01253             }
01254             return;
01255         }
01256         else
01257         {
01258             ncols_sub = ( ( ( degree + 2 ) * ( degree + 1 ) ) >> 1 ) - interp;
01259         }
01260     }
01261     *degree_qr = degree;
01262 
01263     // std::cout << "degree_qr: " << *degree_qr << std::endl;
01264 
01265     /* DBG
01266      * std::cout<<"before Qtb"<<std::endl;
01267     std::cout<<std::endl;
01268     std::cout<<"bs = "<<std::endl;
01269     std::cout<<std::endl;
01270     for (int k=0; k< ndim; k++){
01271         for (int j=0; j<npts2fit; ++j){
01272         std::cout<<"  "<<bs[npts2fit*k+j]<<std::endl;
01273           }
01274       }
01275     std::cout<<std::endl;*/
01276 
01277     // step 7. compute Q'b
01278     DGMSolver::compute_qtransposeB( npts2fit, ncols_sub, &( V[0] ), ndim, bs );
01279 
01280     /* DBG
01281      * std::cout<<"after Qtb"<<std::endl;
01282     std::cout<<"bs = "<<std::endl;
01283     std::cout<<std::endl;
01284     for (int k=0; k< ndim; k++){
01285         for (int j=0; j<npts2fit; ++j){
01286         std::cout<<"  "<<bs[npts2fit*k+j]<<std::endl;
01287           }
01288       }
01289     std::cout<<std::endl;*/
01290 
01291     // step 8. perform backward substitution and scale the solution
01292     // assign diagonals of V
01293     for( int i = 0; i < ncols_sub; ++i )
01294     {
01295         V[i * npts2fit + i] = D[i];
01296     }
01297 
01298     // backsolve
01299     if( safeguard )
01300     {
01301         // for debug
01302         // std::cout << "ts size " << ts.size() << std::endl;
01303         DGMSolver::backsolve_polyfit_safeguarded( 2, degree, interp, npts2fit, ncols_sub, &( V[0] ), ndim, bs,
01304                                                   &( ts[0] ), degree_out );
01305     }
01306     else
01307     {
01308         DGMSolver::backsolve( npts2fit, ncols_sub, &( V[0] ), 1, bs, &( ts[0] ) );
01309         *degree_out = degree;
01310     }
01311     /*if(V_init){
01312         delete [] V_init;
01313     }else{
01314         delete [] V;
01315     }*/
01316 }
01317 
01318 void HiReconstruction::polyfit3d_curve_get_coeff( const int nverts,
01319                                                   const double* ngbcors,
01320                                                   const double* ngbtangs,
01321                                                   int degree,
01322                                                   const bool interp,
01323                                                   const bool safeguard,
01324                                                   const int ncoords,
01325                                                   double* coords,
01326                                                   const int ncoeffs,
01327                                                   double* coeffs,
01328                                                   int* degree_out )
01329 {
01330     if( !nverts )
01331     {
01332         return;
01333     }
01334     // step 1. compute local coordinates system
01335     double tang[3] = { ngbtangs[0], ngbtangs[1], ngbtangs[2] };
01336     if( coords && ncoords > 2 )
01337     {
01338         coords[0] = tang[0];
01339         coords[1] = tang[1];
01340         coords[2] = tang[2];
01341     }
01342     if( !coeffs || !ncoeffs )
01343     {
01344         return;
01345     }
01346     else
01347     {
01348         assert( ncoeffs >= 3 * ( degree + 1 ) );
01349     }
01350     // step 2. project onto local coordinate system
01351     int npts2fit = nverts - interp;
01352     if( !npts2fit )
01353     {
01354         *degree_out = 0;
01355         for( int i = 0; i < ncoeffs; ++i )
01356         {
01357             coeffs[0] = 0;
01358         }
01359         return;
01360     }
01361     std::vector< double > us( npts2fit );      // double *us = new double[npts2fit];
01362     std::vector< double > bs( npts2fit * 3 );  // double *bs = new double[npts2fit*3];
01363     double uu[3];
01364     for( int i = interp; i < nverts; ++i )
01365     {
01366         int k = i - interp;
01367         DGMSolver::vec_linear_operation( 3, 1, ngbcors + 3 * i, -1, ngbcors, uu );
01368         us[k]                = DGMSolver::vec_innerprod( 3, uu, tang );
01369         bs[k]                = uu[0];
01370         bs[npts2fit + k]     = uu[1];
01371         bs[2 * npts2fit + k] = uu[2];
01372     }
01373 
01374     // step 3. copmute weights
01375     std::vector< double > ws( npts2fit );
01376     int nzeros = compute_weights( npts2fit, 1, &( us[0] ), nverts, ngbtangs, degree, _MINEPS, &( ws[0] ) );
01377     assert( nzeros <= npts2fit );
01378 
01379     // step 4. adjust according to number of zero-weights
01380     if( nzeros )
01381     {
01382         if( nzeros == npts2fit )
01383         {
01384             // singular case
01385             *degree_out = 0;
01386             for( int i = 0; i < ncoeffs; ++i )
01387             {
01388                 coeffs[i] = 0;
01389             }
01390             return;
01391         }
01392         int npts_new = npts2fit - nzeros;
01393         std::vector< double > bs_temp( 3 * npts_new );
01394         int index = 0;
01395         for( int i = 0; i < npts2fit; ++i )
01396         {
01397             if( ws[i] )
01398             {
01399                 if( i > index )
01400                 {
01401                     us[index] = us[i];
01402                     ws[index] = ws[i];
01403                 }
01404                 bs_temp[index]                = bs[i];
01405                 bs_temp[index + npts_new]     = bs[i + npts2fit];
01406                 bs_temp[index + 2 * npts_new] = bs[i + 2 * npts2fit];
01407                 ++index;
01408             }
01409         }
01410         assert( index == npts_new );
01411         npts2fit = npts_new;
01412         us.resize( index );
01413         ws.resize( index );
01414         bs = bs_temp;
01415         // destroy bs_temp;
01416         std::vector< double >().swap( bs_temp );
01417     }
01418 
01419     // step 5. fitting
01420     eval_vander_univar_cmf( npts2fit, &( us[0] ), 3, &( bs[0] ), degree, &( ws[0] ), interp, safeguard, degree_out );
01421     // step 6. write results to output pointers
01422     int ncoeffs_out_pvpd = *degree_out + 1;
01423     assert( ncoeffs >= 3 * ncoeffs_out_pvpd );
01424     // write to coeffs consecutively, bs's size is not changed by eval_vander_univar_cmf
01425     coeffs[0] = coeffs[ncoeffs_out_pvpd] = coeffs[2 * ncoeffs_out_pvpd] = 0;
01426     for( int i = 0; i < ncoeffs_out_pvpd - interp; ++i )
01427     {
01428         coeffs[i + interp]                        = bs[i];
01429         coeffs[i + interp + ncoeffs_out_pvpd]     = bs[i + npts2fit];
01430         coeffs[i + interp + 2 * ncoeffs_out_pvpd] = bs[i + 2 * npts2fit];
01431     }
01432 }
01433 
01434 void HiReconstruction::eval_vander_univar_cmf( const int npts2fit,
01435                                                const double* us,
01436                                                const int ndim,
01437                                                double* bs,
01438                                                int degree,
01439                                                const double* ws,
01440                                                const bool interp,
01441                                                const bool safeguard,
01442                                                int* degree_out )
01443 {
01444     // step 1. determine degree of polynomials to fit according to number of points
01445     int ncols = degree + 1 - interp;
01446     while( npts2fit < ncols && degree >= 1 )
01447     {
01448         --degree;
01449         ncols = degree + 1 - interp;
01450     }
01451     if( !degree )
01452     {
01453         if( interp )
01454         {
01455             for( int icol = 0; icol < ndim; ++icol )
01456             {
01457                 bs[icol * npts2fit] = 0;
01458             }
01459         }
01460         for( int irow = 1; irow < npts2fit; ++irow )
01461         {
01462             for( int icol = 0; icol < ndim; ++icol )
01463             {
01464                 bs[icol * npts2fit + irow] = 0;
01465             }
01466         }
01467         *degree_out = 0;
01468         return;
01469     }
01470     // step 2. construct Vandermonde matrix
01471     std::vector< double > V;  // V(npts2fit*(ncols+interp));
01472     DGMSolver::gen_vander_multivar( npts2fit, 1, us, degree, V );
01473 
01474     if( interp )
01475     {
01476         V.erase( V.begin(), V.begin() + npts2fit );
01477     }
01478 
01479     // step 3. scale rows with respect to weights
01480     for( int i = 0; i < npts2fit; ++i )
01481     {
01482         for( int j = 0; j < ncols; ++j )
01483         {
01484             V[j * npts2fit + i] *= ws[i];
01485         }
01486         for( int k = 0; k < ndim; ++k )
01487         {
01488             bs[k * npts2fit + i] *= ws[i];
01489         }
01490     }
01491 
01492     // step 4. scale columns to reduce condition number
01493     std::vector< double > ts( ncols );
01494     DGMSolver::rescale_matrix( npts2fit, ncols, &( V[0] ), &( ts[0] ) );
01495 
01496     // step 5. perform Householder QR factorization
01497     std::vector< double > D( ncols );
01498     int rank;
01499     DGMSolver::qr_polyfit_safeguarded( npts2fit, ncols, &( V[0] ), &( D[0] ), &rank );
01500 
01501     // step 6. adjust degree of fitting
01502     int ncols_sub = ncols;
01503     while( rank < ncols_sub )
01504     {
01505         --degree;
01506         if( !degree )
01507         {
01508             // matrix is singular, consider curve on flat plane passing center and orthogonal to
01509             // tangent line
01510             *degree_out = 0;
01511             for( int i = 0; i < npts2fit; ++i )
01512             {
01513                 for( int k = 0; k < ndim; ++k )
01514                 {
01515                     bs[k * npts2fit + i] = 0;
01516                 }
01517             }
01518         }
01519         ncols_sub = degree + 1 - interp;
01520     }
01521 
01522     // step 7. compute Q'*bs
01523     DGMSolver::compute_qtransposeB( npts2fit, ncols_sub, &( V[0] ), ndim, bs );
01524 
01525     // step 8. perform backward substitution and scale solutions
01526     // assign diagonals of V
01527     for( int i = 0; i < ncols_sub; ++i )
01528     {
01529         V[i * npts2fit + i] = D[i];
01530     }
01531     // backsolve
01532     if( safeguard )
01533     {
01534         DGMSolver::backsolve_polyfit_safeguarded( 1, degree, interp, npts2fit, ncols, &( V[0] ), ndim, bs, ws,
01535                                                   degree_out );
01536     }
01537     else
01538     {
01539         DGMSolver::backsolve( npts2fit, ncols_sub, &( V[0] ), ndim, bs, &( ts[0] ) );
01540         *degree_out = degree;
01541     }
01542 }
01543 
01544 int HiReconstruction::compute_weights( const int nrows,
01545                                        const int ncols,
01546                                        const double* us,
01547                                        const int nngbs,
01548                                        const double* ngbnrms,
01549                                        const int degree,
01550                                        const double toler,
01551                                        double* ws )
01552 {
01553     assert( nrows <= _MAXPNTS && ws );
01554     bool interp = false;
01555     if( nngbs != nrows )
01556     {
01557         assert( nngbs == nrows + 1 );
01558         interp = true;
01559     }
01560     double epsilon = 1e-2;
01561 
01562     // First, compute squared distance from each input piont to the center
01563     for( int i = 0; i < nrows; ++i )
01564     {
01565         ws[i] = DGMSolver::vec_innerprod( ncols, us + i * ncols, us + i * ncols );
01566     }
01567 
01568     // Second, compute a small correction termt o guard against zero
01569     double h = 0;
01570     for( int i = 0; i < nrows; ++i )
01571     {
01572         h += ws[i];
01573     }
01574     h /= (double)nrows;
01575 
01576     // Finally, compute the weights for each vertex
01577     int nzeros = 0;
01578     for( int i = 0; i < nrows; ++i )
01579     {
01580         double costheta = DGMSolver::vec_innerprod( 3, ngbnrms, ngbnrms + 3 * ( i + interp ) );
01581         if( costheta > toler )
01582         {
01583             ws[i] = costheta * pow( ws[i] / h + epsilon, -1 * (double)degree / 2.0 );
01584         }
01585         else
01586         {
01587             ws[i] = 0;
01588             ++nzeros;
01589         }
01590     }
01591     return nzeros;
01592 }
01593 bool HiReconstruction::check_barycentric_coords( const int nws, const double* naturalcoords )
01594 {
01595     double sum = 0;
01596     for( int i = 0; i < nws; ++i )
01597     {
01598         if( naturalcoords[i] < -_MINEPS )
01599         {
01600             return false;
01601         }
01602         sum += naturalcoords[i];
01603     }
01604     if( fabs( 1 - sum ) > _MINEPS )
01605     {
01606         return false;
01607     }
01608     else
01609     {
01610         return true;
01611     }
01612 }
01613 }  // namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines