39 GISMO_ASSERT(points.cols()==param_values.cols(),
"Pointset dimensions problem "<< points.cols() <<
" != " <<param_values.cols() );
42 m_param_values = param_values;
46 m_points.transposeInPlace();
50 m_offset[1] = m_points.rows();
57 gsMappedBasis<2,T> & mbasis)
59 m_param_values = param_values;
63 m_points.transposeInPlace();
64 m_offset =
give(offset);
70 m_last_lambda = lambda;
76 const int num_basis = m_basis->size();
77 const short_t dimension = m_points.cols();
81 gsSparseMatrix<T> A_mat(num_basis + m_constraintsLHS.rows(), num_basis + m_constraintsLHS.rows());
85 int nonZerosPerCol = 1;
86 for (
int i = 0; i < m_basis->domainDim(); ++i)
88 nonZerosPerCol *= ( 2 * m_basis->basis(0).degree(i) + 1 ) * 4;
90 A_mat.reservePerColumn( nonZerosPerCol );
93 gsMatrix<T> m_B(num_basis + m_constraintsRHS.rows(), dimension);
99 assembleSystem(A_mat, m_B);
105 applySmoothing(lambda, A_mat);
107 if(m_constraintsLHS.rows() > 0)
108 extendSystem(A_mat, m_B);
114 A_mat.makeCompressed();
116 typename gsSparseSolver<T>::BiCGSTABILUT solver( A_mat );
120 gsWarn<<
"The preconditioner failed. Aborting.\n";
127 x = solver.solve(m_B);
130 x.conservativeResize(num_basis, gsEigen::NoChange);
138 m_result = bb->makeGeometry(
give(x) ).release();
140 m_mresult = gsMappedSpline<2,T> ( *
static_cast<gsMappedBasis<2,T>*
>(m_basis),
give(x));
149 compute(m_last_lambda);
151 const index_t d = m_param_values.rows();
152 const index_t n = m_points.cols();
154 std::vector<gsMatrix<T> > vals;
156 for (
index_t it = 0; it<maxIter; ++it)
163 # pragma omp parallel for default(shared) private(der,DD,vals)
164 for (
index_t s = 0; s<m_points.rows(); ++s)
167 vals = m_result->evalAllDers(m_param_values.col(s), 1);
170 der = vals[1].reshaped(d,n);
171 DD = vals[0].transpose() - m_points.row(s);
172 const T cv = ( DD.normalized() * der.row(k).transpose().normalized() ).value();
173 const T a =
math::abs(0.5*EIGEN_PI-math::acos(cv));
174 # pragma omp critical (max_avg_ang)
176 maxAng = math::max(maxAng, a );
189 avgAng /= d*m_points.rows();
194 gsVector<T> newParam;
195 # pragma omp parallel for default(shared) private(newParam)
196 for (
index_t i = 0; i<m_points.rows(); ++i)
199 const auto & curr = m_points.row(i).transpose();
200 newParam = m_param_values.col(i);
201 m_result->closestPointTo(curr, newParam, accuracy,
true);
204 if ((m_result->eval(newParam) - curr).norm()
205 < (m_result->eval(m_param_values.col(i))
207 m_param_values.col(i) = newParam;
214 compute(m_last_lambda);
223 const int num_patches ( m_basis->nPieces() );
229 for (
index_t h = 0; h < num_patches; h++ )
231 auto & basis = m_basis->basis(h);
234 for (
index_t k = m_offset[h]; k < m_offset[h+1]; ++k)
236 curr_point = m_param_values.col(k);
239 basis.eval_into(curr_point, value);
242 basis.active_into(curr_point, actives);
244 const index_t numActive = actives.rows();
246 for (
index_t i = 0; i != numActive; ++i)
250 m_B.row(ii) += value.
at(i) * m_points.row(k);
251 for (
index_t j = 0; j != numActive; ++j)
253 A_mat(ii, actives.
at(j)) += value.at(i) * value.at(j);
263 index_t basisSize = m_basis->size();
270 m_B.bottomRows(m_constraintsRHS.rows()) = m_constraintsRHS;
272 for (
index_t k=0; k<m_constraintsLHS.outerSize(); ++k)
276 A_mat(basisSize + it.row(), it.col()) = it.value();
277 A_mat(it.col(), basisSize + it.row()) = it.value();
285 m_last_lambda = lambda;
287 const int num_basis=m_basis->size();
289 gsSparseMatrix<T> A_mat(num_basis + m_constraintsLHS.rows(), num_basis + m_constraintsLHS.rows());
290 int nonZerosPerCol = 1;
291 for (
int i = 0; i < m_basis->domainDim(); ++i)
292 nonZerosPerCol *= ( 2 * m_basis->basis(0).degree(i) + 1 );
293 A_mat.reservePerColumn( nonZerosPerCol );
294 const_cast<gsFitting*
>(
this)->applySmoothing(lambda, A_mat);
301 m_last_lambda = lambda;
302 const int num_patches(m_basis->nPieces());
303 const short_t dim(m_basis->domainDim());
304 const short_t stride = dim * (dim + 1) / 2;
312 const int tid = omp_get_thread_num();
313 const int nt = omp_get_num_threads();
316 for (
index_t h = 0; h < num_patches; h++)
318 auto & basis = m_basis->basis(h);
323 for (
short_t i = 0; i != dim; ++i)
325 numNodes[i] = basis.degree(i);
330 typename gsBasis<T>::domainIter domIt = basis.makeDomainIterator();
334 for ( domIt->next(tid); domIt->good(); domIt->next(nt) )
336 for (; domIt->good(); domIt->next() )
340 QuRule.
mapTo(domIt->lowerCorner(), domIt->upperCorner(), quNodes, quWeights);
341 basis.deriv2_into(quNodes, der2);
342 basis.active_into(domIt->center, actives);
343 const index_t numActive = actives.rows();
344 localA.setZero(numActive, numActive);
347 for (
index_t k = 0; k < quWeights.rows(); ++k)
349 const T weight = quWeights[k] * lambda;
351 for (
index_t i = 0; i != numActive; ++i)
352 for (
index_t j = 0; j != numActive; ++j)
356 for (
short_t s = 0; s < stride; s++)
362 localAij += der2(i * stride + s, k) *
363 der2(j * stride + s, k);
368 localAij += T(2) * der2(i * stride + s, k) *
369 der2(j * stride + s, k);
372 localA(i, j) += weight * localAij;
376 for (
index_t i = 0; i != numActive; ++i)
378 const int ii = actives(i, 0);
379 for (
index_t j = 0; j != numActive; ++j)
380 A_mat(ii, actives(j, 0)) += localA(i, j);
390 m_pointErrors.clear();
394 m_result->eval_into(m_param_values, val_i);
395 m_pointErrors.push_back( (m_points.row(0) - val_i.col(0).transpose()).norm() );
396 m_max_error = m_min_error = m_pointErrors.back();
398 for (
index_t i = 1; i < m_points.rows(); i++)
402 const T err = (m_points.row(i) - val_i.col(i).transpose()).norm() ;
404 m_pointErrors.push_back(err);
406 if ( err > m_max_error ) m_max_error = err;
407 if ( err < m_min_error ) m_min_error = err;
415 m_pointErrors.clear();
418 m_result->eval_into(m_param_values, values);
420 for (
index_t i = 0; i != m_points.rows(); i++)
422 const T err = (m_points.row(i) - values.col(i).transpose()).cwiseAbs().maxCoeff();
424 m_pointErrors.push_back(err);
426 if ( i == 0 || m_max_error < err ) m_max_error = err;
427 if ( i == 0 || err < m_min_error ) m_min_error = err;
439 const int num_patches(m_basis->nPieces());
443 for (
index_t h = 0; h < num_patches; h++)
446 for (
index_t k = m_offset[h]; k < m_offset[h + 1]; ++k)
448 curr_point = m_param_values.col(k);
451 m_result->eval_into(curr_point, results);
454 m_mresult.eval_into(h, curr_point, results);
457 const T err = (m_points.row(k) - results.transpose()).squaredNorm();
464 error += math::sqrt(err);
467 gsWarn <<
"Unknown type in computeApproxError(error, type)...\n";
478 errors.reserve(m_points.rows());
484 const int num_patches(m_basis->nPieces());
486 for (
index_t h = 0; h < num_patches; h++)
488 for (
index_t k = m_offset[h]; k < m_offset[h + 1]; ++k)
490 curr_point = m_param_values.col(k);
493 m_result->eval_into(curr_point, results);
496 m_mresult.eval_into(h, curr_point, results);
499 results.transposeInPlace();
501 err = (m_points.row(k) - results).
template lpNorm<gsEigen::Infinity>();
506 errors.push_back(err);
509 errors.push_back(math::sqrt(err));
512 gsWarn <<
"Unknown type in get_Error(errors, type)...\n";
523 if(coefs.size() == 0)
527 "Prescribed indices and coefs must have the same length.");
533 for(
size_t r=0; r<indices.size(); r++)
536 lhs(r-duplicates, fix) = 1;
537 rhs.row(r-duplicates) = coefs[r];
540 setConstraints(lhs, rhs);
546 if(fixedSides.size() == 0)
549 std::vector<index_t> indices;
550 std::vector<gsMatrix<T> > coefs;
552 for(std::vector<boxSide>::const_iterator it=fixedSides.begin(); it!=fixedSides.end(); ++it)
555 for(
index_t r=0; r<ind.rows(); r++)
559 if(std::find(indices.begin(), indices.end(), fix) == indices.end())
561 indices.push_back(fix);
562 coefs.push_back(this->m_result->coef(fix));
566 setConstraints(indices, coefs);
573 std::vector<gsBSpline<T> > tmp = fixedCurves;
574 std::vector<gsGeometry<T> *> fixedCurves_input(tmp.size());
575 for (
size_t k=0; k!=fixedCurves.size(); k++)
576 fixedCurves_input[k] =
dynamic_cast<gsGeometry<T> *
>(&(tmp[k]));
577 setConstraints(fixedSides, fixedCurves_input);
584 if(fixedSides.size() == 0)
588 "fixedCurves and fixedSides are of different sizes.");
590 std::vector<index_t> indices;
591 std::vector<gsMatrix<T> > coefs;
592 for(
size_t s=0; s<fixedSides.size(); s++)
594 gsMatrix<T> coefsThisSide = fixedCurves[s]->coefs();
595 gsMatrix<index_t> indicesThisSide = m_basis->basis(0).boundaryOffset(fixedSides[s],0);
596 GISMO_ASSERT(coefsThisSide.rows() == indicesThisSide.rows(),
597 "Coef number mismatch between prescribed curve and basis side.");
599 for(
index_t r=0; r<indicesThisSide.rows(); r++)
601 index_t fix = indicesThisSide(r,0);
603 if(std::find(indices.begin(), indices.end(), fix) == indices.end())
605 indices.push_back(fix);
606 coefs.push_back(coefsThisSide.row(r));
611 setConstraints(indices, coefs);
Iterator over the elements of a tensor-structured grid.
Abstract base class representing a geometry map.
Definition: gsGeometry.h:92
void computeApproxError(T &error, int type=0) const
Computes the approximation error of the fitted curve to the original point cloud. ...
Definition: gsFitting.hpp:434
void setConstraints(const gsSparseMatrix< T > &lhs, const gsMatrix< T > &rhs)
Definition: gsFitting.h:133
virtual ~gsFitting()
Destructor.
Definition: gsFitting.hpp:28
void applySmoothing(T lambda, gsSparseMatrix< T > &A_mat)
Definition: gsFitting.hpp:299
#define short_t
Definition: gsConfig.h:35
void computeMaxNormErrors()
Computes the maximum norm error for each point.
Definition: gsFitting.hpp:413
void computeErrors()
Computes the euclidean error for each point.
Definition: gsFitting.hpp:388
Provides declaration of Basis abstract interface.
S give(S &x)
Definition: gsMemory.h:266
Provides declaration of Geometry abstract interface.
#define index_t
Definition: gsConfig.h:32
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
A B-spline function of one argument, with arbitrary target dimension.
Definition: gsBSpline.h:50
void get_Error(std::vector< T > &errors, int type=0) const
return the errors for each point
Definition: gsFitting.hpp:475
void assembleSystem(gsSparseMatrix< T > &A_mat, gsMatrix< T > &B)
Assembles system for the least square fit.
Definition: gsFitting.hpp:220
Class for performing a least squares fit of a parametrized point cloud with a gsGeometry.
Definition: gsFitting.h:32
T at(index_t i) const
Returns the i-th element of the vectorization of the matrix.
Definition: gsMatrix.h:211
#define gsWarn
Definition: gsDebug.h:50
gsFitting()
default constructor
Definition: gsFitting.h:36
virtual short_t domainDim() const =0
Dimension of the (source) domain.
virtual void mapTo(const gsVector< T > &lower, const gsVector< T > &upper, gsMatrix< T > &nodes, gsVector< T > &weights) const
Maps quadrature rule (i.e., points and weights) from the reference domain to an element.
Definition: gsQuadRule.h:177
Represents a B-spline curve/function with one parameter.
void extendSystem(gsSparseMatrix< T > &A_mat, gsMatrix< T > &m_B)
Extends the system of equations by taking constraints into account.
Definition: gsFitting.hpp:260
This is the main header file that collects wrappers of Eigen for linear algebra.
EIGEN_STRONG_INLINE abs_expr< E > abs(const E &u)
Absolute value.
Definition: gsExpressions.h:4488
Class that represents the (tensor) Gauss-Legendre quadrature rule.
Definition: gsGaussRule.h:27
A basis represents a family of scalar basis functions defined over a common parameter domain...
Definition: gsBasis.h:78
void compute(T lambda=0)
Computes the least squares fit for a gsBasis.
Definition: gsFitting.hpp:68