00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <stdexcept>
00039 #include <pcl/surface/on_nurbs/fitting_surface_pdm.h>
00040
00041 using namespace pcl;
00042 using namespace on_nurbs;
00043 using namespace Eigen;
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 FittingSurface::FittingSurface (int order, NurbsDataSurface *m_data, Eigen::Vector3d z)
00061 {
00062 if (order < 2)
00063 throw std::runtime_error ("[FittingSurface::FittingSurface] Error order to low (order<2).");
00064
00065 ON::Begin ();
00066
00067 this->m_data = m_data;
00068 m_nurbs = initNurbsPCA (order, m_data, z);
00069
00070 this->init ();
00071 }
00072
00073 FittingSurface::FittingSurface (NurbsDataSurface *m_data, const ON_NurbsSurface &ns)
00074 {
00075 ON::Begin ();
00076
00077 this->m_nurbs = ON_NurbsSurface (ns);
00078 this->m_data = m_data;
00079
00080 this->init ();
00081 }
00082
00083 void
00084 FittingSurface::refine (int dim)
00085 {
00086 std::vector<double> xi;
00087 std::vector<double> elements = getElementVector (m_nurbs, dim);
00088
00089 for (unsigned i = 0; i < elements.size () - 1; i++)
00090 xi.push_back (elements[i] + 0.5 * (elements[i + 1] - elements[i]));
00091
00092 for (unsigned i = 0; i < xi.size (); i++)
00093 m_nurbs.InsertKnot (dim, xi[i], 1);
00094
00095 m_elementsU = getElementVector (m_nurbs, 0);
00096 m_elementsV = getElementVector (m_nurbs, 1);
00097 m_minU = m_elementsU[0];
00098 m_minV = m_elementsV[0];
00099 m_maxU = m_elementsU[m_elementsU.size () - 1];
00100 m_maxV = m_elementsV[m_elementsV.size () - 1];
00101 }
00102
00103 void
00104 FittingSurface::refine (ON_NurbsSurface &nurbs, int dim)
00105 {
00106 std::vector<double> xi;
00107 std::vector<double> elements = getElementVector (nurbs, dim);
00108
00109 for (unsigned i = 0; i < elements.size () - 1; i++)
00110 xi.push_back (elements[i] + 0.5 * (elements[i + 1] - elements[i]));
00111
00112 for (unsigned i = 0; i < xi.size (); i++)
00113 nurbs.InsertKnot (dim, xi[i], 1);
00114 }
00115
00116 void
00117 FittingSurface::assemble (Parameter param)
00118 {
00119 int nBnd = static_cast<int> (m_data->boundary.size ());
00120 int nInt = static_cast<int> (m_data->interior.size ());
00121 int nCurInt = param.regularisation_resU * param.regularisation_resV;
00122 int nCurBnd = 2 * param.regularisation_resU + 2 * param.regularisation_resV;
00123 int nCageReg = (m_nurbs.m_cv_count[0] - 2) * (m_nurbs.m_cv_count[1] - 2);
00124 int nCageRegBnd = 2 * (m_nurbs.m_cv_count[0] - 1) + 2 * (m_nurbs.m_cv_count[1] - 1);
00125
00126 if (param.boundary_weight <= 0.0)
00127 nBnd = 0;
00128 if (param.interior_weight <= 0.0)
00129 nInt = 0;
00130 if (param.boundary_regularisation <= 0.0)
00131 nCurBnd = 0;
00132 if (param.interior_regularisation <= 0.0)
00133 nCurInt = 0;
00134 if (param.interior_smoothness <= 0.0)
00135 nCageReg = 0;
00136 if (param.boundary_smoothness <= 0.0)
00137 nCageRegBnd = 0;
00138
00139 int ncp = m_nurbs.m_cv_count[0] * m_nurbs.m_cv_count[1];
00140 int nrows = nBnd + nInt + nCurInt + nCurBnd + nCageReg + nCageRegBnd;
00141
00142 m_solver.assign (nrows, ncp, 3);
00143
00144 unsigned row = 0;
00145
00146
00147 if (nBnd > 0)
00148 assembleBoundary (param.boundary_weight, row);
00149
00150
00151 if (nInt > 0)
00152 assembleInterior (param.interior_weight, row);
00153
00154
00155 if (nCurInt > 0)
00156 {
00157 if (m_nurbs.Order (0) < 3 || m_nurbs.Order (1) < 3)
00158 printf ("[FittingSurface::assemble] Error insufficient NURBS order to add curvature regularisation.\n");
00159 else
00160 addInteriorRegularisation (2, param.regularisation_resU, param.regularisation_resV,
00161 param.interior_regularisation / param.regularisation_resU, row);
00162 }
00163
00164
00165 if (nCurBnd > 0)
00166 {
00167 if (m_nurbs.Order (0) < 3 || m_nurbs.Order (1) < 3)
00168 printf ("[FittingSurface::assemble] Error insufficient NURBS order to add curvature regularisation.\n");
00169 else
00170 addBoundaryRegularisation (2, param.regularisation_resU, param.regularisation_resV,
00171 param.boundary_regularisation / param.regularisation_resU, row);
00172 }
00173
00174
00175 if (nCageReg > 0)
00176 addCageInteriorRegularisation (param.interior_smoothness, row);
00177
00178 if (nCageRegBnd > 0)
00179 {
00180 addCageBoundaryRegularisation (param.boundary_smoothness, NORTH, row);
00181 addCageBoundaryRegularisation (param.boundary_smoothness, SOUTH, row);
00182 addCageBoundaryRegularisation (param.boundary_smoothness, WEST, row);
00183 addCageBoundaryRegularisation (param.boundary_smoothness, EAST, row);
00184 addCageCornerRegularisation (param.boundary_smoothness * 2.0, row);
00185 }
00186 }
00187
00188 void
00189 FittingSurface::init ()
00190 {
00191 m_elementsU = getElementVector (m_nurbs, 0);
00192 m_elementsV = getElementVector (m_nurbs, 1);
00193 m_minU = m_elementsU[0];
00194 m_minV = m_elementsV[0];
00195 m_maxU = m_elementsU[m_elementsU.size () - 1];
00196 m_maxV = m_elementsV[m_elementsV.size () - 1];
00197
00198 in_max_steps = 100;
00199 in_accuracy = 1e-4;
00200
00201 m_quiet = true;
00202 }
00203
00204 void
00205 FittingSurface::solve (double damp)
00206 {
00207 if (m_solver.solve ())
00208 updateSurf (damp);
00209 }
00210
00211 void
00212 FittingSurface::updateSurf (double damp)
00213 {
00214 int ncp = m_nurbs.m_cv_count[0] * m_nurbs.m_cv_count[1];
00215
00216 for (int A = 0; A < ncp; A++)
00217 {
00218
00219 int I = gl2gr (A);
00220 int J = gl2gc (A);
00221
00222 ON_3dPoint cp_prev;
00223 m_nurbs.GetCV (I, J, cp_prev);
00224
00225 ON_3dPoint cp;
00226 cp.x = cp_prev.x + damp * (m_solver.x (A, 0) - cp_prev.x);
00227 cp.y = cp_prev.y + damp * (m_solver.x (A, 1) - cp_prev.y);
00228 cp.z = cp_prev.z + damp * (m_solver.x (A, 2) - cp_prev.z);
00229
00230 m_nurbs.SetCV (I, J, cp);
00231
00232 }
00233
00234 }
00235
00236 void
00237 FittingSurface::setInvMapParams (unsigned in_max_steps, double in_accuracy)
00238 {
00239 this->in_max_steps = in_max_steps;
00240 this->in_accuracy = in_accuracy;
00241 }
00242
00243 std::vector<double>
00244 FittingSurface::getElementVector (const ON_NurbsSurface &nurbs, int dim)
00245 {
00246 std::vector<double> result;
00247
00248 int idx_min = 0;
00249 int idx_max = nurbs.KnotCount (dim) - 1;
00250 if (nurbs.IsClosed (dim))
00251 {
00252 idx_min = nurbs.Order (dim) - 2;
00253 idx_max = nurbs.KnotCount (dim) - nurbs.Order (dim) + 1;
00254 }
00255
00256 const double* knots = nurbs.Knot (dim);
00257
00258 result.push_back (knots[idx_min]);
00259
00260
00261 for (int E = idx_min + 1; E <= idx_max; E++)
00262 {
00263
00264 if (knots[E] != knots[E - 1])
00265 result.push_back (knots[E]);
00266
00267 }
00268
00269 return result;
00270 }
00271
00272 void
00273 FittingSurface::assembleInterior (double wInt, unsigned &row)
00274 {
00275 m_data->interior_line_start.clear ();
00276 m_data->interior_line_end.clear ();
00277 m_data->interior_error.clear ();
00278 m_data->interior_normals.clear ();
00279 unsigned nInt = static_cast<unsigned> (m_data->interior.size ());
00280 for (unsigned p = 0; p < nInt; p++)
00281 {
00282 Vector3d &pcp = m_data->interior[p];
00283
00284
00285 Vector2d params;
00286 Vector3d pt, tu, tv, n;
00287 double error;
00288 if (p < m_data->interior_param.size ())
00289 {
00290 params = inverseMapping (m_nurbs, pcp, m_data->interior_param[p], error, pt, tu, tv, in_max_steps, in_accuracy);
00291 m_data->interior_param[p] = params;
00292 }
00293 else
00294 {
00295 params = findClosestElementMidPoint (m_nurbs, pcp);
00296 params = inverseMapping (m_nurbs, pcp, params, error, pt, tu, tv, in_max_steps, in_accuracy);
00297 m_data->interior_param.push_back (params);
00298 }
00299 m_data->interior_error.push_back (error);
00300
00301 n = tu.cross (tv);
00302 n.normalize ();
00303
00304 m_data->interior_normals.push_back (n);
00305 m_data->interior_line_start.push_back (pcp);
00306 m_data->interior_line_end.push_back (pt);
00307
00308 double w (wInt);
00309 if (p < m_data->interior_weight.size ())
00310 w = m_data->interior_weight[p];
00311
00312 addPointConstraint (m_data->interior_param[p], m_data->interior[p], w, row);
00313 }
00314 }
00315
00316 void
00317 FittingSurface::assembleBoundary (double wBnd, unsigned &row)
00318 {
00319 m_data->boundary_line_start.clear ();
00320 m_data->boundary_line_end.clear ();
00321 m_data->boundary_error.clear ();
00322 m_data->boundary_normals.clear ();
00323 unsigned nBnd = static_cast<unsigned> (m_data->boundary.size ());
00324 for (unsigned p = 0; p < nBnd; p++)
00325 {
00326 Vector3d &pcp = m_data->boundary[p];
00327
00328 double error;
00329 Vector3d pt, tu, tv, n;
00330 Vector2d params = inverseMappingBoundary (m_nurbs, pcp, error, pt, tu, tv, in_max_steps, in_accuracy);
00331 m_data->boundary_error.push_back (error);
00332
00333 if (p < m_data->boundary_param.size ())
00334 {
00335 m_data->boundary_param[p] = params;
00336 }
00337 else
00338 {
00339 m_data->boundary_param.push_back (params);
00340 }
00341
00342 n = tu.cross (tv);
00343 n.normalize ();
00344
00345 m_data->boundary_normals.push_back (n);
00346 m_data->boundary_line_start.push_back (pcp);
00347 m_data->boundary_line_end.push_back (pt);
00348
00349 double w (wBnd);
00350 if (p < m_data->boundary_weight.size ())
00351 w = m_data->boundary_weight[p];
00352
00353 addPointConstraint (m_data->boundary_param[p], m_data->boundary[p], w, row);
00354 }
00355 }
00356
00357 ON_NurbsSurface
00358 FittingSurface::initNurbs4Corners (int order, ON_3dPoint ll, ON_3dPoint lr, ON_3dPoint ur, ON_3dPoint ul)
00359 {
00360 std::map<int, std::map<int, ON_3dPoint> > cv_map;
00361
00362 double dc = 1.0 / (order - 1);
00363
00364 for (int i = 0; i < order; i++)
00365 {
00366 double di = dc * i;
00367 cv_map[i][0] = ll + (lr - ll) * di;
00368 cv_map[0][i] = ll + (ul - ll) * di;
00369 cv_map[i][order - 1] = ul + (ur - ul) * di;
00370 cv_map[order - 1][i] = lr + (ur - lr) * di;
00371 }
00372
00373 for (int i = 1; i < order - 1; i++)
00374 {
00375 for (int j = 1; j < order - 1; j++)
00376 {
00377 ON_3dPoint du = cv_map[0][j] + (cv_map[order - 1][j] - cv_map[0][j]) * dc * i;
00378 ON_3dPoint dv = cv_map[i][0] + (cv_map[i][order - 1] - cv_map[i][0]) * dc * j;
00379 cv_map[i][j] = du * 0.5 + dv * 0.5;
00380 }
00381 }
00382
00383 ON_NurbsSurface nurbs (3, false, order, order, order, order);
00384 nurbs.MakeClampedUniformKnotVector (0, 1.0);
00385 nurbs.MakeClampedUniformKnotVector (1, 1.0);
00386
00387 for (int i = 0; i < order; i++)
00388 {
00389 for (int j = 0; j < order; j++)
00390 {
00391 nurbs.SetCV (i, j, cv_map[i][j]);
00392 }
00393 }
00394 return nurbs;
00395 }
00396
00397 ON_NurbsSurface
00398 FittingSurface::initNurbsPCA (int order, NurbsDataSurface *m_data, Eigen::Vector3d z)
00399 {
00400 Eigen::Vector3d mean;
00401 Eigen::Matrix3d eigenvectors;
00402 Eigen::Vector3d eigenvalues;
00403
00404 unsigned s = static_cast<unsigned> (m_data->interior.size ());
00405
00406 NurbsTools::pca (m_data->interior, mean, eigenvectors, eigenvalues);
00407
00408 m_data->mean = mean;
00409 m_data->eigenvectors = eigenvectors;
00410
00411 bool flip (false);
00412 if (eigenvectors.col (2).dot (z) < 0.0)
00413 flip = true;
00414
00415 eigenvalues = eigenvalues / s;
00416
00417 Eigen::Vector3d sigma (sqrt (eigenvalues (0)), sqrt (eigenvalues (1)), sqrt (eigenvalues (2)));
00418
00419 ON_NurbsSurface nurbs (3, false, order, order, order, order);
00420 nurbs.MakeClampedUniformKnotVector (0, 1.0);
00421 nurbs.MakeClampedUniformKnotVector (1, 1.0);
00422
00423
00424 double dcu = (4.0 * sigma (0)) / (nurbs.Order (0) - 1);
00425 double dcv = (4.0 * sigma (1)) / (nurbs.Order (1) - 1);
00426
00427 Eigen::Vector3d cv_t, cv;
00428 for (int i = 0; i < nurbs.Order (0); i++)
00429 {
00430 for (int j = 0; j < nurbs.Order (1); j++)
00431 {
00432 cv (0) = -2.0 * sigma (0) + dcu * i;
00433 cv (1) = -2.0 * sigma (1) + dcv * j;
00434 cv (2) = 0.0;
00435 cv_t = eigenvectors * cv + mean;
00436 if (flip)
00437 nurbs.SetCV (nurbs.Order (0) - 1 - i, j, ON_3dPoint (cv_t (0), cv_t (1), cv_t (2)));
00438 else
00439 nurbs.SetCV (i, j, ON_3dPoint (cv_t (0), cv_t (1), cv_t (2)));
00440 }
00441 }
00442 return nurbs;
00443 }
00444
00445 ON_NurbsSurface
00446 FittingSurface::initNurbsPCABoundingBox (int order, NurbsDataSurface *m_data, Eigen::Vector3d z)
00447 {
00448 Eigen::Vector3d mean;
00449 Eigen::Matrix3d eigenvectors;
00450 Eigen::Vector3d eigenvalues;
00451
00452 unsigned s = static_cast<unsigned> (m_data->interior.size ());
00453 m_data->interior_param.clear ();
00454
00455 NurbsTools::pca (m_data->interior, mean, eigenvectors, eigenvalues);
00456
00457 m_data->mean = mean;
00458 m_data->eigenvectors = eigenvectors;
00459
00460 bool flip (false);
00461 if (eigenvectors.col (2).dot (z) < 0.0)
00462 flip = true;
00463
00464 eigenvalues = eigenvalues / s;
00465 Eigen::Matrix3d eigenvectors_inv = eigenvectors.inverse ();
00466
00467 Eigen::Vector3d v_max (-DBL_MAX, -DBL_MAX, -DBL_MAX);
00468 Eigen::Vector3d v_min (DBL_MAX, DBL_MAX, DBL_MAX);
00469 for (unsigned i = 0; i < s; i++)
00470 {
00471 Eigen::Vector3d p (eigenvectors_inv * (m_data->interior[i] - mean));
00472 m_data->interior_param.push_back (Eigen::Vector2d (p (0), p (1)));
00473
00474 if (p (0) > v_max (0))
00475 v_max (0) = p (0);
00476 if (p (1) > v_max (1))
00477 v_max (1) = p (1);
00478 if (p (2) > v_max (2))
00479 v_max (2) = p (2);
00480
00481 if (p (0) < v_min (0))
00482 v_min (0) = p (0);
00483 if (p (1) < v_min (1))
00484 v_min (1) = p (1);
00485 if (p (2) < v_min (2))
00486 v_min (2) = p (2);
00487 }
00488
00489 for (unsigned i = 0; i < s; i++)
00490 {
00491 Eigen::Vector2d &p = m_data->interior_param[i];
00492 if (v_max (0) > v_min (0) && v_max (0) > v_min (0))
00493 {
00494 p (0) = (p (0) - v_min (0)) / (v_max (0) - v_min (0));
00495 p (1) = (p (1) - v_min (1)) / (v_max (1) - v_min (1));
00496 }
00497 else
00498 {
00499 throw std::runtime_error ("[NurbsTools::initNurbsPCABoundingBox] Error: v_max <= v_min");
00500 }
00501 }
00502
00503 ON_NurbsSurface nurbs (3, false, order, order, order, order);
00504 nurbs.MakeClampedUniformKnotVector (0, 1.0);
00505 nurbs.MakeClampedUniformKnotVector (1, 1.0);
00506
00507 double dcu = (v_max (0) - v_min (0)) / (nurbs.Order (0) - 1);
00508 double dcv = (v_max (1) - v_min (1)) / (nurbs.Order (1) - 1);
00509
00510 Eigen::Vector3d cv_t, cv;
00511 for (int i = 0; i < nurbs.Order (0); i++)
00512 {
00513 for (int j = 0; j < nurbs.Order (1); j++)
00514 {
00515 cv (0) = v_min (0) + dcu * i;
00516 cv (1) = v_min (1) + dcv * j;
00517 cv (2) = 0.0;
00518 cv_t = eigenvectors * cv + mean;
00519 if (flip)
00520 nurbs.SetCV (nurbs.Order (0) - 1 - i, j, ON_3dPoint (cv_t (0), cv_t (1), cv_t (2)));
00521 else
00522 nurbs.SetCV (i, j, ON_3dPoint (cv_t (0), cv_t (1), cv_t (2)));
00523 }
00524 }
00525 return nurbs;
00526 }
00527
00528 void
00529 FittingSurface::addPointConstraint (const Eigen::Vector2d ¶ms, const Eigen::Vector3d &point, double weight,
00530 unsigned &row)
00531 {
00532 double *N0 = new double[m_nurbs.Order (0) * m_nurbs.Order (0)];
00533 double *N1 = new double[m_nurbs.Order (1) * m_nurbs.Order (1)];
00534
00535 int E = ON_NurbsSpanIndex (m_nurbs.m_order[0], m_nurbs.m_cv_count[0], m_nurbs.m_knot[0], params (0), 0, 0);
00536 int F = ON_NurbsSpanIndex (m_nurbs.m_order[1], m_nurbs.m_cv_count[1], m_nurbs.m_knot[1], params (1), 0, 0);
00537
00538 ON_EvaluateNurbsBasis (m_nurbs.Order (0), m_nurbs.m_knot[0] + E, params (0), N0);
00539 ON_EvaluateNurbsBasis (m_nurbs.Order (1), m_nurbs.m_knot[1] + F, params (1), N1);
00540
00541 m_solver.f (row, 0, point (0) * weight);
00542 m_solver.f (row, 1, point (1) * weight);
00543 m_solver.f (row, 2, point (2) * weight);
00544
00545 for (int i = 0; i < m_nurbs.Order (0); i++)
00546 {
00547
00548 for (int j = 0; j < m_nurbs.Order (1); j++)
00549 {
00550
00551 m_solver.K (row, lrc2gl (E, F, i, j), weight * N0[i] * N1[j]);
00552
00553 }
00554
00555 }
00556
00557 row++;
00558
00559 delete [] N1;
00560 delete [] N0;
00561 }
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608 void
00609 FittingSurface::addCageInteriorRegularisation (double weight, unsigned &row)
00610 {
00611 for (int i = 1; i < (m_nurbs.m_cv_count[0] - 1); i++)
00612 {
00613 for (int j = 1; j < (m_nurbs.m_cv_count[1] - 1); j++)
00614 {
00615
00616 m_solver.f (row, 0, 0.0);
00617 m_solver.f (row, 1, 0.0);
00618 m_solver.f (row, 2, 0.0);
00619
00620 m_solver.K (row, grc2gl (i + 0, j + 0), -4.0 * weight);
00621 m_solver.K (row, grc2gl (i + 0, j - 1), 1.0 * weight);
00622 m_solver.K (row, grc2gl (i + 0, j + 1), 1.0 * weight);
00623 m_solver.K (row, grc2gl (i - 1, j + 0), 1.0 * weight);
00624 m_solver.K (row, grc2gl (i + 1, j + 0), 1.0 * weight);
00625
00626 row++;
00627 }
00628 }
00629 }
00630
00631 void
00632 FittingSurface::addCageBoundaryRegularisation (double weight, int side, unsigned &row)
00633 {
00634 int i = 0;
00635 int j = 0;
00636
00637 switch (side)
00638 {
00639 case SOUTH:
00640 j = m_nurbs.m_cv_count[1] - 1;
00641 case NORTH:
00642 for (i = 1; i < (m_nurbs.m_cv_count[0] - 1); i++)
00643 {
00644
00645 m_solver.f (row, 0, 0.0);
00646 m_solver.f (row, 1, 0.0);
00647 m_solver.f (row, 2, 0.0);
00648
00649 m_solver.K (row, grc2gl (i + 0, j), -2.0 * weight);
00650 m_solver.K (row, grc2gl (i - 1, j), 1.0 * weight);
00651 m_solver.K (row, grc2gl (i + 1, j), 1.0 * weight);
00652
00653 row++;
00654 }
00655 break;
00656
00657 case EAST:
00658 i = m_nurbs.m_cv_count[0] - 1;
00659 case WEST:
00660 for (j = 1; j < (m_nurbs.m_cv_count[1] - 1); j++)
00661 {
00662
00663 m_solver.f (row, 0, 0.0);
00664 m_solver.f (row, 1, 0.0);
00665 m_solver.f (row, 2, 0.0);
00666
00667 m_solver.K (row, grc2gl (i, j + 0), -2.0 * weight);
00668 m_solver.K (row, grc2gl (i, j - 1), 1.0 * weight);
00669 m_solver.K (row, grc2gl (i, j + 1), 1.0 * weight);
00670
00671 row++;
00672 }
00673 break;
00674 }
00675 }
00676
00677 void
00678 FittingSurface::addCageCornerRegularisation (double weight, unsigned &row)
00679 {
00680 {
00681 int i = 0;
00682 int j = 0;
00683
00684 m_solver.f (row, 0, 0.0);
00685 m_solver.f (row, 1, 0.0);
00686 m_solver.f (row, 2, 0.0);
00687
00688 m_solver.K (row, grc2gl (i + 0, j + 0), -2.0 * weight);
00689 m_solver.K (row, grc2gl (i + 1, j + 0), 1.0 * weight);
00690 m_solver.K (row, grc2gl (i + 0, j + 1), 1.0 * weight);
00691
00692 row++;
00693 }
00694
00695 {
00696 int i = m_nurbs.m_cv_count[0] - 1;
00697 int j = 0;
00698
00699 m_solver.f (row, 0, 0.0);
00700 m_solver.f (row, 1, 0.0);
00701 m_solver.f (row, 2, 0.0);
00702
00703 m_solver.K (row, grc2gl (i + 0, j + 0), -2.0 * weight);
00704 m_solver.K (row, grc2gl (i - 1, j + 0), 1.0 * weight);
00705 m_solver.K (row, grc2gl (i + 0, j + 1), 1.0 * weight);
00706
00707 row++;
00708 }
00709
00710 {
00711 int i = m_nurbs.m_cv_count[0] - 1;
00712 int j = m_nurbs.m_cv_count[1] - 1;
00713
00714 m_solver.f (row, 0, 0.0);
00715 m_solver.f (row, 1, 0.0);
00716 m_solver.f (row, 2, 0.0);
00717
00718 m_solver.K (row, grc2gl (i + 0, j + 0), -2.0 * weight);
00719 m_solver.K (row, grc2gl (i - 1, j + 0), 1.0 * weight);
00720 m_solver.K (row, grc2gl (i + 0, j - 1), 1.0 * weight);
00721
00722 row++;
00723 }
00724
00725 {
00726 int i = 0;
00727 int j = m_nurbs.m_cv_count[1] - 1;
00728
00729 m_solver.f (row, 0, 0.0);
00730 m_solver.f (row, 1, 0.0);
00731 m_solver.f (row, 2, 0.0);
00732
00733 m_solver.K (row, grc2gl (i + 0, j + 0), -2.0 * weight);
00734 m_solver.K (row, grc2gl (i + 1, j + 0), 1.0 * weight);
00735 m_solver.K (row, grc2gl (i + 0, j - 1), 1.0 * weight);
00736
00737 row++;
00738 }
00739
00740 }
00741
00742 void
00743 FittingSurface::addInteriorRegularisation (int order, int resU, int resV, double weight, unsigned &row)
00744 {
00745 double *N0 = new double[m_nurbs.Order (0) * m_nurbs.Order (0)];
00746 double *N1 = new double[m_nurbs.Order (1) * m_nurbs.Order (1)];
00747
00748 double dU = (m_maxU - m_minU) / resU;
00749 double dV = (m_maxV - m_minV) / resV;
00750
00751 for (int u = 0; u < resU; u++)
00752 {
00753 for (int v = 0; v < resV; v++)
00754 {
00755
00756 Vector2d params;
00757 params (0) = m_minU + u * dU + 0.5 * dU;
00758 params (1) = m_minV + v * dV + 0.5 * dV;
00759
00760
00761
00762 int E = ON_NurbsSpanIndex (m_nurbs.m_order[0], m_nurbs.m_cv_count[0], m_nurbs.m_knot[0], params (0), 0, 0);
00763 int F = ON_NurbsSpanIndex (m_nurbs.m_order[1], m_nurbs.m_cv_count[1], m_nurbs.m_knot[1], params (1), 0, 0);
00764
00765 ON_EvaluateNurbsBasis (m_nurbs.Order (0), m_nurbs.m_knot[0] + E, params (0), N0);
00766 ON_EvaluateNurbsBasis (m_nurbs.Order (1), m_nurbs.m_knot[1] + F, params (1), N1);
00767 ON_EvaluateNurbsBasisDerivatives (m_nurbs.Order (0), m_nurbs.m_knot[0] + E, order, N0);
00768 ON_EvaluateNurbsBasisDerivatives (m_nurbs.Order (1), m_nurbs.m_knot[1] + F, order, N1);
00769
00770 m_solver.f (row, 0, 0.0);
00771 m_solver.f (row, 1, 0.0);
00772 m_solver.f (row, 2, 0.0);
00773
00774 for (int i = 0; i < m_nurbs.Order (0); i++)
00775 {
00776
00777 for (int j = 0; j < m_nurbs.Order (1); j++)
00778 {
00779
00780 m_solver.K (row, lrc2gl (E, F, i, j),
00781 weight * (N0[order * m_nurbs.Order (0) + i] * N1[j] + N0[i] * N1[order * m_nurbs.Order (1) + j]));
00782
00783 }
00784
00785 }
00786
00787 row++;
00788
00789 }
00790 }
00791
00792 delete [] N1;
00793 delete [] N0;
00794 }
00795
00796 void
00797 FittingSurface::addBoundaryRegularisation (int order, int resU, int resV, double weight, unsigned &row)
00798 {
00799 double *N0 = new double[m_nurbs.Order (0) * m_nurbs.Order (0)];
00800 double *N1 = new double[m_nurbs.Order (1) * m_nurbs.Order (1)];
00801
00802 double dU = (m_maxU - m_minU) / resU;
00803 double dV = (m_maxV - m_minV) / resV;
00804
00805 for (int u = 0; u < resU; u++)
00806 {
00807
00808 Vector2d params;
00809 params (0) = m_minU + u * dU + 0.5 * dU;
00810 params (1) = m_minV;
00811
00812 int E = ON_NurbsSpanIndex (m_nurbs.m_order[0], m_nurbs.m_cv_count[0], m_nurbs.m_knot[0], params (0), 0, 0);
00813 int F = ON_NurbsSpanIndex (m_nurbs.m_order[1], m_nurbs.m_cv_count[1], m_nurbs.m_knot[1], params (1), 0, 0);
00814
00815 ON_EvaluateNurbsBasis (m_nurbs.Order (0), m_nurbs.m_knot[0] + E, params (0), N0);
00816 ON_EvaluateNurbsBasis (m_nurbs.Order (1), m_nurbs.m_knot[1] + F, params (1), N1);
00817 ON_EvaluateNurbsBasisDerivatives (m_nurbs.Order (0), m_nurbs.m_knot[0] + E, order, N0);
00818 ON_EvaluateNurbsBasisDerivatives (m_nurbs.Order (1), m_nurbs.m_knot[1] + F, order, N1);
00819
00820 m_solver.f (row, 0, 0.0);
00821 m_solver.f (row, 1, 0.0);
00822 m_solver.f (row, 2, 0.0);
00823
00824 for (int i = 0; i < m_nurbs.Order (0); i++)
00825 {
00826
00827 for (int j = 0; j < m_nurbs.Order (1); j++)
00828 {
00829
00830 m_solver.K (row, lrc2gl (E, F, i, j),
00831 weight * (N0[order * m_nurbs.Order (0) + i] * N1[j] + N0[i] * N1[order * m_nurbs.Order (1) + j]));
00832
00833 }
00834
00835 }
00836
00837 row++;
00838
00839 }
00840
00841 for (int u = 0; u < resU; u++)
00842 {
00843
00844 Vector2d params;
00845 params (0) = m_minU + u * dU + 0.5 * dU;
00846 params (1) = m_maxV;
00847
00848 int E = ON_NurbsSpanIndex (m_nurbs.m_order[0], m_nurbs.m_cv_count[0], m_nurbs.m_knot[0], params (0), 0, 0);
00849 int F = ON_NurbsSpanIndex (m_nurbs.m_order[1], m_nurbs.m_cv_count[1], m_nurbs.m_knot[1], params (1), 0, 0);
00850
00851 ON_EvaluateNurbsBasis (m_nurbs.Order (0), m_nurbs.m_knot[0] + E, params (0), N0);
00852 ON_EvaluateNurbsBasis (m_nurbs.Order (1), m_nurbs.m_knot[1] + F, params (1), N1);
00853 ON_EvaluateNurbsBasisDerivatives (m_nurbs.Order (0), m_nurbs.m_knot[0] + E, order, N0);
00854 ON_EvaluateNurbsBasisDerivatives (m_nurbs.Order (1), m_nurbs.m_knot[1] + F, order, N1);
00855
00856 m_solver.f (row, 0, 0.0);
00857 m_solver.f (row, 1, 0.0);
00858 m_solver.f (row, 2, 0.0);
00859
00860 for (int i = 0; i < m_nurbs.Order (0); i++)
00861 {
00862
00863 for (int j = 0; j < m_nurbs.Order (1); j++)
00864 {
00865
00866 m_solver.K (row, lrc2gl (E, F, i, j),
00867 weight * (N0[order * m_nurbs.Order (0) + i] * N1[j] + N0[i] * N1[order * m_nurbs.Order (1) + j]));
00868
00869 }
00870
00871 }
00872
00873 row++;
00874
00875 }
00876
00877 for (int v = 0; v < resV; v++)
00878 {
00879
00880 Vector2d params;
00881 params (0) = m_minU;
00882 params (1) = m_minV + v * dV + 0.5 * dV;
00883
00884 int E = ON_NurbsSpanIndex (m_nurbs.m_order[0], m_nurbs.m_cv_count[0], m_nurbs.m_knot[0], params (0), 0, 0);
00885 int F = ON_NurbsSpanIndex (m_nurbs.m_order[1], m_nurbs.m_cv_count[1], m_nurbs.m_knot[1], params (1), 0, 0);
00886
00887 ON_EvaluateNurbsBasis (m_nurbs.Order (0), m_nurbs.m_knot[0] + E, params (0), N0);
00888 ON_EvaluateNurbsBasis (m_nurbs.Order (1), m_nurbs.m_knot[1] + F, params (1), N1);
00889 ON_EvaluateNurbsBasisDerivatives (m_nurbs.Order (0), m_nurbs.m_knot[0] + E, order, N0);
00890 ON_EvaluateNurbsBasisDerivatives (m_nurbs.Order (1), m_nurbs.m_knot[1] + F, order, N1);
00891
00892 m_solver.f (row, 0, 0.0);
00893 m_solver.f (row, 1, 0.0);
00894 m_solver.f (row, 2, 0.0);
00895
00896 for (int i = 0; i < m_nurbs.Order (0); i++)
00897 {
00898
00899 for (int j = 0; j < m_nurbs.Order (1); j++)
00900 {
00901
00902 m_solver.K (row, lrc2gl (E, F, i, j),
00903 weight * (N0[order * m_nurbs.Order (0) + i] * N1[j] + N0[i] * N1[order * m_nurbs.Order (1) + j]));
00904
00905 }
00906
00907 }
00908
00909 row++;
00910
00911 }
00912
00913 for (int v = 0; v < resV; v++)
00914 {
00915
00916 Vector2d params;
00917 params (0) = m_maxU;
00918 params (1) = m_minV + v * dV + 0.5 * dV;
00919
00920 int E = ON_NurbsSpanIndex (m_nurbs.m_order[0], m_nurbs.m_cv_count[0], m_nurbs.m_knot[0], params (0), 0, 0);
00921 int F = ON_NurbsSpanIndex (m_nurbs.m_order[1], m_nurbs.m_cv_count[1], m_nurbs.m_knot[1], params (1), 0, 0);
00922
00923 ON_EvaluateNurbsBasis (m_nurbs.Order (0), m_nurbs.m_knot[0] + E, params (0), N0);
00924 ON_EvaluateNurbsBasis (m_nurbs.Order (1), m_nurbs.m_knot[1] + F, params (1), N1);
00925 ON_EvaluateNurbsBasisDerivatives (m_nurbs.Order (0), m_nurbs.m_knot[0] + E, order, N0);
00926 ON_EvaluateNurbsBasisDerivatives (m_nurbs.Order (1), m_nurbs.m_knot[1] + F, order, N1);
00927
00928 m_solver.f (row, 0, 0.0);
00929 m_solver.f (row, 1, 0.0);
00930 m_solver.f (row, 2, 0.0);
00931
00932 for (int i = 0; i < m_nurbs.Order (0); i++)
00933 {
00934
00935 for (int j = 0; j < m_nurbs.Order (1); j++)
00936 {
00937
00938 m_solver.K (row, lrc2gl (E, F, i, j),
00939 weight * (N0[order * m_nurbs.Order (0) + i] * N1[j] + N0[i] * N1[order * m_nurbs.Order (1) + j]));
00940
00941 }
00942
00943 }
00944
00945 row++;
00946
00947 }
00948
00949 delete [] N1;
00950 delete [] N0;
00951 }
00952
00953 Vector2d
00954 FittingSurface::inverseMapping (const ON_NurbsSurface &nurbs, const Vector3d &pt, const Vector2d &hint, double &error,
00955 Vector3d &p, Vector3d &tu, Vector3d &tv, int maxSteps, double accuracy, bool quiet)
00956 {
00957
00958 double pointAndTangents[9];
00959
00960 Vector2d current, delta;
00961 Matrix2d A;
00962 Vector2d b;
00963 Vector3d r;
00964 std::vector<double> elementsU = getElementVector (nurbs, 0);
00965 std::vector<double> elementsV = getElementVector (nurbs, 1);
00966 double minU = elementsU[0];
00967 double minV = elementsV[0];
00968 double maxU = elementsU[elementsU.size () - 1];
00969 double maxV = elementsV[elementsV.size () - 1];
00970
00971 current = hint;
00972
00973 for (int k = 0; k < maxSteps; k++)
00974 {
00975
00976 nurbs.Evaluate (current (0), current (1), 1, 3, pointAndTangents);
00977 p (0) = pointAndTangents[0];
00978 p (1) = pointAndTangents[1];
00979 p (2) = pointAndTangents[2];
00980 tu (0) = pointAndTangents[3];
00981 tu (1) = pointAndTangents[4];
00982 tu (2) = pointAndTangents[5];
00983 tv (0) = pointAndTangents[6];
00984 tv (1) = pointAndTangents[7];
00985 tv (2) = pointAndTangents[8];
00986
00987 r = p - pt;
00988
00989 b (0) = -r.dot (tu);
00990 b (1) = -r.dot (tv);
00991
00992 A (0, 0) = tu.dot (tu);
00993 A (0, 1) = tu.dot (tv);
00994 A (1, 0) = A (0, 1);
00995 A (1, 1) = tv.dot (tv);
00996
00997 delta = A.ldlt ().solve (b);
00998
00999 if (delta.norm () < accuracy)
01000 {
01001
01002 error = r.norm ();
01003 return current;
01004
01005 }
01006 else
01007 {
01008 current = current + delta;
01009
01010 if (current (0) < minU)
01011 current (0) = minU;
01012 else if (current (0) > maxU)
01013 current (0) = maxU;
01014
01015 if (current (1) < minV)
01016 current (1) = minV;
01017 else if (current (1) > maxV)
01018 current (1) = maxV;
01019
01020 }
01021
01022 }
01023
01024 error = r.norm ();
01025
01026 if (!quiet)
01027 {
01028 printf ("[FittingSurface::inverseMapping] Warning: Method did not converge (%e %d)\n", accuracy, maxSteps);
01029 printf (" %f %f ... %f %f\n", hint (0), hint (1), current (0), current (1));
01030 }
01031
01032 return current;
01033
01034 }
01035
01036 Vector2d
01037 FittingSurface::inverseMapping (const ON_NurbsSurface &nurbs, const Vector3d &pt, const Vector2d &hint, Vector3d &p,
01038 int maxSteps, double accuracy, bool quiet)
01039 {
01040
01041 double pointAndTangents[9];
01042
01043 Vector2d current, delta;
01044 Matrix2d A;
01045 Vector2d b;
01046 Vector3d r, tu, tv;
01047 std::vector<double> elementsU = getElementVector (nurbs, 0);
01048 std::vector<double> elementsV = getElementVector (nurbs, 1);
01049 double minU = elementsU[0];
01050 double minV = elementsV[0];
01051 double maxU = elementsU[elementsU.size () - 1];
01052 double maxV = elementsV[elementsV.size () - 1];
01053
01054 current = hint;
01055
01056 for (int k = 0; k < maxSteps; k++)
01057 {
01058
01059 nurbs.Evaluate (current (0), current (1), 1, 3, pointAndTangents);
01060 p (0) = pointAndTangents[0];
01061 p (1) = pointAndTangents[1];
01062 p (2) = pointAndTangents[2];
01063 tu (0) = pointAndTangents[3];
01064 tu (1) = pointAndTangents[4];
01065 tu (2) = pointAndTangents[5];
01066 tv (0) = pointAndTangents[6];
01067 tv (1) = pointAndTangents[7];
01068 tv (2) = pointAndTangents[8];
01069
01070 r = p - pt;
01071
01072 b (0) = -r.dot (tu);
01073 b (1) = -r.dot (tv);
01074
01075 A (0, 0) = tu.dot (tu);
01076 A (0, 1) = tu.dot (tv);
01077 A (1, 0) = A (0, 1);
01078 A (1, 1) = tv.dot (tv);
01079
01080 delta = A.ldlt ().solve (b);
01081
01082 if (delta.norm () < accuracy)
01083 {
01084 return current;
01085 }
01086 else
01087 {
01088 current = current + delta;
01089
01090 if (current (0) < minU)
01091 current (0) = minU;
01092 else if (current (0) > maxU)
01093 current (0) = maxU;
01094
01095 if (current (1) < minV)
01096 current (1) = minV;
01097 else if (current (1) > maxV)
01098 current (1) = maxV;
01099
01100 }
01101
01102 }
01103
01104 if (!quiet)
01105 {
01106 printf ("[FittingSurface::inverseMapping] Warning: Method did not converge (%e %d)\n", accuracy, maxSteps);
01107 printf (" %f %f ... %f %f\n", hint (0), hint (1), current (0), current (1));
01108 }
01109
01110 return current;
01111
01112 }
01113
01114 Vector2d
01115 FittingSurface::findClosestElementMidPoint (const ON_NurbsSurface &nurbs, const Vector3d &pt)
01116 {
01117 Vector2d hint;
01118 Vector3d r;
01119 std::vector<double> elementsU = getElementVector (nurbs, 0);
01120 std::vector<double> elementsV = getElementVector (nurbs, 1);
01121
01122 double d_shortest (DBL_MAX);
01123 for (unsigned i = 0; i < elementsU.size () - 1; i++)
01124 {
01125 for (unsigned j = 0; j < elementsV.size () - 1; j++)
01126 {
01127 double points[3];
01128 double d;
01129
01130 double xi = elementsU[i] + 0.5 * (elementsU[i + 1] - elementsU[i]);
01131 double eta = elementsV[j] + 0.5 * (elementsV[j + 1] - elementsV[j]);
01132
01133 nurbs.Evaluate (xi, eta, 0, 3, points);
01134 r (0) = points[0] - pt (0);
01135 r (1) = points[1] - pt (1);
01136 r (2) = points[2] - pt (2);
01137
01138 d = r.squaredNorm ();
01139
01140 if ((i == 0 && j == 0) || d < d_shortest)
01141 {
01142 d_shortest = d;
01143 hint (0) = xi;
01144 hint (1) = eta;
01145 }
01146 }
01147 }
01148
01149 return hint;
01150 }
01151
01152 Vector2d
01153 FittingSurface::inverseMappingBoundary (const ON_NurbsSurface &nurbs, const Vector3d &pt, double &error, Vector3d &p,
01154 Vector3d &tu, Vector3d &tv, int maxSteps, double accuracy, bool quiet)
01155 {
01156
01157 Vector2d result;
01158 double min_err = 100.0;
01159 std::vector<myvec> ini_points;
01160 double err_tmp;
01161 Vector3d p_tmp, tu_tmp, tv_tmp;
01162
01163 std::vector<double> elementsU = getElementVector (nurbs, 0);
01164 std::vector<double> elementsV = getElementVector (nurbs, 1);
01165
01166
01167 for (unsigned i = 0; i < (elementsV.size () - 1); i++)
01168 {
01169 ini_points.push_back (myvec (WEST, elementsV[i] + 0.5 * (elementsV[i + 1] - elementsV[i])));
01170 ini_points.push_back (myvec (EAST, elementsV[i] + 0.5 * (elementsV[i + 1] - elementsV[i])));
01171 }
01172
01173
01174 for (unsigned i = 0; i < (elementsU.size () - 1); i++)
01175 {
01176 ini_points.push_back (myvec (NORTH, elementsU[i] + 0.5 * (elementsU[i + 1] - elementsU[i])));
01177 ini_points.push_back (myvec (SOUTH, elementsU[i] + 0.5 * (elementsU[i + 1] - elementsU[i])));
01178 }
01179
01180 for (unsigned i = 0; i < ini_points.size (); i++)
01181 {
01182
01183 Vector2d params = inverseMappingBoundary (nurbs, pt, ini_points[i].side, ini_points[i].hint, err_tmp, p_tmp,
01184 tu_tmp, tv_tmp, maxSteps, accuracy, quiet);
01185
01186 if (i == 0 || err_tmp < min_err)
01187 {
01188 min_err = err_tmp;
01189 result = params;
01190 p = p_tmp;
01191 tu = tu_tmp;
01192 tv = tv_tmp;
01193 }
01194 }
01195
01196 error = min_err;
01197 return result;
01198
01199 }
01200
01201 Vector2d
01202 FittingSurface::inverseMappingBoundary (const ON_NurbsSurface &nurbs, const Vector3d &pt, int side, double hint,
01203 double &error, Vector3d &p, Vector3d &tu, Vector3d &tv, int maxSteps,
01204 double accuracy, bool quiet)
01205 {
01206
01207 double pointAndTangents[9];
01208 double current, delta;
01209 Vector3d r, t;
01210 Vector2d params;
01211
01212 current = hint;
01213
01214 std::vector<double> elementsU = getElementVector (nurbs, 0);
01215 std::vector<double> elementsV = getElementVector (nurbs, 1);
01216 double minU = elementsU[0];
01217 double minV = elementsV[0];
01218 double maxU = elementsU[elementsU.size () - 1];
01219 double maxV = elementsV[elementsV.size () - 1];
01220
01221 for (int k = 0; k < maxSteps; k++)
01222 {
01223
01224 switch (side)
01225 {
01226
01227 case WEST:
01228
01229 params (0) = minU;
01230 params (1) = current;
01231 nurbs.Evaluate (minU, current, 1, 3, pointAndTangents);
01232 p (0) = pointAndTangents[0];
01233 p (1) = pointAndTangents[1];
01234 p (2) = pointAndTangents[2];
01235 tu (0) = pointAndTangents[3];
01236 tu (1) = pointAndTangents[4];
01237 tu (2) = pointAndTangents[5];
01238 tv (0) = pointAndTangents[6];
01239 tv (1) = pointAndTangents[7];
01240 tv (2) = pointAndTangents[8];
01241
01242 t = tv;
01243
01244 break;
01245 case SOUTH:
01246
01247 params (0) = current;
01248 params (1) = maxV;
01249 nurbs.Evaluate (current, maxV, 1, 3, pointAndTangents);
01250 p (0) = pointAndTangents[0];
01251 p (1) = pointAndTangents[1];
01252 p (2) = pointAndTangents[2];
01253 tu (0) = pointAndTangents[3];
01254 tu (1) = pointAndTangents[4];
01255 tu (2) = pointAndTangents[5];
01256 tv (0) = pointAndTangents[6];
01257 tv (1) = pointAndTangents[7];
01258 tv (2) = pointAndTangents[8];
01259
01260 t = tu;
01261
01262 break;
01263 case EAST:
01264
01265 params (0) = maxU;
01266 params (1) = current;
01267 nurbs.Evaluate (maxU, current, 1, 3, pointAndTangents);
01268 p (0) = pointAndTangents[0];
01269 p (1) = pointAndTangents[1];
01270 p (2) = pointAndTangents[2];
01271 tu (0) = pointAndTangents[3];
01272 tu (1) = pointAndTangents[4];
01273 tu (2) = pointAndTangents[5];
01274 tv (0) = pointAndTangents[6];
01275 tv (1) = pointAndTangents[7];
01276 tv (2) = pointAndTangents[8];
01277
01278 t = tv;
01279
01280 break;
01281 case NORTH:
01282
01283 params (0) = current;
01284 params (1) = minV;
01285 nurbs.Evaluate (current, minV, 1, 3, pointAndTangents);
01286 p (0) = pointAndTangents[0];
01287 p (1) = pointAndTangents[1];
01288 p (2) = pointAndTangents[2];
01289 tu (0) = pointAndTangents[3];
01290 tu (1) = pointAndTangents[4];
01291 tu (2) = pointAndTangents[5];
01292 tv (0) = pointAndTangents[6];
01293 tv (1) = pointAndTangents[7];
01294 tv (2) = pointAndTangents[8];
01295
01296 t = tu;
01297
01298 break;
01299 default:
01300 throw std::runtime_error ("[FittingSurface::inverseMappingBoundary] ERROR: Specify a boundary!");
01301
01302 }
01303
01304 r (0) = pointAndTangents[0] - pt (0);
01305 r (1) = pointAndTangents[1] - pt (1);
01306 r (2) = pointAndTangents[2] - pt (2);
01307
01308 delta = -0.5 * r.dot (t) / t.dot (t);
01309
01310 if (fabs (delta) < accuracy)
01311 {
01312
01313 error = r.norm ();
01314 return params;
01315
01316 }
01317 else
01318 {
01319
01320 current = current + delta;
01321
01322 bool stop = false;
01323
01324 switch (side)
01325 {
01326
01327 case WEST:
01328 case EAST:
01329 if (current < minV)
01330 {
01331 params (1) = minV;
01332 stop = true;
01333 }
01334 else if (current > maxV)
01335 {
01336 params (1) = maxV;
01337 stop = true;
01338 }
01339
01340 break;
01341
01342 case NORTH:
01343 case SOUTH:
01344 if (current < minU)
01345 {
01346 params (0) = minU;
01347 stop = true;
01348 }
01349 else if (current > maxU)
01350 {
01351 params (0) = maxU;
01352 stop = true;
01353 }
01354
01355 break;
01356 }
01357
01358 if (stop)
01359 {
01360 error = r.norm ();
01361 return params;
01362 }
01363
01364 }
01365
01366 }
01367
01368 error = r.norm ();
01369 if (!quiet)
01370 printf (
01371 "[FittingSurface::inverseMappingBoundary] Warning: Method did not converge! (residual: %f, delta: %f, params: %f %f)\n",
01372 error, delta, params (0), params (1));
01373
01374 return params;
01375 }