fitting_curve_2d_asdm.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/fitting_curve_2d_asdm.h>
00039 #include <stdexcept>
00040 
00041 using namespace pcl;
00042 using namespace on_nurbs;
00043 
00044 FittingCurve2dASDM::FittingCurve2dASDM (int order, NurbsDataCurve2d *data) :
00045   FittingCurve2dAPDM (order, data)
00046 {
00047 }
00048 
00049 FittingCurve2dASDM::FittingCurve2dASDM (NurbsDataCurve2d *data, const ON_NurbsCurve &ns) :
00050   FittingCurve2dAPDM (data, ns)
00051 {
00052 
00053 }
00054 
00055 void
00056 FittingCurve2dASDM::assemble (const FittingCurve2dAPDM::Parameter &parameter)
00057 {
00058   int cp_red = m_nurbs.m_order - 2;
00059   int ncp = m_nurbs.m_cv_count - 2 * cp_red;
00060   int nCageReg = m_nurbs.m_cv_count - 2 * cp_red;
00061   int nInt = int (m_data->interior.size ());
00062   //  int nCommon = m_data->common.size();
00063   //  int nClosestP = parameter.closest_point_resolution;
00064 
00065   std::vector<double> elements = getElementVector (m_nurbs);
00066   int nClosestP = int (elements.size ());
00067 
00068   double wInt = 1.0;
00069   if (!m_data->interior_weight.empty ())
00070   {
00071     wInt = m_data->interior_weight[0];
00072   }
00073 
00074   double wCageReg = parameter.smoothness;
00075 
00076   unsigned nrows = 4 * nInt + 2 * nCageReg + 4 * nClosestP;
00077 
00078   m_solver.assign (nrows, ncp * 2, 1);
00079 
00080   unsigned row (0);
00081 
00082   if (wInt > 0.0)
00083     assembleInterior (wInt, parameter.interior_sigma2, parameter.rScale, row);
00084 
00085   assembleClosestPoints (elements, parameter.closest_point_weight, parameter.closest_point_sigma2, row);
00086 
00087   if (wCageReg > 0.0)
00088     addCageRegularisation (wCageReg, row, elements, parameter.smooth_concavity);
00089 
00090   if (row < nrows)
00091   {
00092     m_solver.resize (row);
00093     if (!m_quiet)
00094       printf ("[FittingCurve2dASDM::assemble] Warning: rows do not match: %d %d\n", row, nrows);
00095   }
00096 }
00097 
00098 double
00099 FittingCurve2dASDM::solve (double damp)
00100 {
00101   double cps_diff (0.0);
00102 
00103   if (m_solver.solve ())
00104     cps_diff = updateCurve (damp);
00105 
00106   return cps_diff;
00107 }
00108 
00109 double
00110 FittingCurve2dASDM::updateCurve (double damp)
00111 {
00112   int cp_red = m_nurbs.m_order - 2;
00113   int ncp = m_nurbs.m_cv_count - 2 * cp_red;
00114 
00115   double cps_diff (0.0);
00116 
00117   for (int j = 0; j < ncp; j++)
00118   {
00119 
00120     ON_3dPoint cp_prev;
00121     m_nurbs.GetCV (j, cp_prev);
00122 
00123     double x = m_solver.x (2 * j + 0, 0);
00124     double y = m_solver.x (2 * j + 1, 0);
00125 
00126     cps_diff += sqrt ((x - cp_prev.x) * (x - cp_prev.x) + (y - cp_prev.y) * (y - cp_prev.y));
00127 
00128     ON_3dPoint cp;
00129     cp.x = cp_prev.x + damp * (x - cp_prev.x);
00130     cp.y = cp_prev.y + damp * (y - cp_prev.y);
00131     cp.z = 0.0;
00132 
00133     m_nurbs.SetCV (j, cp);
00134   }
00135 
00136   for (int j = 0; j < 2 * cp_red; j++)
00137   {
00138     ON_3dPoint cp;
00139     m_nurbs.GetCV (2 * cp_red - 1 - j, cp);
00140     m_nurbs.SetCV (m_nurbs.m_cv_count - 1 - j, cp);
00141   }
00142 
00143   return cps_diff / ncp;
00144 }
00145 
00146 void
00147 FittingCurve2dASDM::addPointConstraint (const double &param, const Eigen::Vector2d &point,
00148                                         const Eigen::Vector2d &normal, const Eigen::Vector2d &tangent, double rho,
00149                                         double d, double weight, unsigned &row)
00150 {
00151   int cp_red = m_nurbs.m_order - 2;
00152   int ncp = m_nurbs.m_cv_count - 2 * cp_red;
00153   double *N = new double[m_nurbs.m_order * m_nurbs.m_order];
00154 
00155   int E = ON_NurbsSpanIndex (m_nurbs.m_order, m_nurbs.m_cv_count, m_nurbs.m_knot, param, 0, 0);
00156 
00157   ON_EvaluateNurbsBasis (m_nurbs.m_order, m_nurbs.m_knot + E, param, N);
00158 
00159   m_solver.f (row, 0, normal (0) * point (0) * weight);
00160   for (int i = 0; i < m_nurbs.m_order; i++)
00161   {
00162     m_solver.K (row, 2 * ((E + i) % ncp) + 0, weight * normal (0) * N[i]);
00163   }
00164   row++;
00165 
00166   m_solver.f (row, 0, normal (1) * point (1) * weight);
00167   for (int i = 0; i < m_nurbs.m_order; i++)
00168   {
00169     m_solver.K (row, 2 * ((E + i) % ncp) + 1, weight * normal (1) * N[i]);
00170   }
00171   row++;
00172 
00173   //  if (d >= 0.0 && d > rho)
00174   //    printf("[FittingCurve2dASDM::addPointConstraint] Warning d > rho: %f > %f\n", d, rho);
00175 
00176   if (d < 0.0)
00177   {
00178 
00179     double a = d / (d - rho);
00180 
00181     m_solver.f (row, 0, a * a * tangent (0) * point (0) * weight);
00182     for (int i = 0; i < m_nurbs.m_order; i++)
00183       m_solver.K (row, 2 * ((E + i) % ncp) + 0, a * a * weight * tangent (0) * N[i]);
00184     row++;
00185 
00186     m_solver.f (row, 0, a * a * tangent (1) * point (1) * weight);
00187     for (int i = 0; i < m_nurbs.m_order; i++)
00188       m_solver.K (row, 2 * ((E + i) % ncp) + 1, a * a * weight * tangent (1) * N[i]);
00189     row++;
00190 
00191   }
00192 
00193   delete [] N;
00194 }
00195 
00196 void
00197 FittingCurve2dASDM::addCageRegularisation (double weight, unsigned &row, const std::vector<double> &elements,
00198                                            double wConcav)
00199 {
00200   int cp_red = (m_nurbs.m_order - 2);
00201   int ncp = (m_nurbs.m_cv_count - 2 * cp_red);
00202 
00203   //  m_data->interior_line_start.clear();
00204   //  m_data->interior_line_end.clear();
00205   for (int j = 1; j < ncp + 1; j++)
00206   {
00207 
00208     if (wConcav == 0.0)
00209     {
00210     }
00211     else
00212     {
00213       int i = j % ncp;
00214 
00215       if (i >= int (m_data->closest_points_error.size () - 1))
00216       {
00217         printf ("[FittingCurve2dASDM::addCageRegularisation] Warning, index for closest_points_error out of bounds\n");
00218       }
00219       else
00220       {
00221         Eigen::Vector2d t, n;
00222         double pt[4];
00223 
00224         double xi = elements[i] + 0.5 * (elements[i + 1] - elements[i]);
00225         m_nurbs.Evaluate (xi, 1, 2, pt);
00226         t (0) = pt[2];
00227         t (1) = pt[3];
00228         n (0) = -t (1);
00229         n (1) = t (0);
00230         n.normalize ();
00231 
00232         double err = m_data->closest_points_error[i] + 0.5 * (m_data->closest_points_error[i + 1]
00233             - m_data->closest_points_error[i]);
00234         m_solver.f (row + 0, 0, err * wConcav * n (0));
00235         m_solver.f (row + 1, 0, err * wConcav * n (1));
00236 
00237         //        Eigen::Vector2d p1, p2;
00238         //        p1(0) = pt[0];
00239         //        p1(1) = pt[1];
00240         //        p2 = p1 + n * wConcav * err;
00241         //        m_data->interior_line_start.push_back(p1);
00242         //        m_data->interior_line_end.push_back(p2);
00243       }
00244     }
00245 
00246     m_solver.K (row, 2 * ((j + 0) % ncp) + 0, -2.0 * weight);
00247     m_solver.K (row, 2 * ((j - 1) % ncp) + 0, 1.0 * weight);
00248     m_solver.K (row, 2 * ((j + 1) % ncp) + 0, 1.0 * weight);
00249     row++;
00250 
00251     m_solver.K (row, 2 * ((j + 0) % ncp) + 1, -2.0 * weight);
00252     m_solver.K (row, 2 * ((j - 1) % ncp) + 1, 1.0 * weight);
00253     m_solver.K (row, 2 * ((j + 1) % ncp) + 1, 1.0 * weight);
00254     row++;
00255   }
00256 }
00257 
00258 void
00259 FittingCurve2dASDM::assembleInterior (double wInt, double sigma2, double rScale, unsigned &row)
00260 {
00261   unsigned nInt = unsigned (m_data->interior.size ());
00262   bool wFunction (true);
00263   double ds = 1.0 / (2.0 * sigma2);
00264   m_data->interior_line_start.clear ();
00265   m_data->interior_line_end.clear ();
00266   m_data->interior_error.clear ();
00267   m_data->interior_normals.clear ();
00268 
00269   unsigned updateTNR (false);
00270   if (m_data->interior_ncps_prev != m_nurbs.CVCount ())
00271   {
00272     if (!m_quiet)
00273       printf ("[FittingCurve2dASDM::assembleInterior] updating T, N, rho\n");
00274     m_data->interior_tangents.clear ();
00275     m_data->interior_normals.clear ();
00276     m_data->interior_rho.clear ();
00277     m_data->interior_ncps_prev = m_nurbs.CVCount ();
00278     updateTNR = true;
00279   }
00280 
00281   unsigned i1 (0);
00282   unsigned i2 (0);
00283 
00284   for (unsigned p = 0; p < nInt; p++)
00285   {
00286     Eigen::Vector2d &pcp = m_data->interior[p];
00287 
00288     // inverse mapping
00289     double param;
00290     Eigen::Vector2d pt, t, n;
00291     double error;
00292     if (p < int (m_data->interior_param.size ()))
00293     {
00294       param = findClosestElementMidPoint (m_nurbs, pcp, m_data->interior_param[p]);
00295       param = inverseMapping (m_nurbs, pcp, param, error, pt, t, rScale, in_max_steps, in_accuracy, m_quiet);
00296       m_data->interior_param[p] = param;
00297     }
00298     else
00299     {
00300       param = findClosestElementMidPoint (m_nurbs, pcp);
00301       param = inverseMapping (m_nurbs, pcp, param, error, pt, t, rScale, in_max_steps, in_accuracy, m_quiet);
00302       m_data->interior_param.push_back (param);
00303     }
00304 
00305     m_data->interior_error.push_back (error);
00306 
00307     double dt, kappa, rho, rho_prev;
00308     Eigen::Vector2d n_prev, t_prev;
00309 
00310     double pointAndTangents[6];
00311     m_nurbs.Evaluate (param, 2, 2, pointAndTangents);
00312     pt (0) = pointAndTangents[0];
00313     pt (1) = pointAndTangents[1];
00314     t (0) = pointAndTangents[2];
00315     t (1) = pointAndTangents[3];
00316     n (0) = pointAndTangents[4];
00317     n (1) = pointAndTangents[5];
00318 
00319     dt = t.norm ();
00320     t /= dt;
00321     Eigen::Vector2d in (t (1), -t (0));
00322     n /= dt; // TODO something is wrong with the normal from nurbs.Evaluate(...)
00323     n = in * in.dot (n);
00324 
00325     kappa = n.norm ();
00326     rho = (1.0 / kappa);
00327     n *= rho;
00328 
00329     if (!updateTNR && m_data->interior_rho.size () == nInt)
00330     {
00331       n_prev = m_data->interior_normals[p];
00332       t_prev = m_data->interior_tangents[p];
00333       rho_prev = m_data->interior_rho[p];
00334       //        m_data->interior_normals[p] = n;
00335       //        m_data->interior_tangents[p] = t;
00336       //        m_data->interior_rho[p] = rho;
00337     }
00338     else
00339     {
00340       m_data->interior_tangents.push_back (t);
00341       m_data->interior_normals.push_back (n);
00342       m_data->interior_rho.push_back (rho);
00343       n_prev = n;
00344       t_prev = t;
00345       rho_prev = rho;
00346     }
00347 
00348     double d;
00349     if ((pcp - pt).dot (n) >= 0.0)
00350     {
00351       d = (pcp - pt).norm ();
00352       i1++;
00353     }
00354     else
00355     {
00356       d = -(pcp - pt).norm ();
00357       i2++;
00358     }
00359 
00360     // evaluate if point lies inside or outside the closed curve
00361     Eigen::Vector3d a (pcp (0) - pt (0), pcp (1) - pt (1), 0.0);
00362     Eigen::Vector3d b (t (0), t (1), 0.0);
00363     Eigen::Vector3d z = a.cross (b);
00364 
00365     if (p < m_data->interior_weight.size ())
00366       wInt = m_data->interior_weight[p];
00367 
00368     if (p < m_data->interior_weight_function.size ())
00369       wFunction = m_data->interior_weight_function[p];
00370 
00371     m_data->interior_line_start.push_back (pt);
00372     m_data->interior_line_end.push_back (pcp);
00373 
00374     double w (wInt);
00375     if (z (2) > 0.0 && wFunction)
00376       w = wInt * exp (-(error * error) * ds);
00377 
00378     if (w > 1e-6) // avoids ill-conditioned matrix
00379       addPointConstraint (m_data->interior_param[p], m_data->interior[p], n_prev, t_prev, rho_prev, d, w, row);
00380   }
00381 
00382   //  printf("[FittingCurve2dASDM::assembleInterior] d>0: %d d<0: %d\n", i1, i2);
00383 }
00384 
00385 void
00386 FittingCurve2dASDM::assembleClosestPoints (const std::vector<double> &elements, double weight, double sigma2,
00387                                            unsigned &row)
00388 {
00389   m_data->closest_points.clear ();
00390   m_data->closest_points_param.clear ();
00391   m_data->closest_points_error.clear ();
00392   //  m_data->interior_line_start.clear();
00393   //  m_data->interior_line_end.clear();
00394 
00395   unsigned updateTNR (false);
00396   if (m_data->closest_ncps_prev != m_nurbs.CVCount ())
00397   {
00398     if (!m_quiet)
00399       printf ("[FittingCurve2dASDM::assembleClosestPoints] updating T, N, rho\n");
00400     m_data->closest_tangents.clear ();
00401     m_data->closest_normals.clear ();
00402     m_data->closest_rho.clear ();
00403     m_data->closest_ncps_prev = m_nurbs.CVCount ();
00404     updateTNR = true;
00405   }
00406 
00407   double ds = 1.0 / (2.0 * sigma2);
00408 
00409   for (unsigned i = 0; i < elements.size (); i++)
00410   {
00411 
00412     int j = (i + 1) % int (elements.size ());
00413 
00414     double dxi = elements[j] - elements[i];
00415     double xi = elements[i] + 0.5 * dxi;
00416 
00417     double points[6];
00418     Eigen::Vector2d p1, p2, p3, t, in, n;
00419     m_nurbs.Evaluate (xi, 2, 2, points);
00420     p1 (0) = points[0];
00421     p1 (1) = points[1];
00422     t (0) = points[2];
00423     t (1) = points[3];
00424     n (0) = points[4];
00425     n (1) = points[5];
00426 
00427     double dt, kappa, rho, rho_prev = 0;
00428     Eigen::Vector2d n_prev, t_prev;
00429 
00430     dt = t.norm ();
00431     t /= dt;
00432     in (0) = t (1);
00433     in (1) = -t (0);
00434     n /= dt;
00435     n = in * in.dot (n);
00436 
00437     kappa = n.norm ();
00438     rho = (1.0 / kappa);
00439     n *= rho;
00440 
00441     if (!updateTNR)
00442     {
00443       if (m_data->closest_rho.size () != elements.size ())
00444       {
00445         printf ("[FittingCurve2dASDM::assembleClosestPoints] ERROR: size does not match %d %d\n",
00446                 int (m_data->closest_rho.size ()), int (elements.size ()));
00447       }
00448       else
00449       {
00450         n_prev = m_data->closest_normals[i];
00451         t_prev = m_data->closest_tangents[i];
00452         rho_prev = m_data->closest_rho[i];
00453         //        m_data->closest_normals[i] = n;
00454         //        m_data->closest_tangents[i] = t;
00455         //        m_data->closest_rho[i] = rho;
00456       }
00457     }
00458     else
00459     {
00460       m_data->closest_tangents.push_back (t);
00461       m_data->closest_normals.push_back (n);
00462       m_data->closest_rho.push_back (rho);
00463       n_prev = n;
00464       t_prev = t;
00465       rho_prev = rho;
00466     }
00467 
00468     unsigned idxcp;
00469     unsigned idx = NurbsTools::getClosestPoint (p1, in, m_data->interior, idxcp);
00470     p2 = m_data->interior[idx];
00471     p3 = m_data->interior[idxcp];
00472 
00473     //    double xi2 = m_data->interior_param[idx];
00474 
00475     double error2 = (p2 - p1).squaredNorm ();
00476 
00477     m_data->closest_points.push_back (p3);
00478     m_data->closest_points_param.push_back (xi);
00479     m_data->closest_points_error.push_back ((p3 - p1).squaredNorm ());
00480 
00481     double w (weight);
00482     w = 0.5 * weight * exp (-(error2) * ds);
00483     //    w = weight * std::fabs(in.dot(p2-p1));
00484 
00485     double d;
00486     if ((p2 - p1).dot (n) >= 0.0)
00487       d = (p2 - p1).norm ();
00488     else
00489       d = -(p2 - p1).norm ();
00490 
00491     //    if (weight > 0.0 && (std::fabs(xi2 - xi) < std::fabs(dxi)))
00492     if (w > 0.0)
00493     {
00494       addPointConstraint (xi, p2, n_prev, t_prev, rho_prev, d, w, row);
00495       //      m_data->interior_line_start.push_back(p1);
00496       //      m_data->interior_line_end.push_back(p2);
00497     }
00498 
00499   }
00500 }
00501 


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