00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <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 ¶meter)
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
00063
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 ¶m, 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
00174
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
00204
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
00238
00239
00240
00241
00242
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
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;
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
00335
00336
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
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)
00379 addPointConstraint (m_data->interior_param[p], m_data->interior[p], n_prev, t_prev, rho_prev, d, w, row);
00380 }
00381
00382
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
00393
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
00454
00455
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
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
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
00492 if (w > 0.0)
00493 {
00494 addPointConstraint (xi, p2, n_prev, t_prev, rho_prev, d, w, row);
00495
00496
00497 }
00498
00499 }
00500 }
00501