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 #ifndef MILENA_APPS_MESH_SEGM_SKEL_MISC_HH
00033 # define MILENA_APPS_MESH_SEGM_SKEL_MISC_HH
00034
00035 # include <algorithm>
00036 # include <utility>
00037
00038 # include <mln/algebra/vec.hh>
00039 # include <mln/algebra/mat.hh>
00040
00041 # include <mln/norm/l2.hh>
00042
00043 # include <mln/data/fill.hh>
00044
00045
00052
00053 #ifndef likely
00054 # if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
00055 # define likely(x) (x)
00056 # define unlikely(x) (x)
00057 # else
00058 # define likely(x) (__builtin_expect((x), 1))
00059 # define unlikely(x) (__builtin_expect((x), 0))
00060 # endif
00061 #endif
00062
00063 namespace mln
00064 {
00065
00066 namespace algebra
00067 {
00068
00069
00070
00071
00072
00078 template <unsigned N, typename T>
00079 inline
00080 bool
00081 ldlt_decomp(mat<N, N, T>& A, vec<N, T>& rdiag)
00082 {
00083 vec<N - 1, T> v;
00084 for (unsigned i = 0; i < N; ++i)
00085 {
00086 for (unsigned k = 0; k < i; ++k)
00087 v[k] = A(i, k) * rdiag[k];
00088 for (unsigned j = i; j < N; ++j)
00089 {
00090 T sum = A(i, j);
00091 for (unsigned k = 0; k < i; k++)
00092 sum -= v[k] * A(j, k);
00093 if (i == j)
00094 {
00095 if (unlikely(sum <= T(0)))
00096 return false;
00097 rdiag[i] = T(1) / sum;
00098 }
00099 else
00100 A(j, i) = sum;
00101 }
00102 }
00103 return true;
00104 }
00105
00106
00107
00108
00109
00111 template <unsigned N, typename T>
00112 inline
00113 void
00114 ldlt_solve(const mat<N, N, T>& A, const vec<N, T>& rdiag,
00115 const vec<N, T>& B, vec<N, T>& x)
00116 {
00117 for (unsigned i = 0; i < N; ++i)
00118 {
00119 T sum = B[i];
00120 for (unsigned k = 0; k < i; ++k)
00121 sum -= A(i, k) * x[k];
00122 x[i] = sum * rdiag[i];
00123 }
00124 for (int i = N - 1; i >= 0; --i)
00125 {
00126 T sum = 0;
00127 for (unsigned k = i + 1; k < N; ++k)
00128 sum += A(k, i) * x[k];
00129 x[i] -= sum * rdiag[i];
00130 }
00131 }
00132
00133 }
00134
00135 }
00136
00137
00138
00139
00140
00141
00142 namespace mln
00143 {
00144
00145 namespace geom
00146 {
00147
00148
00149
00150
00151
00161 inline
00162 complex_image< 2, mln::space_2complex_geometry, algebra::vec<3, float> >
00163 mesh_normal(const p_complex<2, space_2complex_geometry>& mesh)
00164 {
00165
00166 static const unsigned D = 2;
00167 typedef space_2complex_geometry G;
00168 typedef algebra::vec<3, float> vec3f;
00169 typedef complex_image< D, G, vec3f > normal_t;
00170
00171 normal_t normal(mesh);
00172 data::fill(normal, literal::zero);
00173
00174 mln::p_n_faces_fwd_piter<D, G> f(mesh, 2);
00175
00176
00177 typedef mln::complex_m_face_neighborhood<D, G> adj_vertices_nbh_t;
00178 adj_vertices_nbh_t adj_vertices_nbh;
00179 mln_niter_(adj_vertices_nbh_t) adj_v(adj_vertices_nbh, f);
00180
00181
00182
00183
00184 adj_v.iter().set_m(0);
00185
00186
00187 for_all(f)
00188 {
00190 std::vector<mln_psite_(normal_t)> p;
00191 p.reserve(3);
00192 for_all(adj_v)
00193 p.push_back(adj_v);
00195 mln_assertion(p.size() == 3);
00196
00197
00198
00199
00200
00201
00202
00203
00204 vec3f a =
00205 p[0].to_site().front().to_vec() - p[1].to_site().front().to_vec();
00206 vec3f b =
00207 p[1].to_site().front().to_vec() - p[2].to_site().front().to_vec();
00208 vec3f c =
00209 p[2].to_site().front().to_vec() - p[0].to_site().front().to_vec();
00210
00211
00212 float l2a = norm::sqr_l2(a);
00213 float l2b = norm::sqr_l2(b);
00214 float l2c = norm::sqr_l2(c);
00215 vec3f face_normal = algebra::vprod(a, b);
00216
00217 normal(p[0]) += face_normal * (1.0f / (l2a * l2c));
00218 normal(p[1]) += face_normal * (1.0f / (l2b * l2a));
00219 normal(p[2]) += face_normal * (1.0f / (l2c * l2b));
00220 }
00221
00222
00223
00224 mln::p_n_faces_fwd_piter<D, G> v(mesh, 0);
00225 for_all(v)
00226 normal(v).normalize();
00227
00228 return normal;
00229 }
00230
00231
00232
00233
00246 inline
00247 std::pair<
00248 complex_image< 2, mln::space_2complex_geometry, algebra::vec<3, float> >,
00249 complex_image< 2, mln::space_2complex_geometry, float >
00250 >
00251 mesh_corner_point_area(const p_complex<2, space_2complex_geometry>& mesh)
00252 {
00253
00254 static const unsigned D = 2;
00255 typedef space_2complex_geometry G;
00256 typedef algebra::vec<3, float> vec3f;
00257
00258
00259 typedef complex_image< D, G, vec3f > corner_area_t;
00260
00261 typedef complex_image< D, G, float > point_area_t;
00262
00263 typedef std::pair<corner_area_t, point_area_t> output_t;
00264
00265
00266 output_t output(mesh, mesh);
00267 corner_area_t& corner_area = output.first;
00268 point_area_t& point_area = output.second;
00269 data::fill(corner_area, literal::zero);
00270 data::fill(point_area, literal::zero);
00271
00272 mln::p_n_faces_fwd_piter<D, G> f(mesh, 2);
00273
00274
00275 typedef mln::complex_m_face_neighborhood<D, G> adj_vertices_nbh_t;
00276 adj_vertices_nbh_t adj_vertices_nbh;
00277 mln_niter_(adj_vertices_nbh_t) adj_v(adj_vertices_nbh, f);
00278
00279
00280
00281
00282 adj_v.iter().set_m(0);
00283
00284 for_all(f)
00285 {
00287 std::vector<mln_psite_(corner_area_t)> p;
00288 p.reserve(3);
00289 for_all(adj_v)
00290 p.push_back(adj_v);
00292 mln_assertion(p.size() == 3);
00293
00294
00295 algebra::vec<3, vec3f> e;
00296
00297 e.set
00298 (p[2].to_site().front().to_vec() - p[1].to_site().front().to_vec(),
00299 p[0].to_site().front().to_vec() - p[2].to_site().front().to_vec(),
00300 p[1].to_site().front().to_vec() - p[0].to_site().front().to_vec());
00301
00302
00303 float area = 0.5f * norm::l2(algebra::vprod(e[0], e[1]));
00304 vec3f sqr_norm;
00305 sqr_norm.set(norm::sqr_l2(e[0]),
00306 norm::sqr_l2(e[1]),
00307 norm::sqr_l2(e[2]));
00308 vec3f edge_weight;
00309 edge_weight.set
00310 (sqr_norm[0] * (sqr_norm[1] + sqr_norm[2] - sqr_norm[0]),
00311 sqr_norm[1] * (sqr_norm[2] + sqr_norm[0] - sqr_norm[1]),
00312 sqr_norm[2] * (sqr_norm[0] + sqr_norm[1] - sqr_norm[2]));
00313
00314 if (edge_weight[0] <= 0.0f)
00315 {
00316 corner_area(f)[1] = -0.25f * sqr_norm[2] * area / (e[0] * e[2]);
00317 corner_area(f)[2] = -0.25f * sqr_norm[1] * area / (e[0] * e[1]);
00318 corner_area(f)[0] = area - corner_area(f)[1] - corner_area(f)[2];
00319 }
00320 else if (edge_weight[1] <= 0.0f)
00321 {
00322 corner_area(f)[2] = -0.25f * sqr_norm[0] * area / (e[1] * e[0]);
00323 corner_area(f)[0] = -0.25f * sqr_norm[2] * area / (e[1] * e[2]);
00324 corner_area(f)[1] = area - corner_area(f)[2] - corner_area(f)[0];
00325 }
00326 else if (edge_weight[2] <= 0.0f)
00327 {
00328 corner_area(f)[0] = -0.25f * sqr_norm[1] * area / (e[2] * e[1]);
00329 corner_area(f)[1] = -0.25f * sqr_norm[0] * area / (e[2] * e[0]);
00330 corner_area(f)[2] = area - corner_area(f)[0] - corner_area(f)[1];
00331 }
00332 else
00333 {
00334 float ewscale =
00335 0.5f * area / (edge_weight[0] + edge_weight[1] + edge_weight[2]);
00336 for (int i = 0; i < 3; ++i)
00337 corner_area(f)[i] =
00338 ewscale * (edge_weight[(i+1)%3] + edge_weight[(i+2)%3]);
00339 }
00340
00341 for (int i = 0; i < 3; ++i)
00342 point_area(p[i]) += corner_area(f)[i];
00343 }
00344
00345 return output;
00346 }
00347
00348
00349 namespace internal
00350 {
00351
00367 static inline unsigned next(unsigned i) { return (i + 1) % 3; }
00368 static inline unsigned prev(unsigned i) { return (i - 1) % 3; }
00372
00373 inline
00374 void
00375 rot_coord_sys(const algebra::vec<3, float> &old_u,
00376 const algebra::vec<3, float> &old_v,
00377 const algebra::vec<3, float> &new_norm,
00378 algebra::vec<3, float> &new_u,
00379 algebra::vec<3, float> &new_v)
00380 {
00381 new_u = old_u;
00382 new_v = old_v;
00383 algebra::vec<3, float> old_norm = vprod(old_u, old_v);
00384 float ndot = old_norm * new_norm;
00385 if (unlikely(ndot <= -1.0f))
00386 {
00387 new_u = -new_u;
00388 new_v = -new_v;
00389 return;
00390 }
00391 algebra::vec<3, float> perp_old = new_norm - ndot * old_norm;
00392 algebra::vec<3, float> dperp =
00393 1.0f / (1 + ndot) * (old_norm + new_norm);
00394 new_u -= dperp * (new_u * perp_old);
00395 new_v -= dperp * (new_v * perp_old);
00396 }
00397
00398
00399
00400
00401
00402
00403
00404 inline
00405 void
00406 proj_curv(const algebra::vec<3, float>& old_u,
00407 const algebra::vec<3, float>& old_v,
00408 float old_ku, float old_kuv, float old_kv,
00409 const algebra::vec<3, float>& new_u,
00410 const algebra::vec<3, float>& new_v,
00411 float& new_ku, float& new_kuv, float& new_kv)
00412 {
00413 algebra::vec<3, float> r_new_u, r_new_v;
00414 rot_coord_sys(new_u, new_v, vprod(old_u, old_v), r_new_u, r_new_v);
00415
00416 float u1 = r_new_u * old_u;
00417 float v1 = r_new_u * old_v;
00418 float u2 = r_new_v * old_u;
00419 float v2 = r_new_v * old_v;
00420 new_ku = old_ku * u1*u1 + old_kuv * (2.0f * u1*v1) + old_kv * v1*v1;
00421 new_kuv = old_ku * u1*u2 + old_kuv * (u1*v2 + u2*v1) + old_kv * v1*v2;
00422 new_kv = old_ku * u2*u2 + old_kuv * (2.0f * u2*v2) + old_kv * v2*v2;
00423 }
00424
00428 inline
00429 void
00430 diagonalize_curv(const algebra::vec<3, float>& old_u,
00431 const algebra::vec<3, float>& old_v,
00432 float ku, float kuv, float kv,
00433 const algebra::vec<3, float>& new_norm,
00434 algebra::vec<3, float>& pdir1,
00435 algebra::vec<3, float>& pdir2,
00436 float& k1, float& k2)
00437 {
00438 algebra::vec<3, float> r_old_u, r_old_v;
00439 rot_coord_sys(old_u, old_v, new_norm, r_old_u, r_old_v);
00440
00441 float c = 1, s = 0, tt = 0;
00442 if (likely(kuv != 0.0f))
00443 {
00444
00445 float h = 0.5f * (kv - ku) / kuv;
00446 tt = (h < 0.0f) ?
00447 1.0f / (h - sqrt(1.0f + h*h)) :
00448 1.0f / (h + sqrt(1.0f + h*h));
00449 c = 1.0f / sqrt(1.0f + tt*tt);
00450 s = tt * c;
00451 }
00452
00453 k1 = ku - tt * kuv;
00454 k2 = kv + tt * kuv;
00455
00456 if (fabs(k1) >= fabs(k2))
00457 pdir1 = c*r_old_u - s*r_old_v;
00458 else
00459 {
00460 std::swap(k1, k2);
00461 pdir1 = s*r_old_u + c*r_old_v;
00462 }
00463 pdir2 = vprod(new_norm, pdir1);
00464 }
00465
00466 }
00467
00468
00480
00481
00482
00483 inline
00484 std::pair<
00485 complex_image< 2, mln::space_2complex_geometry, float >,
00486 complex_image< 2, mln::space_2complex_geometry, float >
00487 >
00488 mesh_curvature(const p_complex<2, space_2complex_geometry>& mesh)
00489 {
00490
00491 static const unsigned D = 2;
00492 typedef space_2complex_geometry G;
00493 typedef algebra::vec<3, float> vec3f;
00494 typedef algebra::mat<3, 3, float> mat3f;
00495
00496 typedef complex_image< D, G, vec3f > corner_area_t;
00497 typedef complex_image< D, G, float > point_area_t;
00498
00499
00500 typedef complex_image< 2, mln::space_2complex_geometry, vec3f > normal_t;
00501 normal_t normal = mesh_normal(mesh);
00502
00503
00504 typedef complex_image< D, G, vec3f > corner_area_t;
00505 typedef complex_image< D, G, float > point_area_t;
00506 typedef std::pair<corner_area_t, point_area_t> corner_point_area_t;
00507 corner_point_area_t corner_point_area = mesh_corner_point_area(mesh);
00508
00509 corner_area_t& corner_area = corner_point_area.first;
00510 point_area_t& point_area = corner_point_area.second;
00511
00512
00513 typedef complex_image< 2, mln::space_2complex_geometry, float > curv_t;
00514 typedef std::pair<curv_t, curv_t> output_t;
00515 output_t output(mesh, mesh);
00516 curv_t& curv1 = output.first;
00517 curv_t& curv2 = output.second;
00518
00519 complex_image< 2, mln::space_2complex_geometry, float > curv12(mesh);
00520
00521 complex_image< 2, mln::space_2complex_geometry, vec3f > pdir1(mesh);
00522 complex_image< 2, mln::space_2complex_geometry, vec3f > pdir2(mesh);
00523
00524
00525
00526
00527
00528 mln::p_n_faces_fwd_piter<D, G> f(mesh, 2);
00529
00530
00531 typedef mln::complex_m_face_neighborhood<D, G> adj_vertices_nbh_t;
00532 adj_vertices_nbh_t adj_vertices_nbh;
00533 mln_niter_(adj_vertices_nbh_t) adj_v(adj_vertices_nbh, f);
00534
00535
00536
00537
00538 adj_v.iter().set_m(0);
00539
00540 for_all(f)
00541 {
00543 std::vector<mln_psite_(curv_t)> p;
00544 p.reserve(3);
00545 for_all(adj_v)
00546 p.push_back(adj_v);
00548 mln_assertion(p.size() == 3);
00549
00550
00551 pdir1(p[0]) =
00552 p[1].to_site().front().to_vec() - p[0].to_site().front().to_vec();
00553 pdir1(p[1]) =
00554 p[2].to_site().front().to_vec() - p[1].to_site().front().to_vec();
00555 pdir1(p[2]) =
00556 p[0].to_site().front().to_vec() - p[2].to_site().front().to_vec();
00557 }
00558
00559 mln::p_n_faces_fwd_piter<D, G> v(mesh, 0);
00560 for_all(v)
00561 {
00562 pdir1(v) = algebra::vprod(pdir1(v), normal(v));
00563 pdir1(v).normalize();
00564 pdir2(v) = algebra::vprod(normal(v), pdir1(v));
00565 }
00566
00567
00568
00569
00570
00571 for_all(f)
00572 {
00573 std::vector<mln_psite_(curv_t)> p;
00574 p.reserve(3);
00575 for_all(adj_v)
00576 p.push_back(adj_v);
00577 mln_assertion(p.size() == 3);
00578
00579
00580 algebra::vec<3, vec3f> e;
00581
00582 e.set
00583 (p[2].to_site().front().to_vec() - p[1].to_site().front().to_vec(),
00584 p[0].to_site().front().to_vec() - p[2].to_site().front().to_vec(),
00585 p[1].to_site().front().to_vec() - p[0].to_site().front().to_vec());
00586
00587
00588 vec3f t = e[0];
00589 t.normalize();
00590 vec3f n = algebra::vprod(e[0], e[1]);
00591
00592
00593 vec3f b = algebra::vprod(n, t);
00594 b.normalize();
00595
00596
00597 vec3f m = literal::zero;
00598 mat3f w = literal::zero;
00599 for (int j = 0; j < 3; ++j)
00600 {
00601 float u = e[j] * t;
00602 float v = e[j] * b;
00603 w(0, 0) += u * u;
00604 w(0, 1) += u * v;
00605
00606
00607
00608
00609
00610
00611
00612 w(2, 2) += v * v;
00613 vec3f dn =
00614 normal(p[internal::prev(j)]) - normal(p[internal::next(j)]);
00615 float dnu = dn * t;
00616 float dnv = dn * b;
00617 m[0] += dnu*u;
00618 m[1] += dnu*v + dnv*u;
00619 m[2] += dnv*v;
00620 }
00621 w(1, 1) = w(0, 0) + w(2, 2);
00622 w(1, 2) = w(0, 1);
00623
00624
00625 vec3f diag;
00626
00627
00628 bool ldlt_decomp_success_p = algebra::ldlt_decomp(w, diag);
00629 mln_assertion(ldlt_decomp_success_p);
00630
00631
00632 (void) ldlt_decomp_success_p;
00633 algebra::ldlt_solve(w, diag, m, m);
00634
00635
00636 for (int j = 0; j < 3; ++j)
00637 {
00638 float c1, c12, c2;
00639 internal::proj_curv(t, b, m[0], m[1], m[2],
00640 pdir1(p[j]), pdir2(p[j]), c1, c12, c2);
00641 float wt = corner_area(f)[j] / point_area(p[j]);
00642 curv1(p[j]) += wt * c1;
00643 curv12(p[j]) += wt * c12;
00644 curv2(p[j]) += wt * c2;
00645 }
00646 }
00647
00648
00649
00650
00651
00652 for_all(v)
00653 internal::diagonalize_curv(pdir1(v), pdir2(v),
00654 curv1(v), curv12(v), curv2(v),
00655 normal(v), pdir1(v), pdir2(v),
00656 curv1(v), curv2(v));
00657
00658 return output;
00659 }
00660
00661 }
00662
00663 }
00664
00665 #endif // ! MILENA_APPS_MESH_SEGM_SKEL_MISC_HH