00001 #ifndef OPENTISSUE_CORE_GEOMETRY_T4_CPU_SCAN_T4_CPU_SCAN_H
00002 #define OPENTISSUE_CORE_GEOMETRY_T4_CPU_SCAN_T4_CPU_SCAN_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/core/geometry/geometry_tetrahedron.h>
00013 #include <OpenTissue/core/geometry/geometry_compute_tetrahedron_aabb.h>
00014 #include <OpenTissue/core/geometry/geometry_tetrahedron_z_slicer.h>
00015 #include <OpenTissue/core/geometry/scan_conversion/scan_conversion_fragment_iterator.h>
00016 #include <OpenTissue/core/geometry/geometry_local_triangle_frame.h>
00017 #include <OpenTissue/core/geometry/geometry_compute_distance_to_triangle.h>
00018 #include <OpenTissue/core/geometry/geometry_compute_signed_distance_to_triangle.h>
00019 #include <OpenTissue/core/containers/mesh/common/util/mesh_compute_angle_weighted_vertex_normals.h>
00020
00021 #include <boost/cast.hpp>
00022
00023 #include <cassert>
00024 #include <cmath>
00025
00026
00027 namespace OpenTissue
00028 {
00029
00030 struct t4_cpu_unsigned {};
00031 struct t4_cpu_signed {};
00032
00044 template<typename surface_mesh, typename grid_type>
00045 inline void t4_cpu_scan(
00046 surface_mesh & surface
00047 , double const & thickness
00048 , grid_type & phi
00049 , t4_cpu_signed const &
00050 )
00051 {
00052 using std::ceil;
00053 using std::floor;
00054 using std::fabs;
00055
00056 assert(thickness>0 || "t4_cpu_scan(): thickness was non-positive");
00057
00058 typedef typename surface_mesh::math_types math_types;
00059 typedef typename math_types::vector3_type vector3_type;
00060 typedef typename math_types::real_type real_type;
00061 typedef typename surface_mesh::face_iterator face_iterator;
00062 typedef typename surface_mesh::face_halfedge_circulator face_halfedge_circulator;
00063 typedef typename grid_type::value_type value_type;
00064
00065 typedef OpenTissue::geometry::ZTetrahedronSlicer<vector3_type> slicer_type;
00066 typedef OpenTissue::geometry::LocalTriangleFrame<vector3_type> local_frame_type;
00067 typedef OpenTissue::geometry::Tetrahedron<math_types> tetrahedron_type;
00068 typedef OpenTissue::scan_conversion::FragmentIterator<vector3_type> fragment_iterator;
00069
00070
00071 local_frame_type local_frame;
00072 tetrahedron_type tetrahedra[5];
00073 vector3_type vertices[4];
00074
00075 real_type const min_x = phi.min_coord(0);
00076 real_type const min_y = phi.min_coord(1);
00077 real_type const min_z = phi.min_coord(2);
00078 real_type const dx = phi.dx();
00079 real_type const dy = phi.dy();
00080 real_type const dz = phi.dz();
00081
00082 mesh::compute_angle_weighted_vertex_normals(surface);
00083
00084 face_iterator end = surface.face_end();
00085 face_iterator face = surface.face_begin();
00086 for(;face!=end;++face)
00087 {
00088 assert(valency( *face )==3 || !"t4_cpu_scan(): Only triangular faces are supported!");
00089
00090 vector3_type nf;
00091 vector3_type ne_i;
00092 vector3_type ne_j;
00093 vector3_type ne_k;
00094
00095 ne_i.clear();
00096 ne_j.clear();
00097 ne_k.clear();
00098
00099
00100 compute_face_normal( *face ,nf);
00101
00102 face_halfedge_circulator h(*face);
00103 vector3_type const & p_i = h->get_origin_iterator()->m_coord;
00104 vector3_type const & nv_i = h->get_origin_iterator()->m_normal;
00105 if(!h->get_twin_iterator()->get_face_handle().is_null())
00106 compute_face_normal( *(h->get_twin_iterator()->get_face_iterator()),ne_k);
00107 ++h;
00108
00109 vector3_type const & p_j = h->get_origin_iterator()->m_coord;
00110 vector3_type const & nv_j = h->get_origin_iterator()->m_normal;
00111 if(!h->get_twin_iterator()->get_face_handle().is_null())
00112 compute_face_normal( *(h->get_twin_iterator()->get_face_iterator()),ne_i);
00113 ++h;
00114
00115 vector3_type const & p_k = h->get_origin_iterator()->m_coord;
00116 vector3_type const & nv_k = h->get_origin_iterator()->m_normal;
00117 if(!h->get_twin_iterator()->get_face_handle().is_null())
00118 compute_face_normal( *(h->get_twin_iterator()->get_face_iterator()),ne_j);
00119
00120
00121 ne_i = unit(nf + ne_i);
00122 ne_j = unit(nf + ne_j);
00123 ne_k = unit(nf + ne_k);
00124
00125 local_frame.init( p_i, p_j, p_k);
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 vector3_type c0 = local_frame.v0() - local_frame.unit_a()*thickness - local_frame.n()*thickness - local_frame.unit_h()*thickness;
00138 vector3_type c1 = local_frame.v1() + local_frame.unit_a()*thickness - local_frame.n()*thickness - local_frame.unit_h()*thickness;
00139 vector3_type c2 = local_frame.v0() - local_frame.unit_a()*thickness + local_frame.n()*thickness - local_frame.unit_h()*thickness;
00140 vector3_type c3 = local_frame.v1() + local_frame.unit_a()*thickness + local_frame.n()*thickness - local_frame.unit_h()*thickness;
00141 vector3_type c4 = local_frame.v0() - local_frame.unit_a()*thickness - local_frame.n()*thickness + local_frame.unit_h()*(thickness+local_frame.h());
00142 vector3_type c5 = local_frame.v1() + local_frame.unit_a()*thickness - local_frame.n()*thickness + local_frame.unit_h()*(thickness+local_frame.h());
00143 vector3_type c6 = local_frame.v0() - local_frame.unit_a()*thickness + local_frame.n()*thickness + local_frame.unit_h()*(thickness+local_frame.h());
00144 vector3_type c7 = local_frame.v1() + local_frame.unit_a()*thickness + local_frame.n()*thickness + local_frame.unit_h()*(thickness+local_frame.h());
00145
00146 tetrahedra[0].set( c0, c4, c5, c6 );
00147 tetrahedra[1].set( c0, c5, c1, c3 );
00148 tetrahedra[2].set( c6, c2, c3, c0 );
00149 tetrahedra[3].set( c7, c6, c3, c5 );
00150 tetrahedra[4].set( c6, c5, c0, c3 );
00151
00152 for(int n=0;n<5;++n)
00153 {
00154 slicer_type slicer(
00155 tetrahedra[n].p0()
00156 , tetrahedra[n].p1()
00157 , tetrahedra[n].p2()
00158 , tetrahedra[n].p3()
00159 );
00160
00161 vector3_type min_coord;
00162 vector3_type max_coord;
00163 OpenTissue::geometry::compute_tetrahedron_aabb(tetrahedra[n],min_coord,max_coord);
00164
00165
00166 int k_min = boost::numeric_cast<int>(ceil( (min_coord(2) - min_z)/dz ));
00167 int k_max = boost::numeric_cast<int>(floor( (max_coord(2) - min_z)/dz ));
00168
00169 for(int k = k_min;k<=k_max;++k)
00170 {
00171 real_type z = k*dz + min_z;
00172
00173 int number_of_vertices = slicer.intersect(z,vertices);
00174
00175 if(number_of_vertices<3)
00176 continue;
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188 for(int m=0;m<number_of_vertices;++m)
00189 {
00190 vertices[m](0) = (vertices[m](0) - min_x)/dx;
00191 vertices[m](1) = (vertices[m](1) - min_y)/dy;
00192 }
00193
00194 int number_of_triangles = (number_of_vertices==3)? 1 : 2;
00195
00196 for(int c=1;c<=number_of_triangles;++c)
00197 {
00198 fragment_iterator pixel(vertices[0],vertices[c],vertices[c+1]);
00199 while(pixel())
00200 {
00201 int i = pixel.x();
00202 int j = pixel.y();
00203
00204 vector3_type p (
00205 i*dx + min_x
00206 , j*dy + min_y
00207 , k*dz + min_z
00208 );
00209
00210
00211
00212 real_type value = OpenTissue::geometry::compute_signed_distance_to_triangle( p, p_i, p_j, p_k, nv_i, nv_j, nv_k, ne_i, ne_j, ne_k);
00213
00214
00215 if(
00216 ( fabs(value) <= thickness )
00217 &&
00218 ( fabs(value) < fabs( phi(i,j,k) ) )
00219 )
00220 phi(i,j,k) = boost::numeric_cast<value_type>( value );
00221 ++pixel;
00222 }
00223 }
00224
00225 }
00226 }
00227 }
00228 }
00229
00230
00242 template<typename surface_mesh, typename grid_type>
00243 inline void t4_cpu_scan(
00244 surface_mesh & surface
00245 , double const & thickness
00246 , grid_type & phi
00247 , t4_cpu_unsigned const &
00248 )
00249 {
00250 using std::ceil;
00251 using std::floor;
00252 using std::fabs;
00253
00254 assert(thickness>0 || "t4_cpu_scan(): thickness was non-positive");
00255
00256 typedef typename surface_mesh::math_types math_types;
00257 typedef typename math_types::vector3_type vector3_type;
00258 typedef typename math_types::real_type real_type;
00259 typedef typename surface_mesh::face_iterator face_iterator;
00260 typedef typename surface_mesh::face_halfedge_circulator face_halfedge_circulator;
00261 typedef typename grid_type::value_type value_type;
00262
00263 typedef OpenTissue::geometry::ZTetrahedronSlicer<vector3_type> slicer_type;
00264 typedef OpenTissue::geometry::LocalTriangleFrame<vector3_type> local_frame_type;
00265 typedef OpenTissue::geometry::Tetrahedron<math_types> tetrahedron_type;
00266 typedef OpenTissue::scan_conversion::FragmentIterator<vector3_type> fragment_iterator;
00267
00268 local_frame_type local_frame;
00269 tetrahedron_type tetrahedra[5];
00270 vector3_type vertices[4];
00271
00272 real_type const min_x = phi.min_coord(0);
00273 real_type const min_y = phi.min_coord(1);
00274 real_type const min_z = phi.min_coord(2);
00275 real_type const max_x = phi.max_coord(0);
00276 real_type const max_y = phi.max_coord(1);
00277 real_type const max_z = phi.max_coord(2);
00278 real_type const dx = phi.dx();
00279 real_type const dy = phi.dy();
00280 real_type const dz = phi.dz();
00281
00282 mesh::compute_angle_weighted_vertex_normals(surface);
00283
00284 face_iterator end = surface.face_end();
00285 face_iterator face = surface.face_begin();
00286 for(;face!=end;++face)
00287 {
00288 assert(valency( *face )==3 || !"t4_cpu_scan(): Only triangular faces are supported!");
00289
00290 face_halfedge_circulator h(*face);
00291 vector3_type const & p_i = h->get_origin_iterator()->m_coord;
00292 ++h;
00293 vector3_type const & p_j = h->get_origin_iterator()->m_coord;
00294 ++h;
00295 vector3_type const & p_k = h->get_origin_iterator()->m_coord;
00296
00297 local_frame.init( p_i, p_j, p_k);
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 vector3_type c0 = local_frame.v0() - local_frame.unit_a()*thickness - local_frame.n()*thickness - local_frame.unit_h()*thickness;
00310 vector3_type c1 = local_frame.v1() + local_frame.unit_a()*thickness - local_frame.n()*thickness - local_frame.unit_h()*thickness;
00311 vector3_type c2 = local_frame.v0() - local_frame.unit_a()*thickness + local_frame.n()*thickness - local_frame.unit_h()*thickness;
00312 vector3_type c3 = local_frame.v1() + local_frame.unit_a()*thickness + local_frame.n()*thickness - local_frame.unit_h()*thickness;
00313 vector3_type c4 = local_frame.v0() - local_frame.unit_a()*thickness - local_frame.n()*thickness + local_frame.unit_h()*(thickness+local_frame.h());
00314 vector3_type c5 = local_frame.v1() + local_frame.unit_a()*thickness - local_frame.n()*thickness + local_frame.unit_h()*(thickness+local_frame.h());
00315 vector3_type c6 = local_frame.v0() - local_frame.unit_a()*thickness + local_frame.n()*thickness + local_frame.unit_h()*(thickness+local_frame.h());
00316 vector3_type c7 = local_frame.v1() + local_frame.unit_a()*thickness + local_frame.n()*thickness + local_frame.unit_h()*(thickness+local_frame.h());
00317
00318 tetrahedra[0].set( c0, c4, c5, c6 );
00319 tetrahedra[1].set( c0, c5, c1, c3 );
00320 tetrahedra[2].set( c6, c2, c3, c0 );
00321 tetrahedra[3].set( c7, c6, c3, c5 );
00322 tetrahedra[4].set( c6, c5, c0, c3 );
00323
00324 for(int n=0;n<5;++n)
00325 {
00326 slicer_type slicer(
00327 tetrahedra[n].p0()
00328 , tetrahedra[n].p1()
00329 , tetrahedra[n].p2()
00330 , tetrahedra[n].p3()
00331 );
00332
00333 vector3_type min_coord;
00334 vector3_type max_coord;
00335 compute_tetrahedron_aabb(tetrahedra[n],min_coord,max_coord);
00336
00337
00338 int k_min = boost::numeric_cast<int>(ceil( (min_coord(2) - min_z)/dz ));
00339 int k_max = boost::numeric_cast<int>(floor( (max_coord(2) - min_z)/dz ));
00340
00341 for(int k = k_min;k<=k_max;++k)
00342 {
00343 real_type z = k*dz + min_z;
00344
00345 int number_of_vertices = slicer.intersect(z,vertices);
00346
00347 if(number_of_vertices<3)
00348 continue;
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 for(int m=0;m<number_of_vertices;++m)
00361 {
00362 vertices[m](0) = (vertices[m](0) - min_x)/dx;
00363 vertices[m](1) = (vertices[m](1) - min_y)/dy;
00364 }
00365
00366 int number_of_triangles = (number_of_vertices==3)? 1 : 2;
00367
00368 for(int c=1;c<=number_of_triangles;++c)
00369 {
00370 fragment_iterator pixel(vertices[0],vertices[c],vertices[c+1]);
00371 while(pixel())
00372 {
00373 int i = pixel.x();
00374 int j = pixel.y();
00375
00376 vector3_type p (
00377 i*dx + min_x
00378 , j*dy + min_y
00379 , k*dz + min_z
00380 );
00381
00382
00383 real_type value = OpenTissue::geometry::compute_distance_to_triangle(p,p_i,p_j,p_k);
00384
00385
00386 if(
00387 ( value <= thickness ) && ( value < phi(i,j,k) )
00388 )
00389 phi(i,j,k) = boost::numeric_cast<value_type>( value );
00390 ++pixel;
00391 }
00392 }
00393
00394 }
00395 }
00396 }
00397 }
00398
00399 }
00400
00401
00402 #endif