![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
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
00013 #include
00014 #include
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 = "<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, °ree_pnt, °ree_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 = "<> 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"< 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