00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <iostream>
00013 #include <vector>
00014 #include <algorithm>
00015 #include <cmath>
00016
00017 using namespace std;
00018
00019 #include "mlib/points.H"
00020 #include "mlib/linear_sys.H"
00021
00022 using namespace mlib;
00023
00024 #include "mesh/bvert.H"
00025 #include "mesh/bface.H"
00026 #include "mesh/bmesh.H"
00027
00028 #include "mesh/bmesh_curvature.H"
00029
00030
00031
00032 void rot_coord_sys(const Wvec &old_u, const Wvec &old_v,
00033 const Wvec &new_norm, Wvec &new_u, Wvec &new_v);
00034 void proj_curv(const Wvec &old_u, const Wvec &old_v,
00035 double old_ku, double old_kuv, double old_kv,
00036 const Wvec &new_u, const Wvec &new_v,
00037 double &new_ku, double &new_kuv, double &new_kv);
00038 void proj_dcurv(const Wvec &old_u, const Wvec &old_v,
00039 const BMESHcurvature_data::dcurv_tensor_t &old_dcurv,
00040 const Wvec &new_u, const Wvec &new_v,
00041 BMESHcurvature_data::dcurv_tensor_t &new_dcurv);
00042 void diagonalize_curv(const Wvec &old_u, const Wvec &old_v,
00043 double ku, double kuv, double kv,
00044 const Wvec &new_norm,
00045 Wvec &pdir1, Wvec &pdir2, double &k1, double &k2);
00046
00047 inline void compute_edge_vectors(const BMESH *mesh, int face_idx, Wvec edges[3]);
00048 inline void compute_ntb_coord_sys(const Wvec edges[3], Wvec &n, Wvec &t, Wvec &b);
00049 inline void compute_initial_vertex_coord_sys(const BMESH *mesh,
00050 vector<Wvec> &pdir1, vector<Wvec> &pdir2);
00051
00052
00053
00054
00055
00056
00057
00058 BMESHcurvature_data::BMESHcurvature_data(const BMESH *mesh_in)
00059 : mesh(mesh_in), mesh_feature_size(0.0)
00060 {
00061
00062 compute_corner_areas();
00063 compute_vertex_areas();
00064 compute_face_curvatures();
00065 compute_vertex_curvatures();
00066 diagonalize_vertex_curvatures();
00067 compute_face_dcurv();
00068 compute_vertex_dcurv();
00069 compute_feature_size();
00070
00071 }
00072
00073
00074
00075 BMESHcurvature_data::curv_tensor_t
00076 BMESHcurvature_data::curv_tensor(const Bvert *v)
00077 {
00078
00079 return vertex_curv[v->index()];
00080
00081 }
00082
00083 BMESHcurvature_data::diag_curv_t
00084 BMESHcurvature_data::diag_curv(const Bvert *v)
00085 {
00086
00087 return diag_vertex_curv[v->index()];
00088
00089 }
00090
00091 double
00092 BMESHcurvature_data::k1(const Bvert *v)
00093 {
00094
00095 return diag_vertex_curv[v->index()].k1();
00096
00097 }
00098
00099 double
00100 BMESHcurvature_data::k2(const Bvert *v)
00101 {
00102
00103 return diag_vertex_curv[v->index()].k2();
00104
00105 }
00106
00107 Wvec
00108 BMESHcurvature_data::pdir1(const Bvert *v)
00109 {
00110
00111 return diag_vertex_curv[v->index()].pdir1();
00112
00113 }
00114
00115 Wvec
00116 BMESHcurvature_data::pdir2(const Bvert *v)
00117 {
00118
00119 return diag_vertex_curv[v->index()].pdir2();
00120
00121 }
00122
00123 BMESHcurvature_data::dcurv_tensor_t
00124 BMESHcurvature_data::dcurv_tensor(const Bvert *v)
00125 {
00126
00127 return vertex_dcurv[v->index()];
00128
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138 void
00139 BMESHcurvature_data::compute_corner_areas()
00140 {
00141
00142 int nf = mesh->nfaces();
00143
00144 corner_areas.clear();
00145 corner_areas.resize(nf);
00146
00147 for (int i = 0; i < nf; i++) {
00148
00149 Wvec e[3];
00150 compute_edge_vectors(mesh, i, e);
00151
00152
00153 double area = mesh->bf(i)->area();
00154 double l2[3] = { e[0].length_sqrd(), e[1].length_sqrd(), e[2].length_sqrd() };
00155 double ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]),
00156 l2[1] * (l2[2] + l2[0] - l2[1]),
00157 l2[2] * (l2[0] + l2[1] - l2[2]) };
00158
00159 if (ew[0] <= 0.0f) {
00160
00161 corner_areas[i][1] = -0.25f * l2[2] * area / (e[0] * e[2]);
00162 corner_areas[i][2] = -0.25f * l2[1] * area / (e[0] * e[1]);
00163 corner_areas[i][0] = area - corner_areas[i][1] - corner_areas[i][2];
00164
00165 } else if (ew[1] <= 0.0f) {
00166
00167 corner_areas[i][2] = -0.25f * l2[0] * area / (e[1] * e[0]);
00168 corner_areas[i][0] = -0.25f * l2[2] * area / (e[1] * e[2]);
00169 corner_areas[i][1] = area - corner_areas[i][2] - corner_areas[i][0];
00170
00171 } else if (ew[2] <= 0.0f) {
00172
00173 corner_areas[i][0] = -0.25f * l2[1] * area / (e[2] * e[1]);
00174 corner_areas[i][1] = -0.25f * l2[0] * area / (e[2] * e[0]);
00175 corner_areas[i][2] = area - corner_areas[i][0] - corner_areas[i][1];
00176
00177 } else {
00178
00179 double ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]);
00180 for (int j = 0; j < 3; j++)
00181 corner_areas[i][j] = ewscale * (ew[(j+1)%3] + ew[(j+2)%3]);
00182
00183 }
00184
00185 }
00186
00187 }
00188
00189
00190
00191
00192
00193
00194 void
00195 BMESHcurvature_data::compute_vertex_areas()
00196 {
00197
00198 int nf = mesh->nfaces();
00199
00200 vertex_areas.clear();
00201 vertex_areas.resize(mesh->nverts());
00202
00203 for (int i = 0; i < nf; i++) {
00204
00205 vertex_areas[mesh->bf(i)->v1()->index()] += corner_areas[i][0];
00206 vertex_areas[mesh->bf(i)->v2()->index()] += corner_areas[i][1];
00207 vertex_areas[mesh->bf(i)->v3()->index()] += corner_areas[i][2];
00208
00209 }
00210
00211 }
00212
00213
00214
00215
00216
00217
00218
00219 void
00220 BMESHcurvature_data::compute_face_curvatures()
00221 {
00222
00223 int nf = mesh->nfaces();
00224
00225 face_curv.clear();
00226 face_curv.resize(nf);
00227
00228
00229 for (int i = 0; i < nf; ++i) {
00230
00231 Wvec e[3];
00232 compute_edge_vectors(mesh, i, e);
00233
00234 Wvec n, t, b;
00235 compute_ntb_coord_sys(e, n, t, b);
00236
00237
00238
00239 double m[3] = { 0, 0, 0 };
00240 double w[3][3] = { {0,0,0}, {0,0,0}, {0,0,0} };
00241 for (int j = 0; j < 3; ++j) {
00242
00243 double u = e[j] * t;
00244 double v = e[j] * b;
00245 w[0][0] += u*u;
00246 w[0][1] += u*v;
00247
00248
00249 w[2][2] += v*v;
00250 Wvec dn = mesh->bf(i)->v(((j+2)%3)+1)->norm()
00251 - mesh->bf(i)->v(((j+1)%3)+1)->norm();
00252 double dnu = dn * t;
00253 double dnv = dn * b;
00254 m[0] += dnu*u;
00255 m[1] += dnu*v + dnv*u;
00256 m[2] += dnv*v;
00257
00258 }
00259
00260 w[1][1] = w[0][0] + w[2][2];
00261 w[1][2] = w[0][1];
00262
00263
00264 double diag[3];
00265 if (!ldltdc<double,3>(w, diag)) {
00266
00267 continue;
00268 }
00269 ldltsl<double,3>(w, diag, m, m);
00270
00271 face_curv[i][0] = m[0];
00272 face_curv[i][1] = m[1];
00273 face_curv[i][2] = m[2];
00274
00275 }
00276
00277 }
00278
00279
00280
00281
00282
00283
00284
00285 void
00286 BMESHcurvature_data::compute_vertex_curvatures()
00287 {
00288
00289 int nv = mesh->nverts();
00290
00291 vertex_curv.clear();
00292 vertex_curv.resize(nv);
00293
00294
00295 vector<Wvec> pdir1(nv), pdir2(nv);
00296
00297 compute_initial_vertex_coord_sys(mesh, pdir1, pdir2);
00298
00299 for(int i = 0; i < mesh->nfaces(); ++i) {
00300
00301 Wvec e[3];
00302 compute_edge_vectors(mesh, i, e);
00303
00304 Wvec n, t, b;
00305 compute_ntb_coord_sys(e, n, t, b);
00306
00307
00308 for(int j = 0; j < 3; ++j){
00309
00310 int vj = mesh->bf(i)->v(j+1)->index();
00311 double c1, c12, c2;
00312 proj_curv(t, b, face_curv[i][0], face_curv[i][1], face_curv[i][2],
00313 pdir1[vj], pdir2[vj], c1, c12, c2);
00314 double wt = corner_areas[i][j] / vertex_areas[vj];
00315 vertex_curv[vj][0] += wt * c1;
00316 vertex_curv[vj][1] += wt * c12;
00317 vertex_curv[vj][2] += wt * c2;
00318
00319 }
00320
00321 }
00322
00323 }
00324
00325
00326
00327
00328
00329
00330
00331 void
00332 BMESHcurvature_data::diagonalize_vertex_curvatures()
00333 {
00334
00335 int nv = mesh->nverts();
00336
00337 diag_vertex_curv.clear();
00338 diag_vertex_curv.resize(nv);
00339
00340 vector<Wvec> pdir1(nv), pdir2(nv);
00341 compute_initial_vertex_coord_sys(mesh, pdir1, pdir2);
00342
00343
00344 vector<double> k1(nv), k2(nv);
00345
00346 for (int i = 0; i < nv; i++){
00347
00348 diagonalize_curv(pdir1[i], pdir2[i],
00349 vertex_curv[i][0], vertex_curv[i][1], vertex_curv[i][2],
00350 mesh->bv(i)->norm(), pdir1[i], pdir2[i],
00351 k1[i], k2[i]);
00352
00353 diag_vertex_curv[i]._k1 = k1[i];
00354 diag_vertex_curv[i]._k2 = k2[i];
00355 diag_vertex_curv[i]._pdir1 = pdir1[i];
00356 diag_vertex_curv[i]._pdir2 = pdir2[i];
00357
00358
00359
00360
00361 }
00362
00363 }
00364
00365
00366
00367
00368
00369
00370
00371 void
00372 BMESHcurvature_data::compute_face_dcurv()
00373 {
00374
00375 int nf = mesh->nfaces();
00376
00377 face_dcurv.clear();
00378 face_dcurv.resize(nf);
00379
00380
00381 for(int i = 0; i < nf; ++i){
00382
00383 Wvec e[3];
00384 compute_edge_vectors(mesh, i, e);
00385
00386 Wvec n, t, b;
00387 compute_ntb_coord_sys(e, n, t, b);
00388
00389
00390
00391 curv_tensor_t fcurv[3];
00392 for(int j = 0; j < 3; ++j){
00393 int vj = mesh->bf(i)->v(j+1)->index();
00394 proj_curv(diag_vertex_curv[vj].pdir1(), diag_vertex_curv[vj].pdir2(),
00395 diag_vertex_curv[vj].k1(), 0, diag_vertex_curv[vj].k2(),
00396 t, b, fcurv[j][0], fcurv[j][1], fcurv[j][2]);
00397
00398 }
00399
00400
00401 double m[4] = { 0, 0, 0, 0 };
00402 double w[4][4] = { {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} };
00403 for(int j = 0; j < 3; ++j){
00404
00405 curv_tensor_t dfcurv = fcurv[(j+2)%3] - fcurv[(j+1)%3];
00406 double u = e[j] * t;
00407 double v = e[j] * b;
00408 double u2 = u*u, v2 = v*v, uv = u*v;
00409 w[0][0] += u2;
00410 w[0][1] += uv;
00411
00412
00413
00414
00415 w[3][3] += v2;
00416 m[0] += u*dfcurv[0];
00417 m[1] += v*dfcurv[0] + 2.0f*u*dfcurv[1];
00418 m[2] += 2.0f*v*dfcurv[1] + u*dfcurv[2];
00419 m[3] += v*dfcurv[2];
00420 }
00421 w[1][1] = 2.0f * w[0][0] + w[3][3];
00422 w[1][2] = 2.0f * w[0][1];
00423 w[2][2] = w[0][0] + 2.0f * w[3][3];
00424 w[2][3] = w[0][1];
00425
00426
00427 double d[4];
00428 if(!ldltdc<double,4>(w, d)){
00429
00430 continue;
00431 }
00432 ldltsl<double,4>(w, d, m, m);
00433
00434 face_dcurv[i][0] = m[0];
00435 face_dcurv[i][1] = m[1];
00436 face_dcurv[i][2] = m[2];
00437 face_dcurv[i][3] = m[3];
00438
00439 }
00440
00441 }
00442
00443
00444
00445
00446
00447
00448
00449 void
00450 BMESHcurvature_data::compute_vertex_dcurv()
00451 {
00452
00453 int nv = mesh->nverts();
00454 int nf = mesh->nfaces();
00455
00456 vertex_dcurv.clear();
00457 vertex_dcurv.resize(nv);
00458
00459 for(int i = 0; i < nf; ++i){
00460
00461 Wvec e[3];
00462 compute_edge_vectors(mesh, i, e);
00463
00464 Wvec n, t, b;
00465 compute_ntb_coord_sys(e, n, t, b);
00466
00467
00468 for(int j = 0; j < 3; ++j){
00469
00470 int vj = mesh->bf(i)->v(j+1)->index();
00471 dcurv_tensor_t this_vert_dcurv;
00472 proj_dcurv(t, b, face_dcurv[i],
00473 diag_vertex_curv[vj].pdir1(), diag_vertex_curv[vj].pdir2(),
00474 this_vert_dcurv);
00475 double wt = corner_areas[i][j] / vertex_areas[vj];
00476 vertex_dcurv[vj] += wt * this_vert_dcurv;
00477
00478 }
00479
00480 }
00481
00482 }
00483
00484
00485
00486
00487
00488
00489 void
00490 BMESHcurvature_data::compute_feature_size()
00491 {
00492
00493 int nv = mesh->nverts();
00494 int nsamp = min(nv, 500);
00495
00496 vector<double> samples;
00497 samples.reserve(nsamp * 2);
00498
00499 for(int i = 0; i < nsamp; ++i){
00500
00501
00502 static unsigned randq = 0;
00503 randq = unsigned(1664525) * randq + unsigned(1013904223);
00504
00505 int ind = randq % nv;
00506 samples.push_back(fabs(diag_vertex_curv[ind].k1()));
00507 samples.push_back(fabs(diag_vertex_curv[ind].k2()));
00508
00509 }
00510
00511 const double frac = 0.1f;
00512 const double mult = 0.01f;
00513 int which = int(frac * samples.size());
00514 nth_element(samples.begin(), samples.begin() + which, samples.end());
00515
00516 mesh_feature_size = mult / samples[which];
00517
00518 }
00519
00520
00521
00522
00523
00524
00525
00526 void
00527 rot_coord_sys(const Wvec &old_u, const Wvec &old_v,
00528 const Wvec &new_norm, Wvec &new_u, Wvec &new_v)
00529 {
00530 new_u = old_u;
00531 new_v = old_v;
00532 Wvec old_norm = cross(old_u, old_v);
00533 double ndot = old_norm * new_norm;
00534 if (ndot <= -1.0f) {
00535 new_u = -new_u;
00536 new_v = -new_v;
00537 return;
00538 }
00539 Wvec perp_old = new_norm - ndot * old_norm;
00540 Wvec dperp = 1.0f / (1 + ndot) * (old_norm + new_norm);
00541 new_u -= dperp * (new_u * perp_old);
00542 new_v -= dperp * (new_v * perp_old);
00543 }
00544
00545
00546
00547
00548
00549
00550
00551
00552 void
00553 proj_curv(const Wvec &old_u, const Wvec &old_v,
00554 double old_ku, double old_kuv, double old_kv,
00555 const Wvec &new_u, const Wvec &new_v,
00556 double &new_ku, double &new_kuv, double &new_kv)
00557 {
00558 Wvec r_new_u, r_new_v;
00559 rot_coord_sys(new_u, new_v, cross(old_u, old_v), r_new_u, r_new_v);
00560
00561 double u1 = r_new_u * old_u;
00562 double v1 = r_new_u * old_v;
00563 double u2 = r_new_v * old_u;
00564 double v2 = r_new_v * old_v;
00565 new_ku = old_ku * u1*u1 + old_kuv * (2.0f * u1*v1) + old_kv * v1*v1;
00566 new_kuv = old_ku * u1*u2 + old_kuv * (u1*v2 + u2*v1) + old_kv * v1*v2;
00567 new_kv = old_ku * u2*u2 + old_kuv * (2.0f * u2*v2) + old_kv * v2*v2;
00568 }
00569
00570
00571
00572
00573
00574
00575 void
00576 proj_dcurv(const Wvec &old_u, const Wvec &old_v,
00577 const BMESHcurvature_data::dcurv_tensor_t &old_dcurv,
00578 const Wvec &new_u, const Wvec &new_v,
00579 BMESHcurvature_data::dcurv_tensor_t &new_dcurv)
00580 {
00581 Wvec r_new_u, r_new_v;
00582 rot_coord_sys(new_u, new_v, cross(old_u, old_v), r_new_u, r_new_v);
00583
00584 double u1 = r_new_u * old_u;
00585 double v1 = r_new_u * old_v;
00586 double u2 = r_new_v * old_u;
00587 double v2 = r_new_v * old_v;
00588
00589 new_dcurv[0] = old_dcurv[0]*u1*u1*u1 +
00590 old_dcurv[1]*3.0f*u1*u1*v1 +
00591 old_dcurv[2]*3.0f*u1*v1*v1 +
00592 old_dcurv[3]*v1*v1*v1;
00593 new_dcurv[1] = old_dcurv[0]*u1*u1*u2 +
00594 old_dcurv[1]*(u1*u1*v2 + 2.0f*u2*u1*v1) +
00595 old_dcurv[2]*(u2*v1*v1 + 2.0f*u1*v1*v2) +
00596 old_dcurv[3]*v1*v1*v2;
00597 new_dcurv[2] = old_dcurv[0]*u1*u2*u2 +
00598 old_dcurv[1]*(u2*u2*v1 + 2.0f*u1*u2*v2) +
00599 old_dcurv[2]*(u1*v2*v2 + 2.0f*u2*v2*v1) +
00600 old_dcurv[3]*v1*v2*v2;
00601 new_dcurv[3] = old_dcurv[0]*u2*u2*u2 +
00602 old_dcurv[1]*3.0f*u2*u2*v2 +
00603 old_dcurv[2]*3.0f*u2*v2*v2 +
00604 old_dcurv[3]*v2*v2*v2;
00605 }
00606
00607
00608
00609
00610
00611
00612
00613
00614 void
00615 diagonalize_curv(const Wvec &old_u, const Wvec &old_v,
00616 double ku, double kuv, double kv,
00617 const Wvec &new_norm,
00618 Wvec &pdir1, Wvec &pdir2, double &k1, double &k2)
00619 {
00620 Wvec r_old_u, r_old_v;
00621 rot_coord_sys(old_u, old_v, new_norm, r_old_u, r_old_v);
00622
00623 double c = 1, s = 0, tt = 0;
00624 if (kuv != 0.0f) {
00625
00626 double h = 0.5f * (kv - ku) / kuv;
00627 tt = (h < 0.0f) ?
00628 1.0f / (h - sqrt(1.0f + h*h)) :
00629 1.0f / (h + sqrt(1.0f + h*h));
00630 c = 1.0f / sqrt(1.0f + tt*tt);
00631 s = tt * c;
00632 }
00633
00634 k1 = ku - tt * kuv;
00635 k2 = kv + tt * kuv;
00636
00637 if (fabs(k1) >= fabs(k2)) {
00638 pdir1 = c*r_old_u - s*r_old_v;
00639 } else {
00640 swap(k1, k2);
00641 pdir1 = s*r_old_u + c*r_old_v;
00642 }
00643 pdir2 = cross(new_norm, pdir1);
00644 }
00645
00646 inline
00647 void
00648 compute_edge_vectors(const BMESH *mesh, int face_idx, Wvec edges[3])
00649 {
00650
00651
00652 edges[0] = mesh->bf(face_idx)->v3()->loc() - mesh->bf(face_idx)->v2()->loc();
00653 edges[1] = mesh->bf(face_idx)->v1()->loc() - mesh->bf(face_idx)->v3()->loc();
00654 edges[2] = mesh->bf(face_idx)->v2()->loc() - mesh->bf(face_idx)->v1()->loc();
00655
00656 }
00657
00658 inline
00659 void
00660 compute_ntb_coord_sys(const Wvec edges[3], Wvec &n, Wvec &t, Wvec &b)
00661 {
00662
00663
00664 t = edges[0].normalized();
00665 n = cross(edges[0], edges[1]);
00666 b = cross(n, t).normalized();
00667
00668 }
00669
00670 inline
00671 void
00672 compute_initial_vertex_coord_sys(const BMESH *mesh,
00673 vector<Wvec> &pdir1, vector<Wvec> &pdir2)
00674 {
00675
00676
00677
00678 for(int i = 0; i < mesh->nfaces(); ++i){
00679
00680 pdir1[mesh->bf(i)->v1()->index()] = mesh->bf(i)->v2()->loc()
00681 - mesh->bf(i)->v1()->loc();
00682 pdir1[mesh->bf(i)->v2()->index()] = mesh->bf(i)->v3()->loc()
00683 - mesh->bf(i)->v2()->loc();
00684 pdir1[mesh->bf(i)->v3()->index()] = mesh->bf(i)->v1()->loc()
00685 - mesh->bf(i)->v3()->loc();
00686
00687 }
00688
00689 for(int i = 0; i < mesh->nverts(); i++){
00690
00691 pdir1[i] = cross(pdir1[i], mesh->bv(i)->norm()).normalized();
00692 pdir2[i] = cross(mesh->bv(i)->norm(), pdir1[i]);
00693
00694 }
00695
00696 }