global_optimization_tdm.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 <pcl/surface/on_nurbs/global_optimization_tdm.h>
00039 #include <pcl/surface/on_nurbs/closing_boundary.h>
00040 #include <stdexcept>
00041 
00042 using namespace pcl;
00043 using namespace on_nurbs;
00044 using namespace Eigen;
00045 
00046 GlobalOptimizationTDM::GlobalOptimizationTDM (const std::vector<NurbsDataSurface*> &data,
00047                                               const std::vector<ON_NurbsSurface*> &nurbs) :
00048   GlobalOptimization (data, nurbs)
00049 {
00050 }
00051 
00052 void
00053 GlobalOptimizationTDM::assemble (Parameter params)
00054 {
00055   // determine number of rows of matrix
00056   m_ncols = 0;
00057   unsigned nnurbs = static_cast<unsigned> (m_nurbs.size ());
00058   unsigned nInt (0), nBnd (0), nCageRegInt (0), nCageRegBnd (0), nCommonBnd (0);
00059   for (unsigned i = 0; i < nnurbs; i++)
00060   {
00061     nInt += static_cast<unsigned> (m_data[i]->interior.size ());
00062     nBnd += static_cast<unsigned> (m_data[i]->boundary.size ());
00063     nCommonBnd += static_cast<unsigned> (m_data[i]->common_boundary_point.size ());
00064     nCageRegInt += (m_nurbs[i]->m_cv_count[0] - 2) * (m_nurbs[i]->m_cv_count[1] - 2);
00065     nCageRegBnd += 2 * (m_nurbs[i]->m_cv_count[0] - 1) + 2 * (m_nurbs[i]->m_cv_count[1] - 1);
00066     m_ncols += m_nurbs[i]->CVCount ();
00067   }
00068 
00069   m_nrows = 0;
00070   if (params.interior_weight > 0.0)
00071     m_nrows += nInt;
00072   if (params.boundary_weight > 0.0)
00073     m_nrows += nBnd;
00074   if (params.interior_smoothness > 0.0)
00075     m_nrows += nCageRegInt;
00076   if (params.boundary_smoothness > 0.0)
00077     m_nrows += nCageRegBnd;
00078   if (params.closing_weight > 0.0)
00079   {
00080     if (params.closing_samples > 0)
00081       m_nrows += (4 * params.closing_samples);
00082     else
00083       m_nrows += nBnd;
00084   }
00085   if (params.common_weight > 0.0)
00086     m_nrows += nCommonBnd;
00087 
00088   m_nrows *= 3;
00089   m_ncols *= 3;
00090 
00091   m_solver.assign (m_nrows, m_ncols, 1);
00092 
00093   for (unsigned i = 0; i < m_data.size (); i++)
00094     m_data[i]->common_boundary_param.clear ();
00095 
00096   // assemble matrix
00097   unsigned row (0);
00098   int ncps (0);
00099 
00100   for (unsigned id = 0; id < nnurbs; id++)
00101   {
00102 
00103     // interior points should lie on surface
00104     assembleInteriorPoints (id, ncps, params.interior_weight, row);
00105 
00106     // boundary points should lie on boundary of surface
00107     assembleBoundaryPoints (id, ncps, params.boundary_weight, row);
00108 
00109     // cage regularisation
00110     assembleRegularisation (id, ncps, params.interior_smoothness, params.boundary_smoothness, row);
00111 
00112     // closing boundaries
00113     assembleClosingBoundaries (id, params.closing_samples, params.closing_sigma, params.closing_weight, row);
00114 
00115     // common boundaries
00116     assembleCommonBoundaries (id, params.common_weight, row);
00117 
00118     ncps += m_nurbs[id]->CVCount ();
00119   }
00120 }
00121 
00122 void
00123 GlobalOptimizationTDM::assemble (ParameterTDM params)
00124 {
00125   // determine number of rows of matrix
00126   m_ncols = 0;
00127   unsigned nnurbs = static_cast<unsigned> (m_nurbs.size ());
00128   unsigned nInt (0), nBnd (0), nCageRegInt (0), nCageRegBnd (0), nCommonBnd (0), nCommonPar (0);
00129   for (unsigned i = 0; i < nnurbs; i++)
00130   {
00131     nInt += static_cast<unsigned> (m_data[i]->interior.size ());
00132     nBnd += static_cast<unsigned> (m_data[i]->boundary.size ());
00133     nCommonBnd += static_cast<unsigned> (m_data[i]->common_boundary_point.size ());
00134     nCommonPar += static_cast<unsigned> (m_data[i]->common_idx.size ());
00135     nCageRegInt += (m_nurbs[i]->m_cv_count[0] - 2) * (m_nurbs[i]->m_cv_count[1] - 2);
00136     nCageRegBnd += 2 * (m_nurbs[i]->m_cv_count[0] - 1) + 2 * (m_nurbs[i]->m_cv_count[1] - 1);
00137     m_ncols += m_nurbs[i]->CVCount ();
00138   }
00139 
00140   m_nrows = 0;
00141   if (params.interior_weight > 0.0)
00142     m_nrows += nInt;
00143   if (params.boundary_weight > 0.0)
00144     m_nrows += nBnd;
00145   if (params.interior_smoothness > 0.0)
00146     m_nrows += nCageRegInt;
00147   if (params.boundary_smoothness > 0.0)
00148     m_nrows += nCageRegBnd;
00149   if (params.closing_weight > 0.0)
00150   {
00151     if (params.closing_samples > 0)
00152       m_nrows += (4 * params.closing_samples) * nnurbs * (nnurbs - 1);
00153     else
00154       m_nrows += nBnd;
00155   }
00156   if (params.common_weight > 0.0)
00157   {
00158     m_nrows += nCommonBnd;
00159     m_nrows += nCommonPar;
00160   }
00161 
00162   m_nrows *= 3;
00163   m_ncols *= 3;
00164 
00165   m_solver.assign (m_nrows, m_ncols, 1);
00166 
00167   //  for (unsigned i = 0; i < m_data.size (); i++)
00168   //    m_data[i]->common_boundary_param.clear ();
00169 
00170   // assemble matrix
00171   unsigned row (0);
00172   int ncps (0);
00173 
00174   for (unsigned id = 0; id < nnurbs; id++)
00175   {
00176 
00177     // interior points should lie on surface
00178     assembleInteriorPointsTD (id, ncps, params.interior_tangent_weight, params.interior_weight, row);
00179 
00180     // boundary points should lie on boundary of surface
00181     assembleBoundaryPoints (id, ncps, params.boundary_weight, row);
00182 
00183     // cage regularisation
00184     assembleRegularisation (id, ncps, params.interior_smoothness, params.boundary_smoothness, row);
00185 
00186     // closing boundaries
00187     assembleClosingBoundariesTD (id, params.closing_samples, params.closing_sigma, params.closing_tangent_weight,
00188                                  params.closing_weight, row);
00189 
00190     // common boundaries
00191     //    assembleCommonBoundaries (id, params.common_weight, row);
00192 
00193     assembleCommonParams (id, params.common_weight, row);
00194 
00195     ncps += m_nurbs[id]->CVCount ();
00196   }
00197 }
00198 
00199 void
00200 GlobalOptimizationTDM::solve (double damp)
00201 {
00202   if (m_solver.solve ())
00203     updateSurf (damp);
00204 }
00205 
00206 void
00207 GlobalOptimizationTDM::updateSurf (double damp)
00208 {
00209   int ncps (0);
00210 
00211   for (unsigned i = 0; i < m_nurbs.size (); i++)
00212   {
00213     ON_NurbsSurface* nurbs = m_nurbs[i];
00214 
00215     int ncp = nurbs->CVCount ();
00216 
00217     for (int A = 0; A < ncp; A++)
00218     {
00219 
00220       int I = gl2gr (*nurbs, A);
00221       int J = gl2gc (*nurbs, A);
00222 
00223       ON_3dPoint cp_prev;
00224       nurbs->GetCV (I, J, cp_prev);
00225 
00226       ON_3dPoint cp;
00227       cp.x = cp_prev.x + damp * (m_solver.x (3 * (ncps + A) + 0, 0) - cp_prev.x);
00228       cp.y = cp_prev.y + damp * (m_solver.x (3 * (ncps + A) + 1, 0) - cp_prev.y);
00229       cp.z = cp_prev.z + damp * (m_solver.x (3 * (ncps + A) + 2, 0) - cp_prev.z);
00230 
00231       nurbs->SetCV (I, J, cp);
00232     }
00233 
00234     ncps += ncp;
00235   }
00236 }
00237 
00238 void
00239 GlobalOptimizationTDM::assembleCommonParams (unsigned id1, double weight, unsigned &row)
00240 {
00241   if (weight <= 0.0)
00242     return;
00243 
00244   NurbsDataSurface *data = m_data[id1];
00245   //ON_NurbsSurface *nurbs = this->m_nurbs[id1];
00246 
00247   for (size_t i = 0; i < data->common_idx.size (); i++)
00248   {
00249     //    Eigen::Vector3d n, tu, tv;
00250     //    Eigen::Vector2d &param1 = data->common_param1[i];
00251     //    double pt[9];
00252     //    nurbs->Evaluate(param1(0),param1(1), 1, 3, pt);
00253     //    tu = Eigen::Vector3d(pt[3], pt[4], pt[5]);
00254     //    tv = Eigen::Vector3d(pt[6], pt[7], pt[8]);
00255     //    tu.normalize();
00256     //    tv.normalize();
00257     //    n = tu.cross(tv);
00258     addParamConstraint (Eigen::Vector2i (id1, data->common_idx[i]), data->common_param1[i], data->common_param2[i],
00259                         weight, row);
00260   }
00261 }
00262 
00263 void
00264 GlobalOptimizationTDM::assembleCommonBoundaries (unsigned id1, double weight, unsigned &row)
00265 {
00266   if (weight <= 0.0)
00267     return;
00268 
00269   //  double ds = 1.0 / (2.0 * sigma * sigma);
00270   Eigen::Vector3d p1, tu1, tv1, p2, tu2, tv2, t1, t2;
00271   Eigen::Vector2d params1, params2;
00272   double error1, error2;
00273   NurbsDataSurface *data1 = m_data[id1];
00274   ON_NurbsSurface* nurbs1 = m_nurbs[id1];
00275 
00276   if (nurbs1->m_order[0] != nurbs1->m_order[1])
00277     printf ("[GlobalOptimizationTDM::assembleCommonBoundaries] Warning, order in u and v direction differ (nurbs1).\n");
00278 
00279   for (unsigned i = 0; i < data1->common_boundary_point.size (); i++)
00280   {
00281     Eigen::Vector3d p0 = data1->common_boundary_point[i];
00282     Eigen::Vector2i id (id1, data1->common_boundary_idx[i]);
00283 
00284     if (id (1) < 0 || id (1) >= static_cast<int> (m_nurbs.size ()))
00285       throw std::runtime_error (
00286                                 "[GlobalOptimizationTDM::assembleCommonBoundaries] Error, common boundary index out of bounds.\n");
00287 
00288     ON_NurbsSurface* nurbs2 = m_nurbs[id (1)];
00289     double w (1.0);
00290 
00291     if (nurbs2->m_order[0] != nurbs2->m_order[1])
00292       printf (
00293               "[GlobalOptimizationTDM::assembleCommonBoundaries] Warning, order in u and v direction differ (nurbs2).\n");
00294 
00295     if (nurbs1->m_order[0] == nurbs2->m_order[0])
00296     {
00297       params1 = FittingSurface::inverseMappingBoundary (*m_nurbs[id (0)], p0, error1, p1, tu1, tv1, im_max_steps,
00298                                                         im_accuracy, true);
00299       params2 = FittingSurface::inverseMappingBoundary (*m_nurbs[id (1)], p0, error2, p2, tu2, tv2, im_max_steps,
00300                                                         im_accuracy, true);
00301 
00302       if (params1 (0) == 0.0 || params1 (0) == 1.0)
00303         t1 = tv1;
00304       if (params1 (1) == 0.0 || params1 (1) == 1.0)
00305         t1 = tu1;
00306       if (params2 (0) == 0.0 || params2 (0) == 1.0)
00307         t2 = tv2;
00308       if (params2 (1) == 0.0 || params2 (1) == 1.0)
00309         t2 = tu2;
00310 
00311       t1.normalize ();
00312       t2.normalize ();
00313 
00314       // weight according to parallel-ness of boundaries
00315       w = t1.dot (t2);
00316       if (w < 0.0)
00317         w = -w;
00318     }
00319     else
00320     {
00321 
00322       if (nurbs1->m_order[0] < nurbs2->m_order[0])
00323       {
00324         params1 = FittingSurface::findClosestElementMidPoint (*m_nurbs[id (0)], p0);
00325         params1 = FittingSurface::inverseMapping (*m_nurbs[id (0)], p0, params1, error1, p1, tu1, tv1, im_max_steps,
00326                                                   im_accuracy, true);
00327         params2 = FittingSurface::inverseMappingBoundary (*m_nurbs[id (1)], p0, error2, p2, tu2, tv2, im_max_steps,
00328                                                           im_accuracy, true);
00329       }
00330       else
00331       {
00332         params1 = FittingSurface::inverseMappingBoundary (*m_nurbs[id (0)], p0, error1, p1, tu1, tv1, im_max_steps,
00333                                                           im_accuracy, true);
00334         params2 = FittingSurface::findClosestElementMidPoint (*m_nurbs[id (1)], p0);
00335         params2 = FittingSurface::inverseMapping (*m_nurbs[id (1)], p0, params2, error2, p2, tu2, tv2, im_max_steps,
00336                                                   im_accuracy);
00337       }
00338 
00339     }
00340 
00341     //m_dbgWin->AddPoint3D(p1(0), p1(1), p1(2), 255, 0, 0, 1.0);
00342     //m_dbgWin->AddPoint3D(p2(0), p2(1), p2(2), 255, 0, 0, 1.0);
00343 
00344     m_data[id (0)]->common_boundary_param.push_back (params1);
00345     m_data[id (1)]->common_boundary_param.push_back (params2);
00346 
00347     //    double error = (p1-p2).norm();
00348     //    double w = weight * exp(-(error * error) * ds);
00349     addParamConstraint (id, params1, params2, weight * w, row);
00350 
00351   }
00352 }
00353 
00354 void
00355 GlobalOptimizationTDM::assembleClosingBoundaries (unsigned id, unsigned samples, double sigma, double weight,
00356                                                   unsigned &row)
00357 {
00358   if (weight <= 0.0 || samples <= 0 || sigma < 0.0)
00359     return;
00360 
00361   double ds = 1.0 / (2.0 * sigma * sigma);
00362 
00363   ON_NurbsSurface *nurbs1 = m_nurbs[id];
00364 
00365   // sample point list from nurbs1
00366   vector_vec3d boundary1, boundary2;
00367   vector_vec2d params1, params2;
00368   ClosingBoundary::sampleFromBoundary (nurbs1, boundary1, params1, samples);
00369 
00370   // for each other nurbs
00371   for (unsigned n2 = (id + 1); n2 < m_nurbs.size (); n2++)
00372   {
00373     ON_NurbsSurface *nurbs2 = m_nurbs[n2];
00374 
00375     // find closest point to boundary
00376     for (unsigned i = 0; i < boundary1.size (); i++)
00377     {
00378       double error;
00379       Eigen::Vector3d p, tu, tv;
00380       Eigen::Vector2d params;
00381       Eigen::Vector3d p0 = boundary1[i];
00382 
00383       params = FittingSurface::inverseMappingBoundary (*nurbs2, p0, error, p, tu, tv, im_max_steps, im_accuracy, true);
00384 
00385       //      boundary2.push_back(p);
00386       //      params2.push_back(params);
00387 
00388       //      double dist = (p - p0).norm();
00389       //      if (error < max_error && dist < max_dist) {
00390       double w = weight * exp (-(error * error) * ds);
00391       addParamConstraint (Eigen::Vector2i (id, n2), params1[i], params, w, row);
00392       //      }
00393     }
00394   }
00395 }
00396 
00397 void
00398 GlobalOptimizationTDM::assembleClosingBoundariesTD (unsigned id, unsigned samples, double sigma, double wTangent,
00399                                                     double weight, unsigned &row)
00400 {
00401   if (weight <= 0.0 || samples <= 0 || sigma < 0.0)
00402     return;
00403 
00404   double ds = 1.0 / (2.0 * sigma * sigma);
00405 
00406   ON_NurbsSurface *nurbs1 = m_nurbs[id];
00407 
00408   // sample point list from nurbs1
00409   vector_vec3d boundary1, boundary2;
00410   vector_vec2d params1, params2;
00411   ClosingBoundary::sampleFromBoundary (nurbs1, boundary1, params1, samples);
00412 
00413   // for each other nurbs
00414   //  for (unsigned n2 = (id + 1); n2 < m_nurbs.size(); n2++) {
00415   for (unsigned n2 = 0; n2 < m_nurbs.size (); n2++)
00416   {
00417     if (id == n2)
00418       continue;
00419     ON_NurbsSurface *nurbs2 = m_nurbs[n2];
00420 
00421     // find closest point to boundary
00422     for (unsigned i = 0; i < boundary1.size (); i++)
00423     {
00424       double error;
00425       Eigen::Vector3d p, n, tu, tv;
00426       Eigen::Vector2d params;
00427       Eigen::Vector3d p0 = boundary1[i];
00428 
00429       params = FittingSurface::inverseMappingBoundary (*nurbs2, p0, error, p, tu, tv, im_max_steps, im_accuracy, true);
00430 
00431       tu.normalize ();
00432       tv.normalize ();
00433       n = tu.cross (tv);
00434 
00435       //      boundary2.push_back(p);
00436       //      params2.push_back(params);
00437 
00438       //      double dist = (p - p0).norm();
00439       //      if (error < max_error && dist < max_dist) {
00440       double w = weight * exp (-(error * error) * ds);
00441       addParamConstraintTD (Eigen::Vector2i (id, n2), params1[i], params, n, tu, tv, wTangent, w, row);
00442       //      }
00443     }
00444   }
00445 }
00446 
00447 void
00448 GlobalOptimizationTDM::assembleInteriorPoints (unsigned id, int ncps, double weight, unsigned &row)
00449 {
00450   if (weight <= 0.0)
00451     return;
00452 
00453   ON_NurbsSurface *nurbs = m_nurbs[id];
00454   NurbsDataSurface *data = m_data[id];
00455   unsigned nInt = static_cast<unsigned> (m_data[id]->interior.size ());
00456 
00457   // interior points should lie on surface
00458   data->interior_line_start.clear ();
00459   data->interior_line_end.clear ();
00460   data->interior_error.clear ();
00461   data->interior_normals.clear ();
00462   //  data->interior_param.clear();
00463 
00464   for (unsigned p = 0; p < nInt; p++)
00465   {
00466     Vector3d pcp;
00467     pcp (0) = data->interior[p] (0);
00468     pcp (1) = data->interior[p] (1);
00469     pcp (2) = data->interior[p] (2);
00470 
00471     // inverse mapping
00472     Vector2d params;
00473     Vector3d pt, tu, tv, n;
00474     double error;
00475     if (p < data->interior_param.size ())
00476     {
00477       params = FittingSurface::inverseMapping (*nurbs, pcp, data->interior_param[p], error, pt, tu, tv, im_max_steps,
00478                                                im_accuracy);
00479       data->interior_param[p] = params;
00480     }
00481     else
00482     {
00483       params = FittingSurface::findClosestElementMidPoint (*m_nurbs[id], pcp);
00484       params = FittingSurface::inverseMapping (*m_nurbs[id], pcp, params, error, pt, tu, tv, im_max_steps, im_accuracy);
00485       data->interior_param.push_back (params);
00486     }
00487     data->interior_error.push_back (error);
00488 
00489     n = tu.cross (tv);
00490     n.normalize ();
00491 
00492     data->interior_normals.push_back (n);
00493     data->interior_line_start.push_back (pcp);
00494     data->interior_line_end.push_back (pt);
00495 
00496     addPointConstraint (id, ncps, params, pcp, weight, row);
00497   }
00498 }
00499 
00500 void
00501 GlobalOptimizationTDM::assembleInteriorPointsTD (unsigned id, int ncps, double wTangent, double weight, unsigned &row)
00502 {
00503   if (weight <= 0.0)
00504     return;
00505 
00506   ON_NurbsSurface *nurbs = m_nurbs[id];
00507   NurbsDataSurface *data = m_data[id];
00508   unsigned nInt = static_cast<unsigned> (m_data[id]->interior.size ());
00509 
00510   // interior points should lie on surface
00511   data->interior_line_start.clear ();
00512   data->interior_line_end.clear ();
00513   data->interior_error.clear ();
00514   data->interior_normals.clear ();
00515   //  data->interior_param.clear();
00516 
00517   for (unsigned p = 0; p < nInt; p++)
00518   {
00519     Vector3d pcp;
00520     pcp (0) = data->interior[p] (0);
00521     pcp (1) = data->interior[p] (1);
00522     pcp (2) = data->interior[p] (2);
00523 
00524     // inverse mapping
00525     Vector2d params;
00526     Vector3d pt, tu, tv, n;
00527     double error;
00528     if (p < data->interior_param.size ())
00529     {
00530       params = FittingSurface::inverseMapping (*nurbs, pcp, data->interior_param[p], error, pt, tu, tv, im_max_steps,
00531                                                im_accuracy);
00532       data->interior_param[p] = params;
00533     }
00534     else
00535     {
00536       params = FittingSurface::findClosestElementMidPoint (*m_nurbs[id], pcp);
00537       params = FittingSurface::inverseMapping (*m_nurbs[id], pcp, params, error, pt, tu, tv, im_max_steps, im_accuracy);
00538       data->interior_param.push_back (params);
00539     }
00540     data->interior_error.push_back (error);
00541 
00542     tu.normalize ();
00543     tv.normalize ();
00544     n = tu.cross (tv);
00545 
00546     data->interior_normals.push_back (n);
00547     data->interior_line_start.push_back (pcp);
00548     data->interior_line_end.push_back (pt);
00549 
00550     addPointConstraintTD (id, ncps, params, pcp, n, tu, tv, wTangent, weight, row);
00551   }
00552 }
00553 
00554 void
00555 GlobalOptimizationTDM::assembleBoundaryPoints (unsigned id, int ncps, double weight, unsigned &row)
00556 {
00557   if (weight <= 0.0)
00558     return;
00559 
00560   ON_NurbsSurface *nurbs = m_nurbs[id];
00561   NurbsDataSurface *data = m_data[id];
00562   unsigned nBnd = static_cast<unsigned> (m_data[id]->boundary.size ());
00563 
00564   // interior points should lie on surface
00565   data->boundary_line_start.clear ();
00566   data->boundary_line_end.clear ();
00567   data->boundary_error.clear ();
00568   data->boundary_normals.clear ();
00569   data->boundary_param.clear ();
00570 
00571   for (unsigned p = 0; p < nBnd; p++)
00572   {
00573     Vector3d pcp;
00574     pcp (0) = data->boundary[p] (0);
00575     pcp (1) = data->boundary[p] (1);
00576     pcp (2) = data->boundary[p] (2);
00577 
00578     // inverse mapping
00579     Vector3d pt, tu, tv, n;
00580     double error;
00581 
00582     Vector2d params =
00583         FittingSurface::inverseMappingBoundary (*nurbs, pcp, error, pt, tu, tv, im_max_steps, im_accuracy);
00584     data->boundary_error.push_back (error);
00585 
00586     if (p < data->boundary_param.size ())
00587     {
00588       data->boundary_param[p] = params;
00589     }
00590     else
00591     {
00592       data->boundary_param.push_back (params);
00593     }
00594 
00595     n = tu.cross (tv);
00596     n.normalize ();
00597 
00598     data->boundary_normals.push_back (n);
00599     data->boundary_line_start.push_back (pcp);
00600     data->boundary_line_end.push_back (pt);
00601 
00602     addPointConstraint (id, ncps, params, pcp, weight, row);
00603   }
00604 }
00605 
00606 void
00607 GlobalOptimizationTDM::assembleRegularisation (unsigned id, int ncps, double wCageRegInt, double wCageRegBnd,
00608                                                unsigned &row)
00609 {
00610   if (wCageRegBnd <= 0.0 || wCageRegInt <= 0.0)
00611   {
00612     printf ("[GlobalOptimizationTDM::assembleRegularisation] Warning, no regularisation may lead "
00613       "to under-determined equation system. Add cage regularisation (smoothing) to avoid.\n");
00614   }
00615 
00616   if (wCageRegInt > 0.0)
00617     addCageInteriorRegularisation (id, ncps, wCageRegInt, row);
00618 
00619   if (wCageRegBnd > 0.0)
00620   {
00621     addCageBoundaryRegularisation (id, ncps, wCageRegBnd, NORTH, row);
00622     addCageBoundaryRegularisation (id, ncps, wCageRegBnd, SOUTH, row);
00623     addCageBoundaryRegularisation (id, ncps, wCageRegBnd, WEST, row);
00624     addCageBoundaryRegularisation (id, ncps, wCageRegBnd, EAST, row);
00625     addCageCornerRegularisation (id, ncps, wCageRegBnd * 2.0, row);
00626   }
00627 }
00628 
00629 void
00630 GlobalOptimizationTDM::addParamConstraint (const Eigen::Vector2i &id, const Eigen::Vector2d &params1,
00631                                            const Eigen::Vector2d &params2, double weight, unsigned &row)
00632 {
00633   vector_vec2d params;
00634   params.push_back (params1);
00635   params.push_back (params2);
00636 
00637   for (unsigned n = 0; n < 2; n++)
00638   {
00639     ON_NurbsSurface* nurbs = m_nurbs[id (n)];
00640 
00641     double *N0 = new double[nurbs->m_order[0] * nurbs->m_order[0]];
00642     double *N1 = new double[nurbs->m_order[1] * nurbs->m_order[1]];
00643 
00644     int E = ON_NurbsSpanIndex (nurbs->m_order[0], nurbs->m_cv_count[0], nurbs->m_knot[0], params[n] (0), 0, 0);
00645     int F = ON_NurbsSpanIndex (nurbs->m_order[1], nurbs->m_cv_count[1], nurbs->m_knot[1], params[n] (1), 0, 0);
00646 
00647     //    m_solver.f(row+0, 0, 0.0);
00648     //    m_solver.f(row+1, 0, 0.0);
00649     //    m_solver.f(row+2, 0, 0.0);
00650 
00651     int ncps (0);
00652     for (int i = 0; i < id (n); i++)
00653       ncps += m_nurbs[i]->CVCount ();
00654 
00655     ON_EvaluateNurbsBasis (nurbs->m_order[0], nurbs->m_knot[0] + E, params[n] (0), N0);
00656     ON_EvaluateNurbsBasis (nurbs->m_order[1], nurbs->m_knot[1] + F, params[n] (1), N1);
00657 
00658     double s (1.0);
00659     n == 0 ? s = 1.0 : s = -1.0;
00660 
00661     for (int i = 0; i < nurbs->m_order[0]; i++)
00662     {
00663       for (int j = 0; j < nurbs->m_order[1]; j++)
00664       {
00665 
00666         double val = weight * N0[i] * N1[j] * s;
00667         unsigned ci = 3 * (ncps + lrc2gl (*nurbs, E, F, i, j));
00668 
00669         m_solver.K (row + 0, ci + 0, val);
00670         m_solver.K (row + 1, ci + 1, val);
00671         m_solver.K (row + 2, ci + 2, val);
00672 
00673       } // j
00674     } // i
00675 
00676     delete [] N1;
00677     delete [] N0;
00678   }
00679 
00680   row += 3;
00681 
00682   //  if (!m_quiet && row % 100)
00683   //    printf("[GlobalOptimizationTDM::addParamConstraint] row: %d / %d\n", row, m_nrows);
00684 }
00685 
00686 void
00687 GlobalOptimizationTDM::addParamConstraintTD (const Eigen::Vector2i &id, const Eigen::Vector2d &params1,
00688                                              const Eigen::Vector2d &params2, const Eigen::Vector3d &n,
00689                                              const Eigen::Vector3d &tu, const Eigen::Vector3d &tv,
00690                                              double tangent_weight, double weight, unsigned &row)
00691 {
00692   vector_vec2d params;
00693   params.push_back (params1);
00694   params.push_back (params2);
00695 
00696   Eigen::Vector3d td = n + tangent_weight * tu + tangent_weight * tv;
00697 
00698   for (unsigned n = 0; n < 2; n++)
00699   {
00700     ON_NurbsSurface* nurbs = m_nurbs[id (n)];
00701 
00702     double *N0 = new double[nurbs->m_order[0] * nurbs->m_order[0]];
00703     double *N1 = new double[nurbs->m_order[1] * nurbs->m_order[1]];
00704 
00705     int E = ON_NurbsSpanIndex (nurbs->m_order[0], nurbs->m_cv_count[0], nurbs->m_knot[0], params[n] (0), 0, 0);
00706     int F = ON_NurbsSpanIndex (nurbs->m_order[1], nurbs->m_cv_count[1], nurbs->m_knot[1], params[n] (1), 0, 0);
00707 
00708     //    m_solver.f(row+0, 0, 0.0);
00709     //    m_solver.f(row+1, 0, 0.0);
00710     //    m_solver.f(row+2, 0, 0.0);
00711 
00712     int ncps (0);
00713     for (int i = 0; i < id (n); i++)
00714       ncps += m_nurbs[i]->CVCount ();
00715 
00716     ON_EvaluateNurbsBasis (nurbs->m_order[0], nurbs->m_knot[0] + E, params[n] (0), N0);
00717     ON_EvaluateNurbsBasis (nurbs->m_order[1], nurbs->m_knot[1] + F, params[n] (1), N1);
00718 
00719     double s (1.0);
00720     n == 0 ? s = 1.0 : s = -1.0;
00721 
00722     for (int i = 0; i < nurbs->m_order[0]; i++)
00723     {
00724       for (int j = 0; j < nurbs->m_order[1]; j++)
00725       {
00726 
00727         double val = weight * N0[i] * N1[j] * s;
00728         unsigned ci = 3 * (ncps + lrc2gl (*nurbs, E, F, i, j));
00729 
00730         m_solver.K (row + 0, ci + 0, td (0) * val);
00731         m_solver.K (row + 1, ci + 1, td (1) * val);
00732         m_solver.K (row + 2, ci + 2, td (2) * val);
00733 
00734       } // j
00735     } // i
00736 
00737     delete [] N1;
00738     delete [] N0;
00739   }
00740 
00741   row += 3;
00742 
00743 //  if (!m_quiet && row % 100)
00744 //    printf ("[GlobalOptimizationTDM::addParamConstraintTD] row: %d / %d\n", row, m_nrows);
00745 }
00746 
00747 void
00748 GlobalOptimizationTDM::addPointConstraint (unsigned id, int ncps, const Eigen::Vector2d &params,
00749                                            const Eigen::Vector3d &point, double weight, unsigned &row)
00750 {
00751   ON_NurbsSurface *nurbs = m_nurbs[id];
00752 
00753   double *N0 = new double[nurbs->m_order[0] * nurbs->m_order[0]];
00754   double *N1 = new double[nurbs->m_order[1] * nurbs->m_order[1]];
00755 
00756   int E = ON_NurbsSpanIndex (nurbs->m_order[0], nurbs->m_cv_count[0], nurbs->m_knot[0], params (0), 0, 0);
00757   int F = ON_NurbsSpanIndex (nurbs->m_order[1], nurbs->m_cv_count[1], nurbs->m_knot[1], params (1), 0, 0);
00758 
00759   ON_EvaluateNurbsBasis (nurbs->m_order[0], nurbs->m_knot[0] + E, params (0), N0);
00760   ON_EvaluateNurbsBasis (nurbs->m_order[1], nurbs->m_knot[1] + F, params (1), N1);
00761 
00762   m_solver.f (row + 0, 0, point (0) * weight);
00763   m_solver.f (row + 1, 0, point (1) * weight);
00764   m_solver.f (row + 2, 0, point (2) * weight);
00765 
00766   for (int i = 0; i < nurbs->m_order[0]; i++)
00767   {
00768 
00769     for (int j = 0; j < nurbs->m_order[1]; j++)
00770     {
00771 
00772       double val = weight * N0[i] * N1[j];
00773       unsigned ci = 3 * (ncps + lrc2gl (*nurbs, E, F, i, j));
00774 
00775       m_solver.K (row + 0, ci + 0, val);
00776       m_solver.K (row + 1, ci + 1, val);
00777       m_solver.K (row + 2, ci + 2, val);
00778 
00779     } // j
00780 
00781   } // i
00782 
00783   row += 3;
00784 
00785   //  if (!m_quiet && !(row % 100))
00786   //    printf("[GlobalOptimizationTDM::addPointConstraint] row: %d / %d\n", row, m_nrows);
00787 
00788   delete [] N1;
00789   delete [] N0;
00790 }
00791 
00792 void
00793 GlobalOptimizationTDM::addPointConstraintTD (unsigned id, int ncps, const Eigen::Vector2d &params,
00794                                              const Eigen::Vector3d &p, const Eigen::Vector3d &n,
00795                                              const Eigen::Vector3d &tu, const Eigen::Vector3d &tv,
00796                                              double tangent_weight, double weight, unsigned &row)
00797 {
00798   ON_NurbsSurface *nurbs = m_nurbs[id];
00799 
00800   double *N0 = new double[nurbs->m_order[0] * nurbs->m_order[0]];
00801   double *N1 = new double[nurbs->m_order[1] * nurbs->m_order[1]];
00802 
00803   int E = ON_NurbsSpanIndex (nurbs->m_order[0], nurbs->m_cv_count[0], nurbs->m_knot[0], params (0), 0, 0);
00804   int F = ON_NurbsSpanIndex (nurbs->m_order[1], nurbs->m_cv_count[1], nurbs->m_knot[1], params (1), 0, 0);
00805 
00806   ON_EvaluateNurbsBasis (nurbs->m_order[0], nurbs->m_knot[0] + E, params (0), N0);
00807   ON_EvaluateNurbsBasis (nurbs->m_order[1], nurbs->m_knot[1] + F, params (1), N1);
00808 
00809   double wt = tangent_weight;
00810   Eigen::Vector3d td = n + wt * tu + wt * tv;
00811 
00812   m_solver.f (row + 0, 0, td (0) * p (0) * weight);
00813   m_solver.f (row + 1, 0, td (1) * p (1) * weight);
00814   m_solver.f (row + 2, 0, td (2) * p (2) * weight);
00815 
00816   for (int i = 0; i < nurbs->m_order[0]; i++)
00817   {
00818 
00819     for (int j = 0; j < nurbs->m_order[1]; j++)
00820     {
00821 
00822       double val = weight * N0[i] * N1[j];
00823       unsigned ci = 3 * (ncps + lrc2gl (*nurbs, E, F, i, j));
00824 
00825       m_solver.K (row + 0, ci + 0, td (0) * val);
00826       m_solver.K (row + 1, ci + 1, td (1) * val);
00827       m_solver.K (row + 2, ci + 2, td (2) * val);
00828 
00829     } // j
00830 
00831   } // i
00832 
00833   row += 3;
00834 
00835   //  if (!m_quiet && !(row % 100))
00836   //    printf("[GlobalOptimizationTDM::addPointConstraint] row: %d / %d\n", row, m_nrows);
00837 
00838   delete [] N1;
00839   delete [] N0;
00840 }
00841 
00842 void
00843 GlobalOptimizationTDM::addCageInteriorRegularisation (unsigned id, int ncps, double weight, unsigned &row)
00844 {
00845   ON_NurbsSurface *nurbs = m_nurbs[id];
00846 
00847   for (int i = 1; i < (nurbs->CVCount (0) - 1); i++)
00848   {
00849     for (int j = 1; j < (nurbs->CVCount (1) - 1); j++)
00850     {
00851 
00852       //      m_solver.f(row+0, 0, 0.0);
00853       //      m_solver.f(row+1, 0, 0.0);
00854       //      m_solver.f(row+2, 0, 0.0);
00855 
00856       m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 0, -4.0 * weight);
00857       m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j - 1)) + 0, 1.0 * weight);
00858       m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 1)) + 0, 1.0 * weight);
00859       m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i - 1, j + 0)) + 0, 1.0 * weight);
00860       m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 1, j + 0)) + 0, 1.0 * weight);
00861 
00862       m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 1, -4.0 * weight);
00863       m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j - 1)) + 1, 1.0 * weight);
00864       m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 1)) + 1, 1.0 * weight);
00865       m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i - 1, j + 0)) + 1, 1.0 * weight);
00866       m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 1, j + 0)) + 1, 1.0 * weight);
00867 
00868       m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 2, -4.0 * weight);
00869       m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j - 1)) + 2, 1.0 * weight);
00870       m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 1)) + 2, 1.0 * weight);
00871       m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i - 1, j + 0)) + 2, 1.0 * weight);
00872       m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 1, j + 0)) + 2, 1.0 * weight);
00873 
00874       row += 3;
00875     }
00876   }
00877   //  if (!m_quiet && !(row % 100))
00878   //    printf("[GlobalOptimizationTDM::addCageInteriorRegularisation] row: %d / %d\n", row, m_nrows);
00879 }
00880 
00881 void
00882 GlobalOptimizationTDM::addCageBoundaryRegularisation (unsigned id, int ncps, double weight, int side, unsigned &row)
00883 {
00884   ON_NurbsSurface *nurbs = m_nurbs[id];
00885 
00886   int i = 0;
00887   int j = 0;
00888 
00889   switch (side)
00890   {
00891     case SOUTH:
00892       j = nurbs->CVCount (1) - 1;
00893     case NORTH:
00894       for (i = 1; i < (nurbs->CVCount (0) - 1); i++)
00895       {
00896 
00897         //      m_solver.f(row+0, 0, 0.0);
00898         //      m_solver.f(row+1, 0, 0.0);
00899         //      m_solver.f(row+2, 0, 0.0);
00900 
00901         m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j)) + 0, -2.0 * weight);
00902         m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i - 1, j)) + 0, 1.0 * weight);
00903         m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 1, j)) + 0, 1.0 * weight);
00904 
00905         m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j)) + 1, -2.0 * weight);
00906         m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i - 1, j)) + 1, 1.0 * weight);
00907         m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 1, j)) + 1, 1.0 * weight);
00908 
00909         m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j)) + 2, -2.0 * weight);
00910         m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i - 1, j)) + 2, 1.0 * weight);
00911         m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 1, j)) + 2, 1.0 * weight);
00912 
00913         row += 3;
00914       }
00915       break;
00916 
00917     case EAST:
00918       i = nurbs->CVCount (0) - 1;
00919     case WEST:
00920       for (j = 1; j < (nurbs->CVCount (1) - 1); j++)
00921       {
00922 
00923         //      m_solver.f(row+0, 0, 0.0);
00924         //      m_solver.f(row+1, 0, 0.0);
00925         //      m_solver.f(row+2, 0, 0.0);
00926 
00927         m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i, j + 0)) + 0, -2.0 * weight);
00928         m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i, j - 1)) + 0, 1.0 * weight);
00929         m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i, j + 1)) + 0, 1.0 * weight);
00930 
00931         m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i, j + 0)) + 1, -2.0 * weight);
00932         m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i, j - 1)) + 1, 1.0 * weight);
00933         m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i, j + 1)) + 1, 1.0 * weight);
00934 
00935         m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i, j + 0)) + 2, -2.0 * weight);
00936         m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i, j - 1)) + 2, 1.0 * weight);
00937         m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i, j + 1)) + 2, 1.0 * weight);
00938 
00939         row += 3;
00940       }
00941       break;
00942   }
00943   //  if (!m_quiet && !(row % 100))
00944   //    printf("[GlobalOptimizationTDM::addCageBoundaryRegularisation] row: %d / %d\n", row, m_nrows);
00945 }
00946 
00947 void
00948 GlobalOptimizationTDM::addCageCornerRegularisation (unsigned id, int ncps, double weight, unsigned &row)
00949 {
00950   ON_NurbsSurface *nurbs = m_nurbs[id];
00951 
00952   { // NORTH-WEST
00953     int i = 0;
00954     int j = 0;
00955 
00956     //      m_solver.f(row+0, 0, 0.0);
00957     //      m_solver.f(row+1, 0, 0.0);
00958     //      m_solver.f(row+2, 0, 0.0);
00959 
00960     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 0, -2.0 * weight);
00961     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 1, j + 0)) + 0, 1.0 * weight);
00962     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 1)) + 0, 1.0 * weight);
00963 
00964     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 1, -2.0 * weight);
00965     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 1, j + 0)) + 1, 1.0 * weight);
00966     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 1)) + 1, 1.0 * weight);
00967 
00968     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 2, -2.0 * weight);
00969     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 1, j + 0)) + 2, 1.0 * weight);
00970     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 1)) + 2, 1.0 * weight);
00971 
00972     row += 3;
00973   }
00974 
00975   { // NORTH-EAST
00976     int i = nurbs->CVCount (0) - 1;
00977     int j = 0;
00978 
00979     //      m_solver.f(row+0, 0, 0.0);
00980     //      m_solver.f(row+1, 0, 0.0);
00981     //      m_solver.f(row+2, 0, 0.0);
00982 
00983     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 0, -2.0 * weight);
00984     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i - 1, j + 0)) + 0, 1.0 * weight);
00985     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 1)) + 0, 1.0 * weight);
00986 
00987     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 1, -2.0 * weight);
00988     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i - 1, j + 0)) + 1, 1.0 * weight);
00989     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 1)) + 1, 1.0 * weight);
00990 
00991     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 2, -2.0 * weight);
00992     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i - 1, j + 0)) + 2, 1.0 * weight);
00993     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 1)) + 2, 1.0 * weight);
00994 
00995     row += 3;
00996   }
00997 
00998   { // SOUTH-EAST
00999     int i = nurbs->CVCount (0) - 1;
01000     int j = nurbs->CVCount (1) - 1;
01001 
01002     //      m_solver.f(row+0, 0, 0.0);
01003     //      m_solver.f(row+1, 0, 0.0);
01004     //      m_solver.f(row+2, 0, 0.0);
01005 
01006     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 0, -2.0 * weight);
01007     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i - 1, j + 0)) + 0, 1.0 * weight);
01008     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j - 1)) + 0, 1.0 * weight);
01009 
01010     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 1, -2.0 * weight);
01011     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i - 1, j + 0)) + 1, 1.0 * weight);
01012     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j - 1)) + 1, 1.0 * weight);
01013 
01014     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 2, -2.0 * weight);
01015     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i - 1, j + 0)) + 2, 1.0 * weight);
01016     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j - 1)) + 2, 1.0 * weight);
01017 
01018     row += 3;
01019   }
01020 
01021   { // SOUTH-WEST
01022     int i = 0;
01023     int j = nurbs->CVCount (1) - 1;
01024 
01025     //      m_solver.f(row+0, 0, 0.0);
01026     //      m_solver.f(row+1, 0, 0.0);
01027     //      m_solver.f(row+2, 0, 0.0);
01028 
01029     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 0, -2.0 * weight);
01030     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 1, j + 0)) + 0, 1.0 * weight);
01031     m_solver.K (row + 0, 3 * (ncps + grc2gl (*nurbs, i + 0, j - 1)) + 0, 1.0 * weight);
01032 
01033     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 1, -2.0 * weight);
01034     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 1, j + 0)) + 1, 1.0 * weight);
01035     m_solver.K (row + 1, 3 * (ncps + grc2gl (*nurbs, i + 0, j - 1)) + 1, 1.0 * weight);
01036 
01037     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j + 0)) + 2, -2.0 * weight);
01038     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 1, j + 0)) + 2, 1.0 * weight);
01039     m_solver.K (row + 2, 3 * (ncps + grc2gl (*nurbs, i + 0, j - 1)) + 2, 1.0 * weight);
01040 
01041     row += 3;
01042   }
01043 
01044   //  if (!m_quiet && !(row % 100))
01045   //    printf("[GlobalOptimizationTDM::addCageCornerRegularisation] row: %d / %d\n", row, m_nrows);
01046 }
01047 


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