00001
00002 #include "imesh_project.h"
00003
00004
00005
00006
00007 #include <imesh/imesh_operations.h>
00008 #include <imesh/algo/imesh_intersect.h>
00009 #include <vgl/vgl_point_2d.h>
00010 #include <vgl/vgl_homg_point_2d.h>
00011 #include <vgl/vgl_homg_point_3d.h>
00012 #include <vgl/vgl_vector_3d.h>
00013 #include <vgl/vgl_plane_3d.h>
00014 #include <vgl/vgl_line_3d_2_points.h>
00015 #include <vgl/vgl_triangle_test.h>
00016 #include <vgl/vgl_intersection.h>
00017 #include <vgl/vgl_distance.h>
00018 #include <vgl/vgl_triangle_scan_iterator.h>
00019 #include <vcl_algorithm.h>
00020 #include <vcl_limits.h>
00021 #include <vcl_cmath.h>
00022 #include <vcl_cassert.h>
00023
00024
00025 void
00026 imesh_project_verts(const imesh_vertex_array<3>& verts3d,
00027 const vpgl_proj_camera<double>& camera,
00028 vcl_vector<vgl_point_2d<double> >& verts2d)
00029 {
00030 verts2d.resize(verts3d.size());
00031 for (unsigned int i=0; i<verts3d.size(); ++i)
00032 verts2d[i] = camera.project(verts3d[i]);
00033 }
00034
00035 void
00036 imesh_project_verts(const vcl_vector<vgl_point_3d<double> >& verts3d,
00037 const vpgl_proj_camera<double>& camera,
00038 vcl_vector<vgl_point_2d<double> >& verts2d)
00039 {
00040 verts2d.resize(verts3d.size());
00041 for (unsigned int i=0; i<verts3d.size(); ++i)
00042 verts2d[i] = camera.project(verts3d[i]);
00043 }
00044
00045
00046 void
00047 imesh_project_verts(const vcl_vector<vgl_point_3d<double> >& verts3d,
00048 const vpgl_proj_camera<double>& camera,
00049 vcl_vector<vgl_point_2d<double> >& verts2d,
00050 vcl_vector<double>& depths)
00051 {
00052 verts2d.resize(verts3d.size());
00053 depths.resize(verts3d.size());
00054 for (unsigned int i=0; i<verts3d.size(); ++i) {
00055 vgl_homg_point_2d<double> pt = camera.project(verts3d[i]);
00056 verts2d[i] = pt;
00057 depths[i] = pt.w();
00058 }
00059 }
00060
00061
00062 void
00063 imesh_project_verts(const imesh_vertex_array<3>& verts3d,
00064 const vpgl_proj_camera<double>& camera,
00065 vcl_vector<vgl_point_2d<double> >& verts2d,
00066 vcl_vector<double>& depths)
00067 {
00068 verts2d.resize(verts3d.size());
00069 depths.resize(verts3d.size());
00070 for (unsigned int i=0; i<verts3d.size(); ++i) {
00071 vgl_homg_point_2d<double> pt = camera.project(verts3d[i]);
00072 verts2d[i] = pt;
00073 depths[i] = pt.w();
00074 }
00075 }
00076
00077
00078 void
00079 imesh_distort_verts(const vcl_vector<vgl_point_2d<double> >& in_verts,
00080 const bpgl_lens_distortion<double>& lens,
00081 vcl_vector<vgl_point_2d<double> >& out_verts)
00082 {
00083 out_verts.resize(in_verts.size());
00084 for (unsigned int i=0; i<in_verts.size(); ++i)
00085 out_verts[i] = lens.undistort(vgl_homg_point_2d<double>(in_verts[i]));
00086 }
00087
00088
00089
00090 void imesh_render_triangle(const vgl_point_2d<double>& v1,
00091 const vgl_point_2d<double>& v2,
00092 const vgl_point_2d<double>& v3,
00093 vil_image_view<bool>& image)
00094 {
00095 vgl_triangle_scan_iterator<double> tsi;
00096 tsi.a.x = v1.x(); tsi.a.y = v1.y();
00097 tsi.b.x = v2.x(); tsi.b.y = v2.y();
00098 tsi.c.x = v3.x(); tsi.c.y = v3.y();
00099 for (tsi.reset(); tsi.next(); ) {
00100 int y = tsi.scany();
00101 if (y<0 || y>=int(image.nj())) continue;
00102 int min_x = tsi.startx();
00103 int max_x = tsi.endx();
00104 if (min_x >= (int)image.ni() || max_x < 0)
00105 continue;
00106 if (min_x < 0) min_x = 0;
00107 if (max_x >= (int)image.ni()) max_x = image.ni()-1;
00108 for (int x = min_x; x <= max_x; ++x) {
00109 image(x,y) = true;
00110 }
00111 }
00112 }
00113
00114
00115
00116 void imesh_render_triangle_interp(const vgl_point_2d<double>& v1,
00117 const vgl_point_2d<double>& v2,
00118 const vgl_point_2d<double>& v3,
00119 const double& i1, const double& i2, const double& i3,
00120 vil_image_view<double>& image)
00121 {
00122 vgl_triangle_scan_iterator<double> tsi;
00123 tsi.a.x= v1.x(); tsi.a.y = v1.y();
00124 tsi.b.x = v2.x(); tsi.b.y = v2.y();
00125 tsi.c.x = v3.x(); tsi.c.y = v3.y();
00126 vgl_vector_3d<double> b1(v2.x()-v1.x(), v2.y()-v1.y(), i2-i1);
00127 vgl_vector_3d<double> b2(v3.x()-v1.x(), v3.y()-v1.y(), i3-i1);
00128 vgl_vector_3d<double> n = cross_product(b1,b2);
00129 double A = -n.x()/n.z();
00130 double B = -n.y()/n.z();
00131 double C = (v1.x()*n.x() + v1.y()*n.y() + i1*n.z())/n.z();
00132 for (tsi.reset(); tsi.next(); ) {
00133 int y = tsi.scany();
00134 if (y<0 || y>=int(image.nj())) continue;
00135 int min_x = tsi.startx();
00136 int max_x = tsi.endx();
00137 if (min_x >= (int)image.ni() || max_x < 0)
00138 continue;
00139 if (min_x < 0) min_x = 0;
00140 if (max_x >= (int)image.ni()) max_x = image.ni()-1;
00141 double new_i = B*y+C;
00142 for (int x = min_x; x <= max_x; ++x) {
00143 double depth = new_i + A*x;
00144 if (depth < image(x,y))
00145 image(x,y) = depth;
00146 }
00147 }
00148 }
00149
00150
00151 void
00152 imesh_render_triangles(const imesh_regular_face_array<3>& tris,
00153 const vcl_vector<vgl_point_2d<double> >& img_verts,
00154 vil_image_view<bool>& image)
00155 {
00156 for (unsigned i=0; i<tris.size(); ++i) {
00157 imesh_render_triangle(img_verts[tris(i,0)],
00158 img_verts[tris(i,1)],
00159 img_verts[tris(i,2)],
00160 image);
00161 }
00162 }
00163
00164
00165 void
00166 imesh_render_faces(const imesh_mesh& mesh,
00167 const vcl_vector<vgl_point_2d<double> >& img_verts,
00168 vil_image_view<bool>& image)
00169 {
00170 const imesh_face_array_base& faces = mesh.faces();
00171 vcl_auto_ptr<imesh_regular_face_array<3> > tri_data;
00172 const imesh_regular_face_array<3>* tris;
00173 if (faces.regularity() != 3) {
00174 tri_data = imesh_triangulate(faces);
00175 tris = tri_data.get();
00176 }
00177 else {
00178 tris = static_cast<const imesh_regular_face_array<3>*>(&faces);
00179 }
00180 imesh_render_triangles(*tris,img_verts,image);
00181 }
00182
00183
00184 void
00185 imesh_render_triangles_interp(const imesh_regular_face_array<3>& tris,
00186 const vcl_vector<vgl_point_2d<double> >& img_verts,
00187 const vcl_vector<double>& vals,
00188 vil_image_view<double>& image)
00189 {
00190 for (unsigned i=0; i<tris.size(); ++i) {
00191 const imesh_regular_face<3>& tri = tris[i];
00192 imesh_render_triangle_interp(img_verts[tri[0]],
00193 img_verts[tri[1]],
00194 img_verts[tri[2]],
00195 vals[tri[0]],
00196 vals[tri[1]],
00197 vals[tri[2]],
00198 image);
00199 }
00200 }
00201
00202 void
00203 imesh_render_faces_interp(const imesh_mesh& mesh,
00204 const vcl_vector<vgl_point_2d<double> >& img_verts,
00205 const vcl_vector<double>& vals,
00206 vil_image_view<double>& image)
00207 {
00208 const imesh_face_array_base& faces = mesh.faces();
00209 vcl_auto_ptr<imesh_regular_face_array<3> > tri_data;
00210 const imesh_regular_face_array<3>* tris;
00211 if (faces.regularity() != 3) {
00212 tri_data = imesh_triangulate(faces);
00213 tris = tri_data.get();
00214 }
00215 else {
00216 tris = static_cast<const imesh_regular_face_array<3>*>(&faces);
00217 }
00218 imesh_render_triangles_interp(*tris,img_verts,vals,image);
00219 }
00220
00221
00222
00223
00224 void imesh_project(const imesh_mesh& mesh,
00225 const vpgl_proj_camera<double>& camera,
00226 const bpgl_lens_distortion<double>& lens,
00227 vil_image_view<bool>& image)
00228 {
00229 assert(mesh.vertices().dim() == 3);
00230 const imesh_vertex_array<3>& verts3d =
00231 static_cast<const imesh_vertex_array<3>&>(mesh.vertices());
00232 vcl_vector<vgl_point_2d<double> > verts2d;
00233 imesh_project_verts(verts3d, camera, verts2d);
00234 imesh_distort_verts(verts2d, lens, verts2d);
00235 imesh_render_faces(mesh, verts2d, image);
00236 }
00237
00238
00239
00240
00241
00242 void imesh_project(const imesh_mesh& mesh,
00243 const vcl_vector<vgl_vector_3d<double> >& normals,
00244 const vpgl_proj_camera<double>& camera,
00245 const bpgl_lens_distortion<double>& lens,
00246 vil_image_view<bool>& image,
00247 vgl_box_2d<unsigned int>* bbox)
00248 {
00249 const imesh_face_array_base& faces = mesh.faces();
00250 vcl_auto_ptr<imesh_regular_face_array<3> > tri_data;
00251 const imesh_regular_face_array<3>* tri_ptr;
00252 if (faces.regularity() != 3) {
00253 tri_data = imesh_triangulate(faces);
00254 tri_ptr = tri_data.get();
00255 }
00256 else {
00257 tri_ptr = static_cast<const imesh_regular_face_array<3>*>(&faces);
00258 }
00259 const imesh_regular_face_array<3>& tris = *tri_ptr;
00260 const imesh_vertex_array<3>& verts3d = mesh.vertices<3>();
00261
00262 vcl_vector<vgl_point_2d<double> > verts2d;
00263 imesh_project_verts(verts3d, camera, verts2d);
00264 imesh_distort_verts(verts2d, lens, verts2d);
00265
00266 if (bbox) {
00267 bbox->set_min_x(0); bbox->set_min_y(0);
00268 bbox->set_max_x(image.ni()-1); bbox->set_max_y(image.nj()-1);
00269 imesh_projection_bounds(verts2d,*bbox);
00270 }
00271
00272 vgl_homg_point_3d<double> c(camera.camera_center());
00273 if (c.w() < 0.0)
00274 c.rescale_w(-c.w());
00275
00276 typedef vcl_vector<vgl_vector_3d<double> >::const_iterator itr_n;
00277 itr_n n = normals.begin();
00278 for (unsigned int i=0; i<tris.size(); ++i, ++n) {
00279 const vgl_point_3d<double>& v1 = verts3d[tris(i,0)];
00280 vgl_vector_3d<double> d(c.x()-v1.x()*c.w(),
00281 c.y()-v1.y()*c.w(),
00282 c.z()-v1.z()*c.w());
00283 if (dot_product(*n,d) < 0.0)
00284 continue;
00285 imesh_render_triangle(verts2d[tris(i,0)],
00286 verts2d[tris(i,1)],
00287 verts2d[tris(i,2)],
00288 image);
00289 }
00290 }
00291
00292
00293
00294
00295 void imesh_project(const imesh_mesh& mesh,
00296 const vpgl_proj_camera<double>& camera,
00297 vil_image_view<bool>& image)
00298 {
00299 assert(mesh.vertices().dim() == 3);
00300 vcl_vector<vgl_point_2d<double> > verts2d;
00301 imesh_project_verts(mesh.vertices<3>(), camera, verts2d);
00302 imesh_render_faces(mesh, verts2d, image);
00303 }
00304
00305
00306
00307
00308 void imesh_project_depth(const imesh_mesh& mesh,
00309 const vpgl_proj_camera<double>& camera,
00310 vil_image_view<double>& image)
00311 {
00312 assert(mesh.vertices().dim() == 3);
00313 vcl_vector<vgl_point_2d<double> > verts2d;
00314 vcl_vector<double> depths;
00315 image.fill(vcl_numeric_limits<double>::infinity());
00316 imesh_project_verts(mesh.vertices<3>(), camera, verts2d, depths);
00317 imesh_render_faces_interp(mesh, verts2d, depths, image);
00318 }
00319
00320
00321
00322
00323
00324 void imesh_projection_bounds(const vcl_vector<vgl_point_2d<double> >& img_pts,
00325 vgl_box_2d<unsigned int>& bbox)
00326 {
00327 assert(!img_pts.empty());
00328 typedef vcl_vector<vgl_point_2d<double> >::const_iterator itr_p;
00329
00330 int i0 = bbox.max_x(), i1 = bbox.min_x(),
00331 j0 = bbox.max_y(), j1 = bbox.min_y();
00332 for (itr_p p = img_pts.begin(); p != img_pts.end(); ++p) {
00333 double x = p->x(), y = p->y();
00334 int v = static_cast<int>(vcl_ceil(x))-1;
00335 if (v < i0) i0 = v;
00336 v = static_cast<int>(vcl_floor(x))+1;
00337 if (v > i1) i1 = v;
00338
00339 v = static_cast<int>(vcl_ceil(y))-1;
00340 if (v < j0) j0 = v;
00341 v = static_cast<int>(vcl_floor(y))+1;
00342 if (v > j1) j1 = v;
00343 }
00344 if (i0 > static_cast<int>(bbox.min_x())) bbox.set_min_x(static_cast<unsigned int>(i0));
00345 if (i1 < static_cast<int>(bbox.max_x())) bbox.set_max_x(static_cast<unsigned int>(i1));
00346 if (j0 > static_cast<int>(bbox.min_y())) bbox.set_min_y(static_cast<unsigned int>(j0));
00347 if (j1 < static_cast<int>(bbox.max_y())) bbox.set_max_y(static_cast<unsigned int>(j1));
00348 }
00349
00350
00351
00352
00353 int imesh_project_onto_mesh(const imesh_mesh& mesh,
00354 const vcl_vector<vgl_vector_3d<double> >& normals,
00355 const vcl_vector<vgl_point_2d<double> >& verts2d,
00356 const vpgl_perspective_camera<double>& camera,
00357 const vgl_point_2d<double>& pt_2d,
00358 vgl_point_3d<double>& pt_3d)
00359 {
00360 int tri_idx = -1;
00361
00362 vgl_line_3d_2_points<double> ray = camera.backproject(pt_2d);
00363 vgl_vector_3d<double> d = ray.direction();
00364 normalize(d);
00365
00366 vgl_point_3d<double> center = camera.get_camera_center();
00367
00368
00369 assert(mesh.faces().regularity() == 3);
00370 const imesh_regular_face_array<3>& tris =
00371 static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00372
00373 assert(mesh.vertices().dim() == 3);
00374 const imesh_vertex_array<3>& verts3d = mesh.vertices<3>();
00375
00376 typedef imesh_regular_face_array<3>::const_iterator itr_t;
00377 typedef vcl_vector<vgl_vector_3d<double> >::const_iterator itr_n;
00378 itr_n n = normals.begin();
00379 double depth = vcl_numeric_limits<double>::infinity();
00380 int i = 0;
00381 for (itr_t itr = tris.begin(); itr != tris.end(); ++itr, ++n, ++i) {
00382 if (dot_product(*n,d) > 0.0)
00383 continue;
00384 const vgl_point_2d<double>& a = verts2d[(*itr)[0]];
00385 const vgl_point_2d<double>& b = verts2d[(*itr)[1]];
00386 const vgl_point_2d<double>& c = verts2d[(*itr)[2]];
00387 if (vgl_triangle_test_inside<double>(a.x(), a.y(), b.x(), b.y(),
00388 c.x(), c.y(), pt_2d.x(), pt_2d.y())) {
00389 vgl_plane_3d<double> tri(verts3d[(*itr)[0]],
00390 verts3d[(*itr)[1]],
00391 verts3d[(*itr)[2]]);
00392 vgl_point_3d<double> pt3 = vgl_intersection(ray, tri);
00393 double dist = vgl_distance(pt3,center);
00394 if (dist < depth) {
00395 depth = dist;
00396 pt_3d = pt3;
00397 tri_idx = i;
00398 }
00399 }
00400 }
00401 return tri_idx;
00402 }
00403
00404
00405
00406
00407 void imesh_project_onto_mesh(const imesh_mesh& mesh,
00408 const vcl_vector<vgl_vector_3d<double> >& normals,
00409 const vpgl_perspective_camera<double>& camera,
00410 const vcl_vector< vgl_point_2d<double> >& pts_2d,
00411 vcl_vector<unsigned int >& idx_2d,
00412 vcl_vector<vgl_point_3d<double> >& pts_3d)
00413 {
00414 vcl_vector<vgl_point_2d<double> > verts2d;
00415 assert(mesh.vertices().dim() == 3);
00416 imesh_project_verts(mesh.vertices<3>(), camera, verts2d);
00417
00418 vgl_point_3d<double> pt_3d;
00419 for (unsigned int i=0; i<pts_2d.size(); ++i)
00420 {
00421 if (imesh_project_onto_mesh(mesh, normals, verts2d, camera, pts_2d[i], pt_3d)) {
00422 pts_3d.push_back(pt_3d);
00423 idx_2d.push_back(i);
00424 }
00425 }
00426 }
00427
00428
00429
00430 namespace{
00431
00432 void
00433 xy_to_barycentric(const vgl_point_2d<double>& pt_xy,
00434 const vgl_point_2d<double>& a,
00435 const vgl_point_2d<double>& b,
00436 const vgl_point_2d<double>& c,
00437 vgl_point_2d<double>& pt_bary)
00438 {
00439 vgl_vector_2d<double> v1(b-a), v2(c-a), vp(pt_xy-a);
00440 vgl_vector_2d<double> v1n(-v1.y(), v1.x());
00441 vgl_vector_2d<double> v2n(v2.y(), -v2.x());
00442 double s = 1.0/(v2.y()*v1.x() - v2.x()*v1.y());
00443 pt_bary.y() = s * dot_product(v1n,vp);
00444 pt_bary.x() = s * dot_product(v2n,vp);
00445 }
00446
00447 void
00448 barycentric_to_xy(const vgl_point_2d<double>& pt_bary,
00449 const vgl_point_2d<double>& a,
00450 const vgl_point_2d<double>& b,
00451 const vgl_point_2d<double>& c,
00452 vgl_point_2d<double>& pt_xy)
00453 {
00454 double z = 1.0 - pt_bary.x() - pt_bary.y();
00455 pt_xy.x() = z*a.x() + pt_bary.x()*b.x() + pt_bary.y()*c.x();
00456 pt_xy.y() = z*a.y() + pt_bary.x()*b.y() + pt_bary.y()*c.y();
00457 }
00458
00459 };
00460
00461
00462
00463
00464
00465 int imesh_project_onto_mesh_barycentric(const imesh_mesh& mesh,
00466 const vcl_vector<vgl_vector_3d<double> >& normals,
00467 const vcl_vector<vgl_point_2d<double> >& verts2d,
00468 const vpgl_perspective_camera<double>& camera,
00469 const vgl_point_2d<double>& pt_img,
00470 vgl_point_2d<double>& pt_bary)
00471 {
00472 vgl_point_3d<double> pt_3d;
00473
00474
00475 assert(mesh.faces().regularity() == 3);
00476 const imesh_regular_face_array<3>& tris =
00477 static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00478
00479 int tri_idx = imesh_project_onto_mesh(mesh, normals, verts2d, camera, pt_img, pt_3d);
00480 if (tri_idx >= 0) {
00481 const imesh_regular_face<3>& tri = tris[tri_idx];
00482 const vgl_point_2d<double>& a = verts2d[tri[0]];
00483 const vgl_point_2d<double>& b = verts2d[tri[1]];
00484 const vgl_point_2d<double>& c = verts2d[tri[2]];
00485 xy_to_barycentric(pt_img,a,b,c,pt_bary);
00486 }
00487
00488 return tri_idx;
00489 }
00490
00491
00492
00493
00494
00495 int imesh_project_onto_mesh_texture(const imesh_mesh& mesh,
00496 const vcl_vector<vgl_point_2d<double> >& verts2d,
00497 const vpgl_perspective_camera<double>& camera,
00498 const vgl_point_2d<double>& pt_img,
00499 vgl_point_2d<double>& pt_uv)
00500 {
00501 if (!mesh.faces().has_normals() || !mesh.has_tex_coords())
00502 return -1;
00503
00504
00505 assert(mesh.faces().regularity() == 3);
00506 const imesh_regular_face_array<3>& tris =
00507 static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00508
00509 const vcl_vector<vgl_point_2d<double> >& tex_coords = mesh.tex_coords();
00510
00511 vgl_point_2d<double> pt_bary;
00512 int tri_idx = imesh_project_onto_mesh_barycentric(mesh, tris.normals(),
00513 verts2d, camera,
00514 pt_img, pt_bary);
00515 unsigned int i1, i2, i3;
00516 if (mesh.has_tex_coords() == imesh_mesh::TEX_COORD_ON_VERT) {
00517 const imesh_regular_face<3>& tri = tris[tri_idx];
00518 i1 = tri[0];
00519 i2 = tri[1];
00520 i3 = tri[2];
00521 }
00522 else {
00523 imesh_half_edge_set::f_const_iterator fi = mesh.half_edges().face_begin(tri_idx);
00524 assert(tris[tri_idx][0] == fi->vert_index());
00525 i1 = fi->edge_index();
00526 i2 = (++fi)->edge_index();
00527 i3 = (++fi)->edge_index();
00528 }
00529 if (tri_idx >= 0) {
00530 const vgl_point_2d<double>& a = tex_coords[i1];
00531 const vgl_point_2d<double>& b = tex_coords[i2];
00532 const vgl_point_2d<double>& c = tex_coords[i3];
00533 barycentric_to_xy(pt_bary,a,b,c,pt_uv);
00534 }
00535
00536 return tri_idx;
00537 }
00538
00539
00540
00541
00542 int imesh_project_texture_to_barycentric(const imesh_mesh& mesh,
00543 const vgl_point_2d<double>& pt_2d,
00544 vgl_point_2d<double>& pt_uv)
00545 {
00546
00547 assert(mesh.faces().regularity() == 3);
00548 const imesh_regular_face_array<3>& tris =
00549 static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00550 typedef imesh_regular_face_array<3>::const_iterator itr_t;
00551
00552 if (!mesh.has_tex_coords())
00553 return imesh_invalid_idx;
00554
00555 const vcl_vector<vgl_point_2d<double> >& tc = mesh.tex_coords();
00556
00557 if (mesh.has_tex_coords() == imesh_mesh::TEX_COORD_ON_VERT)
00558 {
00559 int i = 0;
00560 for (itr_t itr = tris.begin(); itr != tris.end(); ++itr, ++i) {
00561 const vgl_point_2d<double>& a = tc[(*itr)[0]];
00562 const vgl_point_2d<double>& b = tc[(*itr)[1]];
00563 const vgl_point_2d<double>& c = tc[(*itr)[2]];
00564 double dsc = vgl_triangle_test_discriminant(a.x(),a.y(),b.x(),b.y(),c.x(),c.y());
00565 if (dsc <= 0.0) continue;
00566 xy_to_barycentric(pt_2d,a,b,c,pt_uv);
00567 if (pt_uv.x() < 0.0) continue;
00568 if (pt_uv.y() < 0.0) continue;
00569 if (pt_uv.x()+pt_uv.y() >1.0) continue;
00570
00571 return i;
00572 }
00573 }
00574
00575 return imesh_invalid_idx;
00576 }
00577
00578 #if 1
00579 namespace{
00580
00581
00582 bool trace_texture(const imesh_mesh& mesh,
00583 const vgl_point_2d<double>& end_xy,
00584 vcl_vector<unsigned long>& idxs,
00585 vcl_vector<vgl_point_2d<double> >& isect_bary)
00586 {
00587 const vcl_vector<vgl_point_2d<double> >& tc = mesh.tex_coords();
00588 assert(mesh.faces().regularity() == 3);
00589 const imesh_regular_face_array<3>& tris =
00590 static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00591 assert(mesh.has_half_edges());
00592 const imesh_half_edge_set& he = mesh.half_edges();
00593 assert(!isect_bary.empty());
00594
00595 double eps = 1e-2;
00596 double eps2 = eps*eps;
00597
00598 vgl_point_2d<double> nbary;
00599
00600
00601 unsigned long tidx = idxs.back();
00602 vgl_point_2d<double> bary = isect_bary.back();
00603
00604
00605 unsigned long heidx = tidx>>2;
00606
00607
00608 for (;;)
00609 {
00610 unsigned int fidx = he[heidx].face_index();
00611 const vgl_point_2d<double>& a = tc[tris[fidx][0]];
00612 const vgl_point_2d<double>& b = tc[tris[fidx][1]];
00613 const vgl_point_2d<double>& c = tc[tris[fidx][2]];
00614
00615 xy_to_barycentric(end_xy,a,b,c,nbary);
00616
00617 vgl_vector_2d<double> duv(bary-nbary);
00618
00619 if (duv.sqr_length() <eps2)
00620 return true;
00621
00622
00623 if (nbary.x() > 0 && nbary.y() > 0 && 1.0-nbary.x()-nbary.y()>0) {
00624 idxs.push_back(heidx<<2);
00625 isect_bary.push_back(nbary);
00626 return true;
00627 }
00628 else if ((nbary.x()==0.0 && nbary.y()>0 && nbary.y()<1) ||
00629 (nbary.y()==0.0 && nbary.x()>0 && nbary.x()<1) ||
00630 (nbary.x()+nbary.y()==1.0 && nbary.x()>0 && nbary.y()>0)) {
00631 idxs.push_back((heidx<<2) + 1);
00632 isect_bary.push_back(nbary);
00633 return true;
00634 }
00635
00636
00637 unsigned char s = imesh_triangle_intersect(bary.x(),bary.y(),duv.x(),duv.y(), eps);
00638 typedef imesh_half_edge_set::f_const_iterator fitr;
00639 fitr fi = he.face_begin(fidx);
00640 assert(fi->face_index() == fidx);
00641 if (s == 3 || s == 5 || s == 6)
00642 {
00643 double t = 1 - bary.x();
00644 if (s==6) {
00645 ++fi;
00646 t = bary.x();
00647 }
00648 if (s==5) {
00649 ++fi;
00650 ++fi;
00651 t = bary.y();
00652 }
00653
00654
00655
00656 heidx = fi->pair_index();
00657 fidx = he[heidx].face_index();
00658
00659
00660 if (fidx == imesh_invalid_idx ||
00661 (!mesh.valid_tex_faces().empty() &&
00662 !mesh.valid_tex_faces()[fidx]) )
00663 {
00664
00665 idxs.push_back((fi->half_edge_index()<<2) + 1);
00666 isect_bary.push_back(bary);
00667 return false;
00668 }
00669
00670
00671 fi = he.face_begin(fidx);
00672 unsigned char s2 = 0;
00673 for (; fi->half_edge_index() != heidx && s2<4; ++s2, ++fi)
00674 ;
00675 bary.set(0,0);
00676 switch (s2)
00677 {
00678 case 0: bary.x() = t; break;
00679 case 1: bary.x() = 1-t; bary.y()=t; break;
00680 case 2: bary.y() = 1-t; break;
00681 default:
00682 assert(false);
00683 }
00684
00685
00686 idxs.push_back((heidx<<2) + 1);
00687 isect_bary.push_back(bary);
00688 }
00689 else if (s == 1 || s == 2 || s == 4)
00690 {
00691 if (s==2) {
00692 ++fi;
00693 }
00694 if (s==4) {
00695 ++fi;
00696 ++fi;
00697 }
00698 assert(fi->vert_index() == tris[fidx][(s==4)?2:s-1]);
00699
00700
00701 vgl_vector_2d<double> dir(end_xy-tc[fi->vert_index()]);
00702 normalize(dir);
00703
00704
00705 imesh_half_edge_set::v_const_iterator vi(fi);
00706 imesh_half_edge_set::v_const_iterator vend(vi);
00707 ++vi;
00708 double max_ang = -2*vnl_math::pi;
00709 unsigned long max_heidx = 0;
00710 for (; vi!=vend; ++vi) {
00711 vgl_vector_2d<double> d(tc[he[vi->pair_index()].vert_index()]
00712 - tc[vi->vert_index()]);
00713
00714 double ang = vcl_atan2(d.y()*dir.x()-d.x()*dir.y(),
00715 d.x()*dir.x()+d.y()*dir.y());
00716 if (ang > 0) ang -= 2*vnl_math::pi;
00717 if (ang > max_ang) {
00718 max_ang = ang;
00719 max_heidx = vi->half_edge_index();
00720 }
00721 }
00722
00723 heidx = max_heidx;
00724 fidx = he[heidx].face_index();
00725
00726
00727 if (fidx == imesh_invalid_idx ||
00728 (!mesh.valid_tex_faces().empty() &&
00729 !mesh.valid_tex_faces()[fidx]) )
00730 {
00731
00732 idxs.push_back((fi->half_edge_index()<<2) + 2);
00733 isect_bary.push_back(bary);
00734 return false;
00735 }
00736
00737
00738 unsigned vidx = fi->vert_index();
00739 fi = he.face_begin(fidx);
00740 unsigned char s2 = 0;
00741 for (; fi->vert_index() != vidx && s2<4; ++s2, ++fi)
00742 ;
00743 bary.set(0,0);
00744 switch (s2)
00745 {
00746 case 0: break;
00747 case 1: bary.x() = 1; break;
00748 case 2: bary.y() = 1; break;
00749 default:
00750 assert(false);
00751 }
00752
00753
00754 idxs.push_back((heidx<<2) + 2);
00755 isect_bary.push_back(bary);
00756 }
00757 else
00758 {
00759 vcl_cout << "invalid intersection" << vcl_endl;
00760 return false;
00761 }
00762 }
00763 return false;
00764 }
00765
00766 }
00767 #endif
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781 bool imesh_project_texture_to_barycentric(const imesh_mesh& mesh,
00782 const vcl_vector<vgl_point_2d<double> >& pts_2d,
00783 vcl_vector<vgl_point_2d<double> >& pts_uv,
00784 vcl_vector<unsigned long>& idxs,
00785 vcl_vector<int>& map_back)
00786 {
00787 bool clipped = false;
00788 const unsigned int npts = pts_2d.size();
00789 pts_uv.clear();
00790 idxs.clear();
00791 map_back.clear();
00792 map_back.resize(npts,-1);
00793 assert(mesh.faces().regularity() == 3);
00794 assert(mesh.has_half_edges());
00795 const imesh_half_edge_set& he = mesh.half_edges();
00796
00797
00798 unsigned int i;
00799 unsigned int idx=0;
00800 vgl_point_2d<double> pt_uv;
00801 for (i=0; i<npts; ++i)
00802 {
00803 const vgl_point_2d<double>& pt = pts_2d[i];
00804 if (pt.x() >= 0.0 && pt.x() <= 1.0 && pt.y() >= 0.0 && pt.y() <= 1.0)
00805 {
00806 idx = imesh_project_texture_to_barycentric(mesh,pt,pt_uv);
00807 if (idx != imesh_invalid_idx)
00808 break;
00809 }
00810 clipped = true;
00811 }
00812 if (i==npts)
00813 return false;
00814
00815 idxs.push_back(he.face_begin(idx)->half_edge_index()<<2);
00816 pts_uv.push_back(pt_uv);
00817 map_back[i] = 0;
00818
00819
00820 bool valid = true;
00821 int num_found = 0;
00822 for (unsigned int j=(i+1)%npts; j!=i; j=(j+1)%npts, ++num_found )
00823 {
00824 valid = trace_texture(mesh,pts_2d[j],idxs,pts_uv);
00825 if (!valid)
00826 break;
00827 map_back[j] = idxs.size()-1;
00828 }
00829
00830 if (!valid)
00831 {
00832 vcl_vector<vgl_point_2d<double> > rev_pts_uv(1,pts_uv.front());
00833 vcl_vector<unsigned long> rev_idxs(1,idxs.front());
00834 vcl_vector<int> rev_map_back(pts_2d.size(),-1);
00835 rev_map_back[i]=0;
00836 const unsigned int step = npts-1;
00837 for (unsigned int j=(i+step)%npts; j!=i; j=(j+step)%npts )
00838 {
00839 valid = trace_texture(mesh,pts_2d[j],rev_idxs,rev_pts_uv);
00840 if (!valid)
00841 break;
00842 rev_map_back[j] = rev_idxs.size()-1;
00843 }
00844
00845
00846 for (unsigned int j=0; j<npts; ++j)
00847 {
00848 if (map_back[j] >=0)
00849 map_back[j] += rev_idxs.size()-1;
00850 else if (rev_map_back[j] >= 0)
00851 map_back[j] = rev_idxs.size()-1 - rev_map_back[j];
00852 }
00853
00854 vcl_reverse(rev_pts_uv.begin(),rev_pts_uv.end());
00855 vcl_reverse(rev_idxs.begin(),rev_idxs.end());
00856 unsigned int num_new_pts = rev_pts_uv.size();
00857 rev_pts_uv.resize(rev_pts_uv.size()+pts_uv.size()-1);
00858 vcl_copy(pts_uv.begin()+1, pts_uv.end(), rev_pts_uv.begin()+num_new_pts);
00859 rev_idxs.resize(rev_idxs.size()+idxs.size()-1);
00860 vcl_copy(idxs.begin()+1, idxs.end(), rev_idxs.begin()+num_new_pts);
00861
00862
00863 idxs.swap(rev_idxs);
00864 pts_uv.swap(rev_pts_uv);
00865
00866 return true;
00867 }
00868
00869
00870 valid = trace_texture(mesh,pts_2d[i],idxs,pts_uv);
00871 if (!valid)
00872 return true;
00873
00874 idxs.pop_back();
00875 pts_uv.pop_back();
00876
00877 assert(pts_uv.size() == idxs.size());
00878
00879 return clipped;
00880 }
00881
00882
00883
00884
00885 vnl_matrix_fixed<double,3,3>
00886 imesh_project_texture_to_3d_map(const imesh_mesh& mesh, unsigned int tidx)
00887 {
00888 assert(mesh.has_tex_coords());
00889 const imesh_regular_face_array<3>& triangles =
00890 static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00891 const imesh_regular_face<3>& tri = triangles[tidx];
00892 const vcl_vector<vgl_point_2d<double> >& tex = mesh.tex_coords();
00893 const imesh_vertex_array<3>& verts = mesh.vertices<3>();
00894
00895 vnl_matrix_fixed<double,3,3> M1;
00896 {
00897 const vgl_point_2d<double>& a = tex[tri[0]];
00898 const vgl_point_2d<double>& b = tex[tri[1]];
00899 const vgl_point_2d<double>& c = tex[tri[2]];
00900 vgl_vector_2d<double> v1(b-a), v2(c-a);
00901 double s = 1.0 / (v2.y()*v1.x() - v2.x()*v1.y());
00902 M1(0,0) = v2.y()*s; M1(0,1) = -v2.x()*s; M1(0,2) = -a.x()*s;
00903 M1(1,0) = -v1.y()*s; M1(1,1) = v1.x()*s; M1(1,2) = -a.y()*s;
00904 M1(2,0) = 0.0; M1(2,1) = 0.0; M1(2,2) = 1.0;
00905 }
00906
00907 vnl_matrix_fixed<double,3,3> M2;
00908 {
00909 const imesh_vertex<3>& a = verts[tri[0]];
00910 const imesh_vertex<3>& b = verts[tri[1]];
00911 const imesh_vertex<3>& c = verts[tri[2]];
00912 vgl_vector_3d<double> v1(b[0]-a[0],b[1]-a[1],b[2]-a[2]),
00913 v2(c[0]-a[0],c[1]-a[1],c[2]-a[2]);
00914 M2(0,0) = v1.x(); M2(0,1) = v2.x(); M2(0,2) = a[0];
00915 M2(1,0) = v1.y(); M2(1,1) = v2.y(); M2(1,2) = a[1];
00916 M2(2,0) = v1.z(); M2(2,1) = v2.z(); M2(2,2) = a[2];
00917 }
00918
00919
00920 return M2*M1;
00921 }
00922
00923
00924
00925 vnl_matrix_fixed<double,3,3>
00926 imesh_affine_map(const vgl_point_2d<double>& a1,
00927 const vgl_point_2d<double>& b1,
00928 const vgl_point_2d<double>& c1,
00929 const vgl_point_2d<double>& a2,
00930 const vgl_point_2d<double>& b2,
00931 const vgl_point_2d<double>& c2)
00932 {
00933
00934 vnl_matrix_fixed<double,3,3> M1;
00935 {
00936 vgl_vector_2d<double> v1(b1-a1), v2(c1-a1);
00937 double s = 1.0 / (v2.y()*v1.x() - v2.x()*v1.y());
00938 M1(0,0) = v2.y()*s; M1(0,1) = -v2.x()*s; M1(0,2) = (a1.y()*c1.x()-a1.x()*c1.y())*s;
00939 M1(1,0) = -v1.y()*s; M1(1,1) = v1.x()*s; M1(1,2) = (a1.x()*b1.y()-a1.y()*b1.x())*s;
00940 M1(2,0) = 0.0; M1(2,1) = 0.0; M1(2,2) = 1.0;
00941 }
00942
00943
00944 vnl_matrix_fixed<double,3,3> M2;
00945 {
00946 vgl_vector_2d<double> v1(b2-a2), v2(c2-a2);
00947 M2(0,0) = v1.x(); M2(0,1) = v2.x(); M2(0,2) = a2.x();
00948 M2(1,0) = v1.y(); M2(1,1) = v2.y(); M2(1,2) = a2.y();
00949 M2(2,0) = 0.0; M2(2,1) = 0.0; M2(2,2) = 1.0;
00950 }
00951
00952 return M2*M1;
00953 }
00954
00955
00956
00957
00958 vgl_point_2d<double>
00959 imesh_project_barycentric_to_texture(const imesh_mesh& mesh,
00960 const vgl_point_2d<double>& pt_uv,
00961 unsigned int idx)
00962 {
00963 assert(mesh.has_tex_coords());
00964 const vcl_vector<vgl_point_2d<double> >& tc = mesh.tex_coords();
00965 const vgl_point_2d<double>& a = tc[mesh.faces()(idx,0)];
00966 const vgl_point_2d<double>& b = tc[mesh.faces()(idx,1)];
00967 const vgl_point_2d<double>& c = tc[mesh.faces()(idx,2)];
00968 vgl_point_2d<double> p;
00969 barycentric_to_xy(pt_uv,a,b,c,p);
00970 return p;
00971 }
00972
00973
00974
00975
00976 vgl_point_3d<double>
00977 imesh_project_barycentric_to_mesh(const imesh_mesh& mesh,
00978 const vgl_point_2d<double>& pt_uv,
00979 unsigned int idx)
00980 {
00981 vgl_point_3d<double> pt(0,0,0);
00982 unsigned int v1 = mesh.faces()(idx,0);
00983 unsigned int v2 = mesh.faces()(idx,1);
00984 unsigned int v3 = mesh.faces()(idx,2);
00985 const imesh_vertex_array<3>& verts = mesh.vertices<3>();
00986 pt += (1-pt_uv.x()-pt_uv.y())*vgl_vector_3d<double>(verts[v1][0],verts[v1][1],verts[v1][2]);
00987 pt += pt_uv.x()*vgl_vector_3d<double>(verts[v2][0],verts[v2][1],verts[v2][2]);
00988 pt += pt_uv.y()*vgl_vector_3d<double>(verts[v3][0],verts[v3][1],verts[v3][2]);
00989
00990 return pt;
00991 }