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/closing_boundary.h>
00039
00040 using namespace pcl;
00041 using namespace on_nurbs;
00042
00043 double
00044 ClosingBoundary::getLineDistance (const Eigen::Vector3d &P0, const Eigen::Vector3d &u, const Eigen::Vector3d &Q0,
00045 const Eigen::Vector3d &v, Eigen::Vector3d &P, Eigen::Vector3d &Q)
00046 {
00047 Eigen::Vector3d w0 = P0 - Q0;
00048
00049 double a = u.dot (u);
00050 double b = u.dot (v);
00051 double c = v.dot (v);
00052 double d = u.dot (w0);
00053 double e = v.dot (w0);
00054
00055 double s = (b * e - c * d) / (a * c - b * b);
00056 double t = (a * e - b * d) / (a * c - b * b);
00057
00058 P = P0 + u * s;
00059 Q = Q0 + v * t;
00060
00061 Eigen::Vector3d wc = P - Q;
00062 return wc.norm ();
00063 }
00064
00065 Eigen::Vector3d
00066 ClosingBoundary::intersectPlanes (const Eigen::Vector3d &N1, double d1, const Eigen::Vector3d &N2, double d2,
00067 const Eigen::Vector3d &N3, double d3)
00068 {
00069 return (N2.cross (N3) * d1 + N3.cross (N1) * d2 + N1.cross (N2) * d3) / N1.dot (N2.cross (N3));
00070 }
00071
00072 Eigen::Vector3d
00073 ClosingBoundary::commonBoundaryPoint1 (
00074 ON_NurbsSurface &n1, ON_NurbsSurface &n2,
00075 Eigen::Vector2d ¶ms1, Eigen::Vector2d ¶ms2,
00076 const Eigen::Vector3d &start,
00077 unsigned nsteps, double &error, double accuracy)
00078 {
00079 Eigen::Vector3d current = start;
00080
00081 double error1 (DBL_MAX);
00082 double error2 (DBL_MAX);
00083
00084 Eigen::Vector3d p1, p2, tu1, tu2, tv1, tv2;
00085
00086 params1 = FittingSurface::findClosestElementMidPoint (n1, current);
00087 params2 = FittingSurface::findClosestElementMidPoint (n2, current);
00088 params1 = FittingSurface::inverseMapping (n1, current, params1, error1, p1, tu1, tv1, nsteps, accuracy, true);
00089 params2 = FittingSurface::inverseMapping (n2, current, params2, error2, p2, tu2, tv2, nsteps, accuracy, true);
00090
00091 for (unsigned i = 0; i < nsteps; i++)
00092 {
00093 params1 = FittingSurface::inverseMapping (n1, current, params1, error1, p1, tu1, tv1, nsteps, accuracy, true);
00094 params2 = FittingSurface::inverseMapping (n2, current, params2, error2, p2, tu2, tv2, nsteps, accuracy, true);
00095
00096
00097
00098
00099
00100 current = (p1 + p2) * 0.5;
00101 }
00102
00103
00104
00105
00106 error = 0.5 * (error1 + error2);
00107
00108 return current;
00109 }
00110
00111 Eigen::Vector3d
00112 ClosingBoundary::commonBoundaryPoint2 (
00113 ON_NurbsSurface &n1, ON_NurbsSurface &n2,
00114 Eigen::Vector2d ¶ms1, Eigen::Vector2d ¶ms2,
00115 const Eigen::Vector3d &start,
00116 unsigned nsteps, double &error, double accuracy)
00117 {
00118 Eigen::Vector3d current = start;
00119
00120 double error1 (DBL_MAX);
00121 double error2 (DBL_MAX);
00122
00123 Eigen::Vector3d p1, p2, tu1, tu2, tv1, tv2;
00124
00125 params1 = FittingSurface::findClosestElementMidPoint (n1, current);
00126 params2 = FittingSurface::findClosestElementMidPoint (n2, current);
00127 params1 = FittingSurface::inverseMapping (n1, current, params1, error1, p1, tu1, tv1, nsteps, accuracy, true);
00128 params2 = FittingSurface::inverseMapping (n2, current, params2, error2, p2, tu2, tv2, nsteps, accuracy, true);
00129
00130 for (unsigned i = 0; i < nsteps; i++)
00131 {
00132 params1 = FittingSurface::inverseMapping (n1, current, params1, error1, p1, tu1, tv1, nsteps, accuracy, true);
00133 params2 = FittingSurface::inverseMapping (n2, current, params2, error2, p2, tu2, tv2, nsteps, accuracy, true);
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 Eigen::Vector3d n1 = tu1.cross (tv1);
00144 n1.normalize ();
00145
00146 Eigen::Vector3d n2 = tu2.cross (tv2);
00147 n2.normalize ();
00148
00149 Eigen::Vector3d l1 = (p2 - n1 * n1.dot (p2 - p1)) - p1;
00150 l1.normalize ();
00151
00152 Eigen::Vector3d l2 = (p1 - n2 * n2.dot (p1 - p2)) - p2;
00153 l2.normalize ();
00154
00155
00156
00157
00158 Eigen::Vector3d P, Q;
00159 getLineDistance (p1, l1, p2, l2, P, Q);
00160
00161 current = (P + Q) * 0.5;
00162 }
00163
00164 error = 0.5 * (error1 + error2);
00165
00166
00167
00168
00169 return current;
00170 }
00171
00172 Eigen::Vector3d
00173 ClosingBoundary::commonBoundaryPoint3 (
00174 ON_NurbsSurface &n1, ON_NurbsSurface &n2,
00175 Eigen::Vector2d ¶ms1, Eigen::Vector2d ¶ms2,
00176 const Eigen::Vector3d &start,
00177 unsigned nsteps, double &error, double accuracy)
00178 {
00179 Eigen::Vector3d current = start;
00180
00181 double error1 (DBL_MAX);
00182 double error2 (DBL_MAX);
00183
00184 Eigen::Vector3d p1, p2, tu1, tu2, tv1, tv2;
00185
00186 params1 = FittingSurface::findClosestElementMidPoint (n1, current);
00187 params2 = FittingSurface::findClosestElementMidPoint (n2, current);
00188 params1 = FittingSurface::inverseMapping (n1, current, params1, error1, p1, tu1, tv1, nsteps, accuracy, true);
00189 params2 = FittingSurface::inverseMapping (n2, current, params2, error2, p2, tu2, tv2, nsteps, accuracy, true);
00190
00191 for (unsigned i = 0; i < nsteps; i++)
00192 {
00193 params1 = FittingSurface::inverseMapping (n1, current, params1, error1, p1, tu1, tv1, nsteps, accuracy, true);
00194 params2 = FittingSurface::inverseMapping (n2, current, params2, error2, p2, tu2, tv2, nsteps, accuracy, true);
00195
00196
00197
00198
00199
00200 Eigen::Vector3d n1 = tu1.cross (tv1);
00201 n1.normalize ();
00202 double d1 = n1.dot (p1);
00203
00204 Eigen::Vector3d n2 = tu2.cross (tv2);
00205 n2.normalize ();
00206 double d2 = n2.dot (p2);
00207
00208 Eigen::Vector3d n3 = (p1 - current).cross (p2 - current);
00209 n3.normalize ();
00210 double d3 = n3.dot (current);
00211
00212 current = intersectPlanes (n1, d1, n2, d2, n3, d3);
00213 }
00214
00215
00216
00217
00218 error = 0.5 * (error1 + error2);
00219
00220 return current;
00221 }
00222
00223 void
00224 ClosingBoundary::sampleUniform (ON_NurbsSurface *nurbs, vector_vec3d &point_list, unsigned samples)
00225 {
00226 double ds = 1.0 / (samples - 1);
00227
00228 double minU = nurbs->Knot (0, 0);
00229 double maxU = nurbs->Knot (0, nurbs->KnotCount (0) - 1);
00230 double minV = nurbs->Knot (1, 0);
00231 double maxV = nurbs->Knot (1, nurbs->KnotCount (1) - 1);
00232
00233 Eigen::Vector2d params;
00234 Eigen::Vector3d point;
00235
00236 double points[3];
00237
00238 for (unsigned j = 0; j < samples; j++)
00239 {
00240 params (1) = minV + (maxV - minV) * ds * j;
00241 for (unsigned i = 0; i < samples; i++)
00242 {
00243 params (0) = minU + (maxU - minU) * ds * i;
00244 nurbs->Evaluate (params (0), params (1), 0, 3, points);
00245 point_list.push_back (Eigen::Vector3d (points[0], points[1], points[2]));
00246 }
00247 }
00248 }
00249
00250 void
00251 ClosingBoundary::sampleRandom (ON_NurbsSurface *nurbs, vector_vec3d &point_list, unsigned samples)
00252 {
00253 double minU = nurbs->Knot (0, 0);
00254 double maxU = nurbs->Knot (0, nurbs->KnotCount (0) - 1);
00255 double minV = nurbs->Knot (1, 0);
00256 double maxV = nurbs->Knot (1, nurbs->KnotCount (1) - 1);
00257
00258 Eigen::Vector2d params;
00259 Eigen::Vector3d point;
00260
00261 double points[3];
00262
00263 for (unsigned i = 0; i < samples; i++)
00264 {
00265 params (0) = minU + (maxU - minU) * (double (rand ()) / RAND_MAX);
00266 params (1) = minV + (maxV - minV) * (double (rand ()) / RAND_MAX);
00267 nurbs->Evaluate (params (0), params (1), 0, 3, points);
00268 point_list.push_back (Eigen::Vector3d (points[0], points[1], points[2]));
00269 }
00270 }
00271
00272 void
00273 ClosingBoundary::sampleFromBoundary (ON_NurbsSurface *nurbs, vector_vec3d &point_list, vector_vec2d ¶m_list,
00274 unsigned samples)
00275 {
00276 double ds = 1.0 / (samples - 1);
00277
00278 double minU = nurbs->Knot (0, 0);
00279 double maxU = nurbs->Knot (0, nurbs->KnotCount (0) - 1);
00280 double minV = nurbs->Knot (1, 0);
00281 double maxV = nurbs->Knot (1, nurbs->KnotCount (1) - 1);
00282
00283 Eigen::Vector2d params;
00284 Eigen::Vector3d point;
00285
00286 double points[3];
00287
00288
00289 params (0) = minU;
00290 for (unsigned i = 0; i < samples; i++)
00291 {
00292 params (1) = minV + (maxV - minV) * ds * i;
00293 nurbs->Evaluate (params (0), params (1), 0, 3, points);
00294 point_list.push_back (Eigen::Vector3d (points[0], points[1], points[2]));
00295 param_list.push_back (params);
00296 }
00297
00298
00299 params (0) = maxU;
00300 for (unsigned i = 0; i < samples; i++)
00301 {
00302 params (1) = minV + (maxV - minV) * ds * i;
00303 nurbs->Evaluate (params (0), params (1), 0, 3, points);
00304 point_list.push_back (Eigen::Vector3d (points[0], points[1], points[2]));
00305 param_list.push_back (params);
00306 }
00307
00308
00309 params (1) = minV;
00310 for (unsigned i = 0; i < samples; i++)
00311 {
00312 params (0) = minU + (maxU - minU) * ds * i;
00313 nurbs->Evaluate (params (0), params (1), 0, 3, points);
00314 point_list.push_back (Eigen::Vector3d (points[0], points[1], points[2]));
00315 param_list.push_back (params);
00316 }
00317
00318
00319 params (1) = maxV;
00320 for (unsigned i = 0; i < samples; i++)
00321 {
00322 params (0) = minU + (maxU - minU) * ds * i;
00323 nurbs->Evaluate (params (0), params (1), 0, 3, points);
00324 point_list.push_back (Eigen::Vector3d (points[0], points[1], points[2]));
00325 param_list.push_back (params);
00326 }
00327 }
00328
00329 void
00330 ClosingBoundary::optimizeBoundary (std::vector<ON_NurbsSurface> &nurbs_list, std::vector<NurbsDataSurface> &data_list,
00331 Parameter param)
00332 {
00333 for (unsigned n1 = 0; n1 < nurbs_list.size (); n1++)
00334 data_list[n1].clear_boundary ();
00335
00336
00337 for (unsigned n1 = 0; n1 < nurbs_list.size (); n1++)
00338 {
00339
00340 ON_NurbsSurface *nurbs1 = &nurbs_list[n1];
00341
00342
00343 vector_vec3d boundary1;
00344 vector_vec2d params1;
00345 sampleFromBoundary (nurbs1, boundary1, params1, param.samples);
00346
00347
00348 for (unsigned n2 = (n1 + 1); n2 < nurbs_list.size (); n2++)
00349 {
00350 ON_NurbsSurface *nurbs2 = &nurbs_list[n2];
00351
00352
00353 for (unsigned i = 0; i < boundary1.size (); i++)
00354 {
00355 double error;
00356 Eigen::Vector3d p, tu, tv;
00357 Eigen::Vector3d p0 = boundary1[i];
00358 Eigen::Vector2d params1, params2;
00359
00360 switch (param.type)
00361 {
00362 case COMMON_BOUNDARY_POINT_MEAN:
00363 p = commonBoundaryPoint1 (*nurbs1, *nurbs2, params1, params2, p0, param.com_iter, error, param.accuracy);
00364 break;
00365 case COMMON_BOUNDARY_POINT_TANGENTS:
00366 p = commonBoundaryPoint2 (*nurbs1, *nurbs2, params1, params2, p0, param.com_iter, error, param.accuracy);
00367 break;
00368 case COMMON_BOUNDARY_POINT_PLANES:
00369 p = commonBoundaryPoint3 (*nurbs1, *nurbs2, params1, params2, p0, param.com_iter, error, param.accuracy);
00370 break;
00371 case CLOSEST_POINTS_INTERIOR:
00372 params1 = FittingSurface::findClosestElementMidPoint (*nurbs2, p0);
00373 FittingSurface::inverseMapping (*nurbs2, p0, params1, error, p, tu, tv, param.com_iter, param.accuracy, true);
00374 break;
00375 case CLOSEST_POINTS_BOUNDARY:
00376 FittingSurface::inverseMappingBoundary (*nurbs2, p0, error, p, tu, tv, param.com_iter, param.accuracy, true);
00377 break;
00378 }
00379
00380 double dist = (p - p0).norm ();
00381 if (error < param.max_error && dist < param.max_dist)
00382 {
00383 data_list[n1].boundary.push_back (p);
00384 data_list[n2].boundary.push_back (p);
00385 }
00386 }
00387
00388 }
00389
00390
00391 FittingSurface fit (&data_list[n1], nurbs_list[n1]);
00392 FittingSurface::Parameter paramFP (1.0, param.smoothness, 0.0, 1.0, param.smoothness, 0.0);
00393
00394 std::vector<double> wBnd, wInt;
00395 for (unsigned i = 0; i < data_list[n1].boundary.size (); i++)
00396 data_list[n1].boundary_weight.push_back (param.boundary_weight);
00397 for (unsigned i = 0; i < data_list[n1].interior.size (); i++)
00398 data_list[n1].interior_weight.push_back (param.interior_weight);
00399
00400 for (unsigned i = 0; i < param.fit_iter; i++)
00401 {
00402 fit.assemble (paramFP);
00403 fit.solve ();
00404 }
00405 nurbs_list[n1] = fit.m_nurbs;
00406
00407 }
00408
00409 }