fitting_surface_pdm.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2012-, Open Perception, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the copyright holder(s) nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
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 //FittingSurface::FittingSurface(int order, NurbsDataSurface *m_data, ON_3dPoint ll, ON_3dPoint lr,
00046 //    ON_3dPoint ur, ON_3dPoint ul)
00047 //{
00048 //  if (order < 2)
00049 //    throw std::runtime_error("[FittingSurface::FittingSurface] Error order to low (order<2).");
00050 //
00051 //  ON::Begin();
00052 //
00053 //  this->m_data = m_data;
00054 //
00055 //  m_nurbs = initNurbs4Corners(order, ll, lr, ur, ul);
00056 //
00057 //  this->init();
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   // boundary points should lie on edges of surface
00147   if (nBnd > 0)
00148     assembleBoundary (param.boundary_weight, row);
00149 
00150   // interior points should lie on surface
00151   if (nInt > 0)
00152     assembleInterior (param.interior_weight, row);
00153 
00154   // minimal curvature on surface
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   // minimal curvature on boundary
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   // cage regularisation
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   //for(int E=(m_nurbs.Order(0)-2); E<(m_nurbs.KnotCount(0)-m_nurbs.Order(0)+2); E++) {
00261   for (int E = idx_min + 1; E <= idx_max; E++)
00262   {
00263 
00264     if (knots[E] != knots[E - 1]) // do not count double knots
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     // inverse mapping
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; // seems that the eigenvalues are dependent on the number of points (???)
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   // +- 2 sigma -> 95,45 % aller Messwerte
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; // seems that the eigenvalues are dependent on the number of points (???)
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 &params, 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     } // j
00554 
00555   } // i
00556 
00557   row++;
00558 
00559   delete [] N1;
00560   delete [] N0;
00561 }
00562 
00563 //void FittingSurface::addBoundaryPointConstraint(double paramU, double paramV, double weight, unsigned &row)
00564 //{
00565 //  // edges on surface
00566 //  NurbsTools ntools(&m_nurbs);
00567 //
00568 //  double N0[m_nurbs.Order(0) * m_nurbs.Order(0)];
00569 //  double N1[m_nurbs.Order(1) * m_nurbs.Order(1)];
00570 //
00571 //  double points[3];
00572 //  int E, F;
00573 //  ON_3dPoint closest;
00574 //  int closest_idx;
00575 //
00576 //  m_nurbs.Evaluate(paramU, paramV, 0, 3, points);
00577 //  closest.x = points[0];
00578 //  closest.y = points[1];
00579 //  closest.z = points[2];
00580 //  m_data->boundary.GetClosestPoint(closest, &closest_idx);
00581 //
00582 //  E = ntools.E(paramU);
00583 //  F = ntools.F(paramV);
00584 //  ON_EvaluateNurbsBasis(m_nurbs.Order(0), m_nurbs.m_knot[0] + E, paramU, N0);
00585 //  ON_EvaluateNurbsBasis(m_nurbs.Order(1), m_nurbs.m_knot[1] + F, paramV, N1);
00586 //
00587 //  m_feig(row, 0) = m_data->boundary[closest_idx].x * weight;
00588 //  m_feig(row, 1) = m_data->boundary[closest_idx].y * weight;
00589 //  m_feig(row, 2) = m_data->boundary[closest_idx].z * weight;
00590 //
00591 //  for (int i = 0; i < m_nurbs.Order(0); i++) {
00592 //
00593 //    for (int j = 0; j < m_nurbs.Order(1); j++) {
00594 //#ifdef USE_UMFPACK
00595 //      m_solver.K(row, lrc2gl(E, F, i, j), N0[i] * N1[j] * weight);
00596 //#else
00597 //      m_Keig(row, lrc2gl(E, F, i, j)) = N0[i] * N1[j] * weight;
00598 //#endif
00599 //
00600 //    } // j
00601 //
00602 //  } // i
00603 //
00604 //  row++;
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   { // NORTH-WEST
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   { // NORTH-EAST
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   { // SOUTH-EAST
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   { // SOUTH-WEST
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       //                        printf("%f %f, %f %f\n", m_minU, dU, params(0), params(1));
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); // derivative order?
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         } // i
00784 
00785       } // j
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); // derivative order?
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       } // i
00834 
00835     } // j
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); // derivative order?
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       } // i
00870 
00871     } // j
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); // derivative order?
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       } // i
00906 
00907     } // j
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); // derivative order?
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       } // i
00942 
00943     } // j
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   // NORTH - SOUTH
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   // WEST - EAST
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; // use 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; // use 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; // use 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; // use 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 }


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:24:10